mirror of
https://github.com/Z3Prover/z3
synced 2025-04-10 19:27:06 +00:00
Merge branch 'opt' of https://git01.codeplex.com/z3 into opt
This commit is contained in:
commit
1f7c994e43
452
examples/interp/iz3.cpp
Executable file
452
examples/interp/iz3.cpp
Executable file
|
@ -0,0 +1,452 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "z3.h"
|
||||
|
||||
|
||||
|
||||
int usage(const char **argv){
|
||||
std::cerr << "usage: " << argv[0] << " [options] file.smt" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "options:" << std::endl;
|
||||
std::cerr << " -t,--tree tree interpolation" << std::endl;
|
||||
std::cerr << " -c,--check check result" << std::endl;
|
||||
std::cerr << " -p,--profile profile execution" << std::endl;
|
||||
std::cerr << " -w,--weak weak interpolants" << std::endl;
|
||||
std::cerr << " -f,--flat ouput flat formulas" << std::endl;
|
||||
std::cerr << " -o <file> ouput to SMT-LIB file" << std::endl;
|
||||
std::cerr << " -a,--anon anonymize" << std::endl;
|
||||
std::cerr << " -s,--simple simple proof mode" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
|
||||
bool tree_mode = false;
|
||||
bool check_mode = false;
|
||||
bool profile_mode = false;
|
||||
bool incremental_mode = false;
|
||||
std::string output_file;
|
||||
bool flat_mode = false;
|
||||
bool anonymize = false;
|
||||
bool write = false;
|
||||
|
||||
Z3_config cfg = Z3_mk_config();
|
||||
// Z3_interpolation_options options = Z3_mk_interpolation_options();
|
||||
Z3_params options = 0;
|
||||
|
||||
/* Parse the command line */
|
||||
int argn = 1;
|
||||
while(argn < argc-1){
|
||||
std::string flag = argv[argn];
|
||||
if(flag[0] == '-'){
|
||||
if(flag == "-t" || flag == "--tree")
|
||||
tree_mode = true;
|
||||
else if(flag == "-c" || flag == "--check")
|
||||
check_mode = true;
|
||||
else if(flag == "-p" || flag == "--profile")
|
||||
profile_mode = true;
|
||||
#if 0
|
||||
else if(flag == "-w" || flag == "--weak")
|
||||
Z3_set_interpolation_option(options,"weak","1");
|
||||
else if(flag == "--secondary")
|
||||
Z3_set_interpolation_option(options,"secondary","1");
|
||||
#endif
|
||||
else if(flag == "-i" || flag == "--incremental")
|
||||
incremental_mode = true;
|
||||
else if(flag == "-o"){
|
||||
argn++;
|
||||
if(argn >= argc) return usage(argv);
|
||||
output_file = argv[argn];
|
||||
}
|
||||
else if(flag == "-f" || flag == "--flat")
|
||||
flat_mode = true;
|
||||
else if(flag == "-a" || flag == "--anon")
|
||||
anonymize = true;
|
||||
else if(flag == "-w" || flag == "--write")
|
||||
write = true;
|
||||
else if(flag == "-s" || flag == "--simple")
|
||||
Z3_set_param_value(cfg,"PREPROCESS","false");
|
||||
else
|
||||
return usage(argv);
|
||||
}
|
||||
argn++;
|
||||
}
|
||||
if(argn != argc-1)
|
||||
return usage(argv);
|
||||
const char *filename = argv[argn];
|
||||
|
||||
|
||||
/* Create a Z3 context to contain formulas */
|
||||
Z3_context ctx = Z3_mk_interpolation_context(cfg);
|
||||
|
||||
if(write || anonymize)
|
||||
Z3_set_ast_print_mode(ctx,Z3_PRINT_SMTLIB2_COMPLIANT);
|
||||
else if(!flat_mode)
|
||||
Z3_set_ast_print_mode(ctx,Z3_PRINT_SMTLIB_COMPLIANT);
|
||||
|
||||
/* Read an interpolation problem */
|
||||
|
||||
int num;
|
||||
Z3_ast *constraints;
|
||||
int *parents = 0;
|
||||
const char *error;
|
||||
bool ok;
|
||||
int num_theory;
|
||||
Z3_ast *theory;
|
||||
|
||||
ok = Z3_read_interpolation_problem(ctx, &num, &constraints, tree_mode ? &parents : 0, filename, &error, &num_theory, &theory);
|
||||
|
||||
/* If parse failed, print the error message */
|
||||
|
||||
if(!ok){
|
||||
std::cerr << error << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* if we get only one formula, and it is a conjunction, split it into conjuncts. */
|
||||
if(!tree_mode && num == 1){
|
||||
Z3_app app = Z3_to_app(ctx,constraints[0]);
|
||||
Z3_func_decl func = Z3_get_app_decl(ctx,app);
|
||||
Z3_decl_kind dk = Z3_get_decl_kind(ctx,func);
|
||||
if(dk == Z3_OP_AND){
|
||||
int nconjs = Z3_get_app_num_args(ctx,app);
|
||||
if(nconjs > 1){
|
||||
std::cout << "Splitting formula into " << nconjs << " conjuncts...\n";
|
||||
num = nconjs;
|
||||
constraints = new Z3_ast[num];
|
||||
for(int k = 0; k < num; k++)
|
||||
constraints[k] = Z3_get_app_arg(ctx,app,k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Write out anonymized version. */
|
||||
|
||||
if(write || anonymize){
|
||||
#if 0
|
||||
Z3_anonymize_ast_vector(ctx,num,constraints);
|
||||
#endif
|
||||
std::string ofn = output_file.empty() ? "iz3out.smt2" : output_file;
|
||||
Z3_write_interpolation_problem(ctx, num, constraints, parents, ofn.c_str(), num_theory, theory);
|
||||
std::cout << "anonymized problem written to " << ofn << "\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Compute an interpolant, or get a model. */
|
||||
|
||||
Z3_ast *interpolants = (Z3_ast *)malloc((num-1) * sizeof(Z3_ast));
|
||||
Z3_model model = 0;
|
||||
Z3_lbool result;
|
||||
|
||||
if(!incremental_mode){
|
||||
/* In non-incremental mode, we just pass the constraints. */
|
||||
result = Z3_interpolate(ctx, num, constraints, (unsigned int *)parents, options, interpolants, &model, 0, false, num_theory, theory);
|
||||
}
|
||||
else {
|
||||
|
||||
/* This is a somewhat useless demonstration of incremental mode.
|
||||
Here, we assert the constraints in the context, then pass them to
|
||||
iZ3 in an array, so iZ3 knows the sequence. Note it's safe to pass
|
||||
"true", even though we haven't techically asserted if. */
|
||||
|
||||
Z3_push(ctx);
|
||||
std::vector<Z3_ast> asserted(num);
|
||||
|
||||
/* We start with nothing asserted. */
|
||||
for(int i = 0; i < num; i++)
|
||||
asserted[i] = Z3_mk_true(ctx);
|
||||
|
||||
/* Now we assert the constrints one at a time until UNSAT. */
|
||||
|
||||
for(int i = 0; i < num; i++){
|
||||
asserted[i] = constraints[i];
|
||||
Z3_assert_cnstr(ctx,constraints[i]); // assert one constraint
|
||||
result = Z3_interpolate(ctx, num, &asserted[0], (unsigned int *)parents, options, interpolants, &model, 0, true, 0, 0);
|
||||
if(result == Z3_L_FALSE){
|
||||
for(unsigned j = 0; j < num-1; j++)
|
||||
/* Since we want the interpolant formulas to survive a "pop", we
|
||||
"persist" them here. */
|
||||
Z3_persist_ast(ctx,interpolants[j],1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Z3_pop(ctx,1);
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
|
||||
/* If UNSAT, print the interpolants */
|
||||
case Z3_L_FALSE:
|
||||
printf("unsat\n");
|
||||
if(output_file.empty()){
|
||||
printf("interpolant:\n");
|
||||
for(int i = 0; i < num-1; i++)
|
||||
printf("%s\n", Z3_ast_to_string(ctx, interpolants[i]));
|
||||
}
|
||||
else {
|
||||
#if 0
|
||||
Z3_write_interpolation_problem(ctx,num-1,interpolants,0,output_file.c_str());
|
||||
printf("interpolant written to %s\n",output_file.c_str());
|
||||
#endif
|
||||
}
|
||||
#if 1
|
||||
if(check_mode){
|
||||
std::cout << "Checking interpolant...\n";
|
||||
bool chk;
|
||||
chk = Z3_check_interpolant(ctx,num,constraints,parents,interpolants,&error,num_theory,theory);
|
||||
if(chk)
|
||||
std::cout << "Interpolant is correct\n";
|
||||
else {
|
||||
std::cout << "Interpolant is incorrect\n";
|
||||
std::cout << error;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case Z3_L_UNDEF:
|
||||
printf("fail\n");
|
||||
break;
|
||||
case Z3_L_TRUE:
|
||||
printf("sat\n");
|
||||
printf("model:\n%s\n", Z3_model_to_string(ctx, model));
|
||||
break;
|
||||
}
|
||||
|
||||
if(profile_mode)
|
||||
std::cout << Z3_interpolation_profile(ctx);
|
||||
|
||||
/* Delete the model if there is one */
|
||||
|
||||
if (model)
|
||||
Z3_del_model(ctx, model);
|
||||
|
||||
/* Delete logical context. */
|
||||
|
||||
Z3_del_context(ctx);
|
||||
free(interpolants);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
|
||||
int test(){
|
||||
int i;
|
||||
|
||||
/* Create a Z3 context to contain formulas */
|
||||
|
||||
Z3_config cfg = Z3_mk_config();
|
||||
Z3_context ctx = iz3_mk_context(cfg);
|
||||
|
||||
int num = 2;
|
||||
|
||||
Z3_ast *constraints = (Z3_ast *)malloc(num * sizeof(Z3_ast));
|
||||
|
||||
#if 1
|
||||
Z3_sort arr = Z3_mk_array_sort(ctx,Z3_mk_int_sort(ctx),Z3_mk_bool_sort(ctx));
|
||||
Z3_symbol as = Z3_mk_string_symbol(ctx, "a");
|
||||
Z3_symbol bs = Z3_mk_string_symbol(ctx, "b");
|
||||
Z3_symbol xs = Z3_mk_string_symbol(ctx, "x");
|
||||
|
||||
Z3_ast a = Z3_mk_const(ctx,as,arr);
|
||||
Z3_ast b = Z3_mk_const(ctx,bs,arr);
|
||||
Z3_ast x = Z3_mk_const(ctx,xs,Z3_mk_int_sort(ctx));
|
||||
|
||||
Z3_ast c1 = Z3_mk_eq(ctx,a,Z3_mk_store(ctx,b,x,Z3_mk_true(ctx)));
|
||||
Z3_ast c2 = Z3_mk_not(ctx,Z3_mk_select(ctx,a,x));
|
||||
#else
|
||||
Z3_symbol xs = Z3_mk_string_symbol(ctx, "x");
|
||||
Z3_ast x = Z3_mk_const(ctx,xs,Z3_mk_bool_sort(ctx));
|
||||
Z3_ast c1 = Z3_mk_eq(ctx,x,Z3_mk_true(ctx));
|
||||
Z3_ast c2 = Z3_mk_eq(ctx,x,Z3_mk_false(ctx));
|
||||
|
||||
#endif
|
||||
|
||||
constraints[0] = c1;
|
||||
constraints[1] = c2;
|
||||
|
||||
/* print out the result for grins. */
|
||||
|
||||
// Z3_string smtout = Z3_benchmark_to_smtlib_string (ctx, "foo", "QFLIA", "sat", "", num, constraints, Z3_mk_true(ctx));
|
||||
|
||||
// Z3_string smtout = Z3_ast_to_string(ctx,constraints[0]);
|
||||
// Z3_string smtout = Z3_context_to_string(ctx);
|
||||
// puts(smtout);
|
||||
|
||||
iz3_print(ctx,num,constraints,"iZ3temp.smt");
|
||||
|
||||
/* Make room for interpolants. */
|
||||
|
||||
Z3_ast *interpolants = (Z3_ast *)malloc((num-1) * sizeof(Z3_ast));
|
||||
|
||||
/* Make room for the model. */
|
||||
|
||||
Z3_model model = 0;
|
||||
|
||||
/* Call the prover */
|
||||
|
||||
Z3_lbool result = iz3_interpolate(ctx, num, constraints, interpolants, &model);
|
||||
|
||||
switch (result) {
|
||||
|
||||
/* If UNSAT, print the interpolants */
|
||||
case Z3_L_FALSE:
|
||||
printf("unsat, interpolants:\n");
|
||||
for(i = 0; i < num-1; i++)
|
||||
printf("%s\n", Z3_ast_to_string(ctx, interpolants[i]));
|
||||
break;
|
||||
case Z3_L_UNDEF:
|
||||
printf("fail\n");
|
||||
break;
|
||||
case Z3_L_TRUE:
|
||||
printf("sat\n");
|
||||
printf("model:\n%s\n", Z3_model_to_string(ctx, model));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Delete the model if there is one */
|
||||
|
||||
if (model)
|
||||
Z3_del_model(ctx, model);
|
||||
|
||||
/* Delete logical context (note, we call iz3_del_context, not
|
||||
Z3_del_context */
|
||||
|
||||
iz3_del_context(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct z3_error {
|
||||
Z3_error_code c;
|
||||
z3_error(Z3_error_code _c) : c(_c) {}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
static void throw_z3_error(Z3_error_code c){
|
||||
throw z3_error(c);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
|
||||
/* Create a Z3 context to contain formulas */
|
||||
|
||||
Z3_config cfg = Z3_mk_config();
|
||||
Z3_context ctx = iz3_mk_context(cfg);
|
||||
Z3_set_error_handler(ctx, throw_z3_error);
|
||||
|
||||
/* Make some constraints, by parsing an smtlib formatted file given as arg 1 */
|
||||
|
||||
try {
|
||||
Z3_parse_smtlib_file(ctx, argv[1], 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
catch(const z3_error &err){
|
||||
std::cerr << "Z3 error: " << Z3_get_error_msg(err.c) << "\n";
|
||||
std::cerr << Z3_get_smtlib_error(ctx) << "\n";
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Get the constraints from the parser. */
|
||||
|
||||
int num = Z3_get_smtlib_num_formulas(ctx);
|
||||
|
||||
if(num == 0){
|
||||
std::cerr << "iZ3 error: File contains no formulas.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Z3_ast *constraints = (Z3_ast *)malloc(num * sizeof(Z3_ast));
|
||||
|
||||
int i;
|
||||
for (i = 0; i < num; i++)
|
||||
constraints[i] = Z3_get_smtlib_formula(ctx, i);
|
||||
|
||||
/* if we get only one formula, and it is a conjunction, split it into conjuncts. */
|
||||
if(num == 1){
|
||||
Z3_app app = Z3_to_app(ctx,constraints[0]);
|
||||
Z3_func_decl func = Z3_get_app_decl(ctx,app);
|
||||
Z3_decl_kind dk = Z3_get_decl_kind(ctx,func);
|
||||
if(dk == Z3_OP_AND){
|
||||
int nconjs = Z3_get_app_num_args(ctx,app);
|
||||
if(nconjs > 1){
|
||||
std::cout << "Splitting formula into " << nconjs << " conjuncts...\n";
|
||||
num = nconjs;
|
||||
constraints = new Z3_ast[num];
|
||||
for(int k = 0; k < num; k++)
|
||||
constraints[k] = Z3_get_app_arg(ctx,app,k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* print out the result for grins. */
|
||||
|
||||
// Z3_string smtout = Z3_benchmark_to_smtlib_string (ctx, "foo", "QFLIA", "sat", "", num, constraints, Z3_mk_true(ctx));
|
||||
|
||||
// Z3_string smtout = Z3_ast_to_string(ctx,constraints[0]);
|
||||
// Z3_string smtout = Z3_context_to_string(ctx);
|
||||
// puts(smtout);
|
||||
|
||||
// iz3_print(ctx,num,constraints,"iZ3temp.smt");
|
||||
|
||||
/* Make room for interpolants. */
|
||||
|
||||
Z3_ast *interpolants = (Z3_ast *)malloc((num-1) * sizeof(Z3_ast));
|
||||
|
||||
/* Make room for the model. */
|
||||
|
||||
Z3_model model = 0;
|
||||
|
||||
/* Call the prover */
|
||||
|
||||
Z3_lbool result = iz3_interpolate(ctx, num, constraints, interpolants, &model);
|
||||
|
||||
switch (result) {
|
||||
|
||||
/* If UNSAT, print the interpolants */
|
||||
case Z3_L_FALSE:
|
||||
printf("unsat, interpolants:\n");
|
||||
for(i = 0; i < num-1; i++)
|
||||
printf("%s\n", Z3_ast_to_string(ctx, interpolants[i]));
|
||||
std::cout << "Checking interpolants...\n";
|
||||
const char *error;
|
||||
if(iZ3_check_interpolant(ctx, num, constraints, 0, interpolants, &error))
|
||||
std::cout << "Interpolant is correct\n";
|
||||
else {
|
||||
std::cout << "Interpolant is incorrect\n";
|
||||
std::cout << error << "\n";
|
||||
}
|
||||
break;
|
||||
case Z3_L_UNDEF:
|
||||
printf("fail\n");
|
||||
break;
|
||||
case Z3_L_TRUE:
|
||||
printf("sat\n");
|
||||
printf("model:\n%s\n", Z3_model_to_string(ctx, model));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Delete the model if there is one */
|
||||
|
||||
if (model)
|
||||
Z3_del_model(ctx, model);
|
||||
|
||||
/* Delete logical context (note, we call iz3_del_context, not
|
||||
Z3_del_context */
|
||||
|
||||
iz3_del_context(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -34,7 +34,8 @@ def init_project_def():
|
|||
add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic')
|
||||
add_lib('aig_tactic', ['tactic'], 'tactic/aig')
|
||||
add_lib('solver', ['model', 'tactic'])
|
||||
add_lib('cmd_context', ['solver', 'rewriter'])
|
||||
add_lib('interp', ['solver'])
|
||||
add_lib('cmd_context', ['solver', 'rewriter', 'interp'])
|
||||
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('proof_checker', ['rewriter'], 'ast/proof_checker')
|
||||
|
@ -55,6 +56,7 @@ def init_project_def():
|
|||
add_lib('smt_tactic', ['smt'], 'smt/tactic')
|
||||
add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls')
|
||||
add_lib('qe', ['smt','sat'], 'qe')
|
||||
add_lib('duality', ['smt', 'interp', 'qe'])
|
||||
add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base')
|
||||
add_lib('transforms', ['muz', 'hilbert'], 'muz/transforms')
|
||||
add_lib('rel', ['muz', 'transforms'], 'muz/rel')
|
||||
|
@ -62,14 +64,15 @@ def init_project_def():
|
|||
add_lib('clp', ['muz', 'transforms'], 'muz/clp')
|
||||
add_lib('tab', ['muz', 'transforms'], 'muz/tab')
|
||||
add_lib('bmc', ['muz', 'transforms'], 'muz/bmc')
|
||||
add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc'], 'muz/fp')
|
||||
add_lib('duality_intf', ['muz', 'transforms', 'duality'], 'muz/duality')
|
||||
add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf'], 'muz/fp')
|
||||
add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics')
|
||||
add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv')
|
||||
add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio')
|
||||
add_lib('smtparser', ['portfolio'], 'parsers/smt')
|
||||
add_lib('opt', ['smt', 'smtlogic_tactics'], 'opt')
|
||||
API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h']
|
||||
add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure','opt'],
|
||||
add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure','interp','opt'],
|
||||
includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files)
|
||||
add_exe('shell', ['api', 'sat', 'extra_cmds','opt'], exe_name='z3')
|
||||
add_exe('test', ['api', 'fuzzing'], exe_name='test-z3', install=False)
|
||||
|
@ -84,6 +87,7 @@ def init_project_def():
|
|||
set_z3py_dir('api/python')
|
||||
# Examples
|
||||
add_cpp_example('cpp_example', 'c++')
|
||||
add_cpp_example('iz3', 'interp')
|
||||
add_cpp_example('z3_tptp', 'tptp')
|
||||
add_c_example('c_example', 'c')
|
||||
add_c_example('maxsat')
|
||||
|
|
|
@ -29,6 +29,7 @@ CXX=getenv("CXX", None)
|
|||
CC=getenv("CC", None)
|
||||
CPPFLAGS=getenv("CPPFLAGS", "")
|
||||
CXXFLAGS=getenv("CXXFLAGS", "")
|
||||
EXAMP_DEBUG_FLAG=''
|
||||
LDFLAGS=getenv("LDFLAGS", "")
|
||||
JNI_HOME=getenv("JNI_HOME", None)
|
||||
|
||||
|
@ -70,6 +71,8 @@ VER_BUILD=None
|
|||
VER_REVISION=None
|
||||
PREFIX=os.path.split(os.path.split(os.path.split(PYTHON_PACKAGE_DIR)[0])[0])[0]
|
||||
GMP=False
|
||||
FOCI2=False
|
||||
FOCI2LIB=''
|
||||
VS_PAR=False
|
||||
VS_PAR_NUM=8
|
||||
GPROF=False
|
||||
|
@ -198,6 +201,14 @@ def test_gmp(cc):
|
|||
t.commit()
|
||||
return exec_compiler_cmd([cc, CPPFLAGS, 'tstgmp.cpp', LDFLAGS, '-lgmp']) == 0
|
||||
|
||||
def test_foci2(cc,foci2lib):
|
||||
if is_verbose():
|
||||
print("Testing FOCI2...")
|
||||
t = TempFile('tstfoci2.cpp')
|
||||
t.add('#include<foci2.h>\nint main() { foci2 *f = foci2::create("lia"); return 0; }\n')
|
||||
t.commit()
|
||||
return exec_compiler_cmd([cc, CPPFLAGS, '-Isrc/interp', 'tstfoci2.cpp', LDFLAGS, foci2lib]) == 0
|
||||
|
||||
def test_openmp(cc):
|
||||
if is_verbose():
|
||||
print("Testing OpenMP...")
|
||||
|
@ -443,6 +454,7 @@ def display_help(exit_code):
|
|||
if not IS_WINDOWS:
|
||||
print(" -g, --gmp use GMP.")
|
||||
print(" --gprof enable gprof")
|
||||
print(" -f <path> --foci2=<path> use foci2 library at path")
|
||||
print("")
|
||||
print("Some influential environment variables:")
|
||||
if not IS_WINDOWS:
|
||||
|
@ -458,18 +470,19 @@ def display_help(exit_code):
|
|||
# Parse configuration option for mk_make script
|
||||
def parse_options():
|
||||
global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM
|
||||
global DOTNET_ENABLED, JAVA_ENABLED, STATIC_LIB, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH
|
||||
global DOTNET_ENABLED, JAVA_ENABLED, STATIC_LIB, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH
|
||||
try:
|
||||
options, remainder = getopt.gnu_getopt(sys.argv[1:],
|
||||
'b:dsxhmcvtnp:gj',
|
||||
'b:df:sxhmcvtnp:gj',
|
||||
['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj',
|
||||
'trace', 'nodotnet', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof',
|
||||
'trace', 'nodotnet', 'staticlib', 'prefix=', 'gmp', 'foci2=', 'java', 'parallel=', 'gprof',
|
||||
'githash='])
|
||||
except:
|
||||
print("ERROR: Invalid command line option")
|
||||
display_help(1)
|
||||
|
||||
for opt, arg in options:
|
||||
print('opt = %s, arg = %s' % (opt, arg))
|
||||
if opt in ('-b', '--build'):
|
||||
if arg == 'src':
|
||||
raise MKException('The src directory should not be used to host the Makefile')
|
||||
|
@ -507,6 +520,9 @@ def parse_options():
|
|||
VS_PAR_NUM = int(arg)
|
||||
elif opt in ('-g', '--gmp'):
|
||||
GMP = True
|
||||
elif opt in ('-f', '--foci2'):
|
||||
FOCI2 = True
|
||||
FOCI2LIB = arg
|
||||
elif opt in ('-j', '--java'):
|
||||
JAVA_ENABLED = True
|
||||
elif opt == '--gprof':
|
||||
|
@ -665,6 +681,10 @@ class Component:
|
|||
self.src_dir = os.path.join(SRC_DIR, path)
|
||||
self.to_src_dir = os.path.join(REV_BUILD_DIR, self.src_dir)
|
||||
|
||||
def get_link_name(self):
|
||||
return os.path.join(self.build_dir, self.name) + '$(LIB_EXT)'
|
||||
|
||||
|
||||
# Find fname in the include paths for the given component.
|
||||
# ownerfile is only used for creating error messages.
|
||||
# That is, we were looking for fname when processing ownerfile
|
||||
|
@ -880,7 +900,7 @@ class ExeComponent(Component):
|
|||
out.write(obj)
|
||||
for dep in deps:
|
||||
c_dep = get_component(dep)
|
||||
out.write(' %s$(LIB_EXT)' % os.path.join(c_dep.build_dir, c_dep.name))
|
||||
out.write(' ' + c_dep.get_link_name())
|
||||
out.write('\n')
|
||||
out.write('\t$(LINK) $(LINK_OUT_FLAG)%s $(LINK_FLAGS)' % exefile)
|
||||
for obj in objs:
|
||||
|
@ -888,7 +908,8 @@ class ExeComponent(Component):
|
|||
out.write(obj)
|
||||
for dep in deps:
|
||||
c_dep = get_component(dep)
|
||||
out.write(' %s$(LIB_EXT)' % os.path.join(c_dep.build_dir, c_dep.name))
|
||||
out.write(' ' + c_dep.get_link_name())
|
||||
out.write(' ' + FOCI2LIB)
|
||||
out.write(' $(LINK_EXTRA_FLAGS)\n')
|
||||
out.write('%s: %s\n\n' % (self.name, exefile))
|
||||
|
||||
|
@ -957,6 +978,12 @@ class DLLComponent(Component):
|
|||
self.install = install
|
||||
self.static = static
|
||||
|
||||
def get_link_name(self):
|
||||
if self.static:
|
||||
return os.path.join(self.build_dir, self.name) + '$(LIB_EXT)'
|
||||
else:
|
||||
return self.name + '$(SO_EXT)'
|
||||
|
||||
def mk_makefile(self, out):
|
||||
Component.mk_makefile(self, out)
|
||||
# generate rule for (SO_EXT)
|
||||
|
@ -979,7 +1006,7 @@ class DLLComponent(Component):
|
|||
for dep in deps:
|
||||
if not dep in self.reexports:
|
||||
c_dep = get_component(dep)
|
||||
out.write(' %s$(LIB_EXT)' % os.path.join(c_dep.build_dir, c_dep.name))
|
||||
out.write(' ' + c_dep.get_link_name())
|
||||
out.write('\n')
|
||||
out.write('\t$(LINK) $(SLINK_OUT_FLAG)%s $(SLINK_FLAGS)' % dllfile)
|
||||
for obj in objs:
|
||||
|
@ -988,7 +1015,8 @@ class DLLComponent(Component):
|
|||
for dep in deps:
|
||||
if not dep in self.reexports:
|
||||
c_dep = get_component(dep)
|
||||
out.write(' %s$(LIB_EXT)' % os.path.join(c_dep.build_dir, c_dep.name))
|
||||
out.write(' ' + c_dep.get_link_name())
|
||||
out.write(' ' + FOCI2LIB)
|
||||
out.write(' $(SLINK_EXTRA_FLAGS)')
|
||||
if IS_WINDOWS:
|
||||
out.write(' /DEF:%s.def' % os.path.join(self.to_src_dir, self.name))
|
||||
|
@ -1230,7 +1258,7 @@ class CppExampleComponent(ExampleComponent):
|
|||
out.write(' ')
|
||||
out.write(os.path.join(self.to_ex_dir, cppfile))
|
||||
out.write('\n')
|
||||
out.write('\t%s $(OS_DEFINES) $(LINK_OUT_FLAG)%s $(LINK_FLAGS)' % (self.compiler(), exefile))
|
||||
out.write('\t%s $(OS_DEFINES) $(EXAMP_DEBUG_FLAG) $(LINK_OUT_FLAG)%s $(LINK_FLAGS)' % (self.compiler(), exefile))
|
||||
# Add include dir components
|
||||
out.write(' -I%s' % get_component(API_COMPONENT).to_src_dir)
|
||||
out.write(' -I%s' % get_component(CPP_COMPONENT).to_src_dir)
|
||||
|
@ -1450,7 +1478,7 @@ def mk_config():
|
|||
print('JNI Bindings: %s' % JNI_HOME)
|
||||
print('Java Compiler: %s' % JAVAC)
|
||||
else:
|
||||
global CXX, CC, GMP, CPPFLAGS, CXXFLAGS, LDFLAGS
|
||||
global CXX, CC, GMP, FOCI2, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG
|
||||
OS_DEFINES = ""
|
||||
ARITH = "internal"
|
||||
check_ar()
|
||||
|
@ -1468,6 +1496,14 @@ def mk_config():
|
|||
SLIBEXTRAFLAGS = '%s -lgmp' % SLIBEXTRAFLAGS
|
||||
else:
|
||||
CPPFLAGS = '%s -D_MP_INTERNAL' % CPPFLAGS
|
||||
if FOCI2:
|
||||
if test_foci2(CXX,FOCI2LIB):
|
||||
LDFLAGS = '%s %s' % (LDFLAGS,FOCI2LIB)
|
||||
SLIBEXTRAFLAGS = '%s %s' % (SLIBEXTRAFLAGS,FOCI2LIB)
|
||||
CPPFLAGS = '%s -D_FOCI2' % CPPFLAGS
|
||||
else:
|
||||
print "FAILED\n"
|
||||
FOCI2 = False
|
||||
if GIT_HASH:
|
||||
CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH)
|
||||
CXXFLAGS = '%s -c' % CXXFLAGS
|
||||
|
@ -1480,6 +1516,7 @@ def mk_config():
|
|||
CXXFLAGS = '%s -D_NO_OMP_' % CXXFLAGS
|
||||
if DEBUG_MODE:
|
||||
CXXFLAGS = '%s -g -Wall' % CXXFLAGS
|
||||
EXAMP_DEBUG_FLAG = '-g'
|
||||
else:
|
||||
if GPROF:
|
||||
CXXFLAGS = '%s -O3 -D _EXTERNAL_RELEASE' % CXXFLAGS
|
||||
|
@ -1526,6 +1563,7 @@ def mk_config():
|
|||
config.write('CC=%s\n' % CC)
|
||||
config.write('CXX=%s\n' % CXX)
|
||||
config.write('CXXFLAGS=%s %s\n' % (CPPFLAGS, CXXFLAGS))
|
||||
config.write('EXAMP_DEBUG_FLAG=%s\n' % EXAMP_DEBUG_FLAG)
|
||||
config.write('CXX_OUT_FLAG=-o \n')
|
||||
config.write('OBJ_EXT=.o\n')
|
||||
config.write('LIB_EXT=.a\n')
|
||||
|
|
|
@ -209,6 +209,7 @@ extern "C" {
|
|||
MK_BINARY(Z3_mk_xor, mk_c(c)->get_basic_fid(), OP_XOR, SKIP);
|
||||
MK_NARY(Z3_mk_and, mk_c(c)->get_basic_fid(), OP_AND, SKIP);
|
||||
MK_NARY(Z3_mk_or, mk_c(c)->get_basic_fid(), OP_OR, SKIP);
|
||||
MK_UNARY(Z3_mk_interp, mk_c(c)->get_basic_fid(), OP_INTERP, SKIP);
|
||||
|
||||
Z3_ast mk_ite_core(Z3_context c, Z3_ast t1, Z3_ast t2, Z3_ast t3) {
|
||||
expr * result = mk_c(c)->m().mk_ite(to_expr(t1), to_expr(t2), to_expr(t3));
|
||||
|
@ -923,6 +924,7 @@ extern "C" {
|
|||
case OP_NOT: return Z3_OP_NOT;
|
||||
case OP_IMPLIES: return Z3_OP_IMPLIES;
|
||||
case OP_OEQ: return Z3_OP_OEQ;
|
||||
case OP_INTERP: return Z3_OP_INTERP;
|
||||
|
||||
case PR_UNDEF: return Z3_OP_PR_UNDEF;
|
||||
case PR_TRUE: return Z3_OP_PR_TRUE;
|
||||
|
|
622
src/api/api_interp.cpp
Normal file
622
src/api/api_interp.cpp
Normal file
|
@ -0,0 +1,622 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
api_interp.cpp
|
||||
|
||||
Abstract:
|
||||
API for interpolation
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include<iostream>
|
||||
#include<sstream>
|
||||
#include"z3.h"
|
||||
#include"api_log_macros.h"
|
||||
#include"api_context.h"
|
||||
#include"api_tactic.h"
|
||||
#include"api_solver.h"
|
||||
#include"api_model.h"
|
||||
#include"api_stats.h"
|
||||
#include"api_ast_vector.h"
|
||||
#include"tactic2solver.h"
|
||||
#include"scoped_ctrl_c.h"
|
||||
#include"cancel_eh.h"
|
||||
#include"scoped_timer.h"
|
||||
#include"smt_strategic_solver.h"
|
||||
#include"smt_solver.h"
|
||||
#include"smt_implied_equalities.h"
|
||||
#include"iz3interp.h"
|
||||
#include"iz3profiling.h"
|
||||
#include"iz3hash.h"
|
||||
#include"iz3pp.h"
|
||||
#include"iz3checker.h"
|
||||
|
||||
#ifndef WIN32
|
||||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
// WARNING: don't make a hash_map with this if the range type
|
||||
// has a destructor: you'll get an address dependency!!!
|
||||
namespace stl_ext {
|
||||
template <>
|
||||
class hash<Z3_ast> {
|
||||
public:
|
||||
size_t operator()(const Z3_ast p) const {
|
||||
return (size_t) p;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef interpolation_options_struct *Z3_interpolation_options;
|
||||
|
||||
extern "C" {
|
||||
|
||||
Z3_context Z3_mk_interpolation_context(Z3_config cfg){
|
||||
if(!cfg) cfg = Z3_mk_config();
|
||||
Z3_set_param_value(cfg, "PROOF", "true");
|
||||
Z3_set_param_value(cfg, "MODEL", "true");
|
||||
// Z3_set_param_value(cfg, "PRE_SIMPLIFIER","false");
|
||||
// Z3_set_param_value(cfg, "SIMPLIFY_CLAUSES","false");
|
||||
|
||||
Z3_context ctx = Z3_mk_context(cfg);
|
||||
Z3_del_config(cfg);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void Z3_interpolate_proof(Z3_context ctx,
|
||||
Z3_ast proof,
|
||||
int num,
|
||||
Z3_ast *cnsts,
|
||||
unsigned *parents,
|
||||
Z3_params options,
|
||||
Z3_ast *interps,
|
||||
int num_theory,
|
||||
Z3_ast *theory
|
||||
){
|
||||
|
||||
if(num > 1){ // if we have interpolants to compute
|
||||
|
||||
ptr_vector<ast> pre_cnsts_vec(num); // get constraints in a vector
|
||||
for(int i = 0; i < num; i++){
|
||||
ast *a = to_ast(cnsts[i]);
|
||||
pre_cnsts_vec[i] = a;
|
||||
}
|
||||
|
||||
::vector<int> pre_parents_vec; // get parents in a vector
|
||||
if(parents){
|
||||
pre_parents_vec.resize(num);
|
||||
for(int i = 0; i < num; i++)
|
||||
pre_parents_vec[i] = parents[i];
|
||||
}
|
||||
|
||||
ptr_vector<ast> theory_vec; // get background theory in a vector
|
||||
if(theory){
|
||||
theory_vec.resize(num_theory);
|
||||
for(int i = 0; i < num_theory; i++)
|
||||
theory_vec[i] = to_ast(theory[i]);
|
||||
}
|
||||
|
||||
ptr_vector<ast> interpolants(num-1); // make space for result
|
||||
|
||||
ast_manager &_m = mk_c(ctx)->m();
|
||||
iz3interpolate(_m,
|
||||
to_ast(proof),
|
||||
pre_cnsts_vec,
|
||||
pre_parents_vec,
|
||||
interpolants,
|
||||
theory_vec,
|
||||
0); // ignore params for now FIXME
|
||||
|
||||
// copy result back
|
||||
for(unsigned i = 0; i < interpolants.size(); i++){
|
||||
mk_c(ctx)->save_ast_trail(interpolants[i]);
|
||||
interps[i] = of_ast(interpolants[i]);
|
||||
_m.dec_ref(interpolants[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Z3_lbool Z3_interpolate(Z3_context ctx,
|
||||
int num,
|
||||
Z3_ast *cnsts,
|
||||
unsigned *parents,
|
||||
Z3_params options,
|
||||
Z3_ast *interps,
|
||||
Z3_model *model,
|
||||
Z3_literals *labels,
|
||||
int incremental,
|
||||
int num_theory,
|
||||
Z3_ast *theory
|
||||
){
|
||||
|
||||
|
||||
profiling::timer_start("Solve");
|
||||
|
||||
if(!incremental){
|
||||
|
||||
profiling::timer_start("Z3 assert");
|
||||
|
||||
Z3_push(ctx); // so we can rewind later
|
||||
|
||||
for(int i = 0; i < num; i++)
|
||||
Z3_assert_cnstr(ctx,cnsts[i]); // assert all the constraints
|
||||
|
||||
if(theory){
|
||||
for(int i = 0; i < num_theory; i++)
|
||||
Z3_assert_cnstr(ctx,theory[i]);
|
||||
}
|
||||
|
||||
profiling::timer_stop("Z3 assert");
|
||||
}
|
||||
|
||||
|
||||
// Get a proof of unsat
|
||||
|
||||
Z3_ast proof;
|
||||
Z3_lbool result;
|
||||
|
||||
profiling::timer_start("Z3 solving");
|
||||
result = Z3_check_assumptions(ctx, 0, 0, model, &proof, 0, 0);
|
||||
profiling::timer_stop("Z3 solving");
|
||||
|
||||
switch (result) {
|
||||
case Z3_L_FALSE:
|
||||
|
||||
Z3_interpolate_proof(ctx,
|
||||
proof,
|
||||
num,
|
||||
cnsts,
|
||||
parents,
|
||||
options,
|
||||
interps,
|
||||
num_theory,
|
||||
theory);
|
||||
|
||||
if(!incremental)
|
||||
for(int i = 0; i < num-1; i++)
|
||||
Z3_persist_ast(ctx,interps[i],1);
|
||||
break;
|
||||
|
||||
case Z3_L_UNDEF:
|
||||
if(labels)
|
||||
*labels = Z3_get_relevant_labels(ctx);
|
||||
break;
|
||||
|
||||
case Z3_L_TRUE:
|
||||
if(labels)
|
||||
*labels = Z3_get_relevant_labels(ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
profiling::timer_start("Z3 pop");
|
||||
if(!incremental)
|
||||
Z3_pop(ctx,1);
|
||||
profiling::timer_stop("Z3 pop");
|
||||
|
||||
profiling::timer_stop("Solve");
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
static std::ostringstream itp_err;
|
||||
|
||||
int Z3_check_interpolant(Z3_context ctx,
|
||||
int num,
|
||||
Z3_ast *cnsts,
|
||||
int *parents,
|
||||
Z3_ast *itp,
|
||||
const char **error,
|
||||
int num_theory,
|
||||
Z3_ast *theory){
|
||||
|
||||
ast_manager &_m = mk_c(ctx)->m();
|
||||
itp_err.clear();
|
||||
|
||||
// need a solver -- make one here, but how?
|
||||
params_ref p = params_ref::get_empty(); //FIXME
|
||||
scoped_ptr<solver_factory> sf(mk_smt_solver_factory());
|
||||
scoped_ptr<solver> sp((*(sf))(_m, p, false, true, false, symbol("AUFLIA")));
|
||||
|
||||
ptr_vector<ast> cnsts_vec(num); // get constraints in a vector
|
||||
for(int i = 0; i < num; i++){
|
||||
ast *a = to_ast(cnsts[i]);
|
||||
cnsts_vec[i] = a;
|
||||
}
|
||||
|
||||
ptr_vector<ast> itp_vec(num); // get interpolants in a vector
|
||||
for(int i = 0; i < num-1; i++){
|
||||
ast *a = to_ast(itp[i]);
|
||||
itp_vec[i] = a;
|
||||
}
|
||||
|
||||
::vector<int> parents_vec; // get parents in a vector
|
||||
if(parents){
|
||||
parents_vec.resize(num);
|
||||
for(int i = 0; i < num; i++)
|
||||
parents_vec[i] = parents[i];
|
||||
}
|
||||
|
||||
ptr_vector<ast> theory_vec; // get background theory in a vector
|
||||
if(theory){
|
||||
theory_vec.resize(num_theory);
|
||||
for(int i = 0; i < num_theory; i++)
|
||||
theory_vec[i] = to_ast(theory[i]);
|
||||
}
|
||||
|
||||
bool res = iz3check(_m,
|
||||
sp.get(),
|
||||
itp_err,
|
||||
cnsts_vec,
|
||||
parents_vec,
|
||||
itp_vec,
|
||||
theory_vec);
|
||||
|
||||
*error = res ? 0 : itp_err.str().c_str();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static std::string Z3_profile_string;
|
||||
|
||||
Z3_string Z3_interpolation_profile(Z3_context ctx){
|
||||
std::ostringstream f;
|
||||
profiling::print(f);
|
||||
Z3_profile_string = f.str();
|
||||
return Z3_profile_string.c_str();
|
||||
}
|
||||
|
||||
|
||||
Z3_interpolation_options
|
||||
Z3_mk_interpolation_options(){
|
||||
return (Z3_interpolation_options) new interpolation_options_struct;
|
||||
}
|
||||
|
||||
void
|
||||
Z3_del_interpolation_options(Z3_interpolation_options opts){
|
||||
delete opts;
|
||||
}
|
||||
|
||||
void
|
||||
Z3_set_interpolation_option(Z3_interpolation_options opts,
|
||||
Z3_string name,
|
||||
Z3_string value){
|
||||
opts->map[name] = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
static void tokenize(const std::string &str, std::vector<std::string> &tokens){
|
||||
for(unsigned i = 0; i < str.size();){
|
||||
if(str[i] == ' '){i++; continue;}
|
||||
unsigned beg = i;
|
||||
while(i < str.size() && str[i] != ' ')i++;
|
||||
if(i > beg)
|
||||
tokens.push_back(str.substr(beg,i-beg));
|
||||
}
|
||||
}
|
||||
|
||||
static void get_file_params(const char *filename, hash_map<std::string,std::string> ¶ms){
|
||||
std::ifstream f(filename);
|
||||
if(f){
|
||||
std::string first_line;
|
||||
std::getline(f,first_line);
|
||||
// std::cout << "first line: '" << first_line << "'" << std::endl;
|
||||
if(first_line.size() >= 2 && first_line[0] == ';' && first_line[1] == '!'){
|
||||
std::vector<std::string> tokens;
|
||||
tokenize(first_line.substr(2,first_line.size()-2),tokens);
|
||||
for(unsigned i = 0; i < tokens.size(); i++){
|
||||
std::string &tok = tokens[i];
|
||||
size_t eqpos = tok.find('=');
|
||||
if(eqpos >= 0 && eqpos < tok.size()){
|
||||
std::string left = tok.substr(0,eqpos);
|
||||
std::string right = tok.substr(eqpos+1,tok.size()-eqpos-1);
|
||||
params[left] = right;
|
||||
}
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
#if 0
|
||||
static void iZ3_write_seq(Z3_context ctx, int num, Z3_ast *cnsts, const char *filename, int num_theory, Z3_ast *theory){
|
||||
int num_fmlas = num+num_theory;
|
||||
std::vector<Z3_ast> fmlas(num_fmlas);
|
||||
if(num_theory)
|
||||
std::copy(theory,theory+num_theory,fmlas.begin());
|
||||
for(int i = 0; i < num_theory; i++)
|
||||
fmlas[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),fmlas[i]);
|
||||
std::copy(cnsts,cnsts+num,fmlas.begin()+num_theory);
|
||||
Z3_string smt = Z3_benchmark_to_smtlib_string(ctx,"none","AUFLIA","unknown","",num_fmlas-1,&fmlas[0],fmlas[num_fmlas-1]);
|
||||
std::ofstream f(filename);
|
||||
if(num_theory)
|
||||
f << ";! THEORY=" << num_theory << "\n";
|
||||
f << smt;
|
||||
f.close();
|
||||
}
|
||||
|
||||
void Z3_write_interpolation_problem(Z3_context ctx, int num, Z3_ast *cnsts, int *parents, const char *filename, int num_theory, Z3_ast *theory){
|
||||
if(!parents){
|
||||
iZ3_write_seq(ctx,num,cnsts,filename,num_theory,theory);
|
||||
return;
|
||||
}
|
||||
std::vector<Z3_ast> tcnsts(num);
|
||||
hash_map<int,Z3_ast> syms;
|
||||
for(int j = 0; j < num - 1; j++){
|
||||
std::ostringstream oss;
|
||||
oss << "$P" << j;
|
||||
std::string name = oss.str();
|
||||
Z3_symbol s = Z3_mk_string_symbol(ctx, name.c_str());
|
||||
Z3_ast symbol = Z3_mk_const(ctx, s, Z3_mk_bool_sort(ctx));
|
||||
syms[j] = symbol;
|
||||
tcnsts[j] = Z3_mk_implies(ctx,cnsts[j],symbol);
|
||||
}
|
||||
tcnsts[num-1] = Z3_mk_implies(ctx,cnsts[num-1],Z3_mk_false(ctx));
|
||||
for(int j = num-2; j >= 0; j--){
|
||||
int parent = parents[j];
|
||||
// assert(parent >= 0 && parent < num);
|
||||
tcnsts[parent] = Z3_mk_implies(ctx,syms[j],tcnsts[parent]);
|
||||
}
|
||||
iZ3_write_seq(ctx,num,&tcnsts[0],filename,num_theory,theory);
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
static Z3_ast and_vec(Z3_context ctx,svector<Z3_ast> &c){
|
||||
return (c.size() > 1) ? Z3_mk_and(ctx,c.size(),&c[0]) : c[0];
|
||||
}
|
||||
|
||||
static Z3_ast parents_vector_to_tree(Z3_context ctx, int num, Z3_ast *cnsts, int *parents){
|
||||
Z3_ast res;
|
||||
if(!parents){
|
||||
res = Z3_mk_interp(ctx,cnsts[0]);
|
||||
for(int i = 1; i < num-1; i++){
|
||||
Z3_ast bar[2] = {res,cnsts[i]};
|
||||
res = Z3_mk_interp(ctx,Z3_mk_and(ctx,2,bar));
|
||||
}
|
||||
if(num > 1){
|
||||
Z3_ast bar[2] = {res,cnsts[num-1]};
|
||||
res = Z3_mk_and(ctx,2,bar);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::vector<svector<Z3_ast> > chs(num);
|
||||
for(int i = 0; i < num-1; i++){
|
||||
svector<Z3_ast> &c = chs[i];
|
||||
c.push_back(cnsts[i]);
|
||||
Z3_ast foo = Z3_mk_interp(ctx,and_vec(ctx,c));
|
||||
chs[parents[i]].push_back(foo);
|
||||
}
|
||||
{
|
||||
svector<Z3_ast> &c = chs[num-1];
|
||||
c.push_back(cnsts[num-1]);
|
||||
res = and_vec(ctx,c);
|
||||
}
|
||||
}
|
||||
Z3_inc_ref(ctx,res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void Z3_write_interpolation_problem(Z3_context ctx, int num, Z3_ast *cnsts, int *parents, const char *filename, int num_theory, Z3_ast *theory){
|
||||
std::ofstream f(filename);
|
||||
if(num > 0){
|
||||
ptr_vector<expr> cnsts_vec(num); // get constraints in a vector
|
||||
for(int i = 0; i < num; i++){
|
||||
expr *a = to_expr(cnsts[i]);
|
||||
cnsts_vec[i] = a;
|
||||
}
|
||||
Z3_ast tree = parents_vector_to_tree(ctx,num,cnsts,parents);
|
||||
for(int i = 0; i < num_theory; i++){
|
||||
expr *a = to_expr(theory[i]);
|
||||
cnsts_vec.push_back(a);
|
||||
}
|
||||
iz3pp(mk_c(ctx)->m(),cnsts_vec,to_expr(tree),f);
|
||||
Z3_dec_ref(ctx,tree);
|
||||
}
|
||||
f.close();
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
if(!parents){
|
||||
iZ3_write_seq(ctx,num,cnsts,filename,num_theory,theory);
|
||||
return;
|
||||
}
|
||||
std::vector<Z3_ast> tcnsts(num);
|
||||
hash_map<int,Z3_ast> syms;
|
||||
for(int j = 0; j < num - 1; j++){
|
||||
std::ostringstream oss;
|
||||
oss << "$P" << j;
|
||||
std::string name = oss.str();
|
||||
Z3_symbol s = Z3_mk_string_symbol(ctx, name.c_str());
|
||||
Z3_ast symbol = Z3_mk_const(ctx, s, Z3_mk_bool_sort(ctx));
|
||||
syms[j] = symbol;
|
||||
tcnsts[j] = Z3_mk_implies(ctx,cnsts[j],symbol);
|
||||
}
|
||||
tcnsts[num-1] = Z3_mk_implies(ctx,cnsts[num-1],Z3_mk_false(ctx));
|
||||
for(int j = num-2; j >= 0; j--){
|
||||
int parent = parents[j];
|
||||
// assert(parent >= 0 && parent < num);
|
||||
tcnsts[parent] = Z3_mk_implies(ctx,syms[j],tcnsts[parent]);
|
||||
}
|
||||
iZ3_write_seq(ctx,num,&tcnsts[0],filename,num_theory,theory);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
static std::vector<Z3_ast> read_cnsts;
|
||||
static std::vector<int> read_parents;
|
||||
static std::ostringstream read_error;
|
||||
static std::string read_msg;
|
||||
static std::vector<Z3_ast> read_theory;
|
||||
|
||||
static bool iZ3_parse(Z3_context ctx, const char *filename, const char **error, svector<Z3_ast> &assertions){
|
||||
read_error.clear();
|
||||
try {
|
||||
std::string foo(filename);
|
||||
if(foo.size() >= 5 && foo.substr(foo.size()-5) == ".smt2"){
|
||||
Z3_ast ass = Z3_parse_smtlib2_file(ctx, filename, 0, 0, 0, 0, 0, 0);
|
||||
Z3_app app = Z3_to_app(ctx,ass);
|
||||
int nconjs = Z3_get_app_num_args(ctx,app);
|
||||
assertions.resize(nconjs);
|
||||
for(int k = 0; k < nconjs; k++)
|
||||
assertions[k] = Z3_get_app_arg(ctx,app,k);
|
||||
}
|
||||
else {
|
||||
Z3_parse_smtlib_file(ctx, filename, 0, 0, 0, 0, 0, 0);
|
||||
int numa = Z3_get_smtlib_num_assumptions(ctx);
|
||||
int numf = Z3_get_smtlib_num_formulas(ctx);
|
||||
int num = numa + numf;
|
||||
|
||||
assertions.resize(num);
|
||||
for(int j = 0; j < num; j++){
|
||||
if(j < numa)
|
||||
assertions[j] = Z3_get_smtlib_assumption(ctx,j);
|
||||
else
|
||||
assertions[j] = Z3_get_smtlib_formula(ctx,j-numa);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...) {
|
||||
read_error << "SMTLIB parse error: " << Z3_get_smtlib_error(ctx);
|
||||
read_msg = read_error.str();
|
||||
*error = read_msg.c_str();
|
||||
return false;
|
||||
}
|
||||
Z3_set_error_handler(ctx, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int Z3_read_interpolation_problem(Z3_context ctx, int *_num, Z3_ast **cnsts, int **parents, const char *filename, const char **error, int *ret_num_theory, Z3_ast **theory ){
|
||||
|
||||
hash_map<std::string,std::string> file_params;
|
||||
get_file_params(filename,file_params);
|
||||
|
||||
unsigned num_theory = 0;
|
||||
if(file_params.find("THEORY") != file_params.end())
|
||||
num_theory = atoi(file_params["THEORY"].c_str());
|
||||
|
||||
svector<Z3_ast> assertions;
|
||||
if(!iZ3_parse(ctx,filename,error,assertions))
|
||||
return false;
|
||||
|
||||
if(num_theory > assertions.size())
|
||||
num_theory = assertions.size();
|
||||
unsigned num = assertions.size() - num_theory;
|
||||
|
||||
read_cnsts.resize(num);
|
||||
read_parents.resize(num);
|
||||
read_theory.resize(num_theory);
|
||||
|
||||
for(unsigned j = 0; j < num_theory; j++)
|
||||
read_theory[j] = assertions[j];
|
||||
for(unsigned j = 0; j < num; j++)
|
||||
read_cnsts[j] = assertions[j+num_theory];
|
||||
|
||||
if(ret_num_theory)
|
||||
*ret_num_theory = num_theory;
|
||||
if(theory)
|
||||
*theory = &read_theory[0];
|
||||
|
||||
if(!parents){
|
||||
*_num = num;
|
||||
*cnsts = &read_cnsts[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
for(unsigned j = 0; j < num; j++)
|
||||
read_parents[j] = SHRT_MAX;
|
||||
|
||||
hash_map<Z3_ast,int> pred_map;
|
||||
|
||||
for(unsigned j = 0; j < num; j++){
|
||||
Z3_ast lhs = 0, rhs = read_cnsts[j];
|
||||
|
||||
if(Z3_get_decl_kind(ctx,Z3_get_app_decl(ctx,Z3_to_app(ctx,rhs))) == Z3_OP_IMPLIES){
|
||||
Z3_app app1 = Z3_to_app(ctx,rhs);
|
||||
Z3_ast lhs1 = Z3_get_app_arg(ctx,app1,0);
|
||||
Z3_ast rhs1 = Z3_get_app_arg(ctx,app1,1);
|
||||
if(Z3_get_decl_kind(ctx,Z3_get_app_decl(ctx,Z3_to_app(ctx,lhs1))) == Z3_OP_AND){
|
||||
Z3_app app2 = Z3_to_app(ctx,lhs1);
|
||||
int nconjs = Z3_get_app_num_args(ctx,app2);
|
||||
for(int k = nconjs - 1; k >= 0; --k)
|
||||
rhs1 = Z3_mk_implies(ctx,Z3_get_app_arg(ctx,app2,k),rhs1);
|
||||
rhs = rhs1;
|
||||
}
|
||||
}
|
||||
|
||||
while(1){
|
||||
Z3_app app = Z3_to_app(ctx,rhs);
|
||||
Z3_func_decl func = Z3_get_app_decl(ctx,app);
|
||||
Z3_decl_kind dk = Z3_get_decl_kind(ctx,func);
|
||||
if(dk == Z3_OP_IMPLIES){
|
||||
if(lhs){
|
||||
Z3_ast child = lhs;
|
||||
if(pred_map.find(child) == pred_map.end()){
|
||||
read_error << "formula " << j+1 << ": unknown: " << Z3_ast_to_string(ctx,child);
|
||||
goto fail;
|
||||
}
|
||||
int child_num = pred_map[child];
|
||||
if(read_parents[child_num] != SHRT_MAX){
|
||||
read_error << "formula " << j+1 << ": multiple reference: " << Z3_ast_to_string(ctx,child);
|
||||
goto fail;
|
||||
}
|
||||
read_parents[child_num] = j;
|
||||
}
|
||||
lhs = Z3_get_app_arg(ctx,app,0);
|
||||
rhs = Z3_get_app_arg(ctx,app,1);
|
||||
}
|
||||
else {
|
||||
if(!lhs){
|
||||
read_error << "formula " << j+1 << ": should be (implies {children} fmla parent)";
|
||||
goto fail;
|
||||
}
|
||||
read_cnsts[j] = lhs;
|
||||
Z3_ast name = rhs;
|
||||
if(pred_map.find(name) != pred_map.end()){
|
||||
read_error << "formula " << j+1 << ": duplicate symbol";
|
||||
goto fail;
|
||||
}
|
||||
pred_map[name] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned j = 0; j < num-1; j++)
|
||||
if(read_parents[j] == SHRT_MIN){
|
||||
read_error << "formula " << j+1 << ": unreferenced";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*_num = num;
|
||||
*cnsts = &read_cnsts[0];
|
||||
*parents = &read_parents[0];
|
||||
return true;
|
||||
|
||||
fail:
|
||||
read_msg = read_error.str();
|
||||
*error = read_msg.c_str();
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
|
@ -36,4 +36,3 @@ using System.Security.Permissions;
|
|||
// [assembly: AssemblyVersion("4.2.0.0")]
|
||||
[assembly: AssemblyVersion("4.3.2.0")]
|
||||
[assembly: AssemblyFileVersion("4.3.2.0")]
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ public class BitVecNum extends BitVecExpr
|
|||
{
|
||||
Native.LongPtr res = new Native.LongPtr();
|
||||
if (Native.getNumeralInt64(getContext().nCtx(), getNativeObject(), res) ^ true)
|
||||
throw new Z3Exception("Numeral is not an int64");
|
||||
throw new Z3Exception("Numeral is not a long");
|
||||
return res.value;
|
||||
}
|
||||
|
||||
|
|
|
@ -6424,7 +6424,7 @@ class Tactic:
|
|||
_z3_assert(isinstance(goal, Goal) or isinstance(goal, BoolRef), "Z3 Goal or Boolean expressions expected")
|
||||
goal = _to_goal(goal)
|
||||
if len(arguments) > 0 or len(keywords) > 0:
|
||||
p = args2params(arguments, keywords, a.ctx)
|
||||
p = args2params(arguments, keywords, self.ctx)
|
||||
return ApplyResult(Z3_tactic_apply_ex(self.ctx.ref(), self.tactic, goal.goal, p.params), self.ctx)
|
||||
else:
|
||||
return ApplyResult(Z3_tactic_apply(self.ctx.ref(), self.tactic, goal.goal), self.ctx)
|
||||
|
|
218
src/api/z3_api.h
218
src/api/z3_api.h
|
@ -251,6 +251,8 @@ typedef enum
|
|||
- Z3_OP_OEQ Binary equivalence modulo namings. This binary predicate is used in proof terms.
|
||||
It captures equisatisfiability and equivalence modulo renamings.
|
||||
|
||||
- Z3_OP_INTERP Marks a sub-formula for interpolation.
|
||||
|
||||
- Z3_OP_ANUM Arithmetic numeral.
|
||||
|
||||
- Z3_OP_AGNUM Arithmetic algebraic numeral. Algebraic numbers are used to represent irrational numbers in Z3.
|
||||
|
@ -901,6 +903,7 @@ typedef enum {
|
|||
Z3_OP_NOT,
|
||||
Z3_OP_IMPLIES,
|
||||
Z3_OP_OEQ,
|
||||
Z3_OP_INTERP,
|
||||
|
||||
// Arithmetic
|
||||
Z3_OP_ANUM = 0x200,
|
||||
|
@ -2121,6 +2124,16 @@ END_MLAPI_EXCLUDE
|
|||
*/
|
||||
Z3_ast Z3_API Z3_mk_not(__in Z3_context c, __in Z3_ast a);
|
||||
|
||||
/**
|
||||
\brief \mlh mk_interp c a \endmlh
|
||||
Create an AST node marking a formula position for interpolation.
|
||||
|
||||
The node \c a must have Boolean sort.
|
||||
|
||||
def_API('Z3_mk_interp', AST, (_in(CONTEXT), _in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_interp(__in Z3_context c, __in Z3_ast a);
|
||||
|
||||
/**
|
||||
\brief \mlh mk_ite c t1 t2 t2 \endmlh
|
||||
Create an AST node representing an if-then-else: <tt>ite(t1, t2,
|
||||
|
@ -7863,6 +7876,211 @@ END_MLAPI_EXCLUDE
|
|||
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
@name Interpolation
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/** \brief This function generates a Z3 context suitable for generation of
|
||||
interpolants. Formulas can be generated as abstract syntx trees in
|
||||
this context using the Z3 C API.
|
||||
|
||||
Interpolants are also generated as AST's in this context.
|
||||
|
||||
If cfg is non-null, it will be used as the base configuration
|
||||
for the Z3 context. This makes it possible to set Z3 options
|
||||
to be used during interpolation. This feature should be used
|
||||
with some caution however, as it may be that certain Z3 options
|
||||
are incompatible with interpolation.
|
||||
|
||||
def_API('Z3_mk_interpolation_context', CONTEXT, (_in(CONFIG),))
|
||||
|
||||
*/
|
||||
|
||||
Z3_context Z3_API Z3_mk_interpolation_context(__in Z3_config cfg);
|
||||
|
||||
|
||||
/** Constant reprepresenting a root of a formula tree for tree interpolation */
|
||||
#define IZ3_ROOT SHRT_MAX
|
||||
|
||||
/** This function uses Z3 to determine satisfiability of a set of
|
||||
constraints. If UNSAT, an interpolant is returned, based on the
|
||||
refutation generated by Z3. If SAT, a model is returned.
|
||||
|
||||
If "parents" is non-null, computes a tree interpolant. The tree is
|
||||
defined by the array "parents". This array maps each formula in
|
||||
the tree to its parent, where formulas are indicated by their
|
||||
integer index in "cnsts". The parent of formula n must have index
|
||||
greater than n. The last formula is the root of the tree. Its
|
||||
parent entry should be the constant IZ3_ROOT.
|
||||
|
||||
If "parents" is null, computes a sequence interpolant.
|
||||
|
||||
\param ctx The Z3 context. Must be generated by iz3_mk_context
|
||||
\param num The number of constraints in the sequence
|
||||
\param cnsts Array of constraints (AST's in context ctx)
|
||||
\param parents The parents vector defining the tree structure
|
||||
\param options Interpolation options (may be NULL)
|
||||
\param interps Array to return interpolants (size at least num-1, may be NULL)
|
||||
\param model Returns a Z3 model if constraints SAT (may be NULL)
|
||||
\param labels Returns relevant labels if SAT (may be NULL)
|
||||
\param incremental
|
||||
|
||||
VERY IMPORTANT: All the Z3 formulas in cnsts must be in Z3
|
||||
context ctx. The model and interpolants returned are also
|
||||
in this context.
|
||||
|
||||
The return code is as in Z3_check_assumptions, that is,
|
||||
|
||||
Z3_L_FALSE = constraints UNSAT (interpolants returned)
|
||||
Z3_L_TRUE = constraints SAT (model returned)
|
||||
Z3_L_UNDEF = Z3 produced no result, or interpolation not possible
|
||||
|
||||
Currently, this function supports integer and boolean variables,
|
||||
as well as arrays over these types, with linear arithmetic,
|
||||
uninterpreted functions and quantifiers over integers (that is
|
||||
AUFLIA). Interpolants are produced in AUFLIA. However, some
|
||||
uses of array operations may cause quantifiers to appear in the
|
||||
interpolants even when there are no quantifiers in the input formulas.
|
||||
Although quantifiers may appear in the input formulas, Z3 may give up in
|
||||
this case, returning Z3_L_UNDEF.
|
||||
|
||||
If "incremental" is true, cnsts must contain exactly the set of
|
||||
formulas that are currently asserted in the context. If false,
|
||||
there must be no formulas currently asserted in the context.
|
||||
Setting "incremental" to true makes it posisble to incrementally
|
||||
add and remove constraints from the context until the context
|
||||
becomes UNSAT, at which point an interpolant is computed. Caution
|
||||
must be used, however. Before popping the context, if you wish to
|
||||
keep the interolant formulas, you *must* preserve them by using
|
||||
Z3_persist_ast. Also, if you want to simplify the interpolant
|
||||
formulas using Z3_simplify, you must first pop all of the
|
||||
assertions in the context (or use a different context). Otherwise,
|
||||
the formulas will be simplified *relative* to these constraints,
|
||||
which is almost certainly not what you want.
|
||||
|
||||
|
||||
Current limitations on tree interpolants. In a tree interpolation
|
||||
problem, each constant (0-ary function symbol) must occur only
|
||||
along one path from root to leaf. Function symbols (of arity > 0)
|
||||
are considered to have global scope (i.e., may appear in any
|
||||
interpolant formula).
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
Z3_lbool Z3_API Z3_interpolate(__in Z3_context ctx,
|
||||
__in int num,
|
||||
__in_ecount(num) Z3_ast *cnsts,
|
||||
__in_ecount(num) unsigned *parents,
|
||||
__in Z3_params options,
|
||||
__out_ecount(num-1) Z3_ast *interps,
|
||||
__out Z3_model *model,
|
||||
__out Z3_literals *labels,
|
||||
__in int incremental,
|
||||
__in int num_theory,
|
||||
__in_ecount(num_theory) Z3_ast *theory);
|
||||
|
||||
/** Return a string summarizing cumulative time used for
|
||||
interpolation. This string is purely for entertainment purposes
|
||||
and has no semantics.
|
||||
|
||||
\param ctx The context (currently ignored)
|
||||
|
||||
def_API('Z3_interpolation_profile', STRING, (_in(CONTEXT),))
|
||||
*/
|
||||
|
||||
Z3_string Z3_API Z3_interpolation_profile(__in Z3_context ctx);
|
||||
|
||||
/**
|
||||
\brief Read an interpolation problem from file.
|
||||
|
||||
\param ctx The Z3 context. This resets the error handler of ctx.
|
||||
\param filename The file name to read.
|
||||
\param num Returns length of sequence.
|
||||
\param cnsts Returns sequence of formulas (do not free)
|
||||
\param parents Returns the parents vector (or NULL for sequence)
|
||||
\param error Returns an error message in case of failure (do not free the string)
|
||||
|
||||
Returns true on success.
|
||||
|
||||
File formats: Currently two formats are supported, based on
|
||||
SMT-LIB2. For sequence interpolants, the sequence of constraints is
|
||||
represented by the sequence of "assert" commands in the file.
|
||||
|
||||
For tree interpolants, one symbol of type bool is associated to
|
||||
each vertex of the tree. For each vertex v there is an "assert"
|
||||
of the form:
|
||||
|
||||
(implies (and c1 ... cn f) v)
|
||||
|
||||
where c1 .. cn are the children of v (which must precede v in the file)
|
||||
and f is the formula assiciated to node v. The last formula in the
|
||||
file is the root vertex, and is represented by the predicate "false".
|
||||
|
||||
A solution to a tree interpolation problem can be thought of as a
|
||||
valuation of the vertices that makes all the implications true
|
||||
where each value is represented using the common symbols between
|
||||
the formulas in the subtree and the remainder of the formulas.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
int Z3_API Z3_read_interpolation_problem(__in Z3_context ctx,
|
||||
__out int *num,
|
||||
__out_ecount(*num) Z3_ast **cnsts,
|
||||
__out_ecount(*num) int **parents,
|
||||
__in const char *filename,
|
||||
__out const char **error,
|
||||
__out int *num_theory,
|
||||
__out_ecount(*num_theory) Z3_ast **theory);
|
||||
|
||||
|
||||
|
||||
/** Check the correctness of an interpolant. The Z3 context must
|
||||
have no constraints asserted when this call is made. That means
|
||||
that after interpolating, you must first fully pop the Z3
|
||||
context before calling this. See Z3_interpolate for meaning of parameters.
|
||||
|
||||
\param ctx The Z3 context. Must be generated by Z3_mk_interpolation_context
|
||||
\param num The number of constraints in the sequence
|
||||
\param cnsts Array of constraints (AST's in context ctx)
|
||||
\param parents The parents vector (or NULL for sequence)
|
||||
\param interps The interpolant to check
|
||||
\param error Returns an error message if interpolant incorrect (do not free the string)
|
||||
|
||||
Return value is Z3_L_TRUE if interpolant is verified, Z3_L_FALSE if
|
||||
incorrect, and Z3_L_UNDEF if unknown.
|
||||
|
||||
*/
|
||||
|
||||
int Z3_API Z3_check_interpolant(Z3_context ctx, int num, Z3_ast *cnsts, int *parents, Z3_ast *interps, const char **error,
|
||||
int num_theory, Z3_ast *theory);
|
||||
|
||||
/** Write an interpolation problem to file suitable for reading with
|
||||
Z3_read_interpolation_problem. The output file is a sequence
|
||||
of SMT-LIB2 format commands, suitable for reading with command-line Z3
|
||||
or other interpolating solvers.
|
||||
|
||||
\param ctx The Z3 context. Must be generated by z3_mk_interpolation_context
|
||||
\param num The number of constraints in the sequence
|
||||
\param cnsts Array of constraints
|
||||
\param parents The parents vector (or NULL for sequence)
|
||||
\param filename The file name to write
|
||||
|
||||
*/
|
||||
|
||||
void Z3_API Z3_write_interpolation_problem(Z3_context ctx,
|
||||
int num,
|
||||
Z3_ast *cnsts,
|
||||
int *parents,
|
||||
const char *filename,
|
||||
int num_theory,
|
||||
Z3_ast *theory);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -640,6 +640,7 @@ basic_decl_plugin::basic_decl_plugin():
|
|||
m_iff_decl(0),
|
||||
m_xor_decl(0),
|
||||
m_not_decl(0),
|
||||
m_interp_decl(0),
|
||||
m_implies_decl(0),
|
||||
|
||||
m_proof_sort(0),
|
||||
|
@ -863,6 +864,7 @@ void basic_decl_plugin::set_manager(ast_manager * m, family_id id) {
|
|||
m_iff_decl = mk_bool_op_decl("iff", OP_IFF, 2, false, true, false, false, true);
|
||||
m_xor_decl = mk_bool_op_decl("xor", OP_XOR, 2, true, true);
|
||||
m_not_decl = mk_bool_op_decl("not", OP_NOT, 1);
|
||||
m_interp_decl = mk_bool_op_decl("interp", OP_INTERP, 1);
|
||||
m_implies_decl = mk_implies_decl();
|
||||
|
||||
m_proof_sort = m->mk_sort(symbol("Proof"), sort_info(id, PROOF_SORT));
|
||||
|
@ -887,6 +889,7 @@ void basic_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol co
|
|||
op_names.push_back(builtin_name("or", OP_OR));
|
||||
op_names.push_back(builtin_name("xor", OP_XOR));
|
||||
op_names.push_back(builtin_name("not", OP_NOT));
|
||||
op_names.push_back(builtin_name("interp", OP_INTERP));
|
||||
op_names.push_back(builtin_name("=>", OP_IMPLIES));
|
||||
if (logic == symbol::null) {
|
||||
// user friendly aliases
|
||||
|
@ -898,6 +901,7 @@ void basic_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol co
|
|||
op_names.push_back(builtin_name("||", OP_OR));
|
||||
op_names.push_back(builtin_name("equals", OP_EQ));
|
||||
op_names.push_back(builtin_name("equiv", OP_IFF));
|
||||
op_names.push_back(builtin_name("@@", OP_INTERP));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -918,6 +922,7 @@ void basic_decl_plugin::finalize() {
|
|||
DEC_REF(m_and_decl);
|
||||
DEC_REF(m_or_decl);
|
||||
DEC_REF(m_not_decl);
|
||||
DEC_REF(m_interp_decl);
|
||||
DEC_REF(m_iff_decl);
|
||||
DEC_REF(m_xor_decl);
|
||||
DEC_REF(m_implies_decl);
|
||||
|
@ -1016,6 +1021,7 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
|
|||
case OP_AND: return m_and_decl;
|
||||
case OP_OR: return m_or_decl;
|
||||
case OP_NOT: return m_not_decl;
|
||||
case OP_INTERP: return m_interp_decl;
|
||||
case OP_IFF: return m_iff_decl;
|
||||
case OP_IMPLIES: return m_implies_decl;
|
||||
case OP_XOR: return m_xor_decl;
|
||||
|
@ -1051,6 +1057,7 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
|
|||
case OP_AND: return m_and_decl;
|
||||
case OP_OR: return m_or_decl;
|
||||
case OP_NOT: return m_not_decl;
|
||||
case OP_INTERP: return m_interp_decl;
|
||||
case OP_IFF: return m_iff_decl;
|
||||
case OP_IMPLIES: return m_implies_decl;
|
||||
case OP_XOR: return m_xor_decl;
|
||||
|
@ -3146,4 +3153,14 @@ void scoped_mark::pop_scope(unsigned num_scopes) {
|
|||
}
|
||||
}
|
||||
|
||||
// Added by KLM for use in GDB
|
||||
|
||||
// show an expr_ref on stdout
|
||||
|
||||
void prexpr(expr_ref &e){
|
||||
std::cout << mk_pp(e.get(), e.get_manager()) << std::endl;
|
||||
}
|
||||
|
||||
void ast_manager::show_id_gen(){
|
||||
std::cout << "id_gen: " << m_expr_id_gen.show_hash() << " " << m_decl_id_gen.show_hash() << "\n";
|
||||
}
|
||||
|
|
|
@ -1006,7 +1006,7 @@ enum basic_sort_kind {
|
|||
};
|
||||
|
||||
enum basic_op_kind {
|
||||
OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_IFF, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, LAST_BASIC_OP,
|
||||
OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_IFF, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, OP_INTERP, LAST_BASIC_OP,
|
||||
|
||||
PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO,
|
||||
PR_DISTRIBUTIVITY, PR_AND_ELIM, PR_NOT_OR_ELIM, PR_REWRITE, PR_REWRITE_STAR, PR_PULL_QUANT,
|
||||
|
@ -1028,6 +1028,7 @@ protected:
|
|||
func_decl * m_iff_decl;
|
||||
func_decl * m_xor_decl;
|
||||
func_decl * m_not_decl;
|
||||
func_decl * m_interp_decl;
|
||||
func_decl * m_implies_decl;
|
||||
ptr_vector<func_decl> m_eq_decls; // cached eqs
|
||||
ptr_vector<func_decl> m_ite_decls; // cached ites
|
||||
|
@ -1417,6 +1418,8 @@ protected:
|
|||
public:
|
||||
typedef expr_dependency_array_manager::ref expr_dependency_array;
|
||||
|
||||
void show_id_gen();
|
||||
|
||||
protected:
|
||||
small_object_allocator m_alloc;
|
||||
family_manager m_family_manager;
|
||||
|
@ -2000,6 +2003,7 @@ public:
|
|||
app * mk_distinct_expanded(unsigned num_args, expr * const * args);
|
||||
app * mk_true() { return m_true; }
|
||||
app * mk_false() { return m_false; }
|
||||
app * mk_interp(expr * arg) { return mk_app(m_basic_family_id, OP_INTERP, arg); }
|
||||
|
||||
func_decl* mk_and_decl() {
|
||||
sort* domain[2] = { m_bool_sort, m_bool_sort };
|
||||
|
|
|
@ -475,6 +475,7 @@ void float_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol co
|
|||
op_names.push_back(builtin_name("plusInfinity", OP_FLOAT_PLUS_INF));
|
||||
op_names.push_back(builtin_name("minusInfinity", OP_FLOAT_MINUS_INF));
|
||||
op_names.push_back(builtin_name("NaN", OP_FLOAT_NAN));
|
||||
|
||||
op_names.push_back(builtin_name("roundNearestTiesToEven", OP_RM_NEAREST_TIES_TO_EVEN));
|
||||
op_names.push_back(builtin_name("roundNearestTiesToAway", OP_RM_NEAREST_TIES_TO_AWAY));
|
||||
op_names.push_back(builtin_name("roundTowardPositive", OP_RM_TOWARD_POSITIVE));
|
||||
|
@ -486,7 +487,7 @@ void float_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol co
|
|||
op_names.push_back(builtin_name("/", OP_FLOAT_DIV));
|
||||
op_names.push_back(builtin_name("*", OP_FLOAT_MUL));
|
||||
|
||||
op_names.push_back(builtin_name("abs", OP_FLOAT_ABS));
|
||||
op_names.push_back(builtin_name("abs", OP_FLOAT_ABS));
|
||||
op_names.push_back(builtin_name("remainder", OP_FLOAT_REM));
|
||||
op_names.push_back(builtin_name("fusedMA", OP_FLOAT_FUSED_MA));
|
||||
op_names.push_back(builtin_name("squareRoot", OP_FLOAT_SQRT));
|
||||
|
@ -515,6 +516,49 @@ void float_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol co
|
|||
|
||||
if (m_bv_plugin)
|
||||
op_names.push_back(builtin_name("asIEEEBV", OP_TO_IEEE_BV));
|
||||
|
||||
// We also support draft version 3
|
||||
op_names.push_back(builtin_name("fp", OP_TO_FLOAT));
|
||||
|
||||
op_names.push_back(builtin_name("RNE", OP_RM_NEAREST_TIES_TO_EVEN));
|
||||
op_names.push_back(builtin_name("RNA", OP_RM_NEAREST_TIES_TO_AWAY));
|
||||
op_names.push_back(builtin_name("RTP", OP_RM_TOWARD_POSITIVE));
|
||||
op_names.push_back(builtin_name("RTN", OP_RM_TOWARD_NEGATIVE));
|
||||
op_names.push_back(builtin_name("RTZ", OP_RM_TOWARD_ZERO));
|
||||
|
||||
op_names.push_back(builtin_name("fp.abs", OP_FLOAT_ABS));
|
||||
op_names.push_back(builtin_name("fp.neg", OP_FLOAT_UMINUS));
|
||||
op_names.push_back(builtin_name("fp.add", OP_FLOAT_ADD));
|
||||
op_names.push_back(builtin_name("fp.sub", OP_FLOAT_SUB));
|
||||
op_names.push_back(builtin_name("fp.mul", OP_FLOAT_MUL));
|
||||
op_names.push_back(builtin_name("fp.div", OP_FLOAT_DIV));
|
||||
op_names.push_back(builtin_name("fp.fma", OP_FLOAT_FUSED_MA));
|
||||
op_names.push_back(builtin_name("fp.sqrt", OP_FLOAT_SQRT));
|
||||
op_names.push_back(builtin_name("fp.rem", OP_FLOAT_REM));
|
||||
op_names.push_back(builtin_name("fp.eq", OP_FLOAT_EQ));
|
||||
op_names.push_back(builtin_name("fp.leq", OP_FLOAT_LE));
|
||||
op_names.push_back(builtin_name("fp.lt", OP_FLOAT_LT));
|
||||
op_names.push_back(builtin_name("fp.geq", OP_FLOAT_GE));
|
||||
op_names.push_back(builtin_name("fp.gt", OP_FLOAT_GT));
|
||||
op_names.push_back(builtin_name("fp.isNormal", OP_FLOAT_IS_NORMAL));
|
||||
op_names.push_back(builtin_name("fp.isSubnormal", OP_FLOAT_IS_SUBNORMAL));
|
||||
op_names.push_back(builtin_name("fp.isZero", OP_FLOAT_IS_ZERO));
|
||||
op_names.push_back(builtin_name("fp.isInfinite", OP_FLOAT_IS_INF));
|
||||
op_names.push_back(builtin_name("fp.isNaN", OP_FLOAT_IS_NAN));
|
||||
op_names.push_back(builtin_name("fp.min", OP_FLOAT_MIN));
|
||||
op_names.push_back(builtin_name("fp.max", OP_FLOAT_MAX));
|
||||
op_names.push_back(builtin_name("fp.convert", OP_TO_FLOAT));
|
||||
|
||||
if (m_bv_plugin) {
|
||||
// op_names.push_back(builtin_name("fp.fromBv", OP_TO_FLOAT));
|
||||
// op_names.push_back(builtin_name("fp.fromUBv", OP_TO_FLOAT));
|
||||
// op_names.push_back(builtin_name("fp.fromSBv", OP_TO_FLOAT));
|
||||
// op_names.push_back(builtin_name("fp.toUBv", OP_TO_IEEE_BV));
|
||||
// op_names.push_back(builtin_name("fp.toSBv", OP_TO_IEEE_BV));
|
||||
}
|
||||
|
||||
op_names.push_back(builtin_name("fp.fromReal", OP_TO_FLOAT));
|
||||
// op_names.push_back(builtin_name("fp.toReal", ?));
|
||||
}
|
||||
|
||||
void float_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
|
||||
|
|
|
@ -479,7 +479,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
|
|||
// otherwise t2 is also a quantifier.
|
||||
return true;
|
||||
}
|
||||
UNREACHABLE();
|
||||
IF_VERBOSE(0, verbose_stream() << "does not match last rule: " << mk_pp(p, m) << "\n";);
|
||||
return false;
|
||||
}
|
||||
case PR_DER: {
|
||||
|
@ -488,13 +488,12 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
|
|||
match_fact(p, fact) &&
|
||||
match_iff(fact.get(), t1, t2) &&
|
||||
match_quantifier(t1, is_forall, decls1, body1) &&
|
||||
is_forall &&
|
||||
match_or(body1.get(), terms1)) {
|
||||
is_forall) {
|
||||
// TBD: check that terms are set of equalities.
|
||||
// t2 is an instance of a predicate in terms1
|
||||
return true;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
IF_VERBOSE(0, verbose_stream() << "does not match last rule: " << mk_pp(p, m) << "\n";);
|
||||
return false;
|
||||
}
|
||||
case PR_HYPOTHESIS: {
|
||||
|
@ -832,7 +831,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
|
|||
}
|
||||
else {
|
||||
IF_VERBOSE(0, verbose_stream() << "Could not establish complementarity for:\n" <<
|
||||
mk_pp(lit1, m) << "\n" << mk_pp(lit2, m) << "\n";);
|
||||
mk_pp(lit1, m) << "\n" << mk_pp(lit2, m) << "\n" << mk_pp(p, m) << "\n";);
|
||||
}
|
||||
fmls[i] = premise1;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ bool array_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * co
|
|||
set_reduce_invoked();
|
||||
if (m_presimp)
|
||||
return false;
|
||||
#if _DEBUG
|
||||
#if Z3DEBUG
|
||||
for (unsigned i = 0; i < num_args && i < f->get_arity(); ++i) {
|
||||
SASSERT(m_manager.get_sort(args[i]) == f->get_domain(i));
|
||||
}
|
||||
|
|
|
@ -240,6 +240,8 @@ protected:
|
|||
symbol m_produce_unsat_cores;
|
||||
symbol m_produce_models;
|
||||
symbol m_produce_assignments;
|
||||
symbol m_produce_interpolants;
|
||||
symbol m_check_interpolants;
|
||||
symbol m_regular_output_channel;
|
||||
symbol m_diagnostic_output_channel;
|
||||
symbol m_random_seed;
|
||||
|
@ -253,7 +255,9 @@ protected:
|
|||
return
|
||||
s == m_print_success || s == m_print_warning || s == m_expand_definitions ||
|
||||
s == m_interactive_mode || s == m_produce_proofs || s == m_produce_unsat_cores ||
|
||||
s == m_produce_models || s == m_produce_assignments || s == m_regular_output_channel || s == m_diagnostic_output_channel ||
|
||||
s == m_produce_models || s == m_produce_assignments || s == m_produce_interpolants ||
|
||||
s == m_check_interpolants ||
|
||||
s == m_regular_output_channel || s == m_diagnostic_output_channel ||
|
||||
s == m_random_seed || s == m_verbosity || s == m_global_decls;
|
||||
}
|
||||
|
||||
|
@ -270,6 +274,8 @@ public:
|
|||
m_produce_unsat_cores(":produce-unsat-cores"),
|
||||
m_produce_models(":produce-models"),
|
||||
m_produce_assignments(":produce-assignments"),
|
||||
m_produce_interpolants(":produce-interpolants"),
|
||||
m_check_interpolants(":check-interpolants"),
|
||||
m_regular_output_channel(":regular-output-channel"),
|
||||
m_diagnostic_output_channel(":diagnostic-output-channel"),
|
||||
m_random_seed(":random-seed"),
|
||||
|
@ -337,6 +343,13 @@ class set_option_cmd : public set_get_option_cmd {
|
|||
check_not_initialized(ctx, m_produce_proofs);
|
||||
ctx.set_produce_proofs(to_bool(value));
|
||||
}
|
||||
else if (m_option == m_produce_interpolants) {
|
||||
check_not_initialized(ctx, m_produce_interpolants);
|
||||
ctx.set_produce_interpolants(to_bool(value));
|
||||
}
|
||||
else if (m_option == m_check_interpolants) {
|
||||
ctx.set_check_interpolants(to_bool(value));
|
||||
}
|
||||
else if (m_option == m_produce_unsat_cores) {
|
||||
check_not_initialized(ctx, m_produce_unsat_cores);
|
||||
ctx.set_produce_unsat_cores(to_bool(value));
|
||||
|
@ -485,6 +498,9 @@ public:
|
|||
else if (opt == m_produce_proofs) {
|
||||
print_bool(ctx, ctx.produce_proofs());
|
||||
}
|
||||
else if (opt == m_produce_interpolants) {
|
||||
print_bool(ctx, ctx.produce_interpolants());
|
||||
}
|
||||
else if (opt == m_produce_unsat_cores) {
|
||||
print_bool(ctx, ctx.produce_unsat_cores());
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ Notes:
|
|||
#include"model_evaluator.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"scoped_timer.h"
|
||||
#include"interpolant_cmds.h"
|
||||
|
||||
func_decls::func_decls(ast_manager & m, func_decl * f):
|
||||
m_decls(TAG(func_decl*, f, 0)) {
|
||||
|
@ -324,6 +325,7 @@ cmd_context::cmd_context(bool main_ctx, ast_manager * m, symbol const & l):
|
|||
install_basic_cmds(*this);
|
||||
install_ext_basic_cmds(*this);
|
||||
install_core_tactic_cmds(*this);
|
||||
install_interpolant_cmds(*this);
|
||||
SASSERT(m != 0 || !has_manager());
|
||||
if (m)
|
||||
init_external_manager();
|
||||
|
@ -381,6 +383,19 @@ void cmd_context::set_produce_proofs(bool f) {
|
|||
m_params.m_proof = f;
|
||||
}
|
||||
|
||||
void cmd_context::set_produce_interpolants(bool f) {
|
||||
// can only be set before initialization
|
||||
// FIXME currently synonym for produce_proofs
|
||||
// also sets the default solver to be simple smt
|
||||
SASSERT(!has_manager());
|
||||
m_params.m_proof = f;
|
||||
// set_solver_factory(mk_smt_solver_factory());
|
||||
}
|
||||
|
||||
void cmd_context::set_check_interpolants(bool f) {
|
||||
m_params.m_check_interpolants = f;
|
||||
}
|
||||
|
||||
bool cmd_context::produce_models() const {
|
||||
return m_params.m_model;
|
||||
}
|
||||
|
@ -389,6 +404,15 @@ bool cmd_context::produce_proofs() const {
|
|||
return m_params.m_proof;
|
||||
}
|
||||
|
||||
bool cmd_context::produce_interpolants() const {
|
||||
// FIXME currently synonym for produce_proofs
|
||||
return m_params.m_proof;
|
||||
}
|
||||
|
||||
bool cmd_context::check_interpolants() const {
|
||||
return m_params.m_check_interpolants;
|
||||
}
|
||||
|
||||
bool cmd_context::produce_unsat_cores() const {
|
||||
return m_params.m_unsat_core;
|
||||
}
|
||||
|
@ -1458,11 +1482,27 @@ void cmd_context::validate_model() {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: really interpolants_enabled ought to be a parameter to the solver factory,
|
||||
// but this is a global change, so for now, we use an alternate solver factory
|
||||
// for interpolation
|
||||
|
||||
void cmd_context::mk_solver() {
|
||||
bool proofs_enabled, models_enabled, unsat_core_enabled;
|
||||
params_ref p;
|
||||
m_params.get_solver_params(m(), p, proofs_enabled, models_enabled, unsat_core_enabled);
|
||||
m_solver = (*m_solver_factory)(m(), p, proofs_enabled, models_enabled, unsat_core_enabled, m_logic);
|
||||
if(produce_interpolants()){
|
||||
SASSERT(m_interpolating_solver_factory);
|
||||
m_solver = (*m_interpolating_solver_factory)(m(), p, true /* must have proofs */, models_enabled, unsat_core_enabled, m_logic);
|
||||
}
|
||||
else
|
||||
m_solver = (*m_solver_factory)(m(), p, proofs_enabled, models_enabled, unsat_core_enabled, m_logic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void cmd_context::set_interpolating_solver_factory(solver_factory * f) {
|
||||
SASSERT(!has_manager());
|
||||
m_interpolating_solver_factory = f;
|
||||
}
|
||||
|
||||
void cmd_context::set_solver_factory(solver_factory * f) {
|
||||
|
|
|
@ -186,6 +186,7 @@ protected:
|
|||
|
||||
svector<scope> m_scopes;
|
||||
scoped_ptr<solver_factory> m_solver_factory;
|
||||
scoped_ptr<solver_factory> m_interpolating_solver_factory;
|
||||
ref<solver> m_solver;
|
||||
ref<check_sat_result> m_check_sat_result;
|
||||
|
||||
|
@ -252,6 +253,8 @@ public:
|
|||
void cancel() { set_cancel(true); }
|
||||
void reset_cancel() { set_cancel(false); }
|
||||
context_params & params() { return m_params; }
|
||||
solver_factory &get_solver_factory() { return *m_solver_factory; }
|
||||
solver_factory &get_interpolating_solver_factory() { return *m_interpolating_solver_factory; }
|
||||
void global_params_updated(); // this method should be invoked when global (and module) params are updated.
|
||||
bool set_logic(symbol const & s);
|
||||
bool has_logic() const { return m_logic != symbol::null; }
|
||||
|
@ -274,12 +277,16 @@ public:
|
|||
void set_random_seed(unsigned s) { m_random_seed = s; }
|
||||
bool produce_models() const;
|
||||
bool produce_proofs() const;
|
||||
bool produce_interpolants() const;
|
||||
bool check_interpolants() const;
|
||||
bool produce_unsat_cores() const;
|
||||
bool well_sorted_check_enabled() const;
|
||||
bool validate_model_enabled() const;
|
||||
void set_produce_models(bool flag);
|
||||
void set_produce_unsat_cores(bool flag);
|
||||
void set_produce_proofs(bool flag);
|
||||
void set_produce_interpolants(bool flag);
|
||||
void set_check_interpolants(bool flag);
|
||||
bool produce_assignments() const { return m_produce_assignments; }
|
||||
void set_produce_assignments(bool flag) { m_produce_assignments = flag; }
|
||||
void set_status(status st) { m_status = st; }
|
||||
|
@ -293,6 +300,7 @@ public:
|
|||
sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast<cmd_context*>(this)->m_sexpr_manager = alloc(sexpr_manager); return *m_sexpr_manager; }
|
||||
|
||||
void set_solver_factory(solver_factory * s);
|
||||
void set_interpolating_solver_factory(solver_factory * s);
|
||||
void set_check_sat_result(check_sat_result * r) { m_check_sat_result = r; }
|
||||
check_sat_result * get_check_sat_result() const { return m_check_sat_result.get(); }
|
||||
check_sat_state cs_state() const;
|
||||
|
|
|
@ -61,6 +61,9 @@ void context_params::set(char const * param, char const * value) {
|
|||
else if (p == "proof") {
|
||||
set_bool(m_proof, param, value);
|
||||
}
|
||||
else if (p == "check_interpolants") {
|
||||
set_bool(m_check_interpolants, param, value);
|
||||
}
|
||||
else if (p == "model") {
|
||||
set_bool(m_model, param, value);
|
||||
}
|
||||
|
@ -96,6 +99,7 @@ void context_params::updt_params(params_ref const & p) {
|
|||
m_well_sorted_check = p.get_bool("type_check", p.get_bool("well_sorted_check", true));
|
||||
m_auto_config = p.get_bool("auto_config", true);
|
||||
m_proof = p.get_bool("proof", false);
|
||||
m_check_interpolants = p.get_bool("check_interpolants", false);
|
||||
m_model = p.get_bool("model", true);
|
||||
m_model_validate = p.get_bool("model_validate", false);
|
||||
m_trace = p.get_bool("trace", false);
|
||||
|
@ -111,6 +115,7 @@ void context_params::collect_param_descrs(param_descrs & d) {
|
|||
d.insert("type_check", CPK_BOOL, "type checker (alias for well_sorted_check)", "true");
|
||||
d.insert("auto_config", CPK_BOOL, "use heuristics to automatically select solver and configure it", "true");
|
||||
d.insert("proof", CPK_BOOL, "proof generation, it must be enabled when the Z3 context is created", "false");
|
||||
d.insert("check_interpolants", CPK_BOOL, "check correctness of interpolants", "false");
|
||||
d.insert("model", CPK_BOOL, "model generation for solvers, this parameter can be overwritten when creating a solver", "true");
|
||||
d.insert("model_validate", CPK_BOOL, "validate models produced by solvers", "false");
|
||||
d.insert("trace", CPK_BOOL, "trace generation for VCC", "false");
|
||||
|
|
|
@ -29,6 +29,8 @@ class context_params {
|
|||
public:
|
||||
bool m_auto_config;
|
||||
bool m_proof;
|
||||
bool m_interpolants;
|
||||
bool m_check_interpolants;
|
||||
bool m_debug_ref_count;
|
||||
bool m_trace;
|
||||
std::string m_trace_file_name;
|
||||
|
|
272
src/cmd_context/interpolant_cmds.cpp
Normal file
272
src/cmd_context/interpolant_cmds.cpp
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
interpolant_cmds.cpp
|
||||
|
||||
Abstract:
|
||||
Commands for interpolation.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-12-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include<sstream>
|
||||
#include"cmd_context.h"
|
||||
#include"cmd_util.h"
|
||||
#include"scoped_timer.h"
|
||||
#include"scoped_ctrl_c.h"
|
||||
#include"cancel_eh.h"
|
||||
#include"ast_pp.h"
|
||||
#include"ast_smt_pp.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"parametric_cmd.h"
|
||||
#include"mpq.h"
|
||||
#include"expr2var.h"
|
||||
#include"pp.h"
|
||||
#include"pp_params.hpp"
|
||||
#include"iz3interp.h"
|
||||
#include"iz3checker.h"
|
||||
#include"iz3profiling.h"
|
||||
#include"interp_params.hpp"
|
||||
|
||||
static void show_interpolant_and_maybe_check(cmd_context & ctx,
|
||||
ptr_vector<ast> &cnsts,
|
||||
expr *t,
|
||||
ptr_vector<ast> &interps,
|
||||
params_ref &m_params,
|
||||
bool check)
|
||||
{
|
||||
|
||||
if (m_params.get_bool("som", false))
|
||||
m_params.set_bool("flat", true);
|
||||
th_rewriter s(ctx.m(), m_params);
|
||||
|
||||
for(unsigned i = 0; i < interps.size(); i++){
|
||||
|
||||
expr_ref r(ctx.m());
|
||||
proof_ref pr(ctx.m());
|
||||
s(to_expr(interps[i]),r,pr);
|
||||
|
||||
ctx.regular_stream() << mk_pp(r.get(), ctx.m()) << std::endl;
|
||||
#if 0
|
||||
ast_smt_pp pp(ctx.m());
|
||||
pp.set_logic(ctx.get_logic().str().c_str());
|
||||
pp.display_smt2(ctx.regular_stream(), to_expr(interps[i]));
|
||||
ctx.regular_stream() << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
s.cleanup();
|
||||
|
||||
// verify, for the paranoid...
|
||||
if(check || ctx.check_interpolants()){
|
||||
std::ostringstream err;
|
||||
ast_manager &_m = ctx.m();
|
||||
|
||||
// need a solver -- make one here FIXME is this right?
|
||||
bool proofs_enabled, models_enabled, unsat_core_enabled;
|
||||
params_ref p;
|
||||
ctx.params().get_solver_params(_m, p, proofs_enabled, models_enabled, unsat_core_enabled);
|
||||
scoped_ptr<solver> sp = (ctx.get_solver_factory())(_m, p, false, true, false, ctx.get_logic());
|
||||
|
||||
if(iz3check(_m,sp.get(),err,cnsts,t,interps))
|
||||
ctx.regular_stream() << "correct\n";
|
||||
else
|
||||
ctx.regular_stream() << "incorrect: " << err.str().c_str() << "\n";
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < interps.size(); i++){
|
||||
ctx.m().dec_ref(interps[i]);
|
||||
}
|
||||
|
||||
interp_params itp_params(m_params);
|
||||
if(itp_params.profile())
|
||||
profiling::print(ctx.regular_stream());
|
||||
|
||||
}
|
||||
|
||||
static void check_can_interpolate(cmd_context & ctx){
|
||||
if (!ctx.produce_interpolants())
|
||||
throw cmd_exception("interpolation is not enabled, use command (set-option :produce-interpolants true)");
|
||||
}
|
||||
|
||||
|
||||
static void get_interpolant_and_maybe_check(cmd_context & ctx, expr * t, params_ref &m_params, bool check) {
|
||||
|
||||
check_can_interpolate(ctx);
|
||||
|
||||
// get the proof, if there is one
|
||||
|
||||
if (!ctx.has_manager() ||
|
||||
ctx.cs_state() != cmd_context::css_unsat)
|
||||
throw cmd_exception("proof is not available");
|
||||
expr_ref pr(ctx.m());
|
||||
pr = ctx.get_check_sat_result()->get_proof();
|
||||
if (pr == 0)
|
||||
throw cmd_exception("proof is not available");
|
||||
|
||||
// get the assertions from the context
|
||||
|
||||
ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
|
||||
ptr_vector<expr>::const_iterator end = ctx.end_assertions();
|
||||
ptr_vector<ast> cnsts(end - it);
|
||||
for (int i = 0; it != end; ++it, ++i)
|
||||
cnsts[i] = *it;
|
||||
|
||||
// compute an interpolant
|
||||
|
||||
ptr_vector<ast> interps;
|
||||
|
||||
try {
|
||||
iz3interpolate(ctx.m(),pr.get(),cnsts,t,interps,0);
|
||||
}
|
||||
catch (iz3_bad_tree &) {
|
||||
throw cmd_exception("interpolation pattern contains non-asserted formula");
|
||||
}
|
||||
catch (iz3_incompleteness &) {
|
||||
throw cmd_exception("incompleteness in interpolator");
|
||||
}
|
||||
|
||||
show_interpolant_and_maybe_check(ctx, cnsts, t, interps, m_params, check);
|
||||
}
|
||||
|
||||
static void get_interpolant(cmd_context & ctx, expr * t, params_ref &m_params) {
|
||||
get_interpolant_and_maybe_check(ctx,t,m_params,false);
|
||||
}
|
||||
|
||||
static void get_and_check_interpolant(cmd_context & ctx, params_ref &m_params, expr * t) {
|
||||
get_interpolant_and_maybe_check(ctx,t,m_params,true);
|
||||
}
|
||||
|
||||
|
||||
static void compute_interpolant_and_maybe_check(cmd_context & ctx, expr * t, params_ref &m_params, bool check){
|
||||
|
||||
// create a fresh solver suitable for interpolation
|
||||
bool proofs_enabled, models_enabled, unsat_core_enabled;
|
||||
params_ref p;
|
||||
ast_manager &_m = ctx.m();
|
||||
// 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
|
||||
_m.toggle_proof_mode(PGM_FINE);
|
||||
ctx.params().get_solver_params(_m, p, proofs_enabled, models_enabled, unsat_core_enabled);
|
||||
p.set_bool("proof", true);
|
||||
scoped_ptr<solver> sp = (ctx.get_interpolating_solver_factory())(_m, p, true, models_enabled, false, ctx.get_logic());
|
||||
|
||||
ptr_vector<ast> cnsts;
|
||||
ptr_vector<ast> interps;
|
||||
model_ref m;
|
||||
|
||||
// compute an interpolant
|
||||
|
||||
lbool res;
|
||||
try {
|
||||
res = iz3interpolate(_m, *sp.get(), t, cnsts, interps, m, 0);
|
||||
}
|
||||
catch (iz3_incompleteness &) {
|
||||
throw cmd_exception("incompleteness in interpolator");
|
||||
}
|
||||
|
||||
switch(res){
|
||||
case l_false:
|
||||
ctx.regular_stream() << "unsat\n";
|
||||
show_interpolant_and_maybe_check(ctx, cnsts, t, interps, m_params, check);
|
||||
break;
|
||||
|
||||
case l_true:
|
||||
ctx.regular_stream() << "sat\n";
|
||||
// TODO: how to return the model to the context, if it exists?
|
||||
break;
|
||||
|
||||
case l_undef:
|
||||
ctx.regular_stream() << "unknown\n";
|
||||
// TODO: how to return the model to the context, if it exists?
|
||||
break;
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
ctx.m().dec_ref(cnsts[i]);
|
||||
|
||||
}
|
||||
|
||||
static expr *make_tree(cmd_context & ctx, const ptr_vector<expr> &exprs){
|
||||
if(exprs.size() == 0)
|
||||
throw cmd_exception("not enough arguments");
|
||||
expr *foo = exprs[0];
|
||||
for(unsigned i = 1; i < exprs.size(); i++){
|
||||
foo = ctx.m().mk_and(ctx.m().mk_interp(foo),exprs[i]);
|
||||
}
|
||||
return foo;
|
||||
}
|
||||
|
||||
static void get_interpolant(cmd_context & ctx, const ptr_vector<expr> &exprs, params_ref &m_params) {
|
||||
expr *foo = make_tree(ctx,exprs);
|
||||
ctx.m().inc_ref(foo);
|
||||
get_interpolant(ctx,foo,m_params);
|
||||
ctx.m().dec_ref(foo);
|
||||
}
|
||||
|
||||
static void compute_interpolant(cmd_context & ctx, const ptr_vector<expr> &exprs, params_ref &m_params) {
|
||||
expr *foo = make_tree(ctx, exprs);
|
||||
ctx.m().inc_ref(foo);
|
||||
compute_interpolant_and_maybe_check(ctx,foo,m_params,false);
|
||||
ctx.m().dec_ref(foo);
|
||||
}
|
||||
|
||||
|
||||
// UNARY_CMD(get_interpolant_cmd, "get-interpolant", "<fmla>", "get interpolant for marked positions in fmla", CPK_EXPR, expr *, get_interpolant(ctx, arg););
|
||||
|
||||
// UNARY_CMD(get_and_check_interpolant_cmd, "get-and-check-interpolant", "<fmla>", "get and check interpolant for marked positions in fmla", CPK_EXPR, expr *, get_and_check_interpolant(ctx, arg););
|
||||
|
||||
class get_interpolant_cmd : public parametric_cmd {
|
||||
protected:
|
||||
ptr_vector<expr> m_targets;
|
||||
public:
|
||||
get_interpolant_cmd(char const * name = "get-interpolant"):parametric_cmd(name) {}
|
||||
|
||||
virtual char const * get_usage() const { return "<fmla>+"; }
|
||||
|
||||
virtual char const * get_main_descr() const {
|
||||
return "get interpolant for formulas";
|
||||
}
|
||||
|
||||
virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) {
|
||||
}
|
||||
|
||||
virtual void prepare(cmd_context & ctx) {
|
||||
parametric_cmd::prepare(ctx);
|
||||
m_targets.resize(0);
|
||||
}
|
||||
|
||||
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const {
|
||||
return CPK_EXPR;
|
||||
}
|
||||
|
||||
virtual void set_next_arg(cmd_context & ctx, expr * arg) {
|
||||
m_targets.push_back(arg);
|
||||
}
|
||||
|
||||
virtual void execute(cmd_context & ctx) {
|
||||
get_interpolant(ctx,m_targets,m_params);
|
||||
}
|
||||
};
|
||||
|
||||
class compute_interpolant_cmd : public get_interpolant_cmd {
|
||||
public:
|
||||
compute_interpolant_cmd(char const * name = "compute-interpolant"):get_interpolant_cmd(name) {}
|
||||
|
||||
virtual void execute(cmd_context & ctx) {
|
||||
compute_interpolant(ctx,m_targets,m_params);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void install_interpolant_cmds(cmd_context & ctx) {
|
||||
ctx.insert(alloc(get_interpolant_cmd));
|
||||
ctx.insert(alloc(compute_interpolant_cmd));
|
||||
// ctx.insert(alloc(get_and_check_interpolant_cmd));
|
||||
}
|
24
src/cmd_context/interpolant_cmds.h
Normal file
24
src/cmd_context/interpolant_cmds.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
interpolant_cmds.h
|
||||
|
||||
Abstract:
|
||||
Commands for interpolation.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-12-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _INTERPOLANT_CMDS_H_
|
||||
#define _INTERPOLANT_CMDS_H_
|
||||
|
||||
class cmd_context;
|
||||
void install_interpolant_cmds(cmd_context & ctx);
|
||||
|
||||
#endif
|
1044
src/duality/duality.h
Normal file
1044
src/duality/duality.h
Normal file
File diff suppressed because it is too large
Load diff
169
src/duality/duality_hash.h
Executable file
169
src/duality/duality_hash.h
Executable file
|
@ -0,0 +1,169 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3hash.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Wrapper for stl hash tables
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
// pull in the headers for has_map and hash_set
|
||||
// these live in non-standard places
|
||||
|
||||
#ifndef IZ3_HASH_H
|
||||
#define IZ3_HASH_H
|
||||
|
||||
//#define USE_UNORDERED_MAP
|
||||
#ifdef USE_UNORDERED_MAP
|
||||
|
||||
#define stl_ext std
|
||||
#define hash_space std
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#define hash_map unordered_map
|
||||
#define hash_set unordered_set
|
||||
|
||||
#else
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
#undef __DEPRECATED
|
||||
#define stl_ext __gnu_cxx
|
||||
#define hash_space stl_ext
|
||||
#include <ext/hash_map>
|
||||
#include <ext/hash_set>
|
||||
#else
|
||||
#ifdef WIN32
|
||||
#define stl_ext stdext
|
||||
#define hash_space std
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#else
|
||||
#define stl_ext std
|
||||
#define hash_space std
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
// stupid STL doesn't include hash function for class string
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
namespace stl_ext {
|
||||
template <>
|
||||
class hash<std::string> {
|
||||
stl_ext::hash<char *> H;
|
||||
public:
|
||||
size_t operator()(const std::string &s) const {
|
||||
return H(s.c_str());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace hash_space {
|
||||
template <>
|
||||
class hash<std::pair<int,int> > {
|
||||
public:
|
||||
size_t operator()(const std::pair<int,int> &p) const {
|
||||
return p.first + p.second;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
template <> inline
|
||||
size_t stdext::hash_value<std::pair<int,int> >(const std::pair<int,int>& p)
|
||||
{ // hash _Keyval to size_t value one-to-one
|
||||
return p.first + p.second;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace hash_space {
|
||||
template <class T>
|
||||
class hash<std::pair<T *, T *> > {
|
||||
public:
|
||||
size_t operator()(const std::pair<T *,T *> &p) const {
|
||||
return (size_t)p.first + (size_t)p.second;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <class T> inline
|
||||
size_t stdext::hash_value<std::pair<T *, T *> >(const std::pair<T *, T *>& p)
|
||||
{ // hash _Keyval to size_t value one-to-one
|
||||
return (size_t)p.first + (size_t)p.second;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
class less<std::pair<int,int> > {
|
||||
public:
|
||||
bool operator()(const pair<int,int> &x, const pair<int,int> &y) const {
|
||||
return x.first < y.first || x.first == y.first && x.second < y.second;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <class T>
|
||||
class less<std::pair<T *,T *> > {
|
||||
public:
|
||||
bool operator()(const pair<T *,T *> &x, const pair<T *,T *> &y) const {
|
||||
return (size_t)x.first < (size_t)y.first || (size_t)x.first == (size_t)y.first && (size_t)x.second < (size_t)y.second;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
namespace stl_ext {
|
||||
template <class T>
|
||||
class hash<T *> {
|
||||
public:
|
||||
size_t operator()(const T *p) const {
|
||||
return (size_t) p;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
|
||||
|
||||
|
||||
template <class K, class T>
|
||||
class hash_map : public stl_ext::hash_map<K,T,stl_ext::hash_compare<K,std::less<K> > > {};
|
||||
|
||||
template <class K>
|
||||
class hash_set : public stl_ext::hash_set<K,stl_ext::hash_compare<K,std::less<K> > > {};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
126
src/duality/duality_profiling.cpp
Executable file
126
src/duality/duality_profiling.cpp
Executable file
|
@ -0,0 +1,126 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
duality_profiling.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
collection performance information for duality
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "duality_wrapper.h"
|
||||
|
||||
namespace Duality {
|
||||
|
||||
void show_time(){
|
||||
output_time(std::cout,current_time());
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
typedef std::map<const char*, struct node> nmap;
|
||||
|
||||
struct node {
|
||||
std::string name;
|
||||
clock_t time;
|
||||
clock_t start_time;
|
||||
nmap sub;
|
||||
struct node *parent;
|
||||
|
||||
node();
|
||||
} top;
|
||||
|
||||
node::node(){
|
||||
time = 0;
|
||||
parent = 0;
|
||||
}
|
||||
|
||||
struct node *current;
|
||||
|
||||
struct init {
|
||||
init(){
|
||||
top.name = "TOTAL";
|
||||
current = ⊤
|
||||
}
|
||||
} initializer;
|
||||
|
||||
struct time_entry {
|
||||
clock_t t;
|
||||
time_entry(){t = 0;};
|
||||
void add(clock_t incr){t += incr;}
|
||||
};
|
||||
|
||||
struct ltstr
|
||||
{
|
||||
bool operator()(const char* s1, const char* s2) const
|
||||
{
|
||||
return strcmp(s1, s2) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<const char*, time_entry, ltstr> tmap;
|
||||
|
||||
static std::ostream *pfs;
|
||||
|
||||
void print_node(node &top, int indent, tmap &totals){
|
||||
for(int i = 0; i < indent; i++) (*pfs) << " ";
|
||||
(*pfs) << top.name;
|
||||
int dots = 70 - 2 * indent - top.name.size();
|
||||
for(int i = 0; i <dots; i++) (*pfs) << ".";
|
||||
output_time(*pfs, top.time);
|
||||
(*pfs) << std::endl;
|
||||
if(indent != 0)totals[top.name.c_str()].add(top.time);
|
||||
for(nmap::iterator it = top.sub.begin(); it != top.sub.end(); it++)
|
||||
print_node(it->second,indent+1,totals);
|
||||
}
|
||||
|
||||
void print_profile(std::ostream &os) {
|
||||
pfs = &os;
|
||||
top.time = 0;
|
||||
for(nmap::iterator it = top.sub.begin(); it != top.sub.end(); it++)
|
||||
top.time += it->second.time;
|
||||
tmap totals;
|
||||
print_node(top,0,totals);
|
||||
(*pfs) << "TOTALS:" << std::endl;
|
||||
for(tmap::iterator it = totals.begin(); it != totals.end(); it++){
|
||||
(*pfs) << (it->first) << " ";
|
||||
output_time(*pfs, it->second.t);
|
||||
(*pfs) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_start(const char *name){
|
||||
node &child = current->sub[name];
|
||||
if(child.name.empty()){ // a new node
|
||||
child.parent = current;
|
||||
child.name = name;
|
||||
}
|
||||
child.start_time = current_time();
|
||||
current = &child;
|
||||
}
|
||||
|
||||
void timer_stop(const char *name){
|
||||
if(current->name != name || !current->parent){
|
||||
std::cerr << "imbalanced timer_start and timer_stop";
|
||||
exit(1);
|
||||
}
|
||||
current->time += (current_time() - current->start_time);
|
||||
current = current->parent;
|
||||
}
|
||||
}
|
38
src/duality/duality_profiling.h
Executable file
38
src/duality/duality_profiling.h
Executable file
|
@ -0,0 +1,38 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
duality_profiling.h
|
||||
|
||||
Abstract:
|
||||
|
||||
collection performance information for duality
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef DUALITYPROFILING_H
|
||||
#define DUALITYPROFILING_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace Duality {
|
||||
/** Start a timer with given name */
|
||||
void timer_start(const char *);
|
||||
/** Stop a timer with given name */
|
||||
void timer_stop(const char *);
|
||||
/** Print out timings */
|
||||
void print_profile(std::ostream &s);
|
||||
/** Show the current time. */
|
||||
void show_time();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
2894
src/duality/duality_rpfp.cpp
Normal file
2894
src/duality/duality_rpfp.cpp
Normal file
File diff suppressed because it is too large
Load diff
2518
src/duality/duality_solver.cpp
Normal file
2518
src/duality/duality_solver.cpp
Normal file
File diff suppressed because it is too large
Load diff
677
src/duality/duality_wrapper.cpp
Normal file
677
src/duality/duality_wrapper.cpp
Normal file
|
@ -0,0 +1,677 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
wrapper.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
wrap various objects in the style expected by duality
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "duality_wrapper.h"
|
||||
#include <iostream>
|
||||
#include "smt_solver.h"
|
||||
#include "iz3interp.h"
|
||||
#include "statistics.h"
|
||||
#include "expr_abstract.h"
|
||||
#include "stopwatch.h"
|
||||
#include "model_smt2_pp.h"
|
||||
#include "qe_lite.h"
|
||||
|
||||
namespace Duality {
|
||||
|
||||
solver::solver(Duality::context& c, bool extensional) : object(c), the_model(c) {
|
||||
params_ref p;
|
||||
p.set_bool("proof", true); // this is currently useless
|
||||
p.set_bool("model", true);
|
||||
p.set_bool("unsat_core", true);
|
||||
p.set_bool("mbqi",true);
|
||||
p.set_str("mbqi.id","itp"); // use mbqi for quantifiers in interpolants
|
||||
p.set_uint("mbqi.max_iterations",1); // use mbqi for quantifiers in interpolants
|
||||
if(true || extensional)
|
||||
p.set_bool("array.extensional",true);
|
||||
scoped_ptr<solver_factory> sf = mk_smt_solver_factory();
|
||||
m_solver = (*sf)(m(), p, true, true, true, ::symbol::null);
|
||||
m_solver->updt_params(p); // why do we have to do this?
|
||||
canceled = false;
|
||||
}
|
||||
|
||||
expr context::constant(const std::string &name, const sort &ty){
|
||||
symbol s = str_symbol(name.c_str());
|
||||
return cook(m().mk_const(m().mk_const_decl(s, ty)));
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op, int n, ::expr **args){
|
||||
switch(op) {
|
||||
case True: return mki(m_basic_fid,OP_TRUE,n,args);
|
||||
case False: return mki(m_basic_fid,OP_FALSE,n,args);
|
||||
case Equal: return mki(m_basic_fid,OP_EQ,n,args);
|
||||
case Distinct: return mki(m_basic_fid,OP_DISTINCT,n,args);
|
||||
case Ite: return mki(m_basic_fid,OP_ITE,n,args);
|
||||
case And: return mki(m_basic_fid,OP_AND,n,args);
|
||||
case Or: return mki(m_basic_fid,OP_OR,n,args);
|
||||
case Iff: return mki(m_basic_fid,OP_IFF,n,args);
|
||||
case Xor: return mki(m_basic_fid,OP_XOR,n,args);
|
||||
case Not: return mki(m_basic_fid,OP_NOT,n,args);
|
||||
case Implies: return mki(m_basic_fid,OP_IMPLIES,n,args);
|
||||
case Oeq: return mki(m_basic_fid,OP_OEQ,n,args);
|
||||
case Interp: return mki(m_basic_fid,OP_INTERP,n,args);
|
||||
case Leq: return mki(m_arith_fid,OP_LE,n,args);
|
||||
case Geq: return mki(m_arith_fid,OP_GE,n,args);
|
||||
case Lt: return mki(m_arith_fid,OP_LT,n,args);
|
||||
case Gt: return mki(m_arith_fid,OP_GT,n,args);
|
||||
case Plus: return mki(m_arith_fid,OP_ADD,n,args);
|
||||
case Sub: return mki(m_arith_fid,OP_SUB,n,args);
|
||||
case Uminus: return mki(m_arith_fid,OP_UMINUS,n,args);
|
||||
case Times: return mki(m_arith_fid,OP_MUL,n,args);
|
||||
case Div: return mki(m_arith_fid,OP_DIV,n,args);
|
||||
case Idiv: return mki(m_arith_fid,OP_IDIV,n,args);
|
||||
case Rem: return mki(m_arith_fid,OP_REM,n,args);
|
||||
case Mod: return mki(m_arith_fid,OP_MOD,n,args);
|
||||
case Power: return mki(m_arith_fid,OP_POWER,n,args);
|
||||
case ToReal: return mki(m_arith_fid,OP_TO_REAL,n,args);
|
||||
case ToInt: return mki(m_arith_fid,OP_TO_INT,n,args);
|
||||
case IsInt: return mki(m_arith_fid,OP_IS_INT,n,args);
|
||||
case Store: return mki(m_array_fid,OP_STORE,n,args);
|
||||
case Select: return mki(m_array_fid,OP_SELECT,n,args);
|
||||
case ConstArray: return mki(m_array_fid,OP_CONST_ARRAY,n,args);
|
||||
case ArrayDefault: return mki(m_array_fid,OP_ARRAY_DEFAULT,n,args);
|
||||
case ArrayMap: return mki(m_array_fid,OP_ARRAY_MAP,n,args);
|
||||
case SetUnion: return mki(m_array_fid,OP_SET_UNION,n,args);
|
||||
case SetIntersect: return mki(m_array_fid,OP_SET_INTERSECT,n,args);
|
||||
case SetDifference: return mki(m_array_fid,OP_SET_DIFFERENCE,n,args);
|
||||
case SetComplement: return mki(m_array_fid,OP_SET_COMPLEMENT,n,args);
|
||||
case SetSubSet: return mki(m_array_fid,OP_SET_SUBSET,n,args);
|
||||
case AsArray: return mki(m_array_fid,OP_AS_ARRAY,n,args);
|
||||
default:
|
||||
assert(0);
|
||||
return expr(*this);
|
||||
}
|
||||
}
|
||||
|
||||
expr context::mki(family_id fid, ::decl_kind dk, int n, ::expr **args){
|
||||
return cook(m().mk_app(fid, dk, 0, 0, n, (::expr **)args));
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op, const std::vector<expr> &args){
|
||||
static std::vector< ::expr*> a(10);
|
||||
if(a.size() < args.size())
|
||||
a.resize(args.size());
|
||||
for(unsigned i = 0; i < args.size(); i++)
|
||||
a[i] = to_expr(args[i].raw());
|
||||
return make(op,args.size(), args.size() ? &a[0] : 0);
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op){
|
||||
return make(op,0,0);
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op, const expr &arg0){
|
||||
::expr *a = to_expr(arg0.raw());
|
||||
return make(op,1,&a);
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op, const expr &arg0, const expr &arg1){
|
||||
::expr *args[2];
|
||||
args[0] = to_expr(arg0.raw());
|
||||
args[1] = to_expr(arg1.raw());
|
||||
return make(op,2,args);
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op, const expr &arg0, const expr &arg1, const expr &arg2){
|
||||
::expr *args[3];
|
||||
args[0] = to_expr(arg0.raw());
|
||||
args[1] = to_expr(arg1.raw());
|
||||
args[2] = to_expr(arg2.raw());
|
||||
return make(op,3,args);
|
||||
}
|
||||
|
||||
expr context::make_quant(decl_kind op, const std::vector<expr> &bvs, const expr &body){
|
||||
if(bvs.size() == 0) return body;
|
||||
std::vector< ::expr *> foo(bvs.size());
|
||||
|
||||
|
||||
std::vector< ::symbol> names;
|
||||
std::vector< ::sort *> types;
|
||||
std::vector< ::expr *> bound_asts;
|
||||
unsigned num_bound = bvs.size();
|
||||
|
||||
for (unsigned i = 0; i < num_bound; ++i) {
|
||||
app* a = to_app(bvs[i].raw());
|
||||
::symbol s(to_app(a)->get_decl()->get_name());
|
||||
names.push_back(s);
|
||||
types.push_back(m().get_sort(a));
|
||||
bound_asts.push_back(a);
|
||||
}
|
||||
expr_ref abs_body(m());
|
||||
expr_abstract(m(), 0, num_bound, &bound_asts[0], to_expr(body.raw()), abs_body);
|
||||
expr_ref result(m());
|
||||
result = m().mk_quantifier(
|
||||
op == Forall,
|
||||
names.size(), &types[0], &names[0], abs_body.get(),
|
||||
0,
|
||||
::symbol(),
|
||||
::symbol(),
|
||||
0, 0,
|
||||
0, 0
|
||||
);
|
||||
return cook(result.get());
|
||||
}
|
||||
|
||||
expr context::make_quant(decl_kind op, const std::vector<sort> &_sorts, const std::vector<symbol> &_names, const expr &body){
|
||||
if(_sorts.size() == 0) return body;
|
||||
|
||||
|
||||
std::vector< ::symbol> names;
|
||||
std::vector< ::sort *> types;
|
||||
std::vector< ::expr *> bound_asts;
|
||||
unsigned num_bound = _sorts.size();
|
||||
|
||||
for (unsigned i = 0; i < num_bound; ++i) {
|
||||
names.push_back(_names[i]);
|
||||
types.push_back(to_sort(_sorts[i].raw()));
|
||||
}
|
||||
expr_ref result(m());
|
||||
result = m().mk_quantifier(
|
||||
op == Forall,
|
||||
names.size(), &types[0], &names[0], to_expr(body.raw()),
|
||||
0,
|
||||
::symbol(),
|
||||
::symbol(),
|
||||
0, 0,
|
||||
0, 0
|
||||
);
|
||||
return cook(result.get());
|
||||
}
|
||||
|
||||
|
||||
decl_kind func_decl::get_decl_kind() const {
|
||||
return ctx().get_decl_kind(*this);
|
||||
}
|
||||
|
||||
decl_kind context::get_decl_kind(const func_decl &t){
|
||||
::func_decl *d = to_func_decl(t.raw());
|
||||
if (null_family_id == d->get_family_id())
|
||||
return Uninterpreted;
|
||||
// return (opr)d->get_decl_kind();
|
||||
if (m_basic_fid == d->get_family_id()) {
|
||||
switch(d->get_decl_kind()) {
|
||||
case OP_TRUE: return True;
|
||||
case OP_FALSE: return False;
|
||||
case OP_EQ: return Equal;
|
||||
case OP_DISTINCT: return Distinct;
|
||||
case OP_ITE: return Ite;
|
||||
case OP_AND: return And;
|
||||
case OP_OR: return Or;
|
||||
case OP_IFF: return Iff;
|
||||
case OP_XOR: return Xor;
|
||||
case OP_NOT: return Not;
|
||||
case OP_IMPLIES: return Implies;
|
||||
case OP_OEQ: return Oeq;
|
||||
case OP_INTERP: return Interp;
|
||||
default:
|
||||
return OtherBasic;
|
||||
}
|
||||
}
|
||||
if (m_arith_fid == d->get_family_id()) {
|
||||
switch(d->get_decl_kind()) {
|
||||
case OP_LE: return Leq;
|
||||
case OP_GE: return Geq;
|
||||
case OP_LT: return Lt;
|
||||
case OP_GT: return Gt;
|
||||
case OP_ADD: return Plus;
|
||||
case OP_SUB: return Sub;
|
||||
case OP_UMINUS: return Uminus;
|
||||
case OP_MUL: return Times;
|
||||
case OP_DIV: return Div;
|
||||
case OP_IDIV: return Idiv;
|
||||
case OP_REM: return Rem;
|
||||
case OP_MOD: return Mod;
|
||||
case OP_POWER: return Power;
|
||||
case OP_TO_REAL: return ToReal;
|
||||
case OP_TO_INT: return ToInt;
|
||||
case OP_IS_INT: return IsInt;
|
||||
default:
|
||||
return OtherArith;
|
||||
}
|
||||
}
|
||||
if (m_array_fid == d->get_family_id()) {
|
||||
switch(d->get_decl_kind()) {
|
||||
case OP_STORE: return Store;
|
||||
case OP_SELECT: return Select;
|
||||
case OP_CONST_ARRAY: return ConstArray;
|
||||
case OP_ARRAY_DEFAULT: return ArrayDefault;
|
||||
case OP_ARRAY_MAP: return ArrayMap;
|
||||
case OP_SET_UNION: return SetUnion;
|
||||
case OP_SET_INTERSECT: return SetIntersect;
|
||||
case OP_SET_DIFFERENCE: return SetDifference;
|
||||
case OP_SET_COMPLEMENT: return SetComplement;
|
||||
case OP_SET_SUBSET: return SetSubSet;
|
||||
case OP_AS_ARRAY: return AsArray;
|
||||
default:
|
||||
return OtherArray;
|
||||
}
|
||||
}
|
||||
|
||||
return Other;
|
||||
}
|
||||
|
||||
|
||||
sort_kind context::get_sort_kind(const sort &s){
|
||||
family_id fid = to_sort(s.raw())->get_family_id();
|
||||
::decl_kind k = to_sort(s.raw())->get_decl_kind();
|
||||
if (m().is_uninterp(to_sort(s.raw()))) {
|
||||
return UninterpretedSort;
|
||||
}
|
||||
else if (fid == m_basic_fid && k == BOOL_SORT) {
|
||||
return BoolSort;
|
||||
}
|
||||
else if (fid == m_arith_fid && k == INT_SORT) {
|
||||
return IntSort;
|
||||
}
|
||||
else if (fid == m_arith_fid && k == REAL_SORT) {
|
||||
return RealSort;
|
||||
}
|
||||
else if (fid == m_array_fid && k == ARRAY_SORT) {
|
||||
return ArraySort;
|
||||
}
|
||||
else {
|
||||
return UnknownSort;
|
||||
}
|
||||
}
|
||||
|
||||
expr func_decl::operator()(unsigned n, expr const * args) const {
|
||||
std::vector< ::expr *> _args(n);
|
||||
for(unsigned i = 0; i < n; i++)
|
||||
_args[i] = to_expr(args[i].raw());
|
||||
return ctx().cook(m().mk_app(to_func_decl(raw()),n,&_args[0]));
|
||||
}
|
||||
|
||||
int solver::get_num_decisions(){
|
||||
::statistics st;
|
||||
m_solver->collect_statistics(st);
|
||||
std::ostringstream ss;
|
||||
st.display(ss);
|
||||
std::string stats = ss.str();
|
||||
int pos = stats.find("decisions:");
|
||||
if(pos < 0) return 0; // for some reason, decisions are not reported if there are none
|
||||
pos += 10;
|
||||
int end = stats.find('\n',pos);
|
||||
std::string val = stats.substr(pos,end-pos);
|
||||
return atoi(val.c_str());
|
||||
}
|
||||
|
||||
void context::print_expr(std::ostream &s, const ast &e){
|
||||
s << mk_pp(e.raw(), m());
|
||||
}
|
||||
|
||||
|
||||
expr expr::simplify(const params &_p) const {
|
||||
::expr * a = to_expr(raw());
|
||||
params_ref p = _p.get();
|
||||
th_rewriter m_rw(m(), p);
|
||||
expr_ref result(m());
|
||||
m_rw(a, result);
|
||||
return ctx().cook(result);
|
||||
}
|
||||
|
||||
expr expr::simplify() const {
|
||||
params p;
|
||||
return simplify(p);
|
||||
}
|
||||
|
||||
expr expr::qe_lite() const {
|
||||
::qe_lite qe(m());
|
||||
expr_ref result(to_expr(raw()),m());
|
||||
proof_ref pf(m());
|
||||
qe(result,pf);
|
||||
return ctx().cook(result);
|
||||
}
|
||||
|
||||
expr clone_quantifier(const expr &q, const expr &b){
|
||||
return q.ctx().cook(q.m().update_quantifier(to_quantifier(q.raw()), to_expr(b.raw())));
|
||||
}
|
||||
|
||||
expr clone_quantifier(const expr &q, const expr &b, const std::vector<expr> &patterns){
|
||||
quantifier *thing = to_quantifier(q.raw());
|
||||
bool is_forall = thing->is_forall();
|
||||
unsigned num_patterns = patterns.size();
|
||||
std::vector< ::expr *> _patterns(num_patterns);
|
||||
for(unsigned i = 0; i < num_patterns; i++)
|
||||
_patterns[i] = to_expr(patterns[i].raw());
|
||||
return q.ctx().cook(q.m().update_quantifier(thing, is_forall, num_patterns, &_patterns[0], to_expr(b.raw())));
|
||||
}
|
||||
|
||||
void expr::get_patterns(std::vector<expr> &pats) const {
|
||||
quantifier *thing = to_quantifier(raw());
|
||||
unsigned num_patterns = thing->get_num_patterns();
|
||||
:: expr * const *it = thing->get_patterns();
|
||||
pats.resize(num_patterns);
|
||||
for(unsigned i = 0; i < num_patterns; i++)
|
||||
pats[i] = expr(ctx(),it[i]);
|
||||
}
|
||||
|
||||
|
||||
func_decl context::fresh_func_decl(char const * prefix, const std::vector<sort> &domain, sort const & range){
|
||||
std::vector < ::sort * > _domain(domain.size());
|
||||
for(unsigned i = 0; i < domain.size(); i++)
|
||||
_domain[i] = to_sort(domain[i].raw());
|
||||
::func_decl* d = m().mk_fresh_func_decl(prefix,
|
||||
_domain.size(),
|
||||
&_domain[0],
|
||||
to_sort(range.raw()));
|
||||
return func_decl(*this,d);
|
||||
}
|
||||
|
||||
func_decl context::fresh_func_decl(char const * prefix, sort const & range){
|
||||
::func_decl* d = m().mk_fresh_func_decl(prefix,
|
||||
0,
|
||||
0,
|
||||
to_sort(range.raw()));
|
||||
return func_decl(*this,d);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
lbool interpolating_solver::interpolate(
|
||||
const std::vector<expr> &assumptions,
|
||||
std::vector<expr> &interpolants,
|
||||
model &model,
|
||||
Z3_literals &labels,
|
||||
bool incremental)
|
||||
{
|
||||
Z3_model _model = 0;
|
||||
Z3_literals _labels = 0;
|
||||
Z3_lbool lb;
|
||||
std::vector<Z3_ast> _assumptions(assumptions.size());
|
||||
std::vector<Z3_ast> _interpolants(assumptions.size()-1);
|
||||
for(unsigned i = 0; i < assumptions.size(); i++)
|
||||
_assumptions[i] = assumptions[i];
|
||||
std::vector<Z3_ast> _theory(theory.size());
|
||||
for(unsigned i = 0; i < theory.size(); i++)
|
||||
_theory[i] = theory[i];
|
||||
|
||||
lb = Z3_interpolate(
|
||||
ctx(),
|
||||
_assumptions.size(),
|
||||
&_assumptions[0],
|
||||
0,
|
||||
0,
|
||||
&_interpolants[0],
|
||||
&_model,
|
||||
&_labels,
|
||||
incremental,
|
||||
_theory.size(),
|
||||
&_theory[0]
|
||||
);
|
||||
|
||||
if(lb == Z3_L_FALSE){
|
||||
interpolants.resize(_interpolants.size());
|
||||
for (unsigned i = 0; i < _interpolants.size(); ++i) {
|
||||
interpolants[i] = expr(ctx(),_interpolants[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (_model) {
|
||||
model = iz3wrapper::model(ctx(), _model);
|
||||
}
|
||||
|
||||
if(_labels){
|
||||
labels = _labels;
|
||||
}
|
||||
|
||||
return lb;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int linearize_assumptions(int num,
|
||||
TermTree *assumptions,
|
||||
std::vector<std::vector <expr> > &linear_assumptions,
|
||||
std::vector<int> &parents){
|
||||
for(unsigned i = 0; i < assumptions->getChildren().size(); i++)
|
||||
num = linearize_assumptions(num, assumptions->getChildren()[i], linear_assumptions, parents);
|
||||
// linear_assumptions[num].push_back(assumptions->getTerm());
|
||||
for(unsigned i = 0; i < assumptions->getChildren().size(); i++)
|
||||
parents[assumptions->getChildren()[i]->getNumber()] = num;
|
||||
parents[num] = SHRT_MAX; // in case we have no parent
|
||||
linear_assumptions[num].push_back(assumptions->getTerm());
|
||||
std::vector<expr> &ts = assumptions->getTerms();
|
||||
for(unsigned i = 0; i < ts.size(); i++)
|
||||
linear_assumptions[num].push_back(ts[i]);
|
||||
return num + 1;
|
||||
}
|
||||
|
||||
static int unlinearize_interpolants(int num,
|
||||
TermTree* assumptions,
|
||||
const std::vector<expr> &interpolant,
|
||||
TermTree * &tree_interpolant)
|
||||
{
|
||||
std::vector<TermTree *> chs(assumptions->getChildren().size());
|
||||
for(unsigned i = 0; i < assumptions->getChildren().size(); i++)
|
||||
num = unlinearize_interpolants(num, assumptions->getChildren()[i], interpolant,chs[i]);
|
||||
expr f;
|
||||
if(num < (int)interpolant.size()) // last interpolant is missing, presumed false
|
||||
f = interpolant[num];
|
||||
tree_interpolant = new TermTree(f,chs);
|
||||
return num + 1;
|
||||
}
|
||||
|
||||
|
||||
lbool interpolating_solver::interpolate_tree(TermTree *assumptions,
|
||||
TermTree *&interpolant,
|
||||
model &model,
|
||||
literals &labels,
|
||||
bool incremental
|
||||
)
|
||||
|
||||
{
|
||||
int size = assumptions->number(0);
|
||||
std::vector<std::vector<expr> > linear_assumptions(size);
|
||||
std::vector<int> parents(size);
|
||||
linearize_assumptions(0,assumptions,linear_assumptions,parents);
|
||||
|
||||
ptr_vector< ::ast> _interpolants(size-1);
|
||||
vector<ptr_vector< ::ast> >_assumptions(size);
|
||||
for(int i = 0; i < size; i++)
|
||||
for(unsigned j = 0; j < linear_assumptions[i].size(); j++)
|
||||
_assumptions[i].push_back(linear_assumptions[i][j]);
|
||||
::vector<int> _parents; _parents.resize(parents.size());
|
||||
for(unsigned i = 0; i < parents.size(); i++)
|
||||
_parents[i] = parents[i];
|
||||
ptr_vector< ::ast> _theory(theory.size());
|
||||
for(unsigned i = 0; i < theory.size(); i++)
|
||||
_theory[i] = theory[i];
|
||||
|
||||
|
||||
if(!incremental){
|
||||
push();
|
||||
for(unsigned i = 0; i < linear_assumptions.size(); i++)
|
||||
for(unsigned j = 0; j < linear_assumptions[i].size(); j++)
|
||||
add(linear_assumptions[i][j]);
|
||||
}
|
||||
|
||||
check_result res = check();
|
||||
|
||||
if(res == unsat){
|
||||
|
||||
interpolation_options_struct opts;
|
||||
if(weak_mode)
|
||||
opts.set("weak","1");
|
||||
|
||||
::ast *proof = m_solver->get_proof();
|
||||
iz3interpolate(m(),proof,_assumptions,_parents,_interpolants,_theory,&opts);
|
||||
|
||||
std::vector<expr> linearized_interpolants(_interpolants.size());
|
||||
for(unsigned i = 0; i < _interpolants.size(); i++)
|
||||
linearized_interpolants[i] = expr(ctx(),_interpolants[i]);
|
||||
|
||||
// since iz3interpolant returns interpolants with one ref count, we decrement here
|
||||
for(unsigned i = 0; i < _interpolants.size(); i++)
|
||||
m().dec_ref(_interpolants[i]);
|
||||
|
||||
unlinearize_interpolants(0,assumptions,linearized_interpolants,interpolant);
|
||||
interpolant->setTerm(ctx().bool_val(false));
|
||||
}
|
||||
|
||||
model_ref _m;
|
||||
m_solver->get_model(_m);
|
||||
model = Duality::model(ctx(),_m.get());
|
||||
|
||||
#if 0
|
||||
if(_labels){
|
||||
labels = _labels;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!incremental)
|
||||
pop();
|
||||
|
||||
return (res == unsat) ? l_false : ((res == sat) ? l_true : l_undef);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void interpolating_solver::SetWeakInterpolants(bool weak){
|
||||
weak_mode = weak;
|
||||
}
|
||||
|
||||
|
||||
void interpolating_solver::SetPrintToFile(const std::string &filename){
|
||||
print_filename = filename;
|
||||
}
|
||||
|
||||
void interpolating_solver::AssertInterpolationAxiom(const expr & t){
|
||||
add(t);
|
||||
theory.push_back(t);
|
||||
}
|
||||
|
||||
|
||||
void interpolating_solver::RemoveInterpolationAxiom(const expr & t){
|
||||
// theory.remove(t);
|
||||
}
|
||||
|
||||
|
||||
const char *interpolating_solver::profile(){
|
||||
// return Z3_interpolation_profile(ctx());
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
static void get_assumptions_rec(stl_ext::hash_set<ast> &memo, const proof &pf, std::vector<expr> &assumps){
|
||||
if(memo.find(pf) != memo.end())return;
|
||||
memo.insert(pf);
|
||||
pfrule dk = pf.rule();
|
||||
if(dk == PR_ASSERTED){
|
||||
expr con = pf.conc();
|
||||
assumps.push_back(con);
|
||||
}
|
||||
else {
|
||||
unsigned nprems = pf.num_prems();
|
||||
for(unsigned i = 0; i < nprems; i++){
|
||||
proof arg = pf.prem(i);
|
||||
get_assumptions_rec(memo,arg,assumps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void proof::get_assumptions(std::vector<expr> &assumps){
|
||||
stl_ext::hash_set<ast> memo;
|
||||
get_assumptions_rec(memo,*this,assumps);
|
||||
}
|
||||
|
||||
|
||||
void ast::show() const{
|
||||
std::cout << mk_pp(raw(), m()) << std::endl;
|
||||
}
|
||||
|
||||
void model::show() const {
|
||||
model_smt2_pp(std::cout, m(), *m_model, 0);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void model::show_hash() const {
|
||||
std::ostringstream ss;
|
||||
model_smt2_pp(ss, m(), *m_model, 0);
|
||||
hash_space::hash<std::string> hasher;
|
||||
unsigned h = hasher(ss.str());
|
||||
std::cout << "model hash: " << h << "\n";
|
||||
}
|
||||
|
||||
void solver::show() {
|
||||
unsigned n = m_solver->get_num_assertions();
|
||||
if(!n)
|
||||
return;
|
||||
ast_smt_pp pp(m());
|
||||
for (unsigned i = 0; i < n-1; ++i)
|
||||
pp.add_assumption(m_solver->get_assertion(i));
|
||||
pp.display_smt2(std::cout, m_solver->get_assertion(n-1));
|
||||
}
|
||||
|
||||
void solver::show_assertion_ids() {
|
||||
#if 0
|
||||
unsigned n = m_solver->get_num_assertions();
|
||||
std::cerr << "assertion ids: ";
|
||||
for (unsigned i = 0; i < n-1; ++i)
|
||||
std::cerr << " " << m_solver->get_assertion(i)->get_id();
|
||||
std::cerr << "\n";
|
||||
#else
|
||||
unsigned n = m_solver->get_num_assertions();
|
||||
std::cerr << "assertion ids hash: ";
|
||||
unsigned h = 0;
|
||||
for (unsigned i = 0; i < n-1; ++i)
|
||||
h += m_solver->get_assertion(i)->get_id();
|
||||
std::cerr << h << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
void include_ast_show(ast &a){
|
||||
a.show();
|
||||
}
|
||||
|
||||
void include_model_show(model &a){
|
||||
a.show();
|
||||
}
|
||||
|
||||
void show_ast(::ast *a, ast_manager &m) {
|
||||
std::cout << mk_pp(a, m) << std::endl;
|
||||
}
|
||||
|
||||
bool expr::is_label (bool &pos,std::vector<symbol> &names) const {
|
||||
buffer< ::symbol> _names;
|
||||
bool res = m().is_label(to_expr(raw()),pos,_names);
|
||||
if(res)
|
||||
for(unsigned i = 0; i < _names.size(); i++)
|
||||
names.push_back(symbol(ctx(),_names[i]));
|
||||
return res;
|
||||
}
|
||||
|
||||
double current_time()
|
||||
{
|
||||
static stopwatch sw;
|
||||
static bool started = false;
|
||||
if(!started){
|
||||
sw.start();
|
||||
started = true;
|
||||
}
|
||||
return sw.get_current_seconds();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
1430
src/duality/duality_wrapper.h
Executable file
1430
src/duality/duality_wrapper.h
Executable file
File diff suppressed because it is too large
Load diff
75
src/interp/foci2.h
Executable file
75
src/interp/foci2.h
Executable file
|
@ -0,0 +1,75 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
foci2.h
|
||||
|
||||
Abstract:
|
||||
|
||||
An interface class for foci2.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef FOCI2_H
|
||||
#define FOCI2_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef WIN32
|
||||
#define FOCI2_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define FOCI2_EXPORT __attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
|
||||
class foci2 {
|
||||
public:
|
||||
virtual ~foci2(){}
|
||||
|
||||
typedef int ast;
|
||||
typedef int symb;
|
||||
|
||||
/** Built-in operators */
|
||||
enum ops {
|
||||
And = 0, Or, Not, Iff, Ite, Equal, Plus, Times, Floor, Leq, Div, Bool, Int, Array, Tsym, Fsym, Forall, Exists, Distinct, LastOp
|
||||
};
|
||||
|
||||
virtual symb mk_func(const std::string &s) = 0;
|
||||
virtual symb mk_pred(const std::string &s) = 0;
|
||||
virtual ast mk_op(ops op, const std::vector<ast> args) = 0;
|
||||
virtual ast mk_op(ops op, ast) = 0;
|
||||
virtual ast mk_op(ops op, ast, ast) = 0;
|
||||
virtual ast mk_op(ops op, ast, ast, ast) = 0;
|
||||
virtual ast mk_int(const std::string &) = 0;
|
||||
virtual ast mk_rat(const std::string &) = 0;
|
||||
virtual ast mk_true() = 0;
|
||||
virtual ast mk_false() = 0;
|
||||
virtual ast mk_app(symb,const std::vector<ast> args) = 0;
|
||||
|
||||
virtual bool get_func(ast, symb &) = 0;
|
||||
virtual bool get_pred(ast, symb &) = 0;
|
||||
virtual bool get_op(ast, ops &) = 0;
|
||||
virtual bool get_true(ast id) = 0;
|
||||
virtual bool get_false(ast id) = 0;
|
||||
virtual bool get_int(ast id, std::string &res) = 0;
|
||||
virtual bool get_rat(ast id, std::string &res) = 0;
|
||||
virtual const std::string &get_symb(symb) = 0;
|
||||
|
||||
virtual int get_num_args(ast) = 0;
|
||||
virtual ast get_arg(ast, int) = 0;
|
||||
|
||||
virtual void show_ast(ast) = 0;
|
||||
|
||||
virtual bool interpolate(const std::vector<ast> &frames, std::vector<ast> &itps, std::vector<int> parents) = 0;
|
||||
|
||||
FOCI2_EXPORT static foci2 *create(const std::string &);
|
||||
};
|
||||
|
||||
#endif
|
25
src/interp/foci2stub/foci2.cpp
Normal file
25
src/interp/foci2stub/foci2.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
foci2.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Fake foci2, to be replaced
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "foci2.h"
|
||||
|
||||
FOCI2_EXPORT foci2 *foci2::create(const std::string &){
|
||||
return 0;
|
||||
}
|
75
src/interp/foci2stub/foci2.h
Executable file
75
src/interp/foci2stub/foci2.h
Executable file
|
@ -0,0 +1,75 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
foci2.h
|
||||
|
||||
Abstract:
|
||||
|
||||
An interface class for foci2.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef FOCI2_H
|
||||
#define FOCI2_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef WIN32
|
||||
#define FOCI2_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define FOCI2_EXPORT __attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
|
||||
class foci2 {
|
||||
public:
|
||||
virtual ~foci2(){}
|
||||
|
||||
typedef int ast;
|
||||
typedef int symb;
|
||||
|
||||
/** Built-in operators */
|
||||
enum ops {
|
||||
And = 0, Or, Not, Iff, Ite, Equal, Plus, Times, Floor, Leq, Div, Bool, Int, Array, Tsym, Fsym, Forall, Exists, Distinct, LastOp
|
||||
};
|
||||
|
||||
virtual symb mk_func(const std::string &s) = 0;
|
||||
virtual symb mk_pred(const std::string &s) = 0;
|
||||
virtual ast mk_op(ops op, const std::vector<ast> args) = 0;
|
||||
virtual ast mk_op(ops op, ast) = 0;
|
||||
virtual ast mk_op(ops op, ast, ast) = 0;
|
||||
virtual ast mk_op(ops op, ast, ast, ast) = 0;
|
||||
virtual ast mk_int(const std::string &) = 0;
|
||||
virtual ast mk_rat(const std::string &) = 0;
|
||||
virtual ast mk_true() = 0;
|
||||
virtual ast mk_false() = 0;
|
||||
virtual ast mk_app(symb,const std::vector<ast> args) = 0;
|
||||
|
||||
virtual bool get_func(ast, symb &) = 0;
|
||||
virtual bool get_pred(ast, symb &) = 0;
|
||||
virtual bool get_op(ast, ops &) = 0;
|
||||
virtual bool get_true(ast id) = 0;
|
||||
virtual bool get_false(ast id) = 0;
|
||||
virtual bool get_int(ast id, std::string &res) = 0;
|
||||
virtual bool get_rat(ast id, std::string &res) = 0;
|
||||
virtual const std::string &get_symb(symb) = 0;
|
||||
|
||||
virtual int get_num_args(ast) = 0;
|
||||
virtual ast get_arg(ast, int) = 0;
|
||||
|
||||
virtual void show_ast(ast) = 0;
|
||||
|
||||
virtual bool interpolate(const std::vector<ast> &frames, std::vector<ast> &itps, std::vector<int> parents) = 0;
|
||||
|
||||
FOCI2_EXPORT static foci2 *create(const std::string &);
|
||||
};
|
||||
|
||||
#endif
|
352
src/interp/iz3base.cpp
Executable file
352
src/interp/iz3base.cpp
Executable file
|
@ -0,0 +1,352 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3base.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Base class for interpolators. Includes an AST manager and a scoping
|
||||
object as bases.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "iz3base.h"
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include "solver.h"
|
||||
#include "../smt/smt_solver.h"
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
|
||||
iz3base::range &iz3base::ast_range(ast t){
|
||||
return ast_ranges_hash[t].rng;
|
||||
}
|
||||
|
||||
iz3base::range &iz3base::sym_range(symb d){
|
||||
return sym_range_hash[d];
|
||||
}
|
||||
|
||||
void iz3base::add_frame_range(int frame, ast t){
|
||||
range &rng = ast_range(t);
|
||||
if(!in_range(frame,rng)){
|
||||
range_add(frame,rng);
|
||||
for(int i = 0, n = num_args(t); i < n; ++i)
|
||||
add_frame_range(frame,arg(t,i));
|
||||
if(op(t) == Uninterpreted)
|
||||
range_add(frame,sym_range(sym(t)));
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
iz3base::range &iz3base::ast_scope(ast t){
|
||||
ranges &rngs = ast_ranges_hash[t];
|
||||
range &rng = rngs.scp;
|
||||
if(!rngs.scope_computed){ // not computed yet
|
||||
rng = range_full();
|
||||
for(int i = 0, n = num_args(t); i < n; ++i)
|
||||
rng = range_glb(rng,ast_scope(arg(t,i)));
|
||||
if(op(t) == Uninterpreted)
|
||||
if(parents.empty() || num_args(t) == 0) // in tree mode, all function syms are global
|
||||
rng = range_glb(rng,sym_range(sym(t)));
|
||||
rngs.scope_computed = true;
|
||||
}
|
||||
return rng;
|
||||
}
|
||||
#else
|
||||
iz3base::range &iz3base::ast_scope(ast t){
|
||||
ranges &rngs = ast_ranges_hash[t];
|
||||
if(rngs.scope_computed) return rngs.scp;
|
||||
range rng = range_full();
|
||||
for(int i = 0, n = num_args(t); i < n; ++i)
|
||||
rng = range_glb(rng,ast_scope(arg(t,i)));
|
||||
if(op(t) == Uninterpreted)
|
||||
if(parents.empty() || num_args(t) == 0) // in tree mode, all function syms are global
|
||||
rng = range_glb(rng,sym_range(sym(t)));
|
||||
rngs = ast_ranges_hash[t];
|
||||
rngs.scope_computed = true;
|
||||
rngs.scp = rng;
|
||||
return rngs.scp;
|
||||
}
|
||||
#endif
|
||||
|
||||
void iz3base::print(const std::string &filename){
|
||||
ast t = make(And,cnsts);
|
||||
std::ofstream f(filename.c_str());
|
||||
print_sat_problem(f,t);
|
||||
f.close();
|
||||
}
|
||||
|
||||
|
||||
void iz3base::gather_conjuncts_rec(ast n, std::vector<ast> &conjuncts, stl_ext::hash_set<ast> &memo){
|
||||
if(memo.find(n) == memo.end()){
|
||||
memo.insert(n);
|
||||
if(op(n) == And){
|
||||
int nargs = num_args(n);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
gather_conjuncts_rec(arg(n,i),conjuncts,memo);
|
||||
}
|
||||
else
|
||||
conjuncts.push_back(n);
|
||||
}
|
||||
}
|
||||
|
||||
void iz3base::gather_conjuncts(ast n, std::vector<ast> &conjuncts){
|
||||
hash_set<ast> memo;
|
||||
gather_conjuncts_rec(n,conjuncts,memo);
|
||||
}
|
||||
|
||||
bool iz3base::is_literal(ast n){
|
||||
if(is_not(n))n = arg(n,0);
|
||||
if(is_true(n) || is_false(n)) return false;
|
||||
if(op(n) == And) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
iz3base::ast iz3base::simplify_and(std::vector<ast> &conjuncts){
|
||||
hash_set<ast> memo;
|
||||
for(unsigned i = 0; i < conjuncts.size(); i++){
|
||||
if(is_false(conjuncts[i]))
|
||||
return conjuncts[i];
|
||||
if(is_true(conjuncts[i]) || memo.find(conjuncts[i]) != memo.end()){
|
||||
std::swap(conjuncts[i],conjuncts.back());
|
||||
conjuncts.pop_back();
|
||||
}
|
||||
else if(memo.find(mk_not(conjuncts[i])) != memo.end())
|
||||
return mk_false(); // contradiction!
|
||||
else
|
||||
memo.insert(conjuncts[i]);
|
||||
}
|
||||
if(conjuncts.empty())return mk_true();
|
||||
return make(And,conjuncts);
|
||||
}
|
||||
|
||||
iz3base::ast iz3base::simplify_with_lit_rec(ast n, ast lit, stl_ext::hash_map<ast,ast> &memo, int depth){
|
||||
if(is_not(n))return mk_not(simplify_with_lit_rec(mk_not(n),lit,memo,depth));
|
||||
if(n == lit) return mk_true();
|
||||
ast not_lit = mk_not(lit);
|
||||
if(n == not_lit) return mk_false();
|
||||
if(op(n) != And || depth <= 0) return n;
|
||||
std::pair<ast,ast> foo(n,ast());
|
||||
std::pair<hash_map<ast,ast>::iterator,bool> bar = memo.insert(foo);
|
||||
ast &res = bar.first->second;
|
||||
if(!bar.second) return res;
|
||||
int nargs = num_args(n);
|
||||
std::vector<ast> args(nargs);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
args[i] = simplify_with_lit_rec(arg(n,i),lit,memo,depth-1);
|
||||
res = simplify_and(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
iz3base::ast iz3base::simplify_with_lit(ast n, ast lit){
|
||||
hash_map<ast,ast> memo;
|
||||
return simplify_with_lit_rec(n,lit,memo,1);
|
||||
}
|
||||
|
||||
iz3base::ast iz3base::simplify(ast n){
|
||||
if(is_not(n)) return mk_not(simplify(mk_not(n)));
|
||||
std::pair<ast,ast> memo_obj(n,ast());
|
||||
std::pair<hash_map<ast,ast>::iterator,bool> memo = simplify_memo.insert(memo_obj);
|
||||
ast &res = memo.first->second;
|
||||
if(!memo.second) return res;
|
||||
switch(op(n)){
|
||||
case And: {
|
||||
std::vector<ast> conjuncts;
|
||||
gather_conjuncts(n,conjuncts);
|
||||
for(unsigned i = 0; i < conjuncts.size(); i++)
|
||||
conjuncts[i] = simplify(conjuncts[i]);
|
||||
#if 0
|
||||
for(unsigned i = 0; i < conjuncts.size(); i++)
|
||||
if(is_literal(conjuncts[i]))
|
||||
for(unsigned j = 0; j < conjuncts.size(); j++)
|
||||
if(j != i)
|
||||
conjuncts[j] = simplify_with_lit(conjuncts[j],conjuncts[i]);
|
||||
#endif
|
||||
res = simplify_and(conjuncts);
|
||||
}
|
||||
break;
|
||||
case Equal: {
|
||||
ast x = arg(n,0);
|
||||
ast y = arg(n,1);
|
||||
if(ast_id(x) > ast_id(y))
|
||||
std::swap(x,y);
|
||||
res = make(Equal,x,y);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = n;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void iz3base::initialize(const std::vector<ast> &_parts, const std::vector<int> &_parents, const std::vector<ast> &_theory){
|
||||
cnsts = _parts;
|
||||
theory = _theory;
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
add_frame_range(i, cnsts[i]);
|
||||
for(unsigned i = 0; i < _theory.size(); i++){
|
||||
add_frame_range(SHRT_MIN, _theory[i]);
|
||||
add_frame_range(SHRT_MAX, _theory[i]);
|
||||
}
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
frame_map[cnsts[i]] = i;
|
||||
for(unsigned i = 0; i < theory.size(); i++)
|
||||
frame_map[theory[i]] = INT_MAX;
|
||||
}
|
||||
|
||||
void iz3base::initialize(const std::vector<std::vector<ast> > &_parts, const std::vector<int> &_parents, const std::vector<ast> &_theory){
|
||||
cnsts.resize(_parts.size());
|
||||
theory = _theory;
|
||||
for(unsigned i = 0; i < _parts.size(); i++)
|
||||
for(unsigned j = 0; j < _parts[i].size(); j++){
|
||||
cnsts[i] = make(And,_parts[i]);
|
||||
add_frame_range(i, _parts[i][j]);
|
||||
frame_map[_parts[i][j]] = i;
|
||||
}
|
||||
for(unsigned i = 0; i < _theory.size(); i++){
|
||||
add_frame_range(SHRT_MIN, _theory[i]);
|
||||
add_frame_range(SHRT_MAX, _theory[i]);
|
||||
frame_map[theory[i]] = INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void iz3base::check_interp(const std::vector<ast> &itps, std::vector<ast> &theory){
|
||||
#if 0
|
||||
Z3_config config = Z3_mk_config();
|
||||
Z3_context vctx = Z3_mk_context(config);
|
||||
int frames = cnsts.size();
|
||||
std::vector<Z3_ast> foocnsts(cnsts);
|
||||
for(unsigned i = 0; i < frames; i++)
|
||||
foocnsts[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),cnsts[i]);
|
||||
Z3_write_interpolation_problem(ctx,frames,&foocnsts[0],0, "temp_lemma.smt", theory.size(), &theory[0]);
|
||||
int vframes,*vparents;
|
||||
Z3_ast *vcnsts;
|
||||
const char *verror;
|
||||
bool ok = Z3_read_interpolation_problem(vctx,&vframes,&vcnsts,0,"temp_lemma.smt",&verror);
|
||||
assert(ok);
|
||||
std::vector<Z3_ast> vvcnsts(vframes);
|
||||
std::copy(vcnsts,vcnsts+vframes,vvcnsts.begin());
|
||||
std::vector<Z3_ast> vitps(itps.size());
|
||||
for(unsigned i = 0; i < itps.size(); i++)
|
||||
vitps[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),itps[i]);
|
||||
Z3_write_interpolation_problem(ctx,itps.size(),&vitps[0],0,"temp_interp.smt");
|
||||
int iframes,*iparents;
|
||||
Z3_ast *icnsts;
|
||||
const char *ierror;
|
||||
ok = Z3_read_interpolation_problem(vctx,&iframes,&icnsts,0,"temp_interp.smt",&ierror);
|
||||
assert(ok);
|
||||
const char *error = 0;
|
||||
bool iok = Z3_check_interpolant(vctx, frames, &vvcnsts[0], parents.size() ? &parents[0] : 0, icnsts, &error);
|
||||
assert(iok);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool iz3base::is_sat(const std::vector<ast> &q, ast &_proof){
|
||||
|
||||
params_ref p;
|
||||
p.set_bool("proof", true); // this is currently useless
|
||||
p.set_bool("model", true);
|
||||
p.set_bool("unsat_core", true);
|
||||
scoped_ptr<solver_factory> sf = mk_smt_solver_factory();
|
||||
::solver *m_solver = (*sf)(m(), p, true, true, true, ::symbol::null);
|
||||
::solver &s = *m_solver;
|
||||
|
||||
for(unsigned i = 0; i < q.size(); i++)
|
||||
s.assert_expr(to_expr(q[i].raw()));
|
||||
lbool res = s.check_sat(0,0);
|
||||
if(res == l_false){
|
||||
::ast *proof = s.get_proof();
|
||||
_proof = cook(proof);
|
||||
}
|
||||
dealloc(m_solver);
|
||||
return res != l_false;
|
||||
}
|
||||
|
||||
|
||||
void iz3base::find_children(const stl_ext::hash_set<ast> &cnsts_set,
|
||||
const ast &tree,
|
||||
std::vector<ast> &cnsts,
|
||||
std::vector<int> &parents,
|
||||
std::vector<ast> &conjuncts,
|
||||
std::vector<int> &children,
|
||||
std::vector<int> &pos_map,
|
||||
bool merge
|
||||
){
|
||||
std::vector<int> my_children;
|
||||
std::vector<ast> my_conjuncts;
|
||||
if(op(tree) == Interp){ // if we've hit an interpolation position...
|
||||
find_children(cnsts_set,arg(tree,0),cnsts,parents,my_conjuncts,my_children,pos_map,merge);
|
||||
if(my_conjuncts.empty())
|
||||
my_conjuncts.push_back(mk_true()); // need at least one conjunct
|
||||
int root = cnsts.size() + my_conjuncts.size() - 1;
|
||||
for(unsigned i = 0; i < my_conjuncts.size(); i++){
|
||||
parents.push_back(root);
|
||||
cnsts.push_back(my_conjuncts[i]);
|
||||
}
|
||||
for(unsigned i = 0; i < my_children.size(); i++)
|
||||
parents[my_children[i]] = root;
|
||||
children.push_back(root);
|
||||
pos_map.push_back(root);
|
||||
}
|
||||
else {
|
||||
if(op(tree) == And){
|
||||
int nargs = num_args(tree);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
find_children(cnsts_set,arg(tree,i),cnsts,parents,my_conjuncts,my_children,pos_map,merge);
|
||||
}
|
||||
if(cnsts_set.find(tree) != cnsts_set.end()){
|
||||
if(merge && !my_conjuncts.empty())
|
||||
my_conjuncts.back() = mk_and(my_conjuncts.back(),tree);
|
||||
else
|
||||
my_conjuncts.push_back(tree);
|
||||
}
|
||||
for(unsigned i = 0; i < my_children.size(); i++)
|
||||
children.push_back(my_children[i]);
|
||||
for(unsigned i = 0; i < my_conjuncts.size(); i++)
|
||||
conjuncts.push_back(my_conjuncts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void iz3base::to_parents_vec_representation(const std::vector<ast> &_cnsts,
|
||||
const ast &tree,
|
||||
std::vector<ast> &cnsts,
|
||||
std::vector<int> &parents,
|
||||
std::vector<ast> &theory,
|
||||
std::vector<int> &pos_map,
|
||||
bool merge
|
||||
){
|
||||
std::vector<int> my_children;
|
||||
std::vector<ast> my_conjuncts;
|
||||
hash_set<ast> cnsts_set;
|
||||
for(unsigned i = 0; i < _cnsts.size(); i++)
|
||||
cnsts_set.insert(_cnsts[i]);
|
||||
ast _tree = (op(tree) != Interp) ? make(Interp,tree) : tree;
|
||||
find_children(cnsts_set,_tree,cnsts,parents,my_conjuncts,my_children,pos_map,merge);
|
||||
if(op(tree) != Interp) pos_map.pop_back();
|
||||
parents[parents.size()-1] = SHRT_MAX;
|
||||
|
||||
// rest of the constraints are the background theory
|
||||
|
||||
hash_set<ast> used_set;
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
used_set.insert(cnsts[i]);
|
||||
for(unsigned i = 0; i < _cnsts.size(); i++)
|
||||
if(used_set.find(_cnsts[i]) == used_set.end())
|
||||
theory.push_back(_cnsts[i]);
|
||||
}
|
||||
|
195
src/interp/iz3base.h
Executable file
195
src/interp/iz3base.h
Executable file
|
@ -0,0 +1,195 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3base.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Base class for interpolators. Includes an AST manager and a scoping
|
||||
object as bases.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef IZ3BASE_H
|
||||
#define IZ3BASE_H
|
||||
|
||||
#include "iz3mgr.h"
|
||||
#include "iz3scopes.h"
|
||||
|
||||
namespace hash_space {
|
||||
template <>
|
||||
class hash<func_decl *> {
|
||||
public:
|
||||
size_t operator()(func_decl * const &s) const {
|
||||
return (size_t) s;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* Base class for interpolators. Includes an AST manager and a scoping
|
||||
object as bases. */
|
||||
|
||||
class iz3base : public iz3mgr, public scopes {
|
||||
|
||||
public:
|
||||
|
||||
/** Get the range in which an expression occurs. This is the
|
||||
smallest subtree containing all occurrences of the
|
||||
expression. */
|
||||
range &ast_range(ast);
|
||||
|
||||
/** Get the scope of an expression. This is the set of tree nodes in
|
||||
which all of the expression's symbols are in scope. */
|
||||
range &ast_scope(ast);
|
||||
|
||||
/** Get the range of a symbol. This is the smallest subtree containing
|
||||
all occurrences of the symbol. */
|
||||
range &sym_range(symb);
|
||||
|
||||
/** Is an expression local (in scope in some frame)? */
|
||||
|
||||
bool is_local(ast node){
|
||||
return !range_is_empty(ast_scope(node));
|
||||
}
|
||||
|
||||
/** Simplify an expression */
|
||||
|
||||
ast simplify(ast);
|
||||
|
||||
/** Constructor */
|
||||
|
||||
iz3base(ast_manager &_m_manager,
|
||||
const std::vector<ast> &_cnsts,
|
||||
const std::vector<int> &_parents,
|
||||
const std::vector<ast> &_theory)
|
||||
: iz3mgr(_m_manager), scopes(_parents) {
|
||||
initialize(_cnsts,_parents,_theory);
|
||||
weak = false;
|
||||
}
|
||||
|
||||
iz3base(const iz3mgr& other,
|
||||
const std::vector<ast> &_cnsts,
|
||||
const std::vector<int> &_parents,
|
||||
const std::vector<ast> &_theory)
|
||||
: iz3mgr(other), scopes(_parents) {
|
||||
initialize(_cnsts,_parents,_theory);
|
||||
weak = false;
|
||||
}
|
||||
|
||||
iz3base(const iz3mgr& other,
|
||||
const std::vector<std::vector<ast> > &_cnsts,
|
||||
const std::vector<int> &_parents,
|
||||
const std::vector<ast> &_theory)
|
||||
: iz3mgr(other), scopes(_parents) {
|
||||
initialize(_cnsts,_parents,_theory);
|
||||
weak = false;
|
||||
}
|
||||
|
||||
iz3base(const iz3mgr& other)
|
||||
: iz3mgr(other), scopes() {
|
||||
weak = false;
|
||||
}
|
||||
|
||||
/* Set our options */
|
||||
void set_option(const std::string &name, const std::string &value){
|
||||
if(name == "weak" && value == "1") weak = true;
|
||||
}
|
||||
|
||||
/* Are we doing weak interpolants? */
|
||||
bool weak_mode(){return weak;}
|
||||
|
||||
/** Print interpolation problem to an SMTLIB format file */
|
||||
void print(const std::string &filename);
|
||||
|
||||
/** Check correctness of a solutino to this problem. */
|
||||
void check_interp(const std::vector<ast> &itps, std::vector<ast> &theory);
|
||||
|
||||
/** For convenience -- is this formula SAT? */
|
||||
bool is_sat(const std::vector<ast> &consts, ast &_proof);
|
||||
|
||||
/** Interpolator for clauses, to be implemented */
|
||||
virtual void interpolate_clause(std::vector<ast> &lits, std::vector<ast> &itps){
|
||||
throw "no interpolator";
|
||||
}
|
||||
|
||||
ast get_proof_check_assump(range &rng){
|
||||
std::vector<ast> cs(theory);
|
||||
cs.push_back(cnsts[rng.hi]);
|
||||
return make(And,cs);
|
||||
}
|
||||
|
||||
int frame_of_assertion(const ast &ass){
|
||||
stl_ext::hash_map<ast,int>::iterator it = frame_map.find(ass);
|
||||
if(it == frame_map.end())
|
||||
throw "unknown assertion";
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
void to_parents_vec_representation(const std::vector<ast> &_cnsts,
|
||||
const ast &tree,
|
||||
std::vector<ast> &cnsts,
|
||||
std::vector<int> &parents,
|
||||
std::vector<ast> &theory,
|
||||
std::vector<int> &pos_map,
|
||||
bool merge = false
|
||||
);
|
||||
|
||||
protected:
|
||||
std::vector<ast> cnsts;
|
||||
std::vector<ast> theory;
|
||||
|
||||
private:
|
||||
|
||||
struct ranges {
|
||||
range rng;
|
||||
range scp;
|
||||
bool scope_computed;
|
||||
ranges(){scope_computed = false;}
|
||||
};
|
||||
|
||||
stl_ext::hash_map<symb,range> sym_range_hash;
|
||||
stl_ext::hash_map<ast,ranges> ast_ranges_hash;
|
||||
stl_ext::hash_map<ast,ast> simplify_memo;
|
||||
stl_ext::hash_map<ast,int> frame_map; // map assertions to frames
|
||||
|
||||
int frames; // number of frames
|
||||
|
||||
protected:
|
||||
void add_frame_range(int frame, ast t);
|
||||
|
||||
private:
|
||||
void initialize(const std::vector<ast> &_parts, const std::vector<int> &_parents, const std::vector<ast> &_theory);
|
||||
|
||||
void initialize(const std::vector<std::vector<ast> > &_parts, const std::vector<int> &_parents, const std::vector<ast> &_theory);
|
||||
|
||||
bool is_literal(ast n);
|
||||
void gather_conjuncts_rec(ast n, std::vector<ast> &conjuncts, stl_ext::hash_set<ast> &memo);
|
||||
void gather_conjuncts(ast n, std::vector<ast> &conjuncts);
|
||||
ast simplify_and(std::vector<ast> &conjuncts);
|
||||
ast simplify_with_lit_rec(ast n, ast lit, stl_ext::hash_map<ast,ast> &memo, int depth);
|
||||
ast simplify_with_lit(ast n, ast lit);
|
||||
void find_children(const stl_ext::hash_set<ast> &cnsts_set,
|
||||
const ast &tree,
|
||||
std::vector<ast> &cnsts,
|
||||
std::vector<int> &parents,
|
||||
std::vector<ast> &conjuncts,
|
||||
std::vector<int> &children,
|
||||
std::vector<int> &pos_map,
|
||||
bool merge
|
||||
);
|
||||
bool weak;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
222
src/interp/iz3checker.cpp
Executable file
222
src/interp/iz3checker.cpp
Executable file
|
@ -0,0 +1,222 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3checker.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
check correctness of interpolant
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "iz3base.h"
|
||||
#include "iz3checker.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
struct iz3checker : iz3base {
|
||||
|
||||
/* HACK: for tree interpolants, we assume that uninterpreted functions
|
||||
are global. This is because in the current state of the tree interpolation
|
||||
code, symbols that appear in sibling sub-trees have to be global, and
|
||||
we have no way to eliminate such function symbols. When tree interpoaltion is
|
||||
fixed, we can tree function symbols the same as constant symbols. */
|
||||
|
||||
bool is_tree;
|
||||
|
||||
void support(const ast &t, std::set<std::string> &res, hash_set<ast> &memo){
|
||||
if(memo.find(t) != memo.end()) return;
|
||||
memo.insert(t);
|
||||
|
||||
int nargs = num_args(t);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
support(arg(t,i),res,memo);
|
||||
|
||||
switch(op(t)){
|
||||
case Uninterpreted:
|
||||
if(nargs == 0 || !is_tree) {
|
||||
std::string name = string_of_symbol(sym(t));
|
||||
res.insert(name);
|
||||
}
|
||||
break;
|
||||
case Forall:
|
||||
case Exists:
|
||||
support(get_quantifier_body(t),res,memo);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
bool check(solver *s, std::ostream &err,
|
||||
const std::vector<ast> &cnsts,
|
||||
const std::vector<int> &parents,
|
||||
const std::vector<ast> &itp,
|
||||
const std::vector<ast> &theory){
|
||||
|
||||
is_tree = !parents.empty();
|
||||
int num = cnsts.size();
|
||||
std::vector<std::vector<int> > children(num);
|
||||
|
||||
for(int i = 0; i < num-1; i++){
|
||||
if(parents.size())
|
||||
children[parents[i]].push_back(i);
|
||||
else
|
||||
children[i+1].push_back(i);
|
||||
}
|
||||
|
||||
for(int i = 0; i < num; i++){
|
||||
s->push();
|
||||
for(unsigned j = 0; j < theory.size(); j++)
|
||||
s->assert_expr(to_expr(theory[j].raw()));
|
||||
s->assert_expr(to_expr(cnsts[i].raw()));
|
||||
std::vector<int> &cs = children[i];
|
||||
for(unsigned j = 0; j < cs.size(); j++)
|
||||
s->assert_expr(to_expr(itp[cs[j]].raw()));
|
||||
if(i != num-1)
|
||||
s->assert_expr(to_expr(mk_not(itp[i]).raw()));
|
||||
lbool result = s->check_sat(0,0);
|
||||
if(result != l_false){
|
||||
err << "interpolant " << i << " is incorrect";
|
||||
|
||||
s->pop(1);
|
||||
for(unsigned j = 0; j < theory.size(); j++)
|
||||
s->assert_expr(to_expr(theory[j].raw()));
|
||||
for(unsigned j = 0; j < cnsts.size(); j++)
|
||||
if(in_range(j,range_downward(i)))
|
||||
s->assert_expr(to_expr(cnsts[j].raw()));
|
||||
if(i != num-1)
|
||||
s->assert_expr(to_expr(mk_not(itp[i]).raw()));
|
||||
lbool result = s->check_sat(0,0);
|
||||
if(result != l_false)
|
||||
err << "interpolant " << i << " is not implied by its downeard closurn";
|
||||
|
||||
return false;
|
||||
}
|
||||
s->pop(1);
|
||||
}
|
||||
|
||||
std::vector<std::set<std::string> > supports(num);
|
||||
for(int i = 0; i < num; i++){
|
||||
hash_set<ast> memo;
|
||||
support(cnsts[i],supports[i],memo);
|
||||
}
|
||||
for(int i = 0; i < num-1; i++){
|
||||
std::vector<bool> Bside(num);
|
||||
for(int j = num-1; j >= 0; j--)
|
||||
Bside[j] = j != i;
|
||||
for(int j = num-1; j >= 0; j--)
|
||||
if(!Bside[j]){
|
||||
std::vector<int> &cs = children[i];
|
||||
for(unsigned k = 0; k < cs.size(); k++)
|
||||
Bside[cs[k]] = false;
|
||||
}
|
||||
std::set<std::string> Asup, Bsup,common,Isup,bad;
|
||||
for(int j = num-1; j >= 0; j--){
|
||||
std::set<std::string> &side = Bside[j] ? Bsup : Asup;
|
||||
side.insert(supports[j].begin(),supports[j].end());
|
||||
}
|
||||
std::set_intersection(Asup.begin(),Asup.end(),Bsup.begin(),Bsup.end(),std::inserter(common,common.begin()));
|
||||
{
|
||||
hash_set<ast> tmemo;
|
||||
for(unsigned j = 0; j < theory.size(); j++)
|
||||
support(theory[j],common,tmemo); // all theory symbols allowed in interps
|
||||
}
|
||||
hash_set<ast> memo;
|
||||
support(itp[i],Isup,memo);
|
||||
std::set_difference(Isup.begin(),Isup.end(),common.begin(),common.end(),std::inserter(bad,bad.begin()));
|
||||
if(!bad.empty()){
|
||||
err << "bad symbols in interpolant " << i << ":";
|
||||
std::copy(bad.begin(),bad.end(),std::ostream_iterator<std::string>(err,","));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check(solver *s, std::ostream &err,
|
||||
const std::vector<ast> &_cnsts,
|
||||
const ast &tree,
|
||||
const std::vector<ast> &itp){
|
||||
|
||||
std::vector<int> pos_map;
|
||||
|
||||
// convert to the parents vector representation
|
||||
|
||||
to_parents_vec_representation(_cnsts, tree, cnsts, parents, theory, pos_map);
|
||||
|
||||
//use the parents vector representation to compute interpolant
|
||||
return check(s,err,cnsts,parents,itp,theory);
|
||||
}
|
||||
|
||||
iz3checker(ast_manager &_m)
|
||||
: iz3base(_m) {
|
||||
}
|
||||
|
||||
iz3checker(iz3mgr &_m)
|
||||
: iz3base(_m) {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
std::vector<T> to_std_vector(const ::vector<T> &v){
|
||||
std::vector<T> _v(v.size());
|
||||
for(unsigned i = 0; i < v.size(); i++)
|
||||
_v[i] = v[i];
|
||||
return _v;
|
||||
}
|
||||
|
||||
|
||||
bool iz3check(ast_manager &_m_manager,
|
||||
solver *s,
|
||||
std::ostream &err,
|
||||
const ptr_vector<ast> &cnsts,
|
||||
const ::vector<int> &parents,
|
||||
const ptr_vector<ast> &interps,
|
||||
const ptr_vector<ast> &theory)
|
||||
{
|
||||
iz3checker chk(_m_manager);
|
||||
return chk.check(s,err,chk.cook(cnsts),to_std_vector(parents),chk.cook(interps),chk.cook(theory));
|
||||
}
|
||||
|
||||
bool iz3check(iz3mgr &mgr,
|
||||
solver *s,
|
||||
std::ostream &err,
|
||||
const std::vector<iz3mgr::ast> &cnsts,
|
||||
const std::vector<int> &parents,
|
||||
const std::vector<iz3mgr::ast> &interps,
|
||||
const std::vector<iz3mgr::ast> &theory)
|
||||
{
|
||||
iz3checker chk(mgr);
|
||||
return chk.check(s,err,cnsts,parents,interps,theory);
|
||||
}
|
||||
|
||||
bool iz3check(ast_manager &_m_manager,
|
||||
solver *s,
|
||||
std::ostream &err,
|
||||
const ptr_vector<ast> &_cnsts,
|
||||
ast *tree,
|
||||
const ptr_vector<ast> &interps)
|
||||
{
|
||||
iz3checker chk(_m_manager);
|
||||
return chk.check(s,err,chk.cook(_cnsts),chk.cook(tree),chk.cook(interps));
|
||||
}
|
49
src/interp/iz3checker.h
Normal file
49
src/interp/iz3checker.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3checker.h
|
||||
|
||||
Abstract:
|
||||
|
||||
check correctness of an interpolant
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef IZ3_CHECKER_H
|
||||
#define IZ3_CHECKER_H
|
||||
|
||||
#include "iz3mgr.h"
|
||||
#include "solver.h"
|
||||
|
||||
bool iz3check(ast_manager &_m_manager,
|
||||
solver *s,
|
||||
std::ostream &err,
|
||||
const ptr_vector<ast> &cnsts,
|
||||
const ::vector<int> &parents,
|
||||
const ptr_vector<ast> &interps,
|
||||
const ptr_vector<ast> &theory);
|
||||
|
||||
bool iz3check(ast_manager &_m_manager,
|
||||
solver *s,
|
||||
std::ostream &err,
|
||||
const ptr_vector<ast> &cnsts,
|
||||
ast *tree,
|
||||
const ptr_vector<ast> &interps);
|
||||
|
||||
bool iz3check(iz3mgr &mgr,
|
||||
solver *s,
|
||||
std::ostream &err,
|
||||
const std::vector<iz3mgr::ast> &cnsts,
|
||||
const std::vector<int> &parents,
|
||||
const std::vector<iz3mgr::ast> &interps,
|
||||
const ptr_vector<iz3mgr::ast> &theory);
|
||||
|
||||
#endif
|
359
src/interp/iz3foci.cpp
Executable file
359
src/interp/iz3foci.cpp
Executable file
|
@ -0,0 +1,359 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3foci.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Implements a secondary solver using foci2.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
|
||||
#include "iz3hash.h"
|
||||
#include "foci2.h"
|
||||
#include "iz3foci.h"
|
||||
|
||||
#ifndef WIN32
|
||||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
class iz3foci_impl : public iz3secondary {
|
||||
|
||||
int frames;
|
||||
int *parents;
|
||||
foci2 *foci;
|
||||
foci2::symb select_op;
|
||||
foci2::symb store_op;
|
||||
foci2::symb mod_op;
|
||||
|
||||
public:
|
||||
iz3foci_impl(iz3mgr *mgr, int _frames, int *_parents) : iz3secondary(*mgr) {
|
||||
frames = _frames;
|
||||
parents = _parents;
|
||||
foci = 0;
|
||||
}
|
||||
|
||||
typedef hash_map<ast,foci2::ast> AstToNode;
|
||||
AstToNode ast_to_node; // maps Z3 ast's to foci expressions
|
||||
|
||||
typedef hash_map<foci2::ast,ast> NodeToAst;
|
||||
NodeToAst node_to_ast; // maps Z3 ast's to foci expressions
|
||||
|
||||
// We only use this for FuncDeclToSymbol, which has no range destructor
|
||||
struct symb_hash {
|
||||
size_t operator()(const symb &s) const {
|
||||
return (size_t) s;
|
||||
}
|
||||
};
|
||||
|
||||
typedef hash_map<symb,foci2::symb> FuncDeclToSymbol;
|
||||
FuncDeclToSymbol func_decl_to_symbol; // maps Z3 func decls to symbols
|
||||
|
||||
typedef hash_map<foci2::symb,symb> SymbolToFuncDecl;
|
||||
SymbolToFuncDecl symbol_to_func_decl; // maps symbols to Z3 func decls
|
||||
|
||||
int from_symb(symb func){
|
||||
std::string name = string_of_symbol(func);
|
||||
bool is_bool = is_bool_type(get_range_type(func));
|
||||
foci2::symb f;
|
||||
if(is_bool)
|
||||
f = foci->mk_pred(name);
|
||||
else
|
||||
f = foci->mk_func(name);
|
||||
symbol_to_func_decl[f] = func;
|
||||
func_decl_to_symbol[func] = f;
|
||||
return f;
|
||||
}
|
||||
|
||||
// create a symbol corresponding to a DeBruijn index of a particular type
|
||||
// the type has to be encoded into the name because the same index can
|
||||
// occur with different types
|
||||
foci2::symb make_deBruijn_symbol(int index, type ty){
|
||||
std::ostringstream s;
|
||||
// s << "#" << index << "#" << type;
|
||||
return foci->mk_func(s.str());
|
||||
}
|
||||
|
||||
int from_Z3_ast(ast t){
|
||||
std::pair<ast,foci2::ast> foo(t,0);
|
||||
std::pair<AstToNode::iterator, bool> bar = ast_to_node.insert(foo);
|
||||
int &res = bar.first->second;
|
||||
if(!bar.second) return res;
|
||||
int nargs = num_args(t);
|
||||
std::vector<foci2::ast> args(nargs);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
args[i] = from_Z3_ast(arg(t,i));
|
||||
|
||||
switch(op(t)){
|
||||
case True:
|
||||
res = foci->mk_true(); break;
|
||||
case False:
|
||||
res = foci->mk_false(); break;
|
||||
case And:
|
||||
res = foci->mk_op(foci2::And,args); break;
|
||||
case Or:
|
||||
res = foci->mk_op(foci2::Or,args); break;
|
||||
case Not:
|
||||
res = foci->mk_op(foci2::Not,args[0]); break;
|
||||
case Iff:
|
||||
res = foci->mk_op(foci2::Iff,args); break;
|
||||
case OP_OEQ: // bit of a mystery, this one...
|
||||
if(args[0] == args[1]) res = foci->mk_true();
|
||||
else res = foci->mk_op(foci2::Iff,args);
|
||||
break;
|
||||
case Ite:
|
||||
if(is_bool_type(get_type(t)))
|
||||
res = foci->mk_op(foci2::And,foci->mk_op(foci2::Or,foci->mk_op(foci2::Not,args[0]),args[1]),foci->mk_op(foci2::Or,args[0],args[2]));
|
||||
else
|
||||
res = foci->mk_op(foci2::Ite,args);
|
||||
break;
|
||||
case Equal:
|
||||
res = foci->mk_op(foci2::Equal,args); break;
|
||||
case Implies:
|
||||
args[0] = foci->mk_op(foci2::Not,args[0]); res = foci->mk_op(foci2::Or,args); break;
|
||||
case Xor:
|
||||
res = foci->mk_op(foci2::Not,foci->mk_op(foci2::Iff,args)); break;
|
||||
case Leq:
|
||||
res = foci->mk_op(foci2::Leq,args); break;
|
||||
case Geq:
|
||||
std::swap(args[0],args[1]); res = foci->mk_op(foci2::Leq,args); break;
|
||||
case Gt:
|
||||
res = foci->mk_op(foci2::Not,foci->mk_op(foci2::Leq,args)); break;
|
||||
case Lt:
|
||||
std::swap(args[0],args[1]); res = foci->mk_op(foci2::Not,foci->mk_op(foci2::Leq,args)); break;
|
||||
case Plus:
|
||||
res = foci->mk_op(foci2::Plus,args); break;
|
||||
case Sub:
|
||||
args[1] = foci->mk_op(foci2::Times,foci->mk_int("-1"),args[1]); res = foci->mk_op(foci2::Plus,args); break;
|
||||
case Uminus:
|
||||
res = foci->mk_op(foci2::Times,foci->mk_int("-1"),args[0]); break;
|
||||
case Times:
|
||||
res = foci->mk_op(foci2::Times,args); break;
|
||||
case Idiv:
|
||||
res = foci->mk_op(foci2::Div,args); break;
|
||||
case Mod:
|
||||
res = foci->mk_app(mod_op,args); break;
|
||||
case Select:
|
||||
res = foci->mk_app(select_op,args); break;
|
||||
case Store:
|
||||
res = foci->mk_app(store_op,args); break;
|
||||
case Distinct:
|
||||
res = foci->mk_op(foci2::Distinct,args); break;
|
||||
case Uninterpreted: {
|
||||
symb func = sym(t);
|
||||
FuncDeclToSymbol::iterator it = func_decl_to_symbol.find(func);
|
||||
foci2::symb f = (it == func_decl_to_symbol.end()) ? from_symb(func) : it->second;
|
||||
if(foci->get_symb(f).substr(0,3) == "lbl" && args.size()==1) // HACK to handle Z3 labels
|
||||
res = args[0];
|
||||
else if(foci->get_symb(f).substr(0,3) == "lbl" && args.size()==0) // HACK to handle Z3 labels
|
||||
res = foci->mk_true();
|
||||
else res = foci->mk_app(f,args);
|
||||
break;
|
||||
}
|
||||
case Numeral: {
|
||||
std::string s = string_of_numeral(t);
|
||||
res = foci->mk_int(s);
|
||||
break;
|
||||
}
|
||||
case Forall:
|
||||
case Exists: {
|
||||
bool is_forall = op(t) == Forall;
|
||||
foci2::ops qop = is_forall ? foci2::Forall : foci2::Exists;
|
||||
int bvs = get_quantifier_num_bound(t);
|
||||
std::vector<int> foci_bvs(bvs);
|
||||
for(int i = 0; i < bvs; i++){
|
||||
std::string name = get_quantifier_bound_name(t,i);
|
||||
//Z3_string name = Z3_get_symbol_string(ctx,sym);
|
||||
// type ty = get_quantifier_bound_type(t,i);
|
||||
foci2::symb f = foci->mk_func(name);
|
||||
foci2::ast v = foci->mk_app(f,std::vector<foci2::ast>());
|
||||
foci_bvs[i] = v;
|
||||
}
|
||||
foci2::ast body = from_Z3_ast(get_quantifier_body(t));
|
||||
foci_bvs.push_back(body);
|
||||
res = foci->mk_op(qop,foci_bvs);
|
||||
node_to_ast[res] = t; // desperate
|
||||
break;
|
||||
}
|
||||
case Variable: { // a deBruijn index
|
||||
int index = get_variable_index_value(t);
|
||||
type ty = get_type(t);
|
||||
foci2::symb symbol = make_deBruijn_symbol(index,ty);
|
||||
res = foci->mk_app(symbol,std::vector<foci2::ast>());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::cerr << "iZ3: unsupported Z3 operator in expression\n ";
|
||||
print_expr(std::cerr,t);
|
||||
std::cerr << "\n";
|
||||
assert(0 && "iZ3: unsupported Z3 operator");
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// convert an expr to Z3 ast
|
||||
ast to_Z3_ast(foci2::ast i){
|
||||
std::pair<foci2::ast,ast> foo(i,ast());
|
||||
std::pair<NodeToAst::iterator,bool> bar = node_to_ast.insert(foo);
|
||||
if(!bar.second) return bar.first->second;
|
||||
ast &res = bar.first->second;
|
||||
|
||||
if(i < 0){
|
||||
res = mk_not(to_Z3_ast(-i));
|
||||
return res;
|
||||
}
|
||||
|
||||
// get the arguments
|
||||
unsigned n = foci->get_num_args(i);
|
||||
std::vector<ast> args(n);
|
||||
for(unsigned j = 0; j < n; j++)
|
||||
args[j] = to_Z3_ast(foci->get_arg(i,j));
|
||||
|
||||
// handle operators
|
||||
foci2::ops o;
|
||||
foci2::symb f;
|
||||
std::string nval;
|
||||
if(foci->get_true(i))
|
||||
res = mk_true();
|
||||
else if(foci->get_false(i))
|
||||
res = mk_false();
|
||||
else if(foci->get_op(i,o)){
|
||||
switch(o){
|
||||
case foci2::And:
|
||||
res = make(And,args); break;
|
||||
case foci2::Or:
|
||||
res = make(Or,args); break;
|
||||
case foci2::Not:
|
||||
res = mk_not(args[0]); break;
|
||||
case foci2::Iff:
|
||||
res = make(Iff,args[0],args[1]); break;
|
||||
case foci2::Ite:
|
||||
res = make(Ite,args[0],args[1],args[2]); break;
|
||||
case foci2::Equal:
|
||||
res = make(Equal,args[0],args[1]); break;
|
||||
case foci2::Plus:
|
||||
res = make(Plus,args); break;
|
||||
case foci2::Times:
|
||||
res = make(Times,args); break;
|
||||
case foci2::Div:
|
||||
res = make(Idiv,args[0],args[1]); break;
|
||||
case foci2::Leq:
|
||||
res = make(Leq,args[0],args[1]); break;
|
||||
case foci2::Distinct:
|
||||
res = make(Distinct,args);
|
||||
break;
|
||||
case foci2::Tsym:
|
||||
res = mk_true();
|
||||
break;
|
||||
case foci2::Fsym:
|
||||
res = mk_false();
|
||||
break;
|
||||
case foci2::Forall:
|
||||
case foci2::Exists:
|
||||
{
|
||||
int nargs = n;
|
||||
std::vector<ast> bounds(nargs-1);
|
||||
for(int i = 0; i < nargs-1; i++)
|
||||
bounds[i] = args[i];
|
||||
opr oz = o == foci2::Forall ? Forall : Exists;
|
||||
res = make_quant(oz,bounds,args[nargs-1]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert("unknown built-in op");
|
||||
}
|
||||
}
|
||||
else if(foci->get_int(i,nval)){
|
||||
res = make_int(nval);
|
||||
}
|
||||
else if(foci->get_func(i,f)){
|
||||
if(f == select_op){
|
||||
assert(n == 2);
|
||||
res = make(Select,args[0],args[1]);
|
||||
}
|
||||
else if(f == store_op){
|
||||
assert(n == 3);
|
||||
res = make(Store,args[0],args[1],args[2]);
|
||||
}
|
||||
else if(f == mod_op){
|
||||
assert(n == 2);
|
||||
res = make(Mod,args[0],args[1]);
|
||||
}
|
||||
else {
|
||||
std::pair<int,symb> foo(f,(symb)0);
|
||||
std::pair<SymbolToFuncDecl::iterator,bool> bar = symbol_to_func_decl.insert(foo);
|
||||
symb &func_decl = bar.first->second;
|
||||
if(bar.second){
|
||||
std::cout << "unknown function symbol:\n";
|
||||
foci->show_ast(i);
|
||||
assert(0);
|
||||
}
|
||||
res = make(func_decl,args);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cerr << "iZ3: unknown FOCI expression kind\n";
|
||||
assert(0 && "iZ3: unknown FOCI expression kind");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int interpolate(const std::vector<ast> &cnsts, std::vector<ast> &itps){
|
||||
assert((int)cnsts.size() == frames);
|
||||
std::string lia("lia");
|
||||
#ifdef _FOCI2
|
||||
foci = foci2::create(lia);
|
||||
#else
|
||||
foci = 0;
|
||||
#endif
|
||||
if(!foci){
|
||||
std::cerr << "iZ3: cannot find foci lia solver.\n";
|
||||
assert(0);
|
||||
}
|
||||
select_op = foci->mk_func("select");
|
||||
store_op = foci->mk_func("store");
|
||||
mod_op = foci->mk_func("mod");
|
||||
std::vector<foci2::ast> foci_cnsts(frames), foci_itps(frames-1), foci_parents;
|
||||
if(parents)
|
||||
foci_parents.resize(frames);
|
||||
for(int i = 0; i < frames; i++){
|
||||
foci_cnsts[i] = from_Z3_ast(cnsts[i]);
|
||||
if(parents)
|
||||
foci_parents[i] = parents[i];
|
||||
}
|
||||
int res = foci->interpolate(foci_cnsts, foci_itps, foci_parents);
|
||||
if(res == 0){
|
||||
assert((int)foci_itps.size() == frames-1);
|
||||
itps.resize(frames-1);
|
||||
for(int i = 0; i < frames-1; i++){
|
||||
// foci->show_ast(foci_itps[i]);
|
||||
itps[i] = to_Z3_ast(foci_itps[i]);
|
||||
}
|
||||
}
|
||||
ast_to_node.clear();
|
||||
node_to_ast.clear();
|
||||
func_decl_to_symbol.clear();
|
||||
symbol_to_func_decl.clear();
|
||||
delete foci;
|
||||
return res;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
iz3secondary *iz3foci::create(iz3mgr *mgr, int num, int *parents){
|
||||
return new iz3foci_impl(mgr,num,parents);
|
||||
}
|
32
src/interp/iz3foci.h
Executable file
32
src/interp/iz3foci.h
Executable file
|
@ -0,0 +1,32 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3foci.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Implements a secondary solver using foci2.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef IZ3FOCI_H
|
||||
#define IZ3FOCI_H
|
||||
|
||||
#include "iz3secondary.h"
|
||||
|
||||
/** Secondary prover based on Cadence FOCI. */
|
||||
|
||||
class iz3foci {
|
||||
public:
|
||||
static iz3secondary *create(iz3mgr *mgr, int num, int *parents);
|
||||
};
|
||||
|
||||
#endif
|
171
src/interp/iz3hash.h
Executable file
171
src/interp/iz3hash.h
Executable file
|
@ -0,0 +1,171 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3hash.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Wrapper for stl hash tables
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
// pull in the headers for has_map and hash_set
|
||||
// these live in non-standard places
|
||||
|
||||
#ifndef IZ3_HASH_H
|
||||
#define IZ3_HASH_H
|
||||
|
||||
//#define USE_UNORDERED_MAP
|
||||
#ifdef USE_UNORDERED_MAP
|
||||
|
||||
#define stl_ext std
|
||||
#define hash_space std
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#define hash_map unordered_map
|
||||
#define hash_set unordered_set
|
||||
|
||||
#else
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
#undef __DEPRECATED
|
||||
#define stl_ext __gnu_cxx
|
||||
#define hash_space stl_ext
|
||||
#include <ext/hash_map>
|
||||
#include <ext/hash_set>
|
||||
#else
|
||||
#ifdef WIN32
|
||||
#define stl_ext stdext
|
||||
#define hash_space std
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#else
|
||||
#define stl_ext std
|
||||
#define hash_space std
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
// stupid STL doesn't include hash function for class string
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
namespace stl_ext {
|
||||
template <>
|
||||
class hash<std::string> {
|
||||
stl_ext::hash<char *> H;
|
||||
public:
|
||||
size_t operator()(const std::string &s) const {
|
||||
return H(s.c_str());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace hash_space {
|
||||
template <>
|
||||
class hash<std::pair<int,int> > {
|
||||
public:
|
||||
size_t operator()(const std::pair<int,int> &p) const {
|
||||
return p.first + p.second;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
template <> inline
|
||||
size_t stdext::hash_value<std::pair<int,int> >(const std::pair<int,int>& p)
|
||||
{ // hash _Keyval to size_t value one-to-one
|
||||
return p.first + p.second;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace hash_space {
|
||||
template <class T>
|
||||
class hash<std::pair<T *, T *> > {
|
||||
public:
|
||||
size_t operator()(const std::pair<T *,T *> &p) const {
|
||||
return (size_t)p.first + (size_t)p.second;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <class T> inline
|
||||
size_t stdext::hash_value<std::pair<T *, T *> >(const std::pair<T *, T *>& p)
|
||||
{ // hash _Keyval to size_t value one-to-one
|
||||
return (size_t)p.first + (size_t)p.second;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
class less<std::pair<int,int> > {
|
||||
public:
|
||||
bool operator()(const pair<int,int> &x, const pair<int,int> &y) const {
|
||||
return x.first < y.first || x.first == y.first && x.second < y.second;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <class T>
|
||||
class less<std::pair<T *,T *> > {
|
||||
public:
|
||||
bool operator()(const pair<T *,T *> &x, const pair<T *,T *> &y) const {
|
||||
return (size_t)x.first < (size_t)y.first || (size_t)x.first == (size_t)y.first && (size_t)x.second < (size_t)y.second;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#if 0
|
||||
namespace stl_ext {
|
||||
template <class T>
|
||||
class hash<T *> {
|
||||
public:
|
||||
size_t operator()(const T *p) const {
|
||||
return (size_t) p;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
|
||||
|
||||
|
||||
template <class K, class T>
|
||||
class hash_map : public stl_ext::hash_map<K,T,stl_ext::hash_compare<K,std::less<K> > > {};
|
||||
|
||||
template <class K>
|
||||
class hash_set : public stl_ext::hash_set<K,stl_ext::hash_compare<K,std::less<K> > > {};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
504
src/interp/iz3interp.cpp
Executable file
504
src/interp/iz3interp.cpp
Executable file
|
@ -0,0 +1,504 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3interp.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Interpolation based on proof translation.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
/* Copyright 2011 Microsoft Research. */
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
|
||||
#include "iz3profiling.h"
|
||||
#include "iz3translate.h"
|
||||
#include "iz3foci.h"
|
||||
#include "iz3proof.h"
|
||||
#include "iz3hash.h"
|
||||
#include "iz3interp.h"
|
||||
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if 1
|
||||
|
||||
struct frame_reducer : public iz3mgr {
|
||||
|
||||
int frames;
|
||||
hash_map<ast,int> frame_map;
|
||||
std::vector<int> assertions_map;
|
||||
std::vector<int> orig_parents_copy;
|
||||
std::vector<bool> used_frames;
|
||||
|
||||
|
||||
frame_reducer(const iz3mgr &other)
|
||||
: iz3mgr(other) {}
|
||||
|
||||
void get_proof_assumptions_rec(z3pf proof, hash_set<ast> &memo, std::vector<bool> &used_frames){
|
||||
if(memo.count(proof))return;
|
||||
memo.insert(proof);
|
||||
pfrule dk = pr(proof);
|
||||
if(dk == PR_ASSERTED){
|
||||
ast con = conc(proof);
|
||||
if(frame_map.find(con) != frame_map.end()){ // false for theory facts
|
||||
int frame = frame_map[con];
|
||||
used_frames[frame] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned nprems = num_prems(proof);
|
||||
for(unsigned i = 0; i < nprems; i++){
|
||||
z3pf arg = prem(proof,i);
|
||||
get_proof_assumptions_rec(arg,memo,used_frames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_frames(const std::vector<std::vector<ast> >&z3_preds,
|
||||
const std::vector<int> &orig_parents,
|
||||
std::vector<std::vector<ast> >&assertions,
|
||||
std::vector<int> &parents,
|
||||
z3pf proof){
|
||||
frames = z3_preds.size();
|
||||
orig_parents_copy = orig_parents;
|
||||
for(unsigned i = 0; i < z3_preds.size(); i++)
|
||||
for(unsigned j = 0; j < z3_preds[i].size(); j++)
|
||||
frame_map[z3_preds[i][j]] = i;
|
||||
used_frames.resize(frames);
|
||||
hash_set<ast> memo;
|
||||
get_proof_assumptions_rec(proof,memo,used_frames);
|
||||
std::vector<int> assertions_back_map(frames);
|
||||
|
||||
for(unsigned i = 0; i < z3_preds.size(); i++)
|
||||
if(used_frames[i] || i == z3_preds.size() - 1){
|
||||
assertions.push_back(z3_preds[i]);
|
||||
assertions_map.push_back(i);
|
||||
assertions_back_map[i] = assertions.size() - 1;
|
||||
}
|
||||
|
||||
if(orig_parents.size()){
|
||||
parents.resize(assertions.size());
|
||||
for(unsigned i = 0; i < assertions.size(); i++){
|
||||
int p = orig_parents[assertions_map[i]];
|
||||
while(p != SHRT_MAX && !used_frames[p])
|
||||
p = orig_parents[p];
|
||||
parents[i] = p == SHRT_MAX ? p : assertions_back_map[p];
|
||||
}
|
||||
}
|
||||
|
||||
// std::cout << "used frames = " << frames << "\n";
|
||||
}
|
||||
|
||||
void fix_interpolants(std::vector<ast> &interpolants){
|
||||
std::vector<ast> unfixed = interpolants;
|
||||
interpolants.resize(frames - 1);
|
||||
for(int i = 0; i < frames - 1; i++)
|
||||
interpolants[i] = mk_true();
|
||||
for(unsigned i = 0; i < unfixed.size(); i++)
|
||||
interpolants[assertions_map[i]] = unfixed[i];
|
||||
for(int i = 0; i < frames-2; i++){
|
||||
int p = orig_parents_copy.size() == 0 ? i+1 : orig_parents_copy[i];
|
||||
if(p < frames - 1 && !used_frames[p])
|
||||
interpolants[p] = interpolants[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
struct frame_reducer {
|
||||
|
||||
|
||||
|
||||
frame_reducer(context _ctx){
|
||||
}
|
||||
|
||||
void get_frames(const std::vector<ast> &z3_preds,
|
||||
const std::vector<int> &orig_parents,
|
||||
std::vector<ast> &assertions,
|
||||
std::vector<int> &parents,
|
||||
ast proof){
|
||||
assertions = z3_preds;
|
||||
parents = orig_parents;
|
||||
}
|
||||
|
||||
void fix_interpolants(std::vector<ast> &interpolants){
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
static lbool test_secondary(context ctx,
|
||||
int num,
|
||||
ast *cnsts,
|
||||
ast *interps,
|
||||
int *parents = 0
|
||||
){
|
||||
iz3secondary *sp = iz3foci::create(ctx,num,parents);
|
||||
std::vector<ast> frames(num), interpolants(num-1);
|
||||
std::copy(cnsts,cnsts+num,frames.begin());
|
||||
int res = sp->interpolate(frames,interpolants);
|
||||
if(res == 0)
|
||||
std::copy(interpolants.begin(),interpolants.end(),interps);
|
||||
return res ? L_TRUE : L_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
struct killme {
|
||||
T *p;
|
||||
killme(){p = 0;}
|
||||
void set(T *_p) {p = _p;}
|
||||
~killme(){
|
||||
if(p)
|
||||
delete p;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class iz3interp : public iz3base {
|
||||
public:
|
||||
|
||||
killme<iz3secondary> sp_killer;
|
||||
killme<iz3translation> tr_killer;
|
||||
|
||||
bool is_linear(std::vector<int> &parents){
|
||||
for(int i = 0; i < ((int)parents.size())-1; i++)
|
||||
if(parents[i] != i+1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void test_secondary(const std::vector<ast> &cnsts,
|
||||
const std::vector<int> &parents,
|
||||
std::vector<ast> &interps
|
||||
){
|
||||
int num = cnsts.size();
|
||||
iz3secondary *sp = iz3foci::create(this,num,(int *)(parents.empty()?0:&parents[0]));
|
||||
int res = sp->interpolate(cnsts, interps);
|
||||
if(res != 0)
|
||||
throw "secondary failed";
|
||||
}
|
||||
|
||||
void proof_to_interpolant(z3pf proof,
|
||||
const std::vector<std::vector<ast> > &cnsts,
|
||||
const std::vector<int> &parents,
|
||||
std::vector<ast> &interps,
|
||||
const std::vector<ast> &theory,
|
||||
interpolation_options_struct *options = 0
|
||||
){
|
||||
#if 0
|
||||
test_secondary(cnsts,parents,interps);
|
||||
return;
|
||||
#endif
|
||||
|
||||
profiling::timer_start("Interpolation prep");
|
||||
|
||||
// get rid of frames not used in proof
|
||||
|
||||
std::vector<std::vector<ast> > cnsts_vec;
|
||||
std::vector<int> parents_vec;
|
||||
frame_reducer fr(*this);
|
||||
fr.get_frames(cnsts,parents,cnsts_vec,parents_vec,proof);
|
||||
|
||||
int num = cnsts_vec.size();
|
||||
std::vector<ast> interps_vec(num-1);
|
||||
|
||||
// if this is really a sequence problem, we can make it easier
|
||||
if(is_linear(parents_vec))
|
||||
parents_vec.clear();
|
||||
|
||||
// create a secondary prover
|
||||
iz3secondary *sp = iz3foci::create(this,num,parents_vec.empty()?0:&parents_vec[0]);
|
||||
sp_killer.set(sp); // kill this on exit
|
||||
|
||||
#define BINARY_INTERPOLATION
|
||||
#ifndef BINARY_INTERPOLATION
|
||||
// create a translator
|
||||
iz3translation *tr = iz3translation::create(*this,sp,cnsts_vec,parents_vec,theory);
|
||||
tr_killer.set(tr);
|
||||
|
||||
// set the translation options, if needed
|
||||
if(options)
|
||||
for(hash_map<std::string,std::string>::iterator it = options->map.begin(), en = options->map.end(); it != en; ++it)
|
||||
tr->set_option(it->first, it->second);
|
||||
|
||||
// create a proof object to hold the translation
|
||||
iz3proof pf(tr);
|
||||
|
||||
profiling::timer_stop("Interpolation prep");
|
||||
|
||||
// translate into an interpolatable proof
|
||||
profiling::timer_start("Proof translation");
|
||||
tr->translate(proof,pf);
|
||||
profiling::timer_stop("Proof translation");
|
||||
|
||||
// translate the proof into interpolants
|
||||
profiling::timer_start("Proof interpolation");
|
||||
for(int i = 0; i < num-1; i++){
|
||||
interps_vec[i] = pf.interpolate(tr->range_downward(i),tr->weak_mode());
|
||||
interps_vec[i] = tr->quantify(interps_vec[i],tr->range_downward(i));
|
||||
}
|
||||
profiling::timer_stop("Proof interpolation");
|
||||
#else
|
||||
iz3base the_base(*this,cnsts_vec,parents_vec,theory);
|
||||
|
||||
profiling::timer_stop("Interpolation prep");
|
||||
|
||||
for(int i = 0; i < num-1; i++){
|
||||
range rng = the_base.range_downward(i);
|
||||
std::vector<std::vector<ast> > cnsts_vec_vec(2);
|
||||
for(unsigned j = 0; j < cnsts_vec.size(); j++){
|
||||
bool is_A = the_base.in_range(j,rng);
|
||||
for(unsigned k = 0; k < cnsts_vec[j].size(); k++)
|
||||
cnsts_vec_vec[is_A ? 0 : 1].push_back(cnsts_vec[j][k]);
|
||||
}
|
||||
|
||||
killme<iz3translation> tr_killer_i;
|
||||
iz3translation *tr = iz3translation::create(*this,sp,cnsts_vec_vec,std::vector<int>(),theory);
|
||||
tr_killer_i.set(tr);
|
||||
|
||||
// set the translation options, if needed
|
||||
if(options)
|
||||
for(hash_map<std::string,std::string>::iterator it = options->map.begin(), en = options->map.end(); it != en; ++it)
|
||||
tr->set_option(it->first, it->second);
|
||||
|
||||
// create a proof object to hold the translation
|
||||
iz3proof pf(tr);
|
||||
|
||||
// translate into an interpolatable proof
|
||||
profiling::timer_start("Proof translation");
|
||||
tr->translate(proof,pf);
|
||||
profiling::timer_stop("Proof translation");
|
||||
|
||||
// translate the proof into interpolants
|
||||
profiling::timer_start("Proof interpolation");
|
||||
interps_vec[i] = pf.interpolate(tr->range_downward(0),tr->weak_mode());
|
||||
interps_vec[i] = tr->quantify(interps_vec[i],tr->range_downward(0));
|
||||
profiling::timer_stop("Proof interpolation");
|
||||
}
|
||||
#endif
|
||||
// put back in the removed frames
|
||||
fr.fix_interpolants(interps_vec);
|
||||
|
||||
interps = interps_vec;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void proof_to_interpolant(z3pf proof,
|
||||
std::vector<ast> &cnsts,
|
||||
const std::vector<int> &parents,
|
||||
std::vector<ast> &interps,
|
||||
const std::vector<ast> &theory,
|
||||
interpolation_options_struct *options = 0
|
||||
){
|
||||
std::vector<std::vector<ast> > cnsts_vec(cnsts.size());
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
cnsts_vec[i].push_back(cnsts[i]);
|
||||
proof_to_interpolant(proof,cnsts_vec,parents,interps,theory,options);
|
||||
}
|
||||
|
||||
// same as above, but represents the tree using an ast
|
||||
|
||||
void proof_to_interpolant(const z3pf &proof,
|
||||
const std::vector<ast> &_cnsts,
|
||||
const ast &tree,
|
||||
std::vector<ast> &interps,
|
||||
interpolation_options_struct *options = 0
|
||||
){
|
||||
std::vector<int> pos_map;
|
||||
|
||||
// convert to the parents vector representation
|
||||
|
||||
to_parents_vec_representation(_cnsts, tree, cnsts, parents, theory, pos_map);
|
||||
|
||||
//use the parents vector representation to compute interpolant
|
||||
proof_to_interpolant(proof,cnsts,parents,interps,theory,options);
|
||||
|
||||
// get the interps for the tree positions
|
||||
std::vector<ast> _interps = interps;
|
||||
interps.resize(pos_map.size());
|
||||
for(unsigned i = 0; i < pos_map.size(); i++)
|
||||
interps[i] = i < _interps.size() ? _interps[i] : mk_false();
|
||||
}
|
||||
|
||||
bool has_interp(hash_map<ast,bool> &memo, const ast &t){
|
||||
if(memo.find(t) != memo.end())
|
||||
return memo[t];
|
||||
bool res = false;
|
||||
if(op(t) == Interp)
|
||||
res = true;
|
||||
else if(op(t) == And){
|
||||
int nargs = num_args(t);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
res |= has_interp(memo, arg(t,i));
|
||||
}
|
||||
memo[t] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
void collect_conjuncts(std::vector<ast> &cnsts, hash_map<ast,bool> &memo, const ast &t){
|
||||
if(!has_interp(memo,t))
|
||||
cnsts.push_back(t);
|
||||
else {
|
||||
int nargs = num_args(t);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
collect_conjuncts(cnsts, memo, arg(t,i));
|
||||
}
|
||||
}
|
||||
|
||||
void assert_conjuncts(solver &s, std::vector<ast> &cnsts, const ast &t){
|
||||
hash_map<ast,bool> memo;
|
||||
collect_conjuncts(cnsts,memo,t);
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
s.assert_expr(to_expr(cnsts[i].raw()));
|
||||
}
|
||||
|
||||
iz3interp(ast_manager &_m_manager)
|
||||
: iz3base(_m_manager) {}
|
||||
};
|
||||
|
||||
void iz3interpolate(ast_manager &_m_manager,
|
||||
ast *proof,
|
||||
const ptr_vector<ast> &cnsts,
|
||||
const ::vector<int> &parents,
|
||||
ptr_vector<ast> &interps,
|
||||
const ptr_vector<ast> &theory,
|
||||
interpolation_options_struct * options)
|
||||
{
|
||||
iz3interp itp(_m_manager);
|
||||
if(options)
|
||||
options->apply(itp);
|
||||
std::vector<iz3mgr::ast> _cnsts(cnsts.size());
|
||||
std::vector<int> _parents(parents.size());
|
||||
std::vector<iz3mgr::ast> _interps;
|
||||
std::vector<iz3mgr::ast> _theory(theory.size());
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
_cnsts[i] = itp.cook(cnsts[i]);
|
||||
for(unsigned i = 0; i < parents.size(); i++)
|
||||
_parents[i] = parents[i];
|
||||
for(unsigned i = 0; i < theory.size(); i++)
|
||||
_theory[i] = itp.cook(theory[i]);
|
||||
iz3mgr::ast _proof = itp.cook(proof);
|
||||
itp.proof_to_interpolant(_proof,_cnsts,_parents,_interps,_theory,options);
|
||||
interps.resize(_interps.size());
|
||||
for(unsigned i = 0; i < interps.size(); i++)
|
||||
interps[i] = itp.uncook(_interps[i]);
|
||||
}
|
||||
|
||||
void iz3interpolate(ast_manager &_m_manager,
|
||||
ast *proof,
|
||||
const ::vector<ptr_vector<ast> > &cnsts,
|
||||
const ::vector<int> &parents,
|
||||
ptr_vector<ast> &interps,
|
||||
const ptr_vector<ast> &theory,
|
||||
interpolation_options_struct * options)
|
||||
{
|
||||
iz3interp itp(_m_manager);
|
||||
if(options)
|
||||
options->apply(itp);
|
||||
std::vector<std::vector<iz3mgr::ast> > _cnsts(cnsts.size());
|
||||
std::vector<int> _parents(parents.size());
|
||||
std::vector<iz3mgr::ast> _interps;
|
||||
std::vector<iz3mgr::ast> _theory(theory.size());
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
for(unsigned j = 0; j < cnsts[i].size(); j++)
|
||||
_cnsts[i].push_back(itp.cook(cnsts[i][j]));
|
||||
for(unsigned i = 0; i < parents.size(); i++)
|
||||
_parents[i] = parents[i];
|
||||
for(unsigned i = 0; i < theory.size(); i++)
|
||||
_theory[i] = itp.cook(theory[i]);
|
||||
iz3mgr::ast _proof = itp.cook(proof);
|
||||
itp.proof_to_interpolant(_proof,_cnsts,_parents,_interps,_theory,options);
|
||||
interps.resize(_interps.size());
|
||||
for(unsigned i = 0; i < interps.size(); i++)
|
||||
interps[i] = itp.uncook(_interps[i]);
|
||||
}
|
||||
|
||||
void iz3interpolate(ast_manager &_m_manager,
|
||||
ast *proof,
|
||||
const ptr_vector<ast> &cnsts,
|
||||
ast *tree,
|
||||
ptr_vector<ast> &interps,
|
||||
interpolation_options_struct * options)
|
||||
{
|
||||
iz3interp itp(_m_manager);
|
||||
if(options)
|
||||
options->apply(itp);
|
||||
std::vector<iz3mgr::ast> _cnsts(cnsts.size());
|
||||
std::vector<iz3mgr::ast> _interps;
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
_cnsts[i] = itp.cook(cnsts[i]);
|
||||
iz3mgr::ast _proof = itp.cook(proof);
|
||||
iz3mgr::ast _tree = itp.cook(tree);
|
||||
itp.proof_to_interpolant(_proof,_cnsts,_tree,_interps,options);
|
||||
interps.resize(_interps.size());
|
||||
for(unsigned i = 0; i < interps.size(); i++)
|
||||
interps[i] = itp.uncook(_interps[i]);
|
||||
}
|
||||
|
||||
lbool iz3interpolate(ast_manager &_m_manager,
|
||||
solver &s,
|
||||
ast *tree,
|
||||
ptr_vector<ast> &cnsts,
|
||||
ptr_vector<ast> &interps,
|
||||
model_ref &m,
|
||||
interpolation_options_struct * options)
|
||||
{
|
||||
iz3interp itp(_m_manager);
|
||||
if(options)
|
||||
options->apply(itp);
|
||||
iz3mgr::ast _tree = itp.cook(tree);
|
||||
std::vector<iz3mgr::ast> _cnsts;
|
||||
itp.assert_conjuncts(s,_cnsts,_tree);
|
||||
profiling::timer_start("solving");
|
||||
lbool res = s.check_sat(0,0);
|
||||
profiling::timer_stop("solving");
|
||||
if(res == l_false){
|
||||
ast *proof = s.get_proof();
|
||||
iz3mgr::ast _proof = itp.cook(proof);
|
||||
std::vector<iz3mgr::ast> _interps;
|
||||
itp.proof_to_interpolant(_proof,_cnsts,_tree,_interps,options);
|
||||
interps.resize(_interps.size());
|
||||
for(unsigned i = 0; i < interps.size(); i++)
|
||||
interps[i] = itp.uncook(_interps[i]);
|
||||
}
|
||||
else if(m){
|
||||
s.get_model(m);
|
||||
}
|
||||
cnsts.resize(_cnsts.size());
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
cnsts[i] = itp.uncook(_cnsts[i]);
|
||||
return res;
|
||||
}
|
||||
|
||||
void interpolation_options_struct::apply(iz3base &b){
|
||||
for(stl_ext::hash_map<std::string,std::string>::iterator it = map.begin(), en = map.end();
|
||||
it != en;
|
||||
++it)
|
||||
b.set_option((*it).first,(*it).second);
|
||||
}
|
||||
|
93
src/interp/iz3interp.h
Normal file
93
src/interp/iz3interp.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3interp.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Interpolation based on proof translation.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef IZ3_INTERP_H
|
||||
#define IZ3_INTERP_H
|
||||
|
||||
#include "iz3hash.h"
|
||||
#include "solver.h"
|
||||
|
||||
class iz3base;
|
||||
|
||||
struct interpolation_options_struct {
|
||||
stl_ext::hash_map<std::string,std::string> map;
|
||||
public:
|
||||
void set(const std::string &name, const std::string &value){
|
||||
map[name] = value;
|
||||
}
|
||||
void apply(iz3base &b);
|
||||
};
|
||||
|
||||
/** This object is thrown if a tree interpolation problem is mal-formed */
|
||||
struct iz3_bad_tree {
|
||||
};
|
||||
|
||||
/** This object is thrown when iz3 fails due to an incompleteness in
|
||||
the secondary solver. */
|
||||
struct iz3_incompleteness {
|
||||
};
|
||||
|
||||
typedef interpolation_options_struct *interpolation_options;
|
||||
|
||||
/* Compute an interpolant from a proof. This version uses the parents vector
|
||||
representation, for compatibility with the old API. */
|
||||
|
||||
void iz3interpolate(ast_manager &_m_manager,
|
||||
ast *proof,
|
||||
const ptr_vector<ast> &cnsts,
|
||||
const ::vector<int> &parents,
|
||||
ptr_vector<ast> &interps,
|
||||
const ptr_vector<ast> &theory,
|
||||
interpolation_options_struct * options = 0);
|
||||
|
||||
/* Same as above, but each constraint is a vector of formulas. */
|
||||
|
||||
void iz3interpolate(ast_manager &_m_manager,
|
||||
ast *proof,
|
||||
const vector<ptr_vector<ast> > &cnsts,
|
||||
const ::vector<int> &parents,
|
||||
ptr_vector<ast> &interps,
|
||||
const ptr_vector<ast> &theory,
|
||||
interpolation_options_struct * options = 0);
|
||||
|
||||
/* Compute an interpolant from a proof. This version uses the ast
|
||||
representation, for compatibility with the new API. */
|
||||
|
||||
void iz3interpolate(ast_manager &_m_manager,
|
||||
ast *proof,
|
||||
const ptr_vector<ast> &cnsts,
|
||||
ast *tree,
|
||||
ptr_vector<ast> &interps,
|
||||
interpolation_options_struct * options);
|
||||
|
||||
/* Compute an interpolant from an ast representing an interpolation
|
||||
problem, if unsat, else return a model (if enabled). Uses the
|
||||
given solver to produce the proof/model. Also returns a vector
|
||||
of the constraints in the problem, helpful for checking correctness.
|
||||
*/
|
||||
|
||||
lbool iz3interpolate(ast_manager &_m_manager,
|
||||
solver &s,
|
||||
ast *tree,
|
||||
ptr_vector<ast> &cnsts,
|
||||
ptr_vector<ast> &interps,
|
||||
model_ref &m,
|
||||
interpolation_options_struct * options);
|
||||
|
||||
#endif
|
871
src/interp/iz3mgr.cpp
Normal file
871
src/interp/iz3mgr.cpp
Normal file
|
@ -0,0 +1,871 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3mgr.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
A wrapper around an ast manager, providing convenience methods.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "iz3mgr.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
|
||||
#include "expr_abstract.h"
|
||||
#include "params.h"
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
|
||||
std::ostream &operator <<(std::ostream &s, const iz3mgr::ast &a){
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
iz3mgr::ast iz3mgr::make_var(const std::string &name, type ty){
|
||||
symbol s = symbol(name.c_str());
|
||||
return cook(m().mk_const(m().mk_const_decl(s, ty)));
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(opr op, int n, raw_ast **args){
|
||||
switch(op) {
|
||||
case True: return mki(m_basic_fid,OP_TRUE,n,args);
|
||||
case False: return mki(m_basic_fid,OP_FALSE,n,args);
|
||||
case Equal: return mki(m_basic_fid,OP_EQ,n,args);
|
||||
case Distinct: return mki(m_basic_fid,OP_DISTINCT,n,args);
|
||||
case Ite: return mki(m_basic_fid,OP_ITE,n,args);
|
||||
case And: return mki(m_basic_fid,OP_AND,n,args);
|
||||
case Or: return mki(m_basic_fid,OP_OR,n,args);
|
||||
case Iff: return mki(m_basic_fid,OP_IFF,n,args);
|
||||
case Xor: return mki(m_basic_fid,OP_XOR,n,args);
|
||||
case Not: return mki(m_basic_fid,OP_NOT,n,args);
|
||||
case Implies: return mki(m_basic_fid,OP_IMPLIES,n,args);
|
||||
case Oeq: return mki(m_basic_fid,OP_OEQ,n,args);
|
||||
case Interp: return mki(m_basic_fid,OP_INTERP,n,args);
|
||||
case Leq: return mki(m_arith_fid,OP_LE,n,args);
|
||||
case Geq: return mki(m_arith_fid,OP_GE,n,args);
|
||||
case Lt: return mki(m_arith_fid,OP_LT,n,args);
|
||||
case Gt: return mki(m_arith_fid,OP_GT,n,args);
|
||||
case Plus: return mki(m_arith_fid,OP_ADD,n,args);
|
||||
case Sub: return mki(m_arith_fid,OP_SUB,n,args);
|
||||
case Uminus: return mki(m_arith_fid,OP_UMINUS,n,args);
|
||||
case Times: return mki(m_arith_fid,OP_MUL,n,args);
|
||||
case Div: return mki(m_arith_fid,OP_DIV,n,args);
|
||||
case Idiv: return mki(m_arith_fid,OP_IDIV,n,args);
|
||||
case Rem: return mki(m_arith_fid,OP_REM,n,args);
|
||||
case Mod: return mki(m_arith_fid,OP_MOD,n,args);
|
||||
case Power: return mki(m_arith_fid,OP_POWER,n,args);
|
||||
case ToReal: return mki(m_arith_fid,OP_TO_REAL,n,args);
|
||||
case ToInt: return mki(m_arith_fid,OP_TO_INT,n,args);
|
||||
case IsInt: return mki(m_arith_fid,OP_IS_INT,n,args);
|
||||
case Store: return mki(m_array_fid,OP_STORE,n,args);
|
||||
case Select: return mki(m_array_fid,OP_SELECT,n,args);
|
||||
case ConstArray: return mki(m_array_fid,OP_CONST_ARRAY,n,args);
|
||||
case ArrayDefault: return mki(m_array_fid,OP_ARRAY_DEFAULT,n,args);
|
||||
case ArrayMap: return mki(m_array_fid,OP_ARRAY_MAP,n,args);
|
||||
case SetUnion: return mki(m_array_fid,OP_SET_UNION,n,args);
|
||||
case SetIntersect: return mki(m_array_fid,OP_SET_INTERSECT,n,args);
|
||||
case SetDifference: return mki(m_array_fid,OP_SET_DIFFERENCE,n,args);
|
||||
case SetComplement: return mki(m_array_fid,OP_SET_COMPLEMENT,n,args);
|
||||
case SetSubSet: return mki(m_array_fid,OP_SET_SUBSET,n,args);
|
||||
case AsArray: return mki(m_array_fid,OP_AS_ARRAY,n,args);
|
||||
default:
|
||||
assert(0);
|
||||
return ast();
|
||||
}
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::mki(family_id fid, decl_kind dk, int n, raw_ast **args){
|
||||
return cook(m().mk_app(fid, dk, 0, 0, n, (expr **)args));
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(opr op, const std::vector<ast> &args){
|
||||
static std::vector<raw_ast*> a(10);
|
||||
if(a.size() < args.size())
|
||||
a.resize(args.size());
|
||||
for(unsigned i = 0; i < args.size(); i++)
|
||||
a[i] = args[i].raw();
|
||||
return make(op,args.size(), args.size() ? &a[0] : 0);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(opr op){
|
||||
return make(op,0,0);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(opr op, const ast &arg0){
|
||||
raw_ast *a = arg0.raw();
|
||||
return make(op,1,&a);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(opr op, const ast &arg0, const ast &arg1){
|
||||
raw_ast *args[2];
|
||||
args[0] = arg0.raw();
|
||||
args[1] = arg1.raw();
|
||||
return make(op,2,args);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(opr op, const ast &arg0, const ast &arg1, const ast &arg2){
|
||||
raw_ast *args[3];
|
||||
args[0] = arg0.raw();
|
||||
args[1] = arg1.raw();
|
||||
args[2] = arg2.raw();
|
||||
return make(op,3,args);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(symb sym, int n, raw_ast **args){
|
||||
return cook(m().mk_app(sym, n, (expr **) args));
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(symb sym, const std::vector<ast> &args){
|
||||
static std::vector<raw_ast*> a(10);
|
||||
if(a.size() < args.size())
|
||||
a.resize(args.size());
|
||||
for(unsigned i = 0; i < args.size(); i++)
|
||||
a[i] = args[i].raw();
|
||||
return make(sym,args.size(), args.size() ? &a[0] : 0);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(symb sym){
|
||||
return make(sym,0,0);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0){
|
||||
raw_ast *a = arg0.raw();
|
||||
return make(sym,1,&a);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0, const ast &arg1){
|
||||
raw_ast *args[2];
|
||||
args[0] = arg0.raw();
|
||||
args[1] = arg1.raw();
|
||||
return make(sym,2,args);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0, const ast &arg1, const ast &arg2){
|
||||
raw_ast *args[3];
|
||||
args[0] = arg0.raw();
|
||||
args[1] = arg1.raw();
|
||||
args[2] = arg2.raw();
|
||||
return make(sym,3,args);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::make_quant(opr op, const std::vector<ast> &bvs, ast &body){
|
||||
if(bvs.size() == 0) return body;
|
||||
std::vector<raw_ast *> foo(bvs.size());
|
||||
|
||||
|
||||
std::vector<symbol> names;
|
||||
std::vector<sort *> types;
|
||||
std::vector<expr *> bound_asts;
|
||||
unsigned num_bound = bvs.size();
|
||||
|
||||
for (unsigned i = 0; i < num_bound; ++i) {
|
||||
app* a = to_app(bvs[i].raw());
|
||||
symbol s(to_app(a)->get_decl()->get_name());
|
||||
names.push_back(s);
|
||||
types.push_back(m().get_sort(a));
|
||||
bound_asts.push_back(a);
|
||||
}
|
||||
expr_ref abs_body(m());
|
||||
expr_abstract(m(), 0, num_bound, &bound_asts[0], to_expr(body.raw()), abs_body);
|
||||
expr_ref result(m());
|
||||
result = m().mk_quantifier(
|
||||
op == Forall,
|
||||
names.size(), &types[0], &names[0], abs_body.get(),
|
||||
0,
|
||||
symbol("itp"),
|
||||
symbol(),
|
||||
0, 0,
|
||||
0, 0
|
||||
);
|
||||
return cook(result.get());
|
||||
}
|
||||
|
||||
// FIXME replace this with existing Z3 functionality
|
||||
|
||||
iz3mgr::ast iz3mgr::clone(const ast &t, const std::vector<ast> &_args){
|
||||
if(_args.size() == 0)
|
||||
return t;
|
||||
|
||||
ast_manager& m = m_manager;
|
||||
expr* a = to_expr(t.raw());
|
||||
static std::vector<raw_ast*> rargs(10);
|
||||
if(rargs.size() < _args.size())
|
||||
rargs.resize(_args.size());
|
||||
for(unsigned i = 0; i < _args.size(); i++)
|
||||
rargs[i] = _args[i].raw();
|
||||
expr* const* args = (expr **)&rargs[0];
|
||||
switch(a->get_kind()) {
|
||||
case AST_APP: {
|
||||
app* e = to_app(a);
|
||||
if (e->get_num_args() != _args.size()) {
|
||||
assert(0);
|
||||
}
|
||||
else {
|
||||
a = m.mk_app(e->get_decl(), _args.size(), args);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AST_QUANTIFIER: {
|
||||
if (_args.size() != 1) {
|
||||
assert(0);
|
||||
}
|
||||
else {
|
||||
a = m.update_quantifier(to_quantifier(a), args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return cook(a);
|
||||
}
|
||||
|
||||
|
||||
void iz3mgr::show(ast t){
|
||||
params_ref p;
|
||||
p.set_bool("flat_assoc",false);
|
||||
std::cout << mk_pp(t.raw(), m(), p) << std::endl;
|
||||
}
|
||||
|
||||
void iz3mgr::show_symb(symb s){
|
||||
std::cout << mk_pp(s, m()) << std::endl;
|
||||
}
|
||||
|
||||
void iz3mgr::print_expr(std::ostream &s, const ast &e){
|
||||
params_ref p;
|
||||
p.set_bool("flat_assoc",false);
|
||||
s << mk_pp(e.raw(), m(), p);
|
||||
}
|
||||
|
||||
|
||||
void iz3mgr::print_clause(std::ostream &s, std::vector<ast> &cls){
|
||||
s << "(";
|
||||
for(unsigned i = 0; i < cls.size(); i++){
|
||||
if(i > 0) s << ",";
|
||||
print_expr(s,cls[i]);
|
||||
}
|
||||
s << ")";
|
||||
}
|
||||
|
||||
void iz3mgr::show_clause(std::vector<ast> &cls){
|
||||
print_clause(std::cout,cls);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void iz3mgr::print_lit(ast lit){
|
||||
ast abslit = is_not(lit) ? arg(lit,0) : lit;
|
||||
int f = op(abslit);
|
||||
if(f == And || f == Or || f == Iff){
|
||||
if(is_not(lit)) std::cout << "~";
|
||||
std::cout << "[" << abslit << "]";
|
||||
}
|
||||
else
|
||||
std::cout << lit;
|
||||
}
|
||||
|
||||
|
||||
static int pretty_cols = 79;
|
||||
static int pretty_indent_chars = 2;
|
||||
|
||||
static int pretty_find_delim(const std::string &s, int pos){
|
||||
int level = 0;
|
||||
int end = s.size();
|
||||
for(; pos < end; pos++){
|
||||
int ch = s[pos];
|
||||
if(ch == '(')level++;
|
||||
if(ch == ')')level--;
|
||||
if(level < 0 || (level == 0 && ch == ','))break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void pretty_newline(std::ostream &f, int indent){
|
||||
f << std::endl;
|
||||
for(int i = 0; i < indent; i++)
|
||||
f << " ";
|
||||
}
|
||||
|
||||
void iz3mgr::pretty_print(std::ostream &f, const std::string &s){
|
||||
int cur_indent = 0;
|
||||
int indent = 0;
|
||||
int col = 0;
|
||||
int pos = 0;
|
||||
while(pos < (int)s.size()){
|
||||
int delim = pretty_find_delim(s,pos);
|
||||
if(s[pos] != ')' && s[pos] != ',' && cur_indent > indent){
|
||||
pretty_newline(f,indent);
|
||||
cur_indent = indent;
|
||||
col = indent;
|
||||
continue;
|
||||
}
|
||||
if (col + delim - pos > pretty_cols) {
|
||||
if (col > indent) {
|
||||
pretty_newline(f,indent);
|
||||
cur_indent = indent;
|
||||
col = indent;
|
||||
continue;
|
||||
}
|
||||
int paren = s.find('(',pos);
|
||||
if(paren != (int)std::string::npos){
|
||||
int chars = paren - pos + 1;
|
||||
f << s.substr(pos,chars);
|
||||
indent += pretty_indent_chars;
|
||||
if(col) pretty_newline(f,indent);
|
||||
cur_indent = indent;
|
||||
pos += chars;
|
||||
col = indent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int chars = delim - pos + 1;
|
||||
f << s.substr(pos,chars);
|
||||
pos += chars;
|
||||
col += chars;
|
||||
if(s[delim] == ')')
|
||||
indent -= pretty_indent_chars;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
iz3mgr::opr iz3mgr::op(const ast &t){
|
||||
ast_kind dk = t.raw()->get_kind();
|
||||
switch(dk){
|
||||
case AST_APP: {
|
||||
expr * e = to_expr(t.raw());
|
||||
func_decl *d = to_app(t.raw())->get_decl();
|
||||
if (null_family_id == d->get_family_id())
|
||||
return Uninterpreted;
|
||||
// return (opr)d->get_decl_kind();
|
||||
if (m_basic_fid == d->get_family_id()) {
|
||||
switch(d->get_decl_kind()) {
|
||||
case OP_TRUE: return True;
|
||||
case OP_FALSE: return False;
|
||||
case OP_EQ: return Equal;
|
||||
case OP_DISTINCT: return Distinct;
|
||||
case OP_ITE: return Ite;
|
||||
case OP_AND: return And;
|
||||
case OP_OR: return Or;
|
||||
case OP_IFF: return Iff;
|
||||
case OP_XOR: return Xor;
|
||||
case OP_NOT: return Not;
|
||||
case OP_IMPLIES: return Implies;
|
||||
case OP_OEQ: return Oeq;
|
||||
case OP_INTERP: return Interp;
|
||||
default:
|
||||
return Other;
|
||||
}
|
||||
}
|
||||
if (m_arith_fid == d->get_family_id()) {
|
||||
switch(d->get_decl_kind()) {
|
||||
case OP_LE: return Leq;
|
||||
case OP_GE: return Geq;
|
||||
case OP_LT: return Lt;
|
||||
case OP_GT: return Gt;
|
||||
case OP_ADD: return Plus;
|
||||
case OP_SUB: return Sub;
|
||||
case OP_UMINUS: return Uminus;
|
||||
case OP_MUL: return Times;
|
||||
case OP_DIV: return Div;
|
||||
case OP_IDIV: return Idiv;
|
||||
case OP_REM: return Rem;
|
||||
case OP_MOD: return Mod;
|
||||
case OP_POWER: return Power;
|
||||
case OP_TO_REAL: return ToReal;
|
||||
case OP_TO_INT: return ToInt;
|
||||
case OP_IS_INT: return IsInt;
|
||||
default:
|
||||
if (m().is_unique_value(e))
|
||||
return Numeral;
|
||||
return Other;
|
||||
}
|
||||
}
|
||||
if (m_array_fid == d->get_family_id()) {
|
||||
switch(d->get_decl_kind()) {
|
||||
case OP_STORE: return Store;
|
||||
case OP_SELECT: return Select;
|
||||
case OP_CONST_ARRAY: return ConstArray;
|
||||
case OP_ARRAY_DEFAULT: return ArrayDefault;
|
||||
case OP_ARRAY_MAP: return ArrayMap;
|
||||
case OP_SET_UNION: return SetUnion;
|
||||
case OP_SET_INTERSECT: return SetIntersect;
|
||||
case OP_SET_DIFFERENCE: return SetDifference;
|
||||
case OP_SET_COMPLEMENT: return SetComplement;
|
||||
case OP_SET_SUBSET: return SetSubSet;
|
||||
case OP_AS_ARRAY: return AsArray;
|
||||
default:
|
||||
return Other;
|
||||
}
|
||||
}
|
||||
|
||||
return Other;
|
||||
}
|
||||
|
||||
|
||||
case AST_QUANTIFIER:
|
||||
return to_quantifier(t.raw())->is_forall() ? Forall : Exists;
|
||||
case AST_VAR:
|
||||
return Variable;
|
||||
default:;
|
||||
}
|
||||
return Other;
|
||||
}
|
||||
|
||||
|
||||
iz3mgr::pfrule iz3mgr::pr(const ast &t){
|
||||
func_decl *d = to_app(t.raw())->get_decl();
|
||||
assert(m_basic_fid == d->get_family_id());
|
||||
return d->get_decl_kind();
|
||||
}
|
||||
|
||||
void iz3mgr::print_sat_problem(std::ostream &out, const ast &t){
|
||||
ast_smt_pp pp(m());
|
||||
pp.set_simplify_implies(false);
|
||||
pp.display_smt2(out, to_expr(t.raw()));
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::z3_simplify(const ast &e){
|
||||
::expr * a = to_expr(e.raw());
|
||||
params_ref p;
|
||||
th_rewriter m_rw(m(), p);
|
||||
expr_ref result(m());
|
||||
m_rw(a, result);
|
||||
return cook(result);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::z3_really_simplify(const ast &e){
|
||||
::expr * a = to_expr(e.raw());
|
||||
params_ref simp_params;
|
||||
simp_params.set_bool(":som",true);
|
||||
simp_params.set_bool(":sort-sums",true);
|
||||
th_rewriter m_rw(m(), simp_params);
|
||||
expr_ref result(m());
|
||||
m_rw(a, result);
|
||||
return cook(result);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static rational lcm(const rational &x, const rational &y){
|
||||
int a = x.numerator();
|
||||
int b = y.numerator();
|
||||
return rational(a * b / gcd(a, b));
|
||||
}
|
||||
#endif
|
||||
|
||||
static rational extract_lcd(std::vector<rational> &res){
|
||||
if(res.size() == 0) return rational(1); // shouldn't happen
|
||||
rational lcd = denominator(res[0]);
|
||||
for(unsigned i = 1; i < res.size(); i++)
|
||||
lcd = lcm(lcd,denominator(res[i]));
|
||||
for(unsigned i = 0; i < res.size(); i++)
|
||||
res[i] *= lcd;
|
||||
return lcd;
|
||||
}
|
||||
|
||||
void iz3mgr::get_farkas_coeffs(const ast &proof, std::vector<ast>& coeffs){
|
||||
std::vector<rational> rats;
|
||||
get_farkas_coeffs(proof,rats);
|
||||
coeffs.resize(rats.size());
|
||||
for(unsigned i = 0; i < rats.size(); i++){
|
||||
sort *is = m().mk_sort(m_arith_fid, INT_SORT);
|
||||
ast coeff = cook(m_arith_util.mk_numeral(rats[i],is));
|
||||
coeffs[i] = coeff;
|
||||
}
|
||||
}
|
||||
|
||||
static void abs_rat(std::vector<rational> &rats){
|
||||
// check that they are all non-neg -- if neg, take abs val and warn!
|
||||
for(unsigned i = 0; i < rats.size(); i++)
|
||||
if(rats[i].is_neg()){
|
||||
// std::cout << "negative Farkas coeff!\n";
|
||||
rats[i] = -rats[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool iz3mgr::is_farkas_coefficient_negative(const ast &proof, int n){
|
||||
rational r;
|
||||
symb s = sym(proof);
|
||||
bool ok = s->get_parameter(n+2).is_rational(r);
|
||||
if(!ok)
|
||||
throw "Bad Farkas coefficient";
|
||||
return r.is_neg();
|
||||
}
|
||||
|
||||
void iz3mgr::get_farkas_coeffs(const ast &proof, std::vector<rational>& rats){
|
||||
symb s = sym(proof);
|
||||
int numps = s->get_num_parameters();
|
||||
rats.resize(numps-2);
|
||||
#if 0
|
||||
if(num_prems(proof) < numps-2){
|
||||
std::cout << "bad farkas rule: " << num_prems(proof) << " premises should be " << numps-2 << "\n";
|
||||
}
|
||||
#endif
|
||||
for(int i = 2; i < numps; i++){
|
||||
rational r;
|
||||
bool ok = s->get_parameter(i).is_rational(r);
|
||||
if(!ok)
|
||||
throw "Bad Farkas coefficient";
|
||||
#if 0
|
||||
{
|
||||
ast con = conc(prem(proof,i-2));
|
||||
ast temp = make_real(r); // for debugging
|
||||
opr o = is_not(con) ? op(arg(con,0)) : op(con);
|
||||
if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt))
|
||||
r = -r;
|
||||
}
|
||||
#endif
|
||||
rats[i-2] = r;
|
||||
}
|
||||
#if 0
|
||||
if(rats.size() != 0 && rats[0].is_neg()){
|
||||
for(unsigned i = 0; i < rats.size(); i++){
|
||||
assert(rats[i].is_neg());
|
||||
rats[i] = -rats[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
abs_rat(rats);
|
||||
extract_lcd(rats);
|
||||
}
|
||||
|
||||
void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector<ast>& coeffs){
|
||||
std::vector<rational> rats;
|
||||
get_assign_bounds_coeffs(proof,rats);
|
||||
coeffs.resize(rats.size());
|
||||
for(unsigned i = 0; i < rats.size(); i++){
|
||||
coeffs[i] = make_int(rats[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector<rational>& rats){
|
||||
symb s = sym(proof);
|
||||
int numps = s->get_num_parameters();
|
||||
rats.resize(numps-1);
|
||||
rats[0] = rational(1);
|
||||
ast conseq = arg(conc(proof),0);
|
||||
opr conseq_o = is_not(conseq) ? op(arg(conseq,0)) : op(conseq);
|
||||
bool conseq_neg = is_not(conseq) ? (conseq_o == Leq || conseq_o == Lt) : (conseq_o == Geq || conseq_o == Gt);
|
||||
for(int i = 2; i < numps; i++){
|
||||
rational r;
|
||||
bool ok = s->get_parameter(i).is_rational(r);
|
||||
if(!ok)
|
||||
throw "Bad Farkas coefficient";
|
||||
{
|
||||
ast con = arg(conc(proof),i-1);
|
||||
ast temp = make_real(r); // for debugging
|
||||
opr o = is_not(con) ? op(arg(con,0)) : op(con);
|
||||
if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt))
|
||||
r = -r;
|
||||
if(conseq_neg)
|
||||
r = -r;
|
||||
}
|
||||
rats[i-1] = r;
|
||||
}
|
||||
#if 0
|
||||
if(rats[1].is_neg()){ // work around bug -- if all coeffs negative, negate them
|
||||
for(unsigned i = 1; i < rats.size(); i++){
|
||||
if(!rats[i].is_neg())
|
||||
throw "Bad Farkas coefficients";
|
||||
rats[i] = -rats[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
abs_rat(rats);
|
||||
extract_lcd(rats);
|
||||
}
|
||||
|
||||
void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector<ast>& coeffs){
|
||||
std::vector<rational> rats;
|
||||
get_assign_bounds_rule_coeffs(proof,rats);
|
||||
coeffs.resize(rats.size());
|
||||
for(unsigned i = 0; i < rats.size(); i++){
|
||||
coeffs[i] = make_int(rats[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector<rational>& rats){
|
||||
symb s = sym(proof);
|
||||
int numps = s->get_num_parameters();
|
||||
rats.resize(numps-1);
|
||||
rats[0] = rational(1);
|
||||
ast conseq = arg(conc(proof),0);
|
||||
opr conseq_o = is_not(conseq) ? op(arg(conseq,0)) : op(conseq);
|
||||
bool conseq_neg = is_not(conseq) ? (conseq_o == Leq || conseq_o == Lt) : (conseq_o == Geq || conseq_o == Gt);
|
||||
for(int i = 2; i < numps; i++){
|
||||
rational r;
|
||||
bool ok = s->get_parameter(i).is_rational(r);
|
||||
if(!ok)
|
||||
throw "Bad Farkas coefficient";
|
||||
{
|
||||
ast con = conc(prem(proof,i-2));
|
||||
ast temp = make_real(r); // for debugging
|
||||
opr o = is_not(con) ? op(arg(con,0)) : op(con);
|
||||
if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt))
|
||||
r = -r;
|
||||
if(conseq_neg)
|
||||
r = -r;
|
||||
}
|
||||
rats[i-1] = r;
|
||||
}
|
||||
#if 0
|
||||
if(rats[1].is_neg()){ // work around bug -- if all coeffs negative, negate them
|
||||
for(unsigned i = 1; i < rats.size(); i++){
|
||||
if(!rats[i].is_neg())
|
||||
throw "Bad Farkas coefficients";
|
||||
rats[i] = -rats[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
abs_rat(rats);
|
||||
extract_lcd(rats);
|
||||
}
|
||||
|
||||
/** Set P to P + cQ, where P and Q are linear inequalities. Assumes P is 0 <= y or 0 < y. */
|
||||
|
||||
void iz3mgr::linear_comb(ast &P, const ast &c, const ast &Q){
|
||||
ast Qrhs;
|
||||
bool strict = op(P) == Lt;
|
||||
if(is_not(Q)){
|
||||
ast nQ = arg(Q,0);
|
||||
switch(op(nQ)){
|
||||
case Gt:
|
||||
Qrhs = make(Sub,arg(nQ,1),arg(nQ,0));
|
||||
break;
|
||||
case Lt:
|
||||
Qrhs = make(Sub,arg(nQ,0),arg(nQ,1));
|
||||
break;
|
||||
case Geq:
|
||||
Qrhs = make(Sub,arg(nQ,1),arg(nQ,0));
|
||||
strict = true;
|
||||
break;
|
||||
case Leq:
|
||||
Qrhs = make(Sub,arg(nQ,0),arg(nQ,1));
|
||||
strict = true;
|
||||
break;
|
||||
default:
|
||||
throw "not an inequality";
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch(op(Q)){
|
||||
case Leq:
|
||||
Qrhs = make(Sub,arg(Q,1),arg(Q,0));
|
||||
break;
|
||||
case Geq:
|
||||
Qrhs = make(Sub,arg(Q,0),arg(Q,1));
|
||||
break;
|
||||
case Lt:
|
||||
Qrhs = make(Sub,arg(Q,1),arg(Q,0));
|
||||
strict = true;
|
||||
break;
|
||||
case Gt:
|
||||
Qrhs = make(Sub,arg(Q,0),arg(Q,1));
|
||||
strict = true;
|
||||
break;
|
||||
default:
|
||||
throw "not an inequality";
|
||||
}
|
||||
}
|
||||
Qrhs = make(Times,c,Qrhs);
|
||||
if(strict)
|
||||
P = make(Lt,arg(P,0),make(Plus,arg(P,1),Qrhs));
|
||||
else
|
||||
P = make(Leq,arg(P,0),make(Plus,arg(P,1),Qrhs));
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::sum_inequalities(const std::vector<ast> &coeffs, const std::vector<ast> &ineqs){
|
||||
ast zero = make_int("0");
|
||||
ast thing = make(Leq,zero,zero);
|
||||
for(unsigned i = 0; i < ineqs.size(); i++){
|
||||
linear_comb(thing,coeffs[i],ineqs[i]);
|
||||
}
|
||||
thing = simplify_ineq(thing);
|
||||
return thing;
|
||||
}
|
||||
|
||||
void iz3mgr::mk_idiv(const ast& t, const rational &d, ast &whole, ast &frac){
|
||||
opr o = op(t);
|
||||
if(o == Plus){
|
||||
int nargs = num_args(t);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
mk_idiv(arg(t,i),d,whole,frac);
|
||||
return;
|
||||
}
|
||||
else if(o == Times){
|
||||
rational coeff;
|
||||
if(is_numeral(arg(t,0),coeff)){
|
||||
if(gcd(coeff,d) == d){
|
||||
whole = make(Plus,whole,make(Times,make_int(coeff/d),arg(t,1)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
frac = make(Plus,frac,t);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::mk_idiv(const ast& q, const rational &d){
|
||||
ast t = z3_simplify(q);
|
||||
if(d == rational(1))
|
||||
return t;
|
||||
else {
|
||||
ast whole = make_int("0");
|
||||
ast frac = whole;
|
||||
mk_idiv(t,d,whole,frac);
|
||||
return z3_simplify(make(Plus,whole,make(Idiv,z3_simplify(frac),make_int(d))));
|
||||
}
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::mk_idiv(const ast& t, const ast &d){
|
||||
rational r;
|
||||
if(is_numeral(d,r))
|
||||
return mk_idiv(t,r);
|
||||
return make(Idiv,t,d);
|
||||
}
|
||||
|
||||
|
||||
// does variable occur in expression?
|
||||
int iz3mgr::occurs_in1(stl_ext::hash_map<ast,bool> &occurs_in_memo,ast var, ast e){
|
||||
std::pair<ast,bool> foo(e,false);
|
||||
std::pair<hash_map<ast,bool>::iterator,bool> bar = occurs_in_memo.insert(foo);
|
||||
bool &res = bar.first->second;
|
||||
if(bar.second){
|
||||
if(e == var) res = true;
|
||||
int nargs = num_args(e);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
res |= occurs_in1(occurs_in_memo,var,arg(e,i));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int iz3mgr::occurs_in(ast var, ast e){
|
||||
hash_map<ast,bool> memo;
|
||||
return occurs_in1(memo,var,e);
|
||||
}
|
||||
|
||||
|
||||
bool iz3mgr::solve_arith(const ast &v, const ast &x, const ast &y, ast &res){
|
||||
if(op(x) == Plus){
|
||||
int n = num_args(x);
|
||||
for(int i = 0; i < n; i++){
|
||||
if(arg(x,i) == v){
|
||||
res = z3_simplify(make(Sub, y, make(Sub, x, v)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// find a controlling equality for a given variable v in a term
|
||||
// a controlling equality is of the form v = t, which, being
|
||||
// false would force the formula to have the specifid truth value
|
||||
// returns t, or null if no such
|
||||
|
||||
iz3mgr::ast iz3mgr::cont_eq(stl_ext::hash_set<ast> &cont_eq_memo, bool truth, ast v, ast e){
|
||||
if(is_not(e)) return cont_eq(cont_eq_memo, !truth,v,arg(e,0));
|
||||
if(cont_eq_memo.find(e) != cont_eq_memo.end())
|
||||
return ast();
|
||||
cont_eq_memo.insert(e);
|
||||
if(!truth && op(e) == Equal){
|
||||
if(arg(e,0) == v) return(arg(e,1));
|
||||
if(arg(e,1) == v) return(arg(e,0));
|
||||
ast res;
|
||||
if(solve_arith(v,arg(e,0),arg(e,1),res)) return res;
|
||||
if(solve_arith(v,arg(e,1),arg(e,0),res)) return res;
|
||||
}
|
||||
if((!truth && op(e) == And) || (truth && op(e) == Or)){
|
||||
int nargs = num_args(e);
|
||||
for(int i = 0; i < nargs; i++){
|
||||
ast res = cont_eq(cont_eq_memo, truth, v, arg(e,i));
|
||||
if(!res.null()) return res;
|
||||
}
|
||||
}
|
||||
if(truth && op(e) == Implies){
|
||||
ast res = cont_eq(cont_eq_memo, !truth, v, arg(e,0));
|
||||
if(!res.null()) return res;
|
||||
res = cont_eq(cont_eq_memo, truth, v, arg(e,1));
|
||||
if(!res.null()) return res;
|
||||
}
|
||||
return ast();
|
||||
}
|
||||
|
||||
// substitute a term t for unbound occurrences of variable v in e
|
||||
|
||||
iz3mgr::ast iz3mgr::subst(stl_ext::hash_map<ast,ast> &subst_memo, ast var, ast t, ast e){
|
||||
if(e == var) return t;
|
||||
std::pair<ast,ast> foo(e,ast());
|
||||
std::pair<hash_map<ast,ast>::iterator,bool> bar = subst_memo.insert(foo);
|
||||
ast &res = bar.first->second;
|
||||
if(bar.second){
|
||||
int nargs = num_args(e);
|
||||
std::vector<ast> args(nargs);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
args[i] = subst(subst_memo,var,t,arg(e,i));
|
||||
opr f = op(e);
|
||||
if(f == Equal && args[0] == args[1]) res = mk_true();
|
||||
else res = clone(e,args);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::subst(ast var, ast t, ast e){
|
||||
hash_map<ast,ast> memo;
|
||||
return subst(memo,var,t,e);
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::subst(stl_ext::hash_map<ast,ast> &subst_memo,ast e){
|
||||
std::pair<ast,ast> foo(e,ast());
|
||||
std::pair<hash_map<ast,ast>::iterator,bool> bar = subst_memo.insert(foo);
|
||||
ast &res = bar.first->second;
|
||||
if(bar.second){
|
||||
int nargs = num_args(e);
|
||||
std::vector<ast> args(nargs);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
args[i] = subst(subst_memo,arg(e,i));
|
||||
opr f = op(e);
|
||||
if(f == Equal && args[0] == args[1]) res = mk_true();
|
||||
else res = clone(e,args);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// apply a quantifier to a formula, with some optimizations
|
||||
// 1) bound variable does not occur -> no quantifier
|
||||
// 2) bound variable must be equal to some term -> substitute
|
||||
|
||||
iz3mgr::ast iz3mgr::apply_quant(opr quantifier, ast var, ast e){
|
||||
if((quantifier == Forall && op(e) == And)
|
||||
|| (quantifier == Exists && op(e) == Or)){
|
||||
int n = num_args(e);
|
||||
std::vector<ast> args(n);
|
||||
for(int i = 0; i < n; i++)
|
||||
args[i] = apply_quant(quantifier,var,arg(e,i));
|
||||
return make(op(e),args);
|
||||
}
|
||||
if(!occurs_in(var,e))return e;
|
||||
hash_set<ast> cont_eq_memo;
|
||||
ast cterm = cont_eq(cont_eq_memo, quantifier == Forall, var, e);
|
||||
if(!cterm.null()){
|
||||
return subst(var,cterm,e);
|
||||
}
|
||||
std::vector<ast> bvs; bvs.push_back(var);
|
||||
return make_quant(quantifier,bvs,e);
|
||||
}
|
718
src/interp/iz3mgr.h
Normal file
718
src/interp/iz3mgr.h
Normal file
|
@ -0,0 +1,718 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3mgr.h
|
||||
|
||||
Abstract:
|
||||
|
||||
A wrapper around an ast manager, providing convenience methods.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef IZ3MGR_H
|
||||
#define IZ3MGR_H
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include "iz3hash.h"
|
||||
|
||||
#include"well_sorted.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"datatype_decl_plugin.h"
|
||||
#include"array_decl_plugin.h"
|
||||
#include"ast_translation.h"
|
||||
#include"ast_pp.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"ast_smt_pp.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"th_rewriter.h"
|
||||
#include"var_subst.h"
|
||||
#include"expr_substitution.h"
|
||||
#include"pp.h"
|
||||
#include"scoped_ctrl_c.h"
|
||||
#include"cancel_eh.h"
|
||||
#include"scoped_timer.h"
|
||||
//# include"pp_params.hpp"
|
||||
|
||||
/* A wrapper around an ast manager, providing convenience methods. */
|
||||
|
||||
/** Shorthands for some built-in operators. */
|
||||
|
||||
|
||||
|
||||
// rename this to keep it accessible, as we use ast for something else
|
||||
typedef ast raw_ast;
|
||||
|
||||
/** Wrapper around an ast pointer */
|
||||
class ast_i {
|
||||
protected:
|
||||
raw_ast *_ast;
|
||||
public:
|
||||
raw_ast * const &raw() const {return _ast;}
|
||||
ast_i(raw_ast *a){_ast = a;}
|
||||
|
||||
ast_i(){_ast = 0;}
|
||||
bool eq(const ast_i &other) const {
|
||||
return _ast == other._ast;
|
||||
}
|
||||
bool lt(const ast_i &other) const {
|
||||
return _ast->get_id() < other._ast->get_id();
|
||||
}
|
||||
friend bool operator==(const ast_i &x, const ast_i&y){
|
||||
return x.eq(y);
|
||||
}
|
||||
friend bool operator!=(const ast_i &x, const ast_i&y){
|
||||
return !x.eq(y);
|
||||
}
|
||||
friend bool operator<(const ast_i &x, const ast_i&y){
|
||||
return x.lt(y);
|
||||
}
|
||||
size_t hash() const {return _ast->get_id();}
|
||||
bool null() const {return !_ast;}
|
||||
};
|
||||
|
||||
/** Reference counting verison of above */
|
||||
class ast_r : public ast_i {
|
||||
ast_manager *_m;
|
||||
public:
|
||||
ast_r(ast_manager *m, raw_ast *a) : ast_i(a) {
|
||||
_m = m;
|
||||
m->inc_ref(a);
|
||||
}
|
||||
|
||||
ast_r() {_m = 0;}
|
||||
|
||||
ast_r(const ast_r &other) : ast_i(other) {
|
||||
_m = other._m;
|
||||
_m->inc_ref(_ast);
|
||||
}
|
||||
|
||||
ast_r &operator=(const ast_r &other) {
|
||||
if(_ast)
|
||||
_m->dec_ref(_ast);
|
||||
_ast = other._ast;
|
||||
_m = other._m;
|
||||
_m->inc_ref(_ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ast_r(){
|
||||
if(_ast)
|
||||
_m->dec_ref(_ast);
|
||||
}
|
||||
|
||||
ast_manager *mgr() const {return _m;}
|
||||
|
||||
};
|
||||
|
||||
// to make ast_r hashable
|
||||
namespace hash_space {
|
||||
template <>
|
||||
class hash<ast_r> {
|
||||
public:
|
||||
size_t operator()(const ast_r &s) const {
|
||||
return s.raw()->get_id();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// to make ast_r hashable in windows
|
||||
#ifdef WIN32
|
||||
template <> inline
|
||||
size_t stdext::hash_value<ast_r >(const ast_r& s)
|
||||
{
|
||||
return s.raw()->get_id();
|
||||
}
|
||||
#endif
|
||||
|
||||
// to make ast_r usable in ordered collections
|
||||
namespace std {
|
||||
template <>
|
||||
class less<ast_r> {
|
||||
public:
|
||||
bool operator()(const ast_r &s, const ast_r &t) const {
|
||||
// return s.raw() < t.raw();
|
||||
return s.raw()->get_id() < t.raw()->get_id();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/** Wrapper around an AST manager, providing convenience methods. */
|
||||
|
||||
class iz3mgr {
|
||||
|
||||
public:
|
||||
typedef ast_r ast;
|
||||
// typedef decl_kind opr;
|
||||
typedef func_decl *symb;
|
||||
typedef sort *type;
|
||||
typedef ast_r z3pf;
|
||||
typedef decl_kind pfrule;
|
||||
|
||||
enum opr {
|
||||
True,
|
||||
False,
|
||||
And,
|
||||
Or,
|
||||
Not,
|
||||
Iff,
|
||||
Ite,
|
||||
Equal,
|
||||
Implies,
|
||||
Distinct,
|
||||
Xor,
|
||||
Oeq,
|
||||
Interp,
|
||||
Leq,
|
||||
Geq,
|
||||
Lt,
|
||||
Gt,
|
||||
Plus,
|
||||
Sub,
|
||||
Uminus,
|
||||
Times,
|
||||
Div,
|
||||
Idiv,
|
||||
Rem,
|
||||
Mod,
|
||||
Power,
|
||||
ToReal,
|
||||
ToInt,
|
||||
IsInt,
|
||||
Select,
|
||||
Store,
|
||||
ConstArray,
|
||||
ArrayDefault,
|
||||
ArrayMap,
|
||||
SetUnion,
|
||||
SetIntersect,
|
||||
SetDifference,
|
||||
SetComplement,
|
||||
SetSubSet,
|
||||
AsArray,
|
||||
Numeral,
|
||||
Forall,
|
||||
Exists,
|
||||
Variable,
|
||||
Uninterpreted,
|
||||
Other
|
||||
};
|
||||
|
||||
opr op(const ast &t);
|
||||
|
||||
unsigned ast_id(const ast &x)
|
||||
{
|
||||
return to_expr(x.raw())->get_id();
|
||||
}
|
||||
|
||||
/** Overloads for constructing ast. */
|
||||
|
||||
ast make_var(const std::string &name, type ty);
|
||||
ast make(opr op, const std::vector<ast> &args);
|
||||
ast make(opr op);
|
||||
ast make(opr op, const ast &arg0);
|
||||
ast make(opr op, const ast &arg0, const ast &arg1);
|
||||
ast make(opr op, const ast &arg0, const ast &arg1, const ast &arg2);
|
||||
ast make(symb sym, const std::vector<ast> &args);
|
||||
ast make(symb sym);
|
||||
ast make(symb sym, const ast &arg0);
|
||||
ast make(symb sym, const ast &arg0, const ast &arg1);
|
||||
ast make(symb sym, const ast &arg0, const ast &arg1, const ast &arg2);
|
||||
ast make_quant(opr op, const std::vector<ast> &bvs, ast &body);
|
||||
ast clone(const ast &t, const std::vector<ast> &args);
|
||||
|
||||
ast_manager &m() {return m_manager;}
|
||||
|
||||
ast cook(raw_ast *a) {return ast(&m_manager,a);}
|
||||
|
||||
std::vector<ast> cook(ptr_vector<raw_ast> v) {
|
||||
std::vector<ast> _v(v.size());
|
||||
for(unsigned i = 0; i < v.size(); i++)
|
||||
_v[i] = cook(v[i]);
|
||||
return _v;
|
||||
}
|
||||
|
||||
raw_ast *uncook(const ast &a) {
|
||||
m_manager.inc_ref(a.raw());
|
||||
return a.raw();
|
||||
}
|
||||
|
||||
/** Methods for destructing ast. */
|
||||
|
||||
|
||||
int num_args(ast t){
|
||||
ast_kind dk = t.raw()->get_kind();
|
||||
switch(dk){
|
||||
case AST_APP:
|
||||
return to_app(t.raw())->get_num_args();
|
||||
case AST_QUANTIFIER:
|
||||
return 1;
|
||||
case AST_VAR:
|
||||
return 0;
|
||||
default:;
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
ast arg(const ast &t, int i){
|
||||
ast_kind dk = t.raw()->get_kind();
|
||||
switch(dk){
|
||||
case AST_APP:
|
||||
return cook(to_app(t.raw())->get_arg(i));
|
||||
case AST_QUANTIFIER:
|
||||
return cook(to_quantifier(t.raw())->get_expr());
|
||||
default:;
|
||||
}
|
||||
assert(0);
|
||||
return ast();
|
||||
}
|
||||
|
||||
void get_args(const ast &t, std::vector<ast> &res){
|
||||
res.resize(num_args(t));
|
||||
for(unsigned i = 0; i < res.size(); i++)
|
||||
res[i] = arg(t,i);
|
||||
}
|
||||
|
||||
symb sym(ast t){
|
||||
return to_app(t.raw())->get_decl();
|
||||
}
|
||||
|
||||
std::string string_of_symbol(symb s){
|
||||
symbol _s = s->get_name();
|
||||
if (_s.is_numerical()) {
|
||||
std::ostringstream buffer;
|
||||
buffer << _s.get_num();
|
||||
return buffer.str();
|
||||
}
|
||||
else {
|
||||
return _s.bare_str();
|
||||
}
|
||||
}
|
||||
|
||||
type get_type(ast t){
|
||||
return m().get_sort(to_expr(t.raw()));
|
||||
}
|
||||
|
||||
std::string string_of_numeral(const ast& t){
|
||||
rational r;
|
||||
expr* e = to_expr(t.raw());
|
||||
assert(e);
|
||||
if (m_arith_util.is_numeral(e, r))
|
||||
return r.to_string();
|
||||
assert(0);
|
||||
return "NaN";
|
||||
}
|
||||
|
||||
bool is_numeral(const ast& t, rational &r){
|
||||
expr* e = to_expr(t.raw());
|
||||
assert(e);
|
||||
return m_arith_util.is_numeral(e, r);
|
||||
}
|
||||
|
||||
rational get_coeff(const ast& t){
|
||||
rational res;
|
||||
if(op(t) == Times && is_numeral(arg(t,0),res))
|
||||
return res;
|
||||
return rational(1);
|
||||
}
|
||||
|
||||
ast get_linear_var(const ast& t){
|
||||
rational res;
|
||||
if(op(t) == Times && is_numeral(arg(t,0),res))
|
||||
return arg(t,1);
|
||||
return t;
|
||||
}
|
||||
|
||||
int get_quantifier_num_bound(const ast &t) {
|
||||
return to_quantifier(t.raw())->get_num_decls();
|
||||
}
|
||||
|
||||
std::string get_quantifier_bound_name(const ast &t, unsigned i) {
|
||||
return to_quantifier(t.raw())->get_decl_names()[i].bare_str();
|
||||
}
|
||||
|
||||
type get_quantifier_bound_type(const ast &t, unsigned i) {
|
||||
return to_quantifier(t.raw())->get_decl_sort(i);
|
||||
}
|
||||
|
||||
ast get_quantifier_body(const ast &t) {
|
||||
return cook(to_quantifier(t.raw())->get_expr());
|
||||
}
|
||||
|
||||
unsigned get_variable_index_value(const ast &t) {
|
||||
var* va = to_var(t.raw());
|
||||
return va->get_idx();
|
||||
}
|
||||
|
||||
bool is_bool_type(type t){
|
||||
family_id fid = to_sort(t)->get_family_id();
|
||||
decl_kind k = to_sort(t)->get_decl_kind();
|
||||
return fid == m().get_basic_family_id() && k == BOOL_SORT;
|
||||
}
|
||||
|
||||
bool is_array_type(type t){
|
||||
family_id fid = to_sort(t)->get_family_id();
|
||||
decl_kind k = to_sort(t)->get_decl_kind();
|
||||
return fid == m_array_fid && k == ARRAY_SORT;
|
||||
}
|
||||
|
||||
type get_range_type(symb s){
|
||||
return to_func_decl(s)->get_range();
|
||||
}
|
||||
|
||||
int get_num_parameters(const symb &s){
|
||||
return to_func_decl(s)->get_num_parameters();
|
||||
}
|
||||
|
||||
ast get_ast_parameter(const symb &s, int idx){
|
||||
return cook(to_func_decl(s)->get_parameters()[idx].get_ast());
|
||||
}
|
||||
|
||||
enum lemma_theory {ArithTheory,ArrayTheory,UnknownTheory};
|
||||
|
||||
lemma_theory get_theory_lemma_theory(const ast &proof){
|
||||
symb s = sym(proof);
|
||||
::symbol p0;
|
||||
bool ok = s->get_parameter(0).is_symbol(p0);
|
||||
if(!ok) return UnknownTheory;
|
||||
std::string foo(p0.bare_str());
|
||||
if(foo == "arith")
|
||||
return ArithTheory;
|
||||
if(foo == "array")
|
||||
return ArrayTheory;
|
||||
return UnknownTheory;
|
||||
}
|
||||
|
||||
enum lemma_kind {FarkasKind,Leq2EqKind,Eq2LeqKind,GCDTestKind,AssignBoundsKind,EqPropagateKind,UnknownKind};
|
||||
|
||||
lemma_kind get_theory_lemma_kind(const ast &proof){
|
||||
symb s = sym(proof);
|
||||
::symbol p0;
|
||||
bool ok = s->get_parameter(1).is_symbol(p0);
|
||||
if(!ok) return UnknownKind;
|
||||
std::string foo(p0.bare_str());
|
||||
if(foo == "farkas")
|
||||
return FarkasKind;
|
||||
if(foo == "triangle-eq")
|
||||
return is_not(arg(conc(proof),0)) ? Eq2LeqKind : Leq2EqKind;
|
||||
if(foo == "gcd-test")
|
||||
return GCDTestKind;
|
||||
if(foo == "assign-bounds")
|
||||
return AssignBoundsKind;
|
||||
if(foo == "eq-propagate")
|
||||
return EqPropagateKind;
|
||||
return UnknownKind;
|
||||
}
|
||||
|
||||
void get_farkas_coeffs(const ast &proof, std::vector<ast>& coeffs);
|
||||
|
||||
void get_farkas_coeffs(const ast &proof, std::vector<rational>& rats);
|
||||
|
||||
void get_assign_bounds_coeffs(const ast &proof, std::vector<rational>& rats);
|
||||
|
||||
void get_assign_bounds_coeffs(const ast &proof, std::vector<ast>& rats);
|
||||
|
||||
void get_assign_bounds_rule_coeffs(const ast &proof, std::vector<rational>& rats);
|
||||
|
||||
void get_assign_bounds_rule_coeffs(const ast &proof, std::vector<ast>& rats);
|
||||
|
||||
bool is_farkas_coefficient_negative(const ast &proof, int n);
|
||||
|
||||
bool is_true(ast t){
|
||||
return op(t) == True;
|
||||
}
|
||||
|
||||
bool is_false(ast t){
|
||||
return op(t) == False;
|
||||
}
|
||||
|
||||
bool is_iff(ast t){
|
||||
return op(t) == Iff;
|
||||
}
|
||||
|
||||
bool is_or(ast t){
|
||||
return op(t) == Or;
|
||||
}
|
||||
|
||||
bool is_not(ast t){
|
||||
return op(t) == Not;
|
||||
}
|
||||
|
||||
/** Simplify an expression using z3 simplifier */
|
||||
|
||||
ast z3_simplify(const ast& e);
|
||||
|
||||
/** Simplify, sorting sums */
|
||||
ast z3_really_simplify(const ast &e);
|
||||
|
||||
|
||||
// Some constructors that simplify things
|
||||
|
||||
ast mk_not(ast x){
|
||||
opr o = op(x);
|
||||
if(o == True) return make(False);
|
||||
if(o == False) return make(True);
|
||||
if(o == Not) return arg(x,0);
|
||||
return make(Not,x);
|
||||
}
|
||||
|
||||
ast mk_and(ast x, ast y){
|
||||
opr ox = op(x);
|
||||
opr oy = op(y);
|
||||
if(ox == True) return y;
|
||||
if(oy == True) return x;
|
||||
if(ox == False) return x;
|
||||
if(oy == False) return y;
|
||||
if(x == y) return x;
|
||||
return make(And,x,y);
|
||||
}
|
||||
|
||||
ast mk_or(ast x, ast y){
|
||||
opr ox = op(x);
|
||||
opr oy = op(y);
|
||||
if(ox == False) return y;
|
||||
if(oy == False) return x;
|
||||
if(ox == True) return x;
|
||||
if(oy == True) return y;
|
||||
if(x == y) return x;
|
||||
return make(Or,x,y);
|
||||
}
|
||||
|
||||
ast mk_implies(ast x, ast y){
|
||||
opr ox = op(x);
|
||||
opr oy = op(y);
|
||||
if(ox == True) return y;
|
||||
if(oy == False) return mk_not(x);
|
||||
if(ox == False) return mk_true();
|
||||
if(oy == True) return y;
|
||||
if(x == y) return mk_true();
|
||||
return make(Implies,x,y);
|
||||
}
|
||||
|
||||
ast mk_or(const std::vector<ast> &x){
|
||||
ast res = mk_false();
|
||||
for(unsigned i = 0; i < x.size(); i++)
|
||||
res = mk_or(res,x[i]);
|
||||
return res;
|
||||
}
|
||||
|
||||
ast mk_and(const std::vector<ast> &x){
|
||||
std::vector<ast> conjs;
|
||||
for(unsigned i = 0; i < x.size(); i++){
|
||||
const ast &e = x[i];
|
||||
opr o = op(e);
|
||||
if(o == False)
|
||||
return mk_false();
|
||||
if(o != True)
|
||||
conjs.push_back(e);
|
||||
}
|
||||
if(conjs.size() == 0)
|
||||
return mk_true();
|
||||
if(conjs.size() == 1)
|
||||
return conjs[0];
|
||||
return make(And,conjs);
|
||||
}
|
||||
|
||||
ast mk_equal(ast x, ast y){
|
||||
if(x == y) return make(True);
|
||||
opr ox = op(x);
|
||||
opr oy = op(y);
|
||||
if(ox == True) return y;
|
||||
if(oy == True) return x;
|
||||
if(ox == False) return mk_not(y);
|
||||
if(oy == False) return mk_not(x);
|
||||
if(ox == False && oy == True) return make(False);
|
||||
if(oy == False && ox == True) return make(False);
|
||||
return make(Equal,x,y);
|
||||
}
|
||||
|
||||
ast z3_ite(ast x, ast y, ast z){
|
||||
opr ox = op(x);
|
||||
opr oy = op(y);
|
||||
opr oz = op(z);
|
||||
if(ox == True) return y;
|
||||
if(ox == False) return z;
|
||||
if(y == z) return y;
|
||||
if(oy == True && oz == False) return x;
|
||||
if(oz == True && oy == False) return mk_not(x);
|
||||
return make(Ite,x,y,z);
|
||||
}
|
||||
|
||||
ast make_int(const std::string &s) {
|
||||
sort *r = m().mk_sort(m_arith_fid, INT_SORT);
|
||||
return cook(m_arith_util.mk_numeral(rational(s.c_str()),r));
|
||||
}
|
||||
|
||||
ast make_int(const rational &s) {
|
||||
sort *r = m().mk_sort(m_arith_fid, INT_SORT);
|
||||
return cook(m_arith_util.mk_numeral(s,r));
|
||||
}
|
||||
|
||||
ast make_real(const std::string &s) {
|
||||
sort *r = m().mk_sort(m_arith_fid, REAL_SORT);
|
||||
return cook(m_arith_util.mk_numeral(rational(s.c_str()),r));
|
||||
}
|
||||
|
||||
ast make_real(const rational &s) {
|
||||
sort *r = m().mk_sort(m_arith_fid, REAL_SORT);
|
||||
return cook(m_arith_util.mk_numeral(s,r));
|
||||
}
|
||||
|
||||
ast mk_false() { return make(False); }
|
||||
|
||||
ast mk_true() { return make(True); }
|
||||
|
||||
ast mk_fresh_constant(char const * prefix, type s){
|
||||
return cook(m().mk_fresh_const(prefix, s));
|
||||
}
|
||||
|
||||
type bool_type() {
|
||||
::sort *s = m().mk_sort(m_basic_fid, BOOL_SORT);
|
||||
return s;
|
||||
}
|
||||
|
||||
type int_type() {
|
||||
::sort *s = m().mk_sort(m_arith_fid, INT_SORT);
|
||||
return s;
|
||||
}
|
||||
|
||||
type real_type() {
|
||||
::sort *s = m().mk_sort(m_arith_fid, REAL_SORT);
|
||||
return s;
|
||||
}
|
||||
|
||||
type array_type(type d, type r) {
|
||||
parameter params[2] = { parameter(d), parameter(to_sort(r)) };
|
||||
::sort * s = m().mk_sort(m_array_fid, ARRAY_SORT, 2, params);
|
||||
return s;
|
||||
}
|
||||
|
||||
symb function(const std::string &str_name, unsigned arity, type *domain, type range) {
|
||||
::symbol name = ::symbol(str_name.c_str());
|
||||
std::vector< ::sort *> sv(arity);
|
||||
for(unsigned i = 0; i < arity; i++)
|
||||
sv[i] = domain[i];
|
||||
::func_decl* d = m().mk_func_decl(name,arity,&sv[0],range);
|
||||
return d;
|
||||
}
|
||||
|
||||
void linear_comb(ast &P, const ast &c, const ast &Q);
|
||||
|
||||
ast sum_inequalities(const std::vector<ast> &coeffs, const std::vector<ast> &ineqs);
|
||||
|
||||
ast simplify_ineq(const ast &ineq){
|
||||
ast res = make(op(ineq),arg(ineq,0),z3_simplify(arg(ineq,1)));
|
||||
return res;
|
||||
}
|
||||
|
||||
void mk_idiv(const ast& t, const rational &d, ast &whole, ast &frac);
|
||||
|
||||
ast mk_idiv(const ast& t, const rational &d);
|
||||
|
||||
ast mk_idiv(const ast& t, const ast &d);
|
||||
|
||||
/** methods for destructing proof terms */
|
||||
|
||||
pfrule pr(const z3pf &t);
|
||||
|
||||
int num_prems(const z3pf &t){return to_app(t.raw())->get_num_args()-1;}
|
||||
|
||||
z3pf prem(const z3pf &t, int n){return arg(t,n);}
|
||||
|
||||
z3pf conc(const z3pf &t){return arg(t,num_prems(t));}
|
||||
|
||||
|
||||
/* quantifier handling */
|
||||
|
||||
// substitute a term t for unbound occurrences of variable v in e
|
||||
|
||||
ast subst(ast var, ast t, ast e);
|
||||
|
||||
// apply a substitution defined by a map
|
||||
ast subst(stl_ext::hash_map<ast,ast> &map, ast e);
|
||||
|
||||
// apply a quantifier to a formula, with some optimizations
|
||||
// 1) bound variable does not occur -> no quantifier
|
||||
// 2) bound variable must be equal to some term -> substitute
|
||||
|
||||
ast apply_quant(opr quantifier, ast var, ast e);
|
||||
|
||||
|
||||
/** For debugging */
|
||||
void show(ast);
|
||||
|
||||
void show_symb(symb s);
|
||||
|
||||
/** Constructor */
|
||||
|
||||
void print_lit(ast lit);
|
||||
|
||||
void print_expr(std::ostream &s, const ast &e);
|
||||
|
||||
void print_clause(std::ostream &s, std::vector<ast> &cls);
|
||||
|
||||
void print_sat_problem(std::ostream &out, const ast &t);
|
||||
|
||||
void show_clause(std::vector<ast> &cls);
|
||||
|
||||
static void pretty_print(std::ostream &f, const std::string &s);
|
||||
|
||||
iz3mgr(ast_manager &_m_manager)
|
||||
: m_manager(_m_manager),
|
||||
m_arith_util(_m_manager)
|
||||
{
|
||||
m_basic_fid = m().get_basic_family_id();
|
||||
m_arith_fid = m().mk_family_id("arith");
|
||||
m_bv_fid = m().mk_family_id("bv");
|
||||
m_array_fid = m().mk_family_id("array");
|
||||
m_dt_fid = m().mk_family_id("datatype");
|
||||
m_datalog_fid = m().mk_family_id("datalog_relation");
|
||||
}
|
||||
|
||||
iz3mgr(const iz3mgr& other)
|
||||
: m_manager(other.m_manager),
|
||||
m_arith_util(other.m_manager)
|
||||
{
|
||||
m_basic_fid = m().get_basic_family_id();
|
||||
m_arith_fid = m().mk_family_id("arith");
|
||||
m_bv_fid = m().mk_family_id("bv");
|
||||
m_array_fid = m().mk_family_id("array");
|
||||
m_dt_fid = m().mk_family_id("datatype");
|
||||
m_datalog_fid = m().mk_family_id("datalog_relation");
|
||||
}
|
||||
|
||||
protected:
|
||||
ast_manager &m_manager;
|
||||
int occurs_in(ast var, ast e);
|
||||
|
||||
private:
|
||||
ast mki(family_id fid, decl_kind sk, int n, raw_ast **args);
|
||||
ast make(opr op, int n, raw_ast **args);
|
||||
ast make(symb sym, int n, raw_ast **args);
|
||||
int occurs_in1(stl_ext::hash_map<ast,bool> &occurs_in_memo, ast var, ast e);
|
||||
bool solve_arith(const ast &v, const ast &x, const ast &y, ast &res);
|
||||
ast cont_eq(stl_ext::hash_set<ast> &cont_eq_memo, bool truth, ast v, ast e);
|
||||
ast subst(stl_ext::hash_map<ast,ast> &subst_memo, ast var, ast t, ast e);
|
||||
|
||||
|
||||
family_id m_basic_fid;
|
||||
family_id m_array_fid;
|
||||
family_id m_arith_fid;
|
||||
family_id m_bv_fid;
|
||||
family_id m_dt_fid;
|
||||
family_id m_datalog_fid;
|
||||
arith_util m_arith_util;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
5
src/interp/iz3params.pyg
Normal file
5
src/interp/iz3params.pyg
Normal file
|
@ -0,0 +1,5 @@
|
|||
def_module_params('interp',
|
||||
description='interpolation parameters',
|
||||
export=True,
|
||||
params=(('profile', BOOL, False, '(INTERP) profile interpolation'),
|
||||
))
|
189
src/interp/iz3pp.cpp
Normal file
189
src/interp/iz3pp.cpp
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3pp.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Pretty-print interpolation problems
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
/* Copyright 2011 Microsoft Research. */
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
|
||||
#include "iz3mgr.h"
|
||||
#include "iz3pp.h"
|
||||
#include "func_decl_dependencies.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"ast_smt_pp.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"expr_functors.h"
|
||||
#include"expr_abstract.h"
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
// We promise not to use this for hash_map with range destructor
|
||||
namespace stl_ext {
|
||||
template <>
|
||||
class hash<expr *> {
|
||||
public:
|
||||
size_t operator()(const expr *p) const {
|
||||
return (size_t) p;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// TBD: algebraic data-types declarations will not be printed.
|
||||
class free_func_visitor {
|
||||
ast_manager& m;
|
||||
func_decl_set m_funcs;
|
||||
obj_hashtable<sort> m_sorts;
|
||||
public:
|
||||
free_func_visitor(ast_manager& m): m(m) {}
|
||||
void operator()(var * n) { }
|
||||
void operator()(app * n) {
|
||||
m_funcs.insert(n->get_decl());
|
||||
sort* s = m.get_sort(n);
|
||||
if (s->get_family_id() == null_family_id) {
|
||||
m_sorts.insert(s);
|
||||
}
|
||||
}
|
||||
void operator()(quantifier * n) { }
|
||||
func_decl_set& funcs() { return m_funcs; }
|
||||
obj_hashtable<sort>& sorts() { return m_sorts; }
|
||||
};
|
||||
|
||||
class iz3pp_helper : public iz3mgr {
|
||||
public:
|
||||
|
||||
void print_tree(const ast &tree, hash_map<expr*,symbol> &cnames, std::ostream &out){
|
||||
hash_map<expr*,symbol>::iterator foo = cnames.find(to_expr(tree.raw()));
|
||||
if(foo != cnames.end()){
|
||||
symbol nm = foo->second;
|
||||
if (is_smt2_quoted_symbol(nm)) {
|
||||
out << mk_smt2_quoted_symbol(nm);
|
||||
}
|
||||
else {
|
||||
out << nm;
|
||||
}
|
||||
}
|
||||
else if(op(tree) == And){
|
||||
out << "(and";
|
||||
int nargs = num_args(tree);
|
||||
for(int i = 0; i < nargs; i++){
|
||||
out << " ";
|
||||
print_tree(arg(tree,i), cnames, out);
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
else if(op(tree) == Interp){
|
||||
out << "(interp ";
|
||||
print_tree(arg(tree,0), cnames, out);
|
||||
out << ")";
|
||||
}
|
||||
else throw iz3pp_bad_tree();
|
||||
}
|
||||
|
||||
|
||||
iz3pp_helper(ast_manager &_m_manager)
|
||||
: iz3mgr(_m_manager) {}
|
||||
};
|
||||
|
||||
void iz3pp(ast_manager &m,
|
||||
const ptr_vector<expr> &cnsts_vec,
|
||||
expr *tree,
|
||||
std::ostream& out) {
|
||||
|
||||
unsigned sz = cnsts_vec.size();
|
||||
expr* const* cnsts = &cnsts_vec[0];
|
||||
|
||||
out << "(set-option :produce-interpolants true)\n";
|
||||
|
||||
free_func_visitor visitor(m);
|
||||
expr_mark visited;
|
||||
bool print_low_level = true; // m_params.print_low_level_smt2();
|
||||
|
||||
#define PP(_e_) if (print_low_level) out << mk_smt_pp(_e_, m); else ast_smt2_pp(out, _e_, env);
|
||||
|
||||
smt2_pp_environment_dbg env(m);
|
||||
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
expr* e = cnsts[i];
|
||||
for_each_expr(visitor, visited, e);
|
||||
}
|
||||
|
||||
// name all the constraints
|
||||
hash_map<expr *, symbol> cnames;
|
||||
int ctr = 1;
|
||||
for(unsigned i = 0; i < sz; i++){
|
||||
symbol nm;
|
||||
std::ostringstream s;
|
||||
s << "f!" << (ctr++);
|
||||
cnames[cnsts[i]] = symbol(s.str().c_str());
|
||||
}
|
||||
|
||||
func_decl_set &funcs = visitor.funcs();
|
||||
func_decl_set::iterator it = funcs.begin(), end = funcs.end();
|
||||
|
||||
obj_hashtable<sort>& sorts = visitor.sorts();
|
||||
obj_hashtable<sort>::iterator sit = sorts.begin(), send = sorts.end();
|
||||
|
||||
|
||||
|
||||
for (; sit != send; ++sit) {
|
||||
PP(*sit);
|
||||
}
|
||||
|
||||
for (; it != end; ++it) {
|
||||
func_decl* f = *it;
|
||||
if(f->get_family_id() == null_family_id){
|
||||
PP(f);
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
out << "(assert ";
|
||||
expr* r = cnsts[i];
|
||||
symbol nm = cnames[r];
|
||||
out << "(! ";
|
||||
PP(r);
|
||||
out << " :named ";
|
||||
if (is_smt2_quoted_symbol(nm)) {
|
||||
out << mk_smt2_quoted_symbol(nm);
|
||||
}
|
||||
else {
|
||||
out << nm;
|
||||
}
|
||||
out << ")";
|
||||
out << ")\n";
|
||||
}
|
||||
out << "(check-sat)\n";
|
||||
out << "(get-interpolant ";
|
||||
iz3pp_helper pp(m);
|
||||
pp.print_tree(pp.cook(tree),cnames,out);
|
||||
out << ")\n";
|
||||
}
|
||||
|
||||
|
35
src/interp/iz3pp.h
Normal file
35
src/interp/iz3pp.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3pp.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Pretty-print interpolation problems
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef IZ3_PP_H
|
||||
#define IZ3_PP_H
|
||||
|
||||
#include "iz3mgr.h"
|
||||
|
||||
/** Exception thrown in case of mal-formed tree interpoloation
|
||||
specification */
|
||||
|
||||
struct iz3pp_bad_tree {
|
||||
};
|
||||
|
||||
void iz3pp(ast_manager &m,
|
||||
const ptr_vector<expr> &cnsts_vec,
|
||||
expr *tree,
|
||||
std::ostream& out);
|
||||
#endif
|
146
src/interp/iz3profiling.cpp
Executable file
146
src/interp/iz3profiling.cpp
Executable file
|
@ -0,0 +1,146 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3profiling.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Some routines for measuring performance.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "iz3profiling.h"
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "stopwatch.h"
|
||||
|
||||
|
||||
// FIXME fill in these stubs
|
||||
|
||||
#define clock_t double
|
||||
|
||||
static double current_time()
|
||||
{
|
||||
static stopwatch sw;
|
||||
static bool started = false;
|
||||
if(!started){
|
||||
sw.start();
|
||||
started = true;
|
||||
}
|
||||
return sw.get_current_seconds();
|
||||
}
|
||||
|
||||
static void output_time(std::ostream &os, clock_t time){
|
||||
os << time;
|
||||
}
|
||||
|
||||
|
||||
namespace profiling {
|
||||
|
||||
void show_time(){
|
||||
output_time(std::cout,current_time());
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
typedef std::map<const char*, struct node> nmap;
|
||||
|
||||
struct node {
|
||||
std::string name;
|
||||
clock_t time;
|
||||
clock_t start_time;
|
||||
nmap sub;
|
||||
struct node *parent;
|
||||
|
||||
node();
|
||||
} top;
|
||||
|
||||
node::node(){
|
||||
time = 0;
|
||||
parent = 0;
|
||||
}
|
||||
|
||||
struct node *current;
|
||||
|
||||
struct init {
|
||||
init(){
|
||||
top.name = "TOTAL";
|
||||
current = ⊤
|
||||
}
|
||||
} initializer;
|
||||
|
||||
struct time_entry {
|
||||
clock_t t;
|
||||
time_entry(){t = 0;};
|
||||
void add(clock_t incr){t += incr;}
|
||||
};
|
||||
|
||||
struct ltstr
|
||||
{
|
||||
bool operator()(const char* s1, const char* s2) const
|
||||
{
|
||||
return strcmp(s1, s2) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<const char*, time_entry, ltstr> tmap;
|
||||
|
||||
static std::ostream *pfs;
|
||||
|
||||
void print_node(node &top, int indent, tmap &totals){
|
||||
for(int i = 0; i < indent; i++) (*pfs) << " ";
|
||||
(*pfs) << top.name;
|
||||
int dots = 70 - 2 * indent - top.name.size();
|
||||
for(int i = 0; i <dots; i++) (*pfs) << ".";
|
||||
output_time(*pfs, top.time);
|
||||
(*pfs) << std::endl;
|
||||
if(indent != 0)totals[top.name.c_str()].add(top.time);
|
||||
for(nmap::iterator it = top.sub.begin(); it != top.sub.end(); it++)
|
||||
print_node(it->second,indent+1,totals);
|
||||
}
|
||||
|
||||
void print(std::ostream &os) {
|
||||
pfs = &os;
|
||||
top.time = 0;
|
||||
for(nmap::iterator it = top.sub.begin(); it != top.sub.end(); it++)
|
||||
top.time += it->second.time;
|
||||
tmap totals;
|
||||
print_node(top,0,totals);
|
||||
(*pfs) << "TOTALS:" << std::endl;
|
||||
for(tmap::iterator it = totals.begin(); it != totals.end(); it++){
|
||||
(*pfs) << (it->first) << " ";
|
||||
output_time(*pfs, it->second.t);
|
||||
(*pfs) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_start(const char *name){
|
||||
node &child = current->sub[name];
|
||||
if(child.name.empty()){ // a new node
|
||||
child.parent = current;
|
||||
child.name = name;
|
||||
}
|
||||
child.start_time = current_time();
|
||||
current = &child;
|
||||
}
|
||||
|
||||
void timer_stop(const char *name){
|
||||
if(current->name != name || !current->parent){
|
||||
std::cerr << "imbalanced timer_start and timer_stop";
|
||||
exit(1);
|
||||
}
|
||||
current->time += (current_time() - current->start_time);
|
||||
current = current->parent;
|
||||
}
|
||||
}
|
37
src/interp/iz3profiling.h
Executable file
37
src/interp/iz3profiling.h
Executable file
|
@ -0,0 +1,37 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3profiling.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Some routines for measuring performance.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef IZ3PROFILING_H
|
||||
#define IZ3PROFILING_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace profiling {
|
||||
/** Start a timer with given name */
|
||||
void timer_start(const char *);
|
||||
/** Stop a timer with given name */
|
||||
void timer_stop(const char *);
|
||||
/** Print out timings */
|
||||
void print(std::ostream &s);
|
||||
/** Show the current time. */
|
||||
void show_time();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
622
src/interp/iz3proof.cpp
Executable file
622
src/interp/iz3proof.cpp
Executable file
|
@ -0,0 +1,622 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3proof.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This class defines a simple interpolating proof system.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
|
||||
#include "iz3proof.h"
|
||||
#include "iz3profiling.h"
|
||||
|
||||
#include<algorithm>
|
||||
#include <iterator>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
// #define FACTOR_INTERPS
|
||||
// #define CHECK_PROOFS
|
||||
|
||||
|
||||
void iz3proof::resolve(ast pivot, std::vector<ast> &cls1, const std::vector<ast> &cls2){
|
||||
#ifdef CHECK_PROOFS
|
||||
std::vector<ast> orig_cls1 = cls1;
|
||||
#endif
|
||||
ast neg_pivot = pv->mk_not(pivot);
|
||||
bool found_pivot1 = false, found_pivot2 = false;
|
||||
for(unsigned i = 0; i < cls1.size(); i++){
|
||||
if(cls1[i] == neg_pivot){
|
||||
cls1[i] = cls1.back();
|
||||
cls1.pop_back();
|
||||
found_pivot1 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
std::set<ast> memo;
|
||||
memo.insert(cls1.begin(),cls1.end());
|
||||
for(unsigned j = 0; j < cls2.size(); j++){
|
||||
if(cls2[j] == pivot)
|
||||
found_pivot2 = true;
|
||||
else
|
||||
if(memo.find(cls2[j]) == memo.end())
|
||||
cls1.push_back(cls2[j]);
|
||||
}
|
||||
}
|
||||
if(found_pivot1 && found_pivot2)
|
||||
return;
|
||||
|
||||
#ifdef CHECK_PROOFS
|
||||
std::cerr << "resolution anomaly: " << nodes.size()-1 << "\n";
|
||||
#if 0
|
||||
std::cerr << "pivot: "; {pv->print_lit(pivot); std::cout << "\n";}
|
||||
std::cerr << "left clause:\n";
|
||||
for(unsigned i = 0; i < orig_cls1.size(); i++)
|
||||
{pv->print_lit(orig_cls1[i]); std::cout << "\n";}
|
||||
std::cerr << "right clause:\n";
|
||||
for(unsigned i = 0; i < cls2.size(); i++)
|
||||
{pv->print_lit(cls2[i]); std::cout << "\n";}
|
||||
throw proof_error();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
iz3proof::node iz3proof::make_resolution(ast pivot, node premise1, node premise2)
|
||||
{
|
||||
if(nodes[premise1].rl == Hypothesis) return premise2; // resolve with hyp is noop
|
||||
if(nodes[premise2].rl == Hypothesis) return premise1;
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Resolution;
|
||||
n.aux = pivot;
|
||||
n.premises.resize(2);
|
||||
n.premises[0] = (premise1);
|
||||
n.premises[1] = (premise2);
|
||||
#ifdef CHECK_PROOFS
|
||||
n.conclusion = nodes[premise1].conclusion;
|
||||
resolve(pivot,n.conclusion,nodes[premise2].conclusion);
|
||||
n.frame = 1;
|
||||
#else
|
||||
n.frame = 0; // compute conclusion lazily
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
iz3proof::node iz3proof::resolve_lemmas(ast pivot, node premise1, node premise2)
|
||||
{
|
||||
std::vector<ast> lits(nodes[premise1].conclusion), itp; // no interpolant
|
||||
resolve(pivot,lits,nodes[premise2].conclusion);
|
||||
return make_lemma(lits,itp);
|
||||
}
|
||||
|
||||
|
||||
iz3proof::node iz3proof::make_assumption(int frame, const std::vector<ast> &assumption){
|
||||
#if 0
|
||||
std::cout << "assumption: \n";
|
||||
for(unsigned i = 0; i < assumption.size(); i++)
|
||||
pv->show(assumption[i]);
|
||||
std::cout << "\n";
|
||||
#endif
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Assumption;
|
||||
n.conclusion.resize(1);
|
||||
n.conclusion = assumption;
|
||||
n.frame = frame;
|
||||
return res;
|
||||
}
|
||||
|
||||
iz3proof::node iz3proof::make_hypothesis(ast hypothesis){
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Hypothesis;
|
||||
n.conclusion.resize(2);
|
||||
n.conclusion[0] = hypothesis;
|
||||
n.conclusion[1] = pv->mk_not(hypothesis);
|
||||
return res;
|
||||
}
|
||||
|
||||
iz3proof::node iz3proof::make_theory(const std::vector<ast> &conclusion, std::vector<node> premises){
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Theory;
|
||||
n.conclusion = conclusion;
|
||||
n.premises = premises;
|
||||
return res;
|
||||
}
|
||||
|
||||
iz3proof::node iz3proof::make_axiom(const std::vector<ast> &conclusion){
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Axiom;
|
||||
n.conclusion = conclusion;
|
||||
return res;
|
||||
}
|
||||
|
||||
iz3proof::node iz3proof::make_contra(node prem, const std::vector<ast> &conclusion){
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Contra;
|
||||
n.conclusion = conclusion;
|
||||
#ifdef CHECK_PROOFS
|
||||
//if(!(conclusion == nodes[prem].conclusion)){
|
||||
//std::cerr << "internal error: proof error\n";
|
||||
//assert(0 && "proof error");
|
||||
//}
|
||||
#endif
|
||||
n.premises.push_back(prem);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
iz3proof::node iz3proof::make_lemma(const std::vector<ast> &conclusion, const std::vector<ast> &interpolation){
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Lemma;
|
||||
n.conclusion = conclusion;
|
||||
n.frame = interps.size();
|
||||
interps.push_back(interpolation);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Make a Reflexivity node. This rule produces |- x = x */
|
||||
|
||||
iz3proof::node iz3proof::make_reflexivity(ast con){
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Reflexivity;
|
||||
n.conclusion.push_back(con);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Make a Symmetry node. This takes a derivation of |- x = y and
|
||||
produces | y = x */
|
||||
|
||||
iz3proof::node iz3proof::make_symmetry(ast con, node prem){
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Reflexivity;
|
||||
n.conclusion.push_back(con);
|
||||
n.premises.push_back(prem);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Make a transitivity node. This takes derivations of |- x = y
|
||||
and |- y = z produces | x = z */
|
||||
|
||||
iz3proof::node iz3proof::make_transitivity(ast con, node prem1, node prem2){
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Transitivity;
|
||||
n.conclusion.push_back(con);
|
||||
n.premises.push_back(prem1);
|
||||
n.premises.push_back(prem2);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/** Make a congruence node. This takes derivations of |- x_i = y_i
|
||||
and produces |- f(x_1,...,x_n) = f(y_1,...,y_n) */
|
||||
|
||||
iz3proof::node iz3proof::make_congruence(ast con, const std::vector<node> &prems){
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = Congruence;
|
||||
n.conclusion.push_back(con);
|
||||
n.premises = prems;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/** Make an equality contradicition node. This takes |- x = y
|
||||
and |- !(x = y) and produces false. */
|
||||
|
||||
iz3proof::node iz3proof::make_eqcontra(node prem1, node prem2){
|
||||
node res = make_node();
|
||||
node_struct &n = nodes[res];
|
||||
n.rl = EqContra;
|
||||
n.premises.push_back(prem1);
|
||||
n.premises.push_back(prem2);
|
||||
return res;
|
||||
}
|
||||
|
||||
iz3proof::node iz3proof::copy_rec(stl_ext::hash_map<node,node> &memo, iz3proof &src, node n){
|
||||
stl_ext::hash_map<node,node>::iterator it = memo.find(n);
|
||||
if(it != memo.end()) return (*it).second;
|
||||
node_struct &ns = src.nodes[n];
|
||||
std::vector<node> prems(ns.premises.size());
|
||||
for(unsigned i = 0; i < prems.size(); i++)
|
||||
prems[i] = copy_rec(memo,src,ns.premises[i]);
|
||||
nodes.push_back(ns);
|
||||
nodes.back().premises.swap(prems);
|
||||
if(ns.rl == Lemma){
|
||||
nodes.back().frame = interps.size();
|
||||
interps.push_back(src.interps[ns.frame]);
|
||||
}
|
||||
int res = nodes.size()-1;
|
||||
memo[n] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
iz3proof::node iz3proof::copy(iz3proof &src, node n){
|
||||
stl_ext::hash_map<node,node> memo;
|
||||
return copy_rec(memo, src, n);
|
||||
}
|
||||
|
||||
bool iz3proof::pred_in_A(ast id){
|
||||
return weak
|
||||
? pv->ranges_intersect(pv->ast_range(id),rng) :
|
||||
pv->range_contained(pv->ast_range(id),rng);
|
||||
}
|
||||
|
||||
bool iz3proof::term_in_B(ast id){
|
||||
prover::range r = pv->ast_scope(id);
|
||||
if(weak) {
|
||||
if(pv->range_min(r) == SHRT_MIN)
|
||||
return !pv->range_contained(r,rng);
|
||||
else
|
||||
return !pv->ranges_intersect(r,rng);
|
||||
}
|
||||
else
|
||||
return !pv->range_contained(r,rng);
|
||||
}
|
||||
|
||||
bool iz3proof::frame_in_A(int frame){
|
||||
return pv->in_range(frame,rng);
|
||||
}
|
||||
|
||||
bool iz3proof::lit_in_B(ast lit){
|
||||
return
|
||||
b_lits.find(lit) != b_lits.end()
|
||||
|| b_lits.find(pv->mk_not(lit)) != b_lits.end();
|
||||
}
|
||||
|
||||
iz3proof::ast iz3proof::my_or(ast x, ast y){
|
||||
return pv->mk_not(pv->mk_and(pv->mk_not(x),pv->mk_not(y)));
|
||||
}
|
||||
|
||||
iz3proof::ast iz3proof::get_A_lits(std::vector<ast> &cls){
|
||||
ast foo = pv->mk_false();
|
||||
for(unsigned i = 0; i < cls.size(); i++){
|
||||
ast lit = cls[i];
|
||||
if(b_lits.find(pv->mk_not(lit)) == b_lits.end()){
|
||||
if(pv->range_max(pv->ast_scope(lit)) == pv->range_min(pv->ast_scope(lit))){
|
||||
std::cout << "bad lit: " << pv->range_max(rng) << " : " << pv->range_max(pv->ast_scope(lit)) << " : " << (pv->ast_id(lit)) << " : ";
|
||||
pv->show(lit);
|
||||
}
|
||||
foo = my_or(foo,lit);
|
||||
}
|
||||
}
|
||||
return foo;
|
||||
}
|
||||
|
||||
iz3proof::ast iz3proof::get_B_lits(std::vector<ast> &cls){
|
||||
ast foo = pv->mk_false();
|
||||
for(unsigned i = 0; i < cls.size(); i++){
|
||||
ast lit = cls[i];
|
||||
if(b_lits.find(pv->mk_not(lit)) != b_lits.end())
|
||||
foo = my_or(foo,lit);
|
||||
}
|
||||
return foo;
|
||||
}
|
||||
|
||||
void iz3proof::set_of_B_lits(std::vector<ast> &cls, std::set<ast> &res){
|
||||
for(unsigned i = 0; i < cls.size(); i++){
|
||||
ast lit = cls[i];
|
||||
if(b_lits.find(pv->mk_not(lit)) != b_lits.end())
|
||||
res.insert(lit);
|
||||
}
|
||||
}
|
||||
|
||||
void iz3proof::set_of_A_lits(std::vector<ast> &cls, std::set<ast> &res){
|
||||
for(unsigned i = 0; i < cls.size(); i++){
|
||||
ast lit = cls[i];
|
||||
if(b_lits.find(pv->mk_not(lit)) == b_lits.end())
|
||||
res.insert(lit);
|
||||
}
|
||||
}
|
||||
|
||||
void iz3proof::find_B_lits(){
|
||||
b_lits.clear();
|
||||
for(unsigned i = 0; i < nodes.size(); i++){
|
||||
node_struct &n = nodes[i];
|
||||
std::vector<ast> &cls = n.conclusion;
|
||||
if(n.rl == Assumption){
|
||||
if(weak) goto lemma;
|
||||
if(!frame_in_A(n.frame))
|
||||
for(unsigned j = 0; j < cls.size(); j++)
|
||||
b_lits.insert(cls[j]);
|
||||
}
|
||||
else if(n.rl == Lemma) {
|
||||
lemma:
|
||||
for(unsigned j = 0; j < cls.size(); j++)
|
||||
if(term_in_B(cls[j]))
|
||||
b_lits.insert(cls[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iz3proof::ast iz3proof::disj_of_set(std::set<ast> &s){
|
||||
ast res = pv->mk_false();
|
||||
for(std::set<ast>::iterator it = s.begin(), en = s.end(); it != en; ++it)
|
||||
res = my_or(*it,res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void iz3proof::mk_and_factor(int p1, int p2, int i, std::vector<ast> &itps, std::vector<std::set<ast> > &disjs){
|
||||
#ifdef FACTOR_INTERPS
|
||||
std::set<ast> &d1 = disjs[p1];
|
||||
std::set<ast> &d2 = disjs[p2];
|
||||
if(!weak){
|
||||
if(pv->is_true(itps[p1])){
|
||||
itps[i] = itps[p2];
|
||||
disjs[i] = disjs[p2];
|
||||
}
|
||||
else if(pv->is_true(itps[p2])){
|
||||
itps[i] = itps[p1];
|
||||
disjs[i] = disjs[p1];
|
||||
}
|
||||
else {
|
||||
std::set<ast> p1only,p2only;
|
||||
std::insert_iterator<std::set<ast> > p1o(p1only,p1only.begin());
|
||||
std::insert_iterator<std::set<ast> > p2o(p2only,p2only.begin());
|
||||
std::insert_iterator<std::set<ast> > dio(disjs[i],disjs[i].begin());
|
||||
std::set_difference(d1.begin(),d1.end(),d2.begin(),d2.end(),p1o);
|
||||
std::set_difference(d2.begin(),d2.end(),d1.begin(),d1.end(),p2o);
|
||||
std::set_intersection(d1.begin(),d1.end(),d2.begin(),d2.end(),dio);
|
||||
ast p1i = my_or(itps[p1],disj_of_set(p1only));
|
||||
ast p2i = my_or(itps[p2],disj_of_set(p2only));
|
||||
itps[i] = pv->mk_and(p1i,p2i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
itps[i] = pv->mk_and(itps[p1],itps[p2]);
|
||||
std::insert_iterator<std::set<ast> > dio(disjs[i],disjs[i].begin());
|
||||
std::set_union(d1.begin(),d1.end(),d2.begin(),d2.end(),dio);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void iz3proof::mk_or_factor(int p1, int p2, int i, std::vector<ast> &itps, std::vector<std::set<ast> > &disjs){
|
||||
#ifdef FACTOR_INTERPS
|
||||
std::set<ast> &d1 = disjs[p1];
|
||||
std::set<ast> &d2 = disjs[p2];
|
||||
if(weak){
|
||||
if(pv->is_false(itps[p1])){
|
||||
itps[i] = itps[p2];
|
||||
disjs[i] = disjs[p2];
|
||||
}
|
||||
else if(pv->is_false(itps[p2])){
|
||||
itps[i] = itps[p1];
|
||||
disjs[i] = disjs[p1];
|
||||
}
|
||||
else {
|
||||
std::set<ast> p1only,p2only;
|
||||
std::insert_iterator<std::set<ast> > p1o(p1only,p1only.begin());
|
||||
std::insert_iterator<std::set<ast> > p2o(p2only,p2only.begin());
|
||||
std::insert_iterator<std::set<ast> > dio(disjs[i],disjs[i].begin());
|
||||
std::set_difference(d1.begin(),d1.end(),d2.begin(),d2.end(),p1o);
|
||||
std::set_difference(d2.begin(),d2.end(),d1.begin(),d1.end(),p2o);
|
||||
std::set_intersection(d1.begin(),d1.end(),d2.begin(),d2.end(),dio);
|
||||
ast p1i = pv->mk_and(itps[p1],pv->mk_not(disj_of_set(p1only)));
|
||||
ast p2i = pv->mk_and(itps[p2],pv->mk_not(disj_of_set(p2only)));
|
||||
itps[i] = my_or(p1i,p2i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
itps[i] = my_or(itps[p1],itps[p2]);
|
||||
std::insert_iterator<std::set<ast> > dio(disjs[i],disjs[i].begin());
|
||||
std::set_union(d1.begin(),d1.end(),d2.begin(),d2.end(),dio);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void iz3proof::interpolate_lemma(node_struct &n){
|
||||
if(interps[n.frame].size())
|
||||
return; // already computed
|
||||
pv->interpolate_clause(n.conclusion,interps[n.frame]);
|
||||
}
|
||||
|
||||
iz3proof::ast iz3proof::interpolate(const prover::range &_rng, bool _weak
|
||||
#ifdef CHECK_PROOFS
|
||||
, ast assump
|
||||
, std::vector<int> *parents
|
||||
#endif
|
||||
){
|
||||
// std::cout << "proof size: " << nodes.size() << "\n";
|
||||
rng = _rng;
|
||||
weak = _weak;
|
||||
#ifdef CHECK_PROOFS
|
||||
if(nodes[nodes.size()-1].conclusion.size() != 0)
|
||||
std::cerr << "internal error: proof conclusion is not empty clause\n";
|
||||
if(!child_interps.size()){
|
||||
child_interps.resize(nodes.size());
|
||||
for(unsigned j = 0; j < nodes.size(); j++)
|
||||
child_interps[j] = pv->mk_true();
|
||||
}
|
||||
#endif
|
||||
std::vector<ast> itps(nodes.size());
|
||||
#ifdef FACTOR_INTERPS
|
||||
std::vector<std::set<ast> > disjs(nodes.size());
|
||||
#endif
|
||||
profiling::timer_start("Blits");
|
||||
find_B_lits();
|
||||
profiling::timer_stop("Blits");
|
||||
profiling::timer_start("interp_proof");
|
||||
// strengthen();
|
||||
for(unsigned i = 0; i < nodes.size(); i++){
|
||||
node_struct &n = nodes[i];
|
||||
ast &q = itps[i];
|
||||
switch(n.rl){
|
||||
case Assumption: {
|
||||
|
||||
if(frame_in_A(n.frame)){
|
||||
/* HypC-A */
|
||||
if(!weak)
|
||||
#ifdef FACTOR_INTERPS
|
||||
{
|
||||
q = pv->mk_false();
|
||||
set_of_B_lits(n.conclusion,disjs[i]);
|
||||
}
|
||||
#else
|
||||
q = get_B_lits(n.conclusion);
|
||||
#endif
|
||||
else
|
||||
q = pv->mk_false();
|
||||
}
|
||||
else {
|
||||
/* HypEq-B */
|
||||
if(!weak)
|
||||
q = pv->mk_true();
|
||||
else
|
||||
#ifdef FACTOR_INTERPS
|
||||
{
|
||||
q = pv->mk_true();
|
||||
set_of_A_lits(n.conclusion,disjs[i]);
|
||||
}
|
||||
#else
|
||||
q = pv->mk_not(get_A_lits(n.conclusion));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Resolution: {
|
||||
ast p = n.aux;
|
||||
p = pv->is_not(p) ? pv->mk_not(p) : p; // should be positive, but just in case
|
||||
if(lit_in_B(p))
|
||||
#ifdef FACTOR_INTERPS
|
||||
mk_and_factor(n.premises[0],n.premises[1],i,itps,disjs);
|
||||
#else
|
||||
q = pv->mk_and(itps[n.premises[0]],itps[n.premises[1]]);
|
||||
#endif
|
||||
else
|
||||
#ifdef FACTOR_INTERPS
|
||||
mk_or_factor(n.premises[0],n.premises[1],i,itps,disjs);
|
||||
#else
|
||||
q = my_or(itps[n.premises[0]],itps[n.premises[1]]);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case Lemma: {
|
||||
interpolate_lemma(n); // make sure lemma interpolants have been computed
|
||||
q = interps[n.frame][pv->range_max(rng)];
|
||||
break;
|
||||
}
|
||||
case Contra: {
|
||||
q = itps[n.premises[0]];
|
||||
#ifdef FACTOR_INTERPS
|
||||
disjs[i] = disjs[n.premises[0]];
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0 && "rule not allowed in interpolated proof");
|
||||
}
|
||||
#ifdef CHECK_PROOFS
|
||||
int this_frame = pv->range_max(rng);
|
||||
if(0 && this_frame == 39) {
|
||||
std::vector<ast> alits;
|
||||
ast s = pv->mk_true();
|
||||
for(unsigned j = 0; j < n.conclusion.size(); j++)
|
||||
if(pred_in_A(n.conclusion[j])){
|
||||
int scpmax = pv->range_max(pv->ast_scope(n.conclusion[j]));
|
||||
if(scpmax == this_frame)
|
||||
s = pv->mk_and(s,pv->mk_not(n.conclusion[j]));
|
||||
}
|
||||
ast ci = child_interps[i];
|
||||
s = pv->mk_and(pv->mk_and(s,pv->mk_and(assump,pv->mk_not(q))),ci);
|
||||
if(pv->is_sat(s)){
|
||||
std::cout << "interpolation invariant violated at step " << i << "\n";
|
||||
assert(0 && "interpolation invariant violated");
|
||||
}
|
||||
}
|
||||
if((*parents)[this_frame] == 39)
|
||||
child_interps[i] = pv->mk_and(child_interps[i],q);
|
||||
#endif
|
||||
}
|
||||
ast &bar = itps[nodes.size()-1];
|
||||
#ifdef FACTOR_INTERPS
|
||||
if(!weak)
|
||||
bar = my_or(bar,disj_of_set(disjs[nodes.size()-1]));
|
||||
else
|
||||
bar = pv->mk_and(bar,pv->mk_not(disj_of_set(disjs[nodes.size()-1])));
|
||||
#endif
|
||||
profiling::timer_stop("interp_proof");
|
||||
profiling::timer_start("simplifying");
|
||||
bar = pv->simplify(bar);
|
||||
profiling::timer_stop("simplifying");
|
||||
return bar;
|
||||
}
|
||||
|
||||
|
||||
void iz3proof::print(std::ostream &s, int id){
|
||||
node_struct &n = nodes[id];
|
||||
switch(n.rl){
|
||||
case Assumption:
|
||||
s << "Assumption(";
|
||||
pv->print_clause(s,n.conclusion);
|
||||
s << ")";
|
||||
break;
|
||||
case Hypothesis:
|
||||
s << "Hyp("; pv->print_expr(s,n.conclusion[0]); s << ")"; break;
|
||||
case Reflexivity:
|
||||
s << "Refl("; pv->print_expr(s,n.conclusion[0]); s << ")"; break;
|
||||
case Symmetry:
|
||||
s << "Symm("; print(s,n.premises[0]); s << ")"; break;
|
||||
case Transitivity:
|
||||
s << "Trans("; print(s,n.premises[0]); s << ","; print(s,n.premises[1]); s << ")"; break;
|
||||
case Congruence:
|
||||
s << "Cong("; pv->print_expr(s,n.conclusion[0]);
|
||||
for(unsigned i = 0; i < n.premises.size(); i++){
|
||||
s << ",";
|
||||
print(s,n.premises[i]);
|
||||
}
|
||||
s << ")"; break;
|
||||
case EqContra:
|
||||
s << "EqContra("; print(s,n.premises[0]); s << ","; print(s,n.premises[1]); s << ")"; break;
|
||||
case Resolution:
|
||||
s << "Res(";
|
||||
pv->print_expr(s,n.aux); s << ",";
|
||||
print(s,n.premises[0]); s << ","; print(s,n.premises[1]); s << ")";
|
||||
break;
|
||||
case Lemma:
|
||||
s << "Lemma(";
|
||||
pv->print_clause(s,n.conclusion);
|
||||
for(unsigned i = 0; i < n.premises.size(); i++){
|
||||
s << ",";
|
||||
print(s,n.premises[i]);
|
||||
}
|
||||
s << ")";
|
||||
break;
|
||||
case Contra:
|
||||
s << "Contra(";
|
||||
print(s,n.premises[0]);
|
||||
s << ")";
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void iz3proof::show(int id){
|
||||
std::ostringstream ss;
|
||||
print(ss,id);
|
||||
iz3base::pretty_print(std::cout,ss.str());
|
||||
// std::cout << ss.str();
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
|
272
src/interp/iz3proof.h
Executable file
272
src/interp/iz3proof.h
Executable file
|
@ -0,0 +1,272 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3proof.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This class defines a simple interpolating proof system.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef IZ3PROOF_H
|
||||
#define IZ3PROOF_H
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "iz3base.h"
|
||||
#include "iz3secondary.h"
|
||||
|
||||
// #define CHECK_PROOFS
|
||||
|
||||
/** This class defines a simple proof system.
|
||||
|
||||
A proof is a dag consisting of "nodes". The children of each node
|
||||
are its "premises". Each node has a "conclusion" that is a clause,
|
||||
represented as a vector of literals.
|
||||
|
||||
The literals are represented by abstract syntax trees. Operations
|
||||
on these, including computation of scopes are provided by iz3base.
|
||||
|
||||
A proof can be interpolated, provided it is restricted to the
|
||||
rules Resolution, Assumption, Contra and Lemma, and that all
|
||||
clauses are strict (i.e., each literal in each clause is local).
|
||||
|
||||
*/
|
||||
|
||||
class iz3proof {
|
||||
public:
|
||||
/** The type of proof nodes (nodes in the derivation tree). */
|
||||
typedef int node;
|
||||
|
||||
/** Enumeration of proof rules. */
|
||||
enum rule {Resolution,Assumption,Hypothesis,Theory,Axiom,Contra,Lemma,Reflexivity,Symmetry,Transitivity,Congruence,EqContra};
|
||||
|
||||
/** Interface to prover. */
|
||||
typedef iz3base prover;
|
||||
|
||||
/** Ast type. */
|
||||
typedef prover::ast ast;
|
||||
|
||||
/** Object thrown in case of a proof error. */
|
||||
struct proof_error {};
|
||||
|
||||
/* Null proof node */
|
||||
static const node null = -1;
|
||||
|
||||
/** Make a resolution node with given pivot liter and premises.
|
||||
The conclusion of premise1 should contain the negation of the
|
||||
pivot literal, while the conclusion of premise2 should containe the
|
||||
pivot literal.
|
||||
*/
|
||||
node make_resolution(ast pivot, node premise1, node premise2);
|
||||
|
||||
/** Make an assumption node. The given clause is assumed in the given frame. */
|
||||
node make_assumption(int frame, const std::vector<ast> &assumption);
|
||||
|
||||
/** Make a hypothesis node. If phi is the hypothesis, this is
|
||||
effectively phi |- phi. */
|
||||
node make_hypothesis(ast hypothesis);
|
||||
|
||||
/** Make a theory node. This can be any inference valid in the theory. */
|
||||
node make_theory(const std::vector<ast> &conclusion, std::vector<node> premises);
|
||||
|
||||
/** Make an axiom node. The conclusion must be an instance of an axiom. */
|
||||
node make_axiom(const std::vector<ast> &conclusion);
|
||||
|
||||
/** Make a Contra node. This rule takes a derivation of the form
|
||||
Gamma |- False and produces |- \/~Gamma. */
|
||||
|
||||
node make_contra(node prem, const std::vector<ast> &conclusion);
|
||||
|
||||
/** Make a lemma node. A lemma node must have an interpolation. */
|
||||
node make_lemma(const std::vector<ast> &conclusion, const std::vector<ast> &interpolation);
|
||||
|
||||
/** Make a Reflexivity node. This rule produces |- x = x */
|
||||
|
||||
node make_reflexivity(ast con);
|
||||
|
||||
/** Make a Symmetry node. This takes a derivation of |- x = y and
|
||||
produces | y = x */
|
||||
|
||||
node make_symmetry(ast con, node prem);
|
||||
|
||||
/** Make a transitivity node. This takes derivations of |- x = y
|
||||
and |- y = z produces | x = z */
|
||||
|
||||
node make_transitivity(ast con, node prem1, node prem2);
|
||||
|
||||
/** Make a congruence node. This takes derivations of |- x_i = y_i
|
||||
and produces |- f(x_1,...,x_n) = f(y_1,...,y_n) */
|
||||
|
||||
node make_congruence(ast con, const std::vector<node> &prems);
|
||||
|
||||
/** Make an equality contradicition node. This takes |- x = y
|
||||
and |- !(x = y) and produces false. */
|
||||
|
||||
node make_eqcontra(node prem1, node prem2);
|
||||
|
||||
/** Get the rule of a node in a proof. */
|
||||
rule get_rule(node n){
|
||||
return nodes[n].rl;
|
||||
}
|
||||
|
||||
/** Get the pivot of a resolution node. */
|
||||
ast get_pivot(node n){
|
||||
return nodes[n].aux;
|
||||
}
|
||||
|
||||
/** Get the frame of an assumption node. */
|
||||
int get_frame(node n){
|
||||
return nodes[n].frame;
|
||||
}
|
||||
|
||||
/** Get the number of literals of the conclusion of a node. */
|
||||
int get_num_conclusion_lits(node n){
|
||||
return get_conclusion(n).size();
|
||||
}
|
||||
|
||||
/** Get the nth literal of the conclusion of a node. */
|
||||
ast get_nth_conclusion_lit(node n, int i){
|
||||
return get_conclusion(n)[i];
|
||||
}
|
||||
|
||||
/** Get the conclusion of a node. */
|
||||
void get_conclusion(node n, std::vector<ast> &result){
|
||||
result = get_conclusion(n);
|
||||
}
|
||||
|
||||
/** Get the number of premises of a node. */
|
||||
int get_num_premises(node n){
|
||||
return nodes[n].premises.size();
|
||||
}
|
||||
|
||||
/** Get the nth premise of a node. */
|
||||
int get_nth_premise(node n, int i){
|
||||
return nodes[n].premises[i];
|
||||
}
|
||||
|
||||
/** Get all the premises of a node. */
|
||||
void get_premises(node n, std::vector<node> &result){
|
||||
result = nodes[n].premises;
|
||||
}
|
||||
|
||||
/** Create a new proof node, replacing the premises of an old
|
||||
one. */
|
||||
|
||||
node clone(node n, std::vector<node> &premises){
|
||||
if(premises == nodes[n].premises)
|
||||
return n;
|
||||
nodes.push_back(nodes[n]);
|
||||
nodes.back().premises = premises;
|
||||
return nodes.size()-1;
|
||||
}
|
||||
|
||||
/** Copy a proof node from src */
|
||||
node copy(iz3proof &src, node n);
|
||||
|
||||
/** Resolve two lemmas on a given literal. */
|
||||
|
||||
node resolve_lemmas(ast pivot, node left, node right);
|
||||
|
||||
/** Swap two proofs. */
|
||||
void swap(iz3proof &other){
|
||||
std::swap(pv,other.pv);
|
||||
nodes.swap(other.nodes);
|
||||
interps.swap(other.interps);
|
||||
}
|
||||
|
||||
/** Compute an interpolant for a proof, where the "A" side is defined by
|
||||
the given range of frames. Parameter "weak", when true, uses different
|
||||
interpolation system that resutls in generally weaker interpolants.
|
||||
*/
|
||||
ast interpolate(const prover::range &_rng, bool weak = false
|
||||
#ifdef CHECK_PROOFS
|
||||
, Z3_ast assump = (Z3_ast)0, std::vector<int> *parents = 0
|
||||
|
||||
#endif
|
||||
);
|
||||
|
||||
/** print proof node to a stream */
|
||||
|
||||
void print(std::ostream &s, node n);
|
||||
|
||||
/** show proof node on stdout */
|
||||
void show(node n);
|
||||
|
||||
/** Construct a proof, with a given prover. */
|
||||
iz3proof(prover *p){
|
||||
pv = p;
|
||||
}
|
||||
|
||||
/** Default constructor */
|
||||
iz3proof(){pv = 0;}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
struct node_struct {
|
||||
rule rl;
|
||||
ast aux;
|
||||
int frame;
|
||||
std::vector<ast> conclusion;
|
||||
std::vector<node> premises;
|
||||
};
|
||||
|
||||
std::vector<node_struct> nodes;
|
||||
std::vector<std::vector<ast> > interps; // interpolations of lemmas
|
||||
prover *pv;
|
||||
|
||||
node make_node(){
|
||||
nodes.push_back(node_struct());
|
||||
return nodes.size()-1;
|
||||
}
|
||||
|
||||
void resolve(ast pivot, std::vector<ast> &cls1, const std::vector<ast> &cls2);
|
||||
|
||||
node copy_rec(stl_ext::hash_map<node,node> &memo, iz3proof &src, node n);
|
||||
|
||||
void interpolate_lemma(node_struct &n);
|
||||
|
||||
// lazily compute the result of resolution
|
||||
// the node member "frame" indicates result is computed
|
||||
const std::vector<ast> &get_conclusion(node x){
|
||||
node_struct &n = nodes[x];
|
||||
if(n.rl == Resolution && !n.frame){
|
||||
n.conclusion = get_conclusion(n.premises[0]);
|
||||
resolve(n.aux,n.conclusion,get_conclusion(n.premises[1]));
|
||||
n.frame = 1;
|
||||
}
|
||||
return n.conclusion;
|
||||
}
|
||||
|
||||
prover::range rng;
|
||||
bool weak;
|
||||
stl_ext::hash_set<ast> b_lits;
|
||||
ast my_or(ast x, ast y);
|
||||
#ifdef CHECK_PROOFS
|
||||
std::vector<Z3_ast> child_interps;
|
||||
#endif
|
||||
bool pred_in_A(ast id);
|
||||
bool term_in_B(ast id);
|
||||
bool frame_in_A(int frame);
|
||||
bool lit_in_B(ast lit);
|
||||
ast get_A_lits(std::vector<ast> &cls);
|
||||
ast get_B_lits(std::vector<ast> &cls);
|
||||
void find_B_lits();
|
||||
ast disj_of_set(std::set<ast> &s);
|
||||
void mk_or_factor(int p1, int p2, int i, std::vector<ast> &itps, std::vector<std::set<ast> > &disjs);
|
||||
void mk_and_factor(int p1, int p2, int i, std::vector<ast> &itps, std::vector<std::set<ast> > &disjs);
|
||||
void set_of_B_lits(std::vector<ast> &cls, std::set<ast> &res);
|
||||
void set_of_A_lits(std::vector<ast> &cls, std::set<ast> &res);
|
||||
};
|
||||
|
||||
#endif
|
2676
src/interp/iz3proof_itp.cpp
Normal file
2676
src/interp/iz3proof_itp.cpp
Normal file
File diff suppressed because it is too large
Load diff
141
src/interp/iz3proof_itp.h
Normal file
141
src/interp/iz3proof_itp.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3proof.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This class defines a simple interpolating proof system.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef IZ3PROOF_ITP_H
|
||||
#define IZ3PROOF_ITP_H
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "iz3base.h"
|
||||
#include "iz3secondary.h"
|
||||
|
||||
// #define CHECK_PROOFS
|
||||
|
||||
/** This class defines a simple proof system.
|
||||
|
||||
As opposed to iz3proof, this class directly computes interpolants,
|
||||
so the proof representation is just the interpolant itself.
|
||||
|
||||
*/
|
||||
|
||||
class iz3proof_itp : public iz3mgr {
|
||||
public:
|
||||
|
||||
/** Enumeration of proof rules. */
|
||||
enum rule {Resolution,Assumption,Hypothesis,Theory,Axiom,Contra,Lemma,Reflexivity,Symmetry,Transitivity,Congruence,EqContra};
|
||||
|
||||
/** Interface to prover. */
|
||||
typedef iz3base prover;
|
||||
|
||||
/** Ast type. */
|
||||
typedef prover::ast ast;
|
||||
|
||||
/** The type of proof nodes (just interpolants). */
|
||||
typedef ast node;
|
||||
|
||||
/** Object thrown in case of a proof error. */
|
||||
struct proof_error {};
|
||||
|
||||
|
||||
/** Make a resolution node with given pivot literal and premises.
|
||||
The conclusion of premise1 should contain the negation of the
|
||||
pivot literal, while the conclusion of premise2 should containe the
|
||||
pivot literal.
|
||||
*/
|
||||
virtual node make_resolution(ast pivot, const std::vector<ast> &conc, node premise1, node premise2) = 0;
|
||||
|
||||
/** Make an assumption node. The given clause is assumed in the given frame. */
|
||||
virtual node make_assumption(int frame, const std::vector<ast> &assumption) = 0;
|
||||
|
||||
/** Make a hypothesis node. If phi is the hypothesis, this is
|
||||
effectively phi |- phi. */
|
||||
virtual node make_hypothesis(const ast &hypothesis) = 0;
|
||||
|
||||
/** Make an axiom node. The conclusion must be an instance of an axiom. */
|
||||
virtual node make_axiom(const std::vector<ast> &conclusion) = 0;
|
||||
|
||||
/** Make an axiom node. The conclusion must be an instance of an axiom. Localize axiom instance to range*/
|
||||
virtual node make_axiom(const std::vector<ast> &conclusion, prover::range) = 0;
|
||||
|
||||
/** Make a Contra node. This rule takes a derivation of the form
|
||||
Gamma |- False and produces |- \/~Gamma. */
|
||||
|
||||
virtual node make_contra(node prem, const std::vector<ast> &conclusion) = 0;
|
||||
|
||||
/** Make a Reflexivity node. This rule produces |- x = x */
|
||||
|
||||
virtual node make_reflexivity(ast con) = 0;
|
||||
|
||||
/** Make a Symmetry node. This takes a derivation of |- x = y and
|
||||
produces | y = x */
|
||||
|
||||
virtual node make_symmetry(ast con, const ast &premcon, node prem) = 0;
|
||||
|
||||
/** Make a transitivity node. This takes derivations of |- x = y
|
||||
and |- y = z produces | x = z */
|
||||
|
||||
virtual node make_transitivity(const ast &x, const ast &y, const ast &z, node prem1, node prem2) = 0;
|
||||
|
||||
/** Make a congruence node. This takes a derivation of |- x_i = y_i
|
||||
and produces |- f(...x_i,...) = f(...,y_i,...) */
|
||||
|
||||
virtual node make_congruence(const ast &xi_eq_yi, const ast &con, const ast &prem1) = 0;
|
||||
|
||||
/** Make a congruence node. This takes derivations of |- x_i1 = y_i1, |- x_i2 = y_i2,...
|
||||
and produces |- f(...x_i1...x_i2...) = f(...y_i1...y_i2...) */
|
||||
|
||||
virtual node make_congruence(const std::vector<ast> &xi_eq_yi, const ast &con, const std::vector<ast> &prems) = 0;
|
||||
|
||||
/** Make a modus-ponens node. This takes derivations of |- x
|
||||
and |- x = y and produces |- y */
|
||||
|
||||
virtual node make_mp(const ast &x_eq_y, const ast &prem1, const ast &prem2) = 0;
|
||||
|
||||
/** Make a farkas proof node. */
|
||||
|
||||
virtual node make_farkas(ast con, const std::vector<node> &prems, const std::vector<ast> &prem_cons, const std::vector<ast> &coeffs) = 0;
|
||||
|
||||
/* Make an axiom instance of the form |- x<=y, y<= x -> x =y */
|
||||
virtual node make_leq2eq(ast x, ast y, const ast &xleqy, const ast &yleqx) = 0;
|
||||
|
||||
/* Make an axiom instance of the form |- x = y -> x <= y */
|
||||
virtual node make_eq2leq(ast x, ast y, const ast &xeqy) = 0;
|
||||
|
||||
/* Make an inference of the form t <= c |- t/d <= floor(c/d) where t
|
||||
is an affine term divisble by d and c is an integer constant */
|
||||
virtual node make_cut_rule(const ast &tleqc, const ast &d, const ast &con, const ast &prem) = 0;
|
||||
|
||||
/* Return an interpolant from a proof of false */
|
||||
virtual ast interpolate(const node &pf) = 0;
|
||||
|
||||
/** Create proof object to construct an interpolant. */
|
||||
static iz3proof_itp *create(prover *p, const prover::range &r, bool _weak);
|
||||
|
||||
protected:
|
||||
iz3proof_itp(iz3mgr &m)
|
||||
: iz3mgr(m)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~iz3proof_itp(){
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
321
src/interp/iz3scopes.cpp
Executable file
321
src/interp/iz3scopes.cpp
Executable file
|
@ -0,0 +1,321 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3scopes.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Calculations with scopes, for both sequence and tree interpolation.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "iz3scopes.h"
|
||||
|
||||
|
||||
/** computes the least common ancestor of two nodes in the tree, or SHRT_MAX if none */
|
||||
int scopes::tree_lca(int n1, int n2){
|
||||
if(!tree_mode())
|
||||
return std::max(n1,n2);
|
||||
if(n1 == SHRT_MIN) return n2;
|
||||
if(n2 == SHRT_MIN) return n1;
|
||||
if(n1 == SHRT_MAX || n2 == SHRT_MAX) return SHRT_MAX;
|
||||
while(n1 != n2){
|
||||
if(n1 == SHRT_MAX || n2 == SHRT_MAX) return SHRT_MAX;
|
||||
assert(n1 >= 0 && n2 >= 0 && n1 < (int)parents.size() && n2 < (int)parents.size());
|
||||
if(n1 < n2) n1 = parents[n1];
|
||||
else n2 = parents[n2];
|
||||
}
|
||||
return n1;
|
||||
}
|
||||
|
||||
/** computes the greatest common descendant two nodes in the tree, or SHRT_MIN if none */
|
||||
int scopes::tree_gcd(int n1, int n2){
|
||||
if(!tree_mode())
|
||||
return std::min(n1,n2);
|
||||
int foo = tree_lca(n1,n2);
|
||||
if(foo == n1) return n2;
|
||||
if(foo == n2) return n1;
|
||||
return SHRT_MIN;
|
||||
}
|
||||
|
||||
#ifndef FULL_TREE
|
||||
|
||||
/** test whether a tree node is contained in a range */
|
||||
bool scopes::in_range(int n, const range &rng){
|
||||
return tree_lca(rng.lo,n) == n && tree_gcd(rng.hi,n) == n;
|
||||
}
|
||||
|
||||
/** test whether two ranges of tree nodes intersect */
|
||||
bool scopes::ranges_intersect(const range &rng1, const range &rng2){
|
||||
return tree_lca(rng1.lo,rng2.hi) == rng2.hi && tree_lca(rng1.hi,rng2.lo) == rng1.hi;
|
||||
}
|
||||
|
||||
|
||||
bool scopes::range_contained(const range &rng1, const range &rng2){
|
||||
return tree_lca(rng2.lo,rng1.lo) == rng1.lo
|
||||
&& tree_lca(rng1.hi,rng2.hi) == rng2.hi;
|
||||
}
|
||||
|
||||
scopes::range scopes::range_lub(const range &rng1, const range &rng2){
|
||||
range res;
|
||||
res.lo = tree_gcd(rng1.lo,rng2.lo);
|
||||
res.hi = tree_lca(rng1.hi,rng2.hi);
|
||||
return res;
|
||||
}
|
||||
|
||||
scopes::range scopes::range_glb(const range &rng1, const range &rng2){
|
||||
range res;
|
||||
res.lo = tree_lca(rng1.lo,rng2.lo);
|
||||
res.hi = tree_gcd(rng1.hi,rng2.hi);
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
class hash<scopes::range_lo > {
|
||||
public:
|
||||
size_t operator()(const scopes::range_lo &p) const {
|
||||
return p.lo + (size_t)p.next;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <> inline
|
||||
size_t stdext::hash_value<scopes::range_lo >(const scopes::range_lo& p)
|
||||
{
|
||||
std::hash<scopes::range_lo> h;
|
||||
return h(p);
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
class less<scopes::range_lo > {
|
||||
public:
|
||||
bool operator()(const scopes::range_lo &x, const scopes::range_lo &y) const {
|
||||
return x.lo < y.lo || x.lo == y.lo && (size_t)x.next < (size_t)y.next;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
struct range_op {
|
||||
scopes::range_lo *x, *y;
|
||||
int hi;
|
||||
range_op(scopes::range_lo *_x, scopes::range_lo *_y, int _hi){
|
||||
x = _x; y = _y; hi = _hi;
|
||||
}
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
class hash<range_op > {
|
||||
public:
|
||||
size_t operator()(const range_op &p) const {
|
||||
return (size_t) p.x + (size_t)p.y + p.hi;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <> inline
|
||||
size_t stdext::hash_value<range_op >(const range_op& p)
|
||||
{
|
||||
std::hash<range_op> h;
|
||||
return h(p);
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
class less<range_op > {
|
||||
public:
|
||||
bool operator()(const range_op &x, const range_op &y) const {
|
||||
return (size_t)x.x < (size_t)y.x || x.x == y.x &&
|
||||
((size_t)x.y < (size_t)y.y || x.y == y.y && x.hi < y.hi);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct range_tables {
|
||||
hash_map<scopes::range_lo, scopes::range_lo *> unique;
|
||||
hash_map<range_op,scopes::range_lo *> lub;
|
||||
hash_map<range_op,scopes::range_lo *> glb;
|
||||
};
|
||||
|
||||
|
||||
scopes::range_lo *scopes::find_range_lo(int lo, range_lo *next){
|
||||
range_lo foo(lo,next);
|
||||
std::pair<range_lo,range_lo *> baz(foo,(range_lo *)0);
|
||||
std::pair<hash_map<range_lo,scopes::range_lo *>::iterator,bool> bar = rt->unique.insert(baz);
|
||||
if(bar.second)
|
||||
bar.first->second = new range_lo(lo,next);
|
||||
return bar.first->second;
|
||||
//std::pair<hash_set<scopes::range_lo>::iterator,bool> bar = rt->unique.insert(foo);
|
||||
// const range_lo *baz = &*(bar.first);
|
||||
// return (range_lo *)baz; // exit const hell
|
||||
}
|
||||
|
||||
scopes::range_lo *scopes::range_lub_lo(range_lo *rng1, range_lo *rng2){
|
||||
if(!rng1) return rng2;
|
||||
if(!rng2) return rng1;
|
||||
if(rng1->lo > rng2->lo)
|
||||
std::swap(rng1,rng2);
|
||||
std::pair<range_op,range_lo *> foo(range_op(rng1,rng2,0),(range_lo *)0);
|
||||
std::pair<hash_map<range_op,scopes::range_lo *>::iterator,bool> bar = rt->lub.insert(foo);
|
||||
range_lo *&res = bar.first->second;
|
||||
if(!bar.second) return res;
|
||||
if(!(rng1->next && rng1->next->lo <= rng2->lo)){
|
||||
for(int lo = rng1->lo; lo <= rng2->lo; lo = parents[lo])
|
||||
if(lo == rng2->lo)
|
||||
{rng2 = rng2->next; break;}
|
||||
}
|
||||
range_lo *baz = range_lub_lo(rng1->next,rng2);
|
||||
res = find_range_lo(rng1->lo,baz);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
scopes::range_lo *scopes::range_glb_lo(range_lo *rng1, range_lo *rng2, int hi){
|
||||
if(!rng1) return rng1;
|
||||
if(!rng2) return rng2;
|
||||
if(rng1->lo > rng2->lo)
|
||||
std::swap(rng1,rng2);
|
||||
std::pair<range_op,range_lo *> cand(range_op(rng1,rng2,hi),(range_lo *)0);
|
||||
std::pair<hash_map<range_op,scopes::range_lo *>::iterator,bool> bar = rt->glb.insert(cand);
|
||||
range_lo *&res = bar.first->second;
|
||||
if(!bar.second) return res;
|
||||
range_lo *foo;
|
||||
if(!(rng1->next && rng1->next->lo <= rng2->lo)){
|
||||
int lim = hi;
|
||||
if(rng1->next) lim = std::min(lim,rng1->next->lo);
|
||||
int a = rng1->lo, b = rng2->lo;
|
||||
while(a != b && b <= lim){
|
||||
a = parents[a];
|
||||
if(a > b)std::swap(a,b);
|
||||
}
|
||||
if(a == b && b <= lim){
|
||||
foo = range_glb_lo(rng1->next,rng2->next,hi);
|
||||
foo = find_range_lo(b,foo);
|
||||
}
|
||||
else
|
||||
foo = range_glb_lo(rng2,rng1->next,hi);
|
||||
}
|
||||
else foo = range_glb_lo(rng1->next,rng2,hi);
|
||||
res = foo;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** computes the lub (smallest containing subtree) of two ranges */
|
||||
scopes::range scopes::range_lub(const range &rng1, const range &rng2){
|
||||
int hi = tree_lca(rng1.hi,rng2.hi);
|
||||
if(hi == SHRT_MAX) return range_full();
|
||||
range_lo *lo = range_lub_lo(rng1.lo,rng2.lo);
|
||||
return range(hi,lo);
|
||||
}
|
||||
|
||||
/** computes the glb (intersection) of two ranges */
|
||||
scopes::range scopes::range_glb(const range &rng1, const range &rng2){
|
||||
if(rng1.hi == SHRT_MAX) return rng2;
|
||||
if(rng2.hi == SHRT_MAX) return rng1;
|
||||
int hi = tree_gcd(rng1.hi,rng2.hi);
|
||||
range_lo *lo = hi == SHRT_MIN ? 0 : range_glb_lo(rng1.lo,rng2.lo,hi);
|
||||
if(!lo) hi = SHRT_MIN;
|
||||
return range(hi,lo);
|
||||
}
|
||||
|
||||
/** is this range empty? */
|
||||
bool scopes::range_is_empty(const range &rng){
|
||||
return rng.hi == SHRT_MIN;
|
||||
}
|
||||
|
||||
/** return an empty range */
|
||||
scopes::range scopes::range_empty(){
|
||||
return range(SHRT_MIN,0);
|
||||
}
|
||||
|
||||
/** return a full range */
|
||||
scopes::range scopes::range_full(){
|
||||
return range(SHRT_MAX,0);
|
||||
}
|
||||
|
||||
/** return the maximal element of a range */
|
||||
int scopes::range_max(const range &rng){
|
||||
return rng.hi;
|
||||
}
|
||||
|
||||
/** return a minimal (not necessarily unique) element of a range */
|
||||
int scopes::range_min(const range &rng){
|
||||
if(rng.hi == SHRT_MAX) return SHRT_MIN;
|
||||
return rng.lo ? rng.lo->lo : SHRT_MAX;
|
||||
}
|
||||
|
||||
|
||||
/** return range consisting of downward closure of a point */
|
||||
scopes::range scopes::range_downward(int _hi){
|
||||
std::vector<bool> descendants(parents.size());
|
||||
for(int i = descendants.size() - 1; i >= 0 ; i--)
|
||||
descendants[i] = i == _hi || parents[i] < parents.size() && descendants[parents[i]];
|
||||
for(unsigned i = 0; i < descendants.size() - 1; i++)
|
||||
if(parents[i] < parents.size())
|
||||
descendants[parents[i]] = false;
|
||||
range_lo *foo = 0;
|
||||
for(int i = descendants.size() - 1; i >= 0; --i)
|
||||
if(descendants[i]) foo = find_range_lo(i,foo);
|
||||
return range(_hi,foo);
|
||||
}
|
||||
|
||||
/** add an element to a range */
|
||||
void scopes::range_add(int i, range &n){
|
||||
range foo = range(i, find_range_lo(i,0));
|
||||
n = range_lub(foo,n);
|
||||
}
|
||||
|
||||
/** Choose an element of rng1 that is near to rng2 */
|
||||
int scopes::range_near(const range &rng1, const range &rng2){
|
||||
|
||||
int frame;
|
||||
int thing = tree_lca(rng1.hi,rng2.hi);
|
||||
if(thing != rng1.hi) return rng1.hi;
|
||||
range line = range(rng1.hi,find_range_lo(rng2.hi,(range_lo *)0));
|
||||
line = range_glb(line,rng1);
|
||||
return range_min(line);
|
||||
}
|
||||
|
||||
|
||||
/** test whether a tree node is contained in a range */
|
||||
bool scopes::in_range(int n, const range &rng){
|
||||
range r = range_empty();
|
||||
range_add(n,r);
|
||||
r = range_glb(rng,r);
|
||||
return !range_is_empty(r);
|
||||
}
|
||||
|
||||
/** test whether two ranges of tree nodes intersect */
|
||||
bool scopes::ranges_intersect(const range &rng1, const range &rng2){
|
||||
range r = range_glb(rng1,rng2);
|
||||
return !range_is_empty(r);
|
||||
}
|
||||
|
||||
|
||||
bool scopes::range_contained(const range &rng1, const range &rng2){
|
||||
range r = range_glb(rng1,rng2);
|
||||
return r.hi == rng1.hi && r.lo == rng1.lo;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
197
src/interp/iz3scopes.h
Executable file
197
src/interp/iz3scopes.h
Executable file
|
@ -0,0 +1,197 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3scopes.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Calculations with scopes, for both sequence and tree interpolation.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#ifndef IZ3SOPES_H
|
||||
#define IZ3SOPES_H
|
||||
|
||||
#include <vector>
|
||||
#include <limits.h>
|
||||
|
||||
class scopes {
|
||||
|
||||
public:
|
||||
/** Construct from parents vector. */
|
||||
scopes(const std::vector<int> &_parents){
|
||||
parents = _parents;
|
||||
}
|
||||
|
||||
scopes(){
|
||||
}
|
||||
|
||||
void initialize(const std::vector<int> &_parents){
|
||||
parents = _parents;
|
||||
}
|
||||
|
||||
/** The parents vector defining the tree structure */
|
||||
std::vector<int> parents;
|
||||
|
||||
// #define FULL_TREE
|
||||
#ifndef FULL_TREE
|
||||
struct range {
|
||||
range(){
|
||||
lo = SHRT_MAX;
|
||||
hi = SHRT_MIN;
|
||||
}
|
||||
short lo, hi;
|
||||
};
|
||||
|
||||
/** computes the lub (smallest containing subtree) of two ranges */
|
||||
range range_lub(const range &rng1, const range &rng2);
|
||||
|
||||
/** computes the glb (intersection) of two ranges */
|
||||
range range_glb(const range &rng1, const range &rng2);
|
||||
|
||||
/** is this range empty? */
|
||||
bool range_is_empty(const range &rng){
|
||||
return rng.hi < rng.lo;
|
||||
}
|
||||
|
||||
/** return an empty range */
|
||||
range range_empty(){
|
||||
range res;
|
||||
res.lo = SHRT_MAX;
|
||||
res.hi = SHRT_MIN;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** return an empty range */
|
||||
range range_full(){
|
||||
range res;
|
||||
res.lo = SHRT_MIN;
|
||||
res.hi = SHRT_MAX;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** return the maximal element of a range */
|
||||
int range_max(const range &rng){
|
||||
return rng.hi;
|
||||
}
|
||||
|
||||
/** return a minimal (not necessarily unique) element of a range */
|
||||
int range_min(const range &rng){
|
||||
return rng.lo;
|
||||
}
|
||||
|
||||
/** return range consisting of downward closure of a point */
|
||||
range range_downward(int _hi){
|
||||
range foo;
|
||||
foo.lo = SHRT_MIN;
|
||||
foo.hi = _hi;
|
||||
return foo;
|
||||
}
|
||||
|
||||
void range_add(int i, range &n){
|
||||
#if 0
|
||||
if(i < n.lo) n.lo = i;
|
||||
if(i > n.hi) n.hi = i;
|
||||
#else
|
||||
range rng; rng.lo = i; rng.hi = i;
|
||||
n = range_lub(rng,n);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Choose an element of rng1 that is near to rng2 */
|
||||
int range_near(const range &rng1, const range &rng2){
|
||||
int frame;
|
||||
int thing = tree_lca(rng1.lo,rng2.hi);
|
||||
if(thing == rng1.lo) frame = rng1.lo;
|
||||
else frame = tree_gcd(thing,rng1.hi);
|
||||
return frame;
|
||||
}
|
||||
#else
|
||||
|
||||
struct range_lo {
|
||||
int lo;
|
||||
range_lo *next;
|
||||
range_lo(int _lo, range_lo *_next){
|
||||
lo = _lo;
|
||||
next = _next;
|
||||
}
|
||||
};
|
||||
|
||||
struct range {
|
||||
int hi;
|
||||
range_lo *lo;
|
||||
range(int _hi, range_lo *_lo){
|
||||
hi = _hi;
|
||||
lo = _lo;
|
||||
}
|
||||
range(){
|
||||
hi = SHRT_MIN;
|
||||
lo = 0;
|
||||
}
|
||||
};
|
||||
|
||||
range_tables *rt;
|
||||
|
||||
/** computes the lub (smallest containing subtree) of two ranges */
|
||||
range range_lub(const range &rng1, const range &rng2);
|
||||
|
||||
/** computes the glb (intersection) of two ranges */
|
||||
range range_glb(const range &rng1, const range &rng2);
|
||||
|
||||
/** is this range empty? */
|
||||
bool range_is_empty(const range &rng);
|
||||
|
||||
/** return an empty range */
|
||||
range range_empty();
|
||||
|
||||
/** return a full range */
|
||||
range range_full();
|
||||
|
||||
/** return the maximal element of a range */
|
||||
int range_max(const range &rng);
|
||||
|
||||
/** return a minimal (not necessarily unique) element of a range */
|
||||
int range_min(const range &rng);
|
||||
|
||||
/** return range consisting of downward closure of a point */
|
||||
range range_downward(int _hi);
|
||||
|
||||
/** add an element to a range */
|
||||
void range_add(int i, range &n);
|
||||
|
||||
/** Choose an element of rng1 that is near to rng2 */
|
||||
int range_near(const range &rng1, const range &rng2);
|
||||
|
||||
range_lo *find_range_lo(int lo, range_lo *next);
|
||||
range_lo *range_lub_lo(range_lo *rng1, range_lo *rng2);
|
||||
range_lo *range_glb_lo(range_lo *rng1, range_lo *rng2, int lim);
|
||||
|
||||
#endif
|
||||
|
||||
/** test whether a tree node is contained in a range */
|
||||
bool in_range(int n, const range &rng);
|
||||
|
||||
/** test whether two ranges of tree nodes intersect */
|
||||
bool ranges_intersect(const range &rng1, const range &rng2);
|
||||
|
||||
/** test whether range rng1 contained in range rng2 */
|
||||
bool range_contained(const range &rng1, const range &rng2);
|
||||
|
||||
private:
|
||||
int tree_lca(int n1, int n2);
|
||||
int tree_gcd(int n1, int n2);
|
||||
bool tree_mode(){return parents.size() != 0;}
|
||||
|
||||
|
||||
|
||||
};
|
||||
#endif
|
40
src/interp/iz3secondary.h
Executable file
40
src/interp/iz3secondary.h
Executable file
|
@ -0,0 +1,40 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3secondary
|
||||
|
||||
Abstract:
|
||||
|
||||
Interface for secondary provers.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#ifndef IZ3SECONDARY_H
|
||||
#define IZ3SECONDARY_H
|
||||
|
||||
/** Interface class for secondary provers. */
|
||||
|
||||
#include "iz3base.h"
|
||||
#include <vector>
|
||||
|
||||
class iz3secondary : public iz3mgr {
|
||||
public:
|
||||
virtual int interpolate(const std::vector<ast> &frames, std::vector<ast> &interpolants) = 0;
|
||||
virtual ~iz3secondary(){}
|
||||
|
||||
protected:
|
||||
iz3secondary(const iz3mgr &mgr) : iz3mgr(mgr) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
1778
src/interp/iz3translate.cpp
Executable file
1778
src/interp/iz3translate.cpp
Executable file
File diff suppressed because it is too large
Load diff
65
src/interp/iz3translate.h
Executable file
65
src/interp/iz3translate.h
Executable file
|
@ -0,0 +1,65 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3translate.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Interface for proof translations from Z3 proofs to interpolatable
|
||||
proofs.
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#ifndef IZ3TRANSLATION_H
|
||||
#define IZ3TRANSLATION_H
|
||||
|
||||
#include "iz3proof.h"
|
||||
#include "iz3secondary.h"
|
||||
|
||||
// This is a interface class for translation from Z3 proof terms to
|
||||
// an interpolatable proof
|
||||
|
||||
class iz3translation : public iz3base {
|
||||
public:
|
||||
virtual iz3proof::node translate(ast, iz3proof &) = 0;
|
||||
virtual ast quantify(ast e, const range &rng){return e;}
|
||||
virtual ~iz3translation(){}
|
||||
|
||||
/** This is thrown when the proof cannot be translated. */
|
||||
struct unsupported {
|
||||
};
|
||||
|
||||
static iz3translation *create(iz3mgr &mgr,
|
||||
iz3secondary *secondary,
|
||||
const std::vector<std::vector<ast> > &frames,
|
||||
const std::vector<int> &parents,
|
||||
const std::vector<ast> &theory);
|
||||
|
||||
protected:
|
||||
iz3translation(iz3mgr &mgr,
|
||||
const std::vector<std::vector<ast> > &_cnsts,
|
||||
const std::vector<int> &_parents,
|
||||
const std::vector<ast> &_theory)
|
||||
: iz3base(mgr,_cnsts,_parents,_theory) {}
|
||||
};
|
||||
|
||||
//#define IZ3_TRANSLATE_DIRECT2
|
||||
#ifdef _FOCI2
|
||||
#define IZ3_TRANSLATE_DIRECT
|
||||
#else
|
||||
#define IZ3_TRANSLATE_FULL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
1767
src/interp/iz3translate_direct.cpp
Executable file
1767
src/interp/iz3translate_direct.cpp
Executable file
File diff suppressed because it is too large
Load diff
|
@ -179,6 +179,7 @@ namespace datalog {
|
|||
void context::push() {
|
||||
m_trail.push_scope();
|
||||
m_trail.push(restore_rules(m_rule_set));
|
||||
m_trail.push(restore_vec_size_trail<context,expr_ref_vector>(m_rule_fmls));
|
||||
m_trail.push(restore_vec_size_trail<context,expr_ref_vector>(m_background));
|
||||
}
|
||||
|
||||
|
@ -186,6 +187,10 @@ namespace datalog {
|
|||
if (m_trail.get_num_scopes() == 0) {
|
||||
throw default_exception("there are no backtracking points to pop to");
|
||||
}
|
||||
if(m_engine.get()){
|
||||
if(get_engine() != DUALITY_ENGINE)
|
||||
throw default_exception("operation is not supported by engine");
|
||||
}
|
||||
m_trail.pop_scope(1);
|
||||
}
|
||||
|
||||
|
@ -699,6 +704,10 @@ namespace datalog {
|
|||
check_existential_tail(r);
|
||||
check_positive_predicates(r);
|
||||
break;
|
||||
case DUALITY_ENGINE:
|
||||
check_existential_tail(r);
|
||||
check_positive_predicates(r);
|
||||
break;
|
||||
case CLP_ENGINE:
|
||||
check_existential_tail(r);
|
||||
check_positive_predicates(r);
|
||||
|
@ -920,6 +929,9 @@ namespace datalog {
|
|||
else if (e == symbol("clp")) {
|
||||
m_engine_type = CLP_ENGINE;
|
||||
}
|
||||
else if (e == symbol("duality")) {
|
||||
m_engine_type = DUALITY_ENGINE;
|
||||
}
|
||||
|
||||
if (m_engine_type == LAST_ENGINE) {
|
||||
expr_fast_mark1 mark;
|
||||
|
@ -945,6 +957,18 @@ namespace datalog {
|
|||
}
|
||||
|
||||
lbool context::query(expr* query) {
|
||||
#if 0
|
||||
// TODO: what?
|
||||
if(get_engine() != DUALITY_ENGINE) {
|
||||
new_query();
|
||||
rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end();
|
||||
rule_ref r(m_rule_manager);
|
||||
for (; it != end; ++it) {
|
||||
r = *it;
|
||||
check_rule(r);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_mc = mk_skip_model_converter();
|
||||
m_last_status = OK;
|
||||
m_last_answer = 0;
|
||||
|
@ -958,6 +982,8 @@ namespace datalog {
|
|||
case CLP_ENGINE:
|
||||
flush_add_rules();
|
||||
break;
|
||||
case DUALITY_ENGINE:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -983,6 +1009,7 @@ namespace datalog {
|
|||
if (get_engine() == DATALOG_ENGINE) {
|
||||
m_rel = dynamic_cast<rel_context_base*>(m_engine.get());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1014,7 +1041,6 @@ namespace datalog {
|
|||
out << "\n---------------\n";
|
||||
out << "Original rules\n";
|
||||
display_rules(out);
|
||||
|
||||
out << "\n---------------\n";
|
||||
out << "Transformed rules\n";
|
||||
m_transformed_rule_set.display(out);
|
||||
|
@ -1076,6 +1102,15 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
|
||||
void context::get_raw_rule_formulas(expr_ref_vector& rules, svector<symbol>& names){
|
||||
for (unsigned i = 0; i < m_rule_fmls.size(); ++i) {
|
||||
expr_ref r = bind_variables(m_rule_fmls[i].get(), true);
|
||||
rules.push_back(r.get());
|
||||
// rules.push_back(m_rule_fmls[i].get());
|
||||
names.push_back(m_rule_names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void context::get_rules_as_formulas(expr_ref_vector& rules, svector<symbol>& names) {
|
||||
expr_ref fml(m);
|
||||
datalog::rule_manager& rm = get_rule_manager();
|
||||
|
|
|
@ -357,6 +357,7 @@ namespace datalog {
|
|||
rule_set & get_rules() { flush_add_rules(); return m_rule_set; }
|
||||
|
||||
void get_rules_as_formulas(expr_ref_vector& fmls, svector<symbol>& names);
|
||||
void get_raw_rule_formulas(expr_ref_vector& fmls, svector<symbol>& names);
|
||||
|
||||
void add_fact(app * head);
|
||||
void add_fact(func_decl * pred, const relation_fact & fact);
|
||||
|
@ -492,14 +493,16 @@ namespace datalog {
|
|||
/**
|
||||
\brief retrieve model from inductive invariant that shows query is unsat.
|
||||
|
||||
\pre engine == 'pdr' - this option is only supported for PDR mode.
|
||||
\pre engine == 'pdr' || engine == 'duality' - this option is only supported
|
||||
for PDR mode and Duality mode.
|
||||
*/
|
||||
model_ref get_model();
|
||||
|
||||
/**
|
||||
\brief retrieve proof from derivation of the query.
|
||||
|
||||
\pre engine == 'pdr' - this option is only supported for PDR mode.
|
||||
\pre engine == 'pdr' || engine == 'duality'- this option is only supported
|
||||
for PDR mode and Duality mode.
|
||||
*/
|
||||
proof_ref get_proof();
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace datalog {
|
|||
QBMC_ENGINE,
|
||||
TAB_ENGINE,
|
||||
CLP_ENGINE,
|
||||
LAST_ENGINE
|
||||
LAST_ENGINE,
|
||||
DUALITY_ENGINE
|
||||
};
|
||||
|
||||
class engine_base {
|
||||
|
|
|
@ -57,7 +57,6 @@ namespace datalog {
|
|||
LAST_CACHE_MODE
|
||||
};
|
||||
|
||||
|
||||
struct std_string_hash_proc {
|
||||
unsigned operator()(const std::string & s) const
|
||||
{ return string_hash(s.c_str(), static_cast<unsigned>(s.length()), 17); }
|
||||
|
|
|
@ -67,6 +67,13 @@ def_module_params('fixedpoint',
|
|||
('print_statistics', BOOL, False, 'print statistics'),
|
||||
('use_utvpi', BOOL, True, 'PDR: Enable UTVPI strategy'),
|
||||
('tab_selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'),
|
||||
('full_expand', BOOL, False, 'DUALITY: Fully expand derivation trees'),
|
||||
('no_conj', BOOL, False, 'DUALITY: No forced covering (conjectures)'),
|
||||
('feasible_edges', BOOL, True, 'DUALITY: Don\'t expand definitley infeasible edges'),
|
||||
('use_underapprox', BOOL, False, 'DUALITY: Use underapproximations'),
|
||||
('stratified_inlining', BOOL, False, 'DUALITY: Use stratified inlining'),
|
||||
('recursion_bound', UINT, UINT_MAX, 'DUALITY: Recursion bound for stratified inlining'),
|
||||
('profile', BOOL, False, 'DUALITY: profile run time'),
|
||||
('dump_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'),
|
||||
))
|
||||
|
||||
|
|
493
src/muz/duality/duality_dl_interface.cpp
Normal file
493
src/muz/duality/duality_dl_interface.cpp
Normal file
|
@ -0,0 +1,493 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
duality_dl_interface.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
SMT2 interface for Duality
|
||||
|
||||
Author:
|
||||
|
||||
Krystof Hoder (t-khoder) 2011-9-22.
|
||||
Modified by Ken McMIllan (kenmcmil) 2013-4-18.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "dl_context.h"
|
||||
#include "dl_mk_coi_filter.h"
|
||||
#include "dl_mk_interp_tail_simplifier.h"
|
||||
#include "dl_mk_subsumption_checker.h"
|
||||
#include "dl_mk_rule_inliner.h"
|
||||
#include "dl_rule.h"
|
||||
#include "dl_rule_transformer.h"
|
||||
#include "smt2parser.h"
|
||||
#include "duality_dl_interface.h"
|
||||
#include "dl_rule_set.h"
|
||||
#include "dl_mk_slice.h"
|
||||
#include "dl_mk_unfold.h"
|
||||
#include "dl_mk_coalesce.h"
|
||||
#include "expr_abstract.h"
|
||||
#include "model_smt2_pp.h"
|
||||
#include "model_v2_pp.h"
|
||||
#include "fixedpoint_params.hpp"
|
||||
#include "scoped_proof.h"
|
||||
|
||||
// template class symbol_table<family_id>;
|
||||
|
||||
|
||||
#include "duality.h"
|
||||
#include "duality_profiling.h"
|
||||
|
||||
// using namespace Duality;
|
||||
|
||||
namespace Duality {
|
||||
|
||||
enum DualityStatus {StatusModel, StatusRefutation, StatusUnknown, StatusNull};
|
||||
|
||||
class duality_data {
|
||||
public:
|
||||
context ctx;
|
||||
RPFP::LogicSolver *ls;
|
||||
RPFP *rpfp;
|
||||
|
||||
DualityStatus status;
|
||||
std::vector<expr> clauses;
|
||||
std::vector<std::vector<RPFP::label_struct> > clause_labels;
|
||||
hash_map<RPFP::Edge *,int> map; // edges to clauses
|
||||
Solver::Counterexample cex;
|
||||
|
||||
duality_data(ast_manager &_m) : ctx(_m,config(params_ref())) {
|
||||
ls = 0;
|
||||
rpfp = 0;
|
||||
status = StatusNull;
|
||||
}
|
||||
~duality_data(){
|
||||
if(rpfp)
|
||||
dealloc(rpfp);
|
||||
if(ls)
|
||||
dealloc(ls);
|
||||
if(cex.tree)
|
||||
delete cex.tree;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
dl_interface::dl_interface(datalog::context& dl_ctx) :
|
||||
engine_base(dl_ctx.get_manager(), "duality"),
|
||||
m_ctx(dl_ctx)
|
||||
|
||||
{
|
||||
_d = 0;
|
||||
// dl_ctx.get_manager().toggle_proof_mode(PGM_FINE);
|
||||
}
|
||||
|
||||
|
||||
dl_interface::~dl_interface() {
|
||||
if(_d)
|
||||
dealloc(_d);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Check if the new rules are weaker so that we can
|
||||
// re-use existing context.
|
||||
//
|
||||
#if 0
|
||||
void dl_interface::check_reset() {
|
||||
// TODO
|
||||
datalog::rule_ref_vector const& new_rules = m_ctx.get_rules().get_rules();
|
||||
datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules();
|
||||
bool is_subsumed = !old_rules.empty();
|
||||
for (unsigned i = 0; is_subsumed && i < new_rules.size(); ++i) {
|
||||
is_subsumed = false;
|
||||
for (unsigned j = 0; !is_subsumed && j < old_rules.size(); ++j) {
|
||||
if (m_ctx.check_subsumes(*old_rules[j], *new_rules[i])) {
|
||||
is_subsumed = true;
|
||||
}
|
||||
}
|
||||
if (!is_subsumed) {
|
||||
TRACE("pdr", new_rules[i]->display(m_ctx, tout << "Fresh rule "););
|
||||
m_context->reset();
|
||||
}
|
||||
}
|
||||
m_old_rules.reset();
|
||||
m_old_rules.add_rules(new_rules.size(), new_rules.c_ptr());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
lbool dl_interface::query(::expr * query) {
|
||||
|
||||
// we restore the initial state in the datalog context
|
||||
m_ctx.ensure_opened();
|
||||
|
||||
// if there is old data, get the cex and dispose (later)
|
||||
Solver::Counterexample old_cex;
|
||||
duality_data *old_data = _d;
|
||||
if(old_data)
|
||||
old_cex = old_data->cex;
|
||||
|
||||
scoped_proof generate_proofs_please(m_ctx.get_manager());
|
||||
|
||||
// make a new problem and solver
|
||||
_d = alloc(duality_data,m_ctx.get_manager());
|
||||
_d->ls = alloc(RPFP::iZ3LogicSolver,_d->ctx);
|
||||
_d->rpfp = alloc(RPFP,_d->ls);
|
||||
|
||||
|
||||
|
||||
expr_ref_vector rules(m_ctx.get_manager());
|
||||
svector< ::symbol> names;
|
||||
// m_ctx.get_rules_as_formulas(rules, names);
|
||||
m_ctx.get_raw_rule_formulas(rules, names);
|
||||
|
||||
// get all the rules as clauses
|
||||
std::vector<expr> &clauses = _d->clauses;
|
||||
clauses.clear();
|
||||
for (unsigned i = 0; i < rules.size(); ++i) {
|
||||
expr e(_d->ctx,rules[i].get());
|
||||
clauses.push_back(e);
|
||||
}
|
||||
|
||||
// turn the query into a clause
|
||||
expr q(_d->ctx,m_ctx.bind_variables(query,false));
|
||||
|
||||
std::vector<sort> b_sorts;
|
||||
std::vector<symbol> b_names;
|
||||
if (q.is_quantifier() && !q.is_quantifier_forall()) {
|
||||
int bound = q.get_quantifier_num_bound();
|
||||
for(int j = 0; j < bound; j++){
|
||||
b_sorts.push_back(q.get_quantifier_bound_sort(j));
|
||||
b_names.push_back(q.get_quantifier_bound_name(j));
|
||||
}
|
||||
q = q.arg(0);
|
||||
}
|
||||
|
||||
expr qc = implies(q,_d->ctx.bool_val(false));
|
||||
qc = _d->ctx.make_quant(Forall,b_sorts,b_names,qc);
|
||||
clauses.push_back(qc);
|
||||
|
||||
// get the background axioms
|
||||
unsigned num_asserts = m_ctx.get_num_assertions();
|
||||
for (unsigned i = 0; i < num_asserts; ++i) {
|
||||
expr e(_d->ctx,m_ctx.get_assertion(i));
|
||||
_d->rpfp->AssertAxiom(e);
|
||||
}
|
||||
|
||||
// creates 1-1 map between clauses and rpfp edges
|
||||
_d->rpfp->FromClauses(clauses);
|
||||
|
||||
// populate the edge-to-clause map
|
||||
for(unsigned i = 0; i < _d->rpfp->edges.size(); ++i)
|
||||
_d->map[_d->rpfp->edges[i]] = i;
|
||||
|
||||
// create a solver object
|
||||
|
||||
Solver *rs = Solver::Create("duality", _d->rpfp);
|
||||
|
||||
rs->LearnFrom(old_cex); // new solver gets hints from old cex
|
||||
|
||||
// set its options
|
||||
IF_VERBOSE(1, rs->SetOption("report","1"););
|
||||
rs->SetOption("full_expand",m_ctx.get_params().full_expand() ? "1" : "0");
|
||||
rs->SetOption("no_conj",m_ctx.get_params().no_conj() ? "1" : "0");
|
||||
rs->SetOption("feasible_edges",m_ctx.get_params().feasible_edges() ? "1" : "0");
|
||||
rs->SetOption("use_underapprox",m_ctx.get_params().use_underapprox() ? "1" : "0");
|
||||
rs->SetOption("stratified_inlining",m_ctx.get_params().stratified_inlining() ? "1" : "0");
|
||||
unsigned rb = m_ctx.get_params().recursion_bound();
|
||||
if(rb != UINT_MAX){
|
||||
std::ostringstream os; os << rb;
|
||||
rs->SetOption("recursion_bound", os.str());
|
||||
}
|
||||
|
||||
// Solve!
|
||||
bool ans;
|
||||
try {
|
||||
ans = rs->Solve();
|
||||
}
|
||||
catch (Duality::solver::cancel_exception &exn){
|
||||
throw default_exception("duality canceled");
|
||||
}
|
||||
|
||||
// profile!
|
||||
|
||||
if(m_ctx.get_params().profile())
|
||||
print_profile(std::cout);
|
||||
|
||||
// save the result and counterexample if there is one
|
||||
_d->status = ans ? StatusModel : StatusRefutation;
|
||||
_d->cex = rs->GetCounterexample();
|
||||
|
||||
if(old_data){
|
||||
old_data->cex.tree = 0; // we own it now
|
||||
dealloc(old_data);
|
||||
}
|
||||
|
||||
|
||||
dealloc(rs);
|
||||
|
||||
// true means the RPFP problem is SAT, so the query is UNSAT
|
||||
return ans ? l_false : l_true;
|
||||
}
|
||||
|
||||
expr_ref dl_interface::get_cover_delta(int level, ::func_decl* pred_orig) {
|
||||
SASSERT(false);
|
||||
return expr_ref(m_ctx.get_manager());
|
||||
}
|
||||
|
||||
void dl_interface::add_cover(int level, ::func_decl* pred, ::expr* property) {
|
||||
SASSERT(false);
|
||||
}
|
||||
|
||||
unsigned dl_interface::get_num_levels(::func_decl* pred) {
|
||||
SASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dl_interface::collect_statistics(::statistics& st) const {
|
||||
}
|
||||
|
||||
void dl_interface::reset_statistics() {
|
||||
}
|
||||
|
||||
static hash_set<func_decl> *local_func_decls;
|
||||
|
||||
static void print_proof(dl_interface *d, std::ostream& out, Solver::Counterexample &cex) {
|
||||
context &ctx = d->dd()->ctx;
|
||||
RPFP::Node &node = *cex.root;
|
||||
RPFP::Edge &edge = *node.Outgoing;
|
||||
|
||||
// first, prove the children (that are actually used)
|
||||
|
||||
for(unsigned i = 0; i < edge.Children.size(); i++){
|
||||
if(!cex.tree->Empty(edge.Children[i])){
|
||||
Solver::Counterexample foo = cex;
|
||||
foo.root = edge.Children[i];
|
||||
print_proof(d,out,foo);
|
||||
}
|
||||
}
|
||||
|
||||
// print the label and the proved fact
|
||||
|
||||
out << "(step s!" << node.number;
|
||||
out << " (" << node.Name.name();
|
||||
for(unsigned i = 0; i < edge.F.IndParams.size(); i++)
|
||||
out << " " << cex.tree->Eval(&edge,edge.F.IndParams[i]);
|
||||
out << ")\n";
|
||||
|
||||
// print the rule number
|
||||
|
||||
out << " rule!" << node.Outgoing->map->number;
|
||||
|
||||
// print the substitution
|
||||
|
||||
out << " (subst\n";
|
||||
RPFP::Edge *orig_edge = edge.map;
|
||||
int orig_clause = d->dd()->map[orig_edge];
|
||||
expr &t = d->dd()->clauses[orig_clause];
|
||||
if (t.is_quantifier() && t.is_quantifier_forall()) {
|
||||
int bound = t.get_quantifier_num_bound();
|
||||
std::vector<sort> sorts;
|
||||
std::vector<symbol> names;
|
||||
hash_map<int,expr> subst;
|
||||
for(int j = 0; j < bound; j++){
|
||||
sort the_sort = t.get_quantifier_bound_sort(j);
|
||||
symbol name = t.get_quantifier_bound_name(j);
|
||||
expr skolem = ctx.constant(symbol(ctx,name),sort(ctx,the_sort));
|
||||
out << " (= " << skolem << " " << cex.tree->Eval(&edge,skolem) << ")\n";
|
||||
expr local_skolem = cex.tree->Localize(&edge,skolem);
|
||||
(*local_func_decls).insert(local_skolem.decl());
|
||||
}
|
||||
}
|
||||
out << " )\n";
|
||||
|
||||
out << " (labels";
|
||||
std::vector<symbol> labels;
|
||||
cex.tree->GetLabels(&edge,labels);
|
||||
for(unsigned j = 0; j < labels.size(); j++){
|
||||
out << " " << labels[j];
|
||||
}
|
||||
|
||||
out << " )\n";
|
||||
|
||||
// reference the proofs of all the children, in syntactic order
|
||||
// "true" means the child is not needed
|
||||
|
||||
out << " (ref ";
|
||||
for(unsigned i = 0; i < edge.Children.size(); i++){
|
||||
if(!cex.tree->Empty(edge.Children[i]))
|
||||
out << " s!" << edge.Children[i]->number;
|
||||
else
|
||||
out << " true";
|
||||
}
|
||||
out << " )";
|
||||
out << ")\n";
|
||||
}
|
||||
|
||||
|
||||
void dl_interface::display_certificate(std::ostream& out) const {
|
||||
((dl_interface *)this)->display_certificate_non_const(out);
|
||||
}
|
||||
|
||||
void dl_interface::display_certificate_non_const(std::ostream& out) {
|
||||
if(_d->status == StatusModel){
|
||||
ast_manager &m = m_ctx.get_manager();
|
||||
model_ref md = get_model();
|
||||
model_smt2_pp(out, m, *md.get(), 0);
|
||||
}
|
||||
else if(_d->status == StatusRefutation){
|
||||
out << "(derivation\n";
|
||||
// negation of the query is the last clause -- prove it
|
||||
hash_set<func_decl> locals;
|
||||
local_func_decls = &locals;
|
||||
print_proof(this,out,_d->cex);
|
||||
out << ")\n";
|
||||
out << "(model \n\"";
|
||||
::model mod(m_ctx.get_manager());
|
||||
model orig_model = _d->cex.tree->dualModel;
|
||||
for(unsigned i = 0; i < orig_model.num_consts(); i++){
|
||||
func_decl cnst = orig_model.get_const_decl(i);
|
||||
if(locals.find(cnst) == locals.end()){
|
||||
expr thing = orig_model.get_const_interp(cnst);
|
||||
mod.register_decl(to_func_decl(cnst.raw()),to_expr(thing.raw()));
|
||||
}
|
||||
}
|
||||
for(unsigned i = 0; i < orig_model.num_funcs(); i++){
|
||||
func_decl cnst = orig_model.get_func_decl(i);
|
||||
if(locals.find(cnst) == locals.end()){
|
||||
func_interp thing = orig_model.get_func_interp(cnst);
|
||||
::func_interp *thing_raw = thing;
|
||||
mod.register_decl(to_func_decl(cnst.raw()),thing_raw->copy());
|
||||
}
|
||||
}
|
||||
model_v2_pp(out,mod);
|
||||
out << "\")\n";
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref dl_interface::get_answer() {
|
||||
SASSERT(false);
|
||||
return expr_ref(m_ctx.get_manager());
|
||||
}
|
||||
|
||||
void dl_interface::cancel() {
|
||||
#if 0
|
||||
if(_d && _d->ls)
|
||||
_d->ls->cancel();
|
||||
#else
|
||||
// HACK: duality can't cancel at all times, we just exit here
|
||||
std::cout << "(error \"duality canceled\")\nunknown\n";
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void dl_interface::cleanup() {
|
||||
}
|
||||
|
||||
void dl_interface::updt_params() {
|
||||
}
|
||||
|
||||
model_ref dl_interface::get_model() {
|
||||
ast_manager &m = m_ctx.get_manager();
|
||||
model_ref md(alloc(::model, m));
|
||||
std::vector<RPFP::Node *> &nodes = _d->rpfp->nodes;
|
||||
expr_ref_vector conjs(m);
|
||||
for (unsigned i = 0; i < nodes.size(); ++i) {
|
||||
RPFP::Node *node = nodes[i];
|
||||
func_decl &pred = node->Name;
|
||||
expr_ref prop(m);
|
||||
prop = to_expr(node->Annotation.Formula);
|
||||
std::vector<expr> ¶ms = node->Annotation.IndParams;
|
||||
expr_ref q(m);
|
||||
expr_ref_vector sig_vars(m);
|
||||
for (unsigned j = 0; j < params.size(); ++j)
|
||||
sig_vars.push_back(params[params.size()-j-1]); // TODO: why backwards?
|
||||
expr_abstract(m, 0, sig_vars.size(), sig_vars.c_ptr(), prop, q);
|
||||
if (params.empty()) {
|
||||
md->register_decl(pred, q);
|
||||
}
|
||||
else {
|
||||
::func_interp* fi = alloc(::func_interp, m, params.size());
|
||||
fi->set_else(q);
|
||||
md->register_decl(pred, fi);
|
||||
}
|
||||
}
|
||||
return md;
|
||||
}
|
||||
|
||||
static proof_ref extract_proof(dl_interface *d, Solver::Counterexample &cex) {
|
||||
context &ctx = d->dd()->ctx;
|
||||
ast_manager &mgr = ctx.m();
|
||||
RPFP::Node &node = *cex.root;
|
||||
RPFP::Edge &edge = *node.Outgoing;
|
||||
RPFP::Edge *orig_edge = edge.map;
|
||||
|
||||
// first, prove the children (that are actually used)
|
||||
|
||||
proof_ref_vector prems(mgr);
|
||||
::vector<expr_ref_vector> substs;
|
||||
int orig_clause = d->dd()->map[orig_edge];
|
||||
expr &t = d->dd()->clauses[orig_clause];
|
||||
prems.push_back(mgr.mk_asserted(ctx.uncook(t)));
|
||||
|
||||
substs.push_back(expr_ref_vector(mgr));
|
||||
if (t.is_quantifier() && t.is_quantifier_forall()) {
|
||||
int bound = t.get_quantifier_num_bound();
|
||||
std::vector<sort> sorts;
|
||||
std::vector<symbol> names;
|
||||
hash_map<int,expr> subst;
|
||||
for(int j = 0; j < bound; j++){
|
||||
sort the_sort = t.get_quantifier_bound_sort(j);
|
||||
symbol name = t.get_quantifier_bound_name(j);
|
||||
expr skolem = ctx.constant(symbol(ctx,name),sort(ctx,the_sort));
|
||||
expr val = cex.tree->Eval(&edge,skolem);
|
||||
expr_ref thing(ctx.uncook(val),mgr);
|
||||
substs[0].push_back(thing);
|
||||
expr local_skolem = cex.tree->Localize(&edge,skolem);
|
||||
(*local_func_decls).insert(local_skolem.decl());
|
||||
}
|
||||
}
|
||||
|
||||
svector<std::pair<unsigned, unsigned> > pos;
|
||||
for(unsigned i = 0; i < edge.Children.size(); i++){
|
||||
if(!cex.tree->Empty(edge.Children[i])){
|
||||
pos.push_back(std::pair<unsigned,unsigned>(i+1,0));
|
||||
Solver::Counterexample foo = cex;
|
||||
foo.root = edge.Children[i];
|
||||
proof_ref prem = extract_proof(d,foo);
|
||||
prems.push_back(prem);
|
||||
substs.push_back(expr_ref_vector(mgr));
|
||||
}
|
||||
}
|
||||
|
||||
func_decl f = node.Name;
|
||||
std::vector<expr> args;
|
||||
for(unsigned i = 0; i < edge.F.IndParams.size(); i++)
|
||||
args.push_back(cex.tree->Eval(&edge,edge.F.IndParams[i]));
|
||||
expr conc = f(args);
|
||||
|
||||
|
||||
::vector< ::proof *> pprems;
|
||||
for(unsigned i = 0; i < prems.size(); i++)
|
||||
pprems.push_back(prems[i].get());
|
||||
|
||||
proof_ref res(mgr.mk_hyper_resolve(pprems.size(),&pprems[0], ctx.uncook(conc), pos, substs),mgr);
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
proof_ref dl_interface::get_proof() {
|
||||
if(_d->status == StatusRefutation){
|
||||
hash_set<func_decl> locals;
|
||||
local_func_decls = &locals;
|
||||
return extract_proof(this,_d->cex);
|
||||
}
|
||||
else
|
||||
return proof_ref(m_ctx.get_manager());
|
||||
}
|
||||
}
|
80
src/muz/duality/duality_dl_interface.h
Normal file
80
src/muz/duality/duality_dl_interface.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
duality_dl_interface.h
|
||||
|
||||
Abstract:
|
||||
|
||||
SMT2 interface for Duality
|
||||
|
||||
Author:
|
||||
|
||||
Krystof Hoder (t-khoder) 2011-9-22.
|
||||
Modified by Ken McMIllan (kenmcmil) 2013-4-18.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _DUALITY_DL_INTERFACE_H_
|
||||
#define _DUALITY_DL_INTERFACE_H_
|
||||
|
||||
#include "lbool.h"
|
||||
#include "dl_rule.h"
|
||||
#include "dl_rule_set.h"
|
||||
#include "dl_engine_base.h"
|
||||
#include "statistics.h"
|
||||
|
||||
namespace datalog {
|
||||
class context;
|
||||
}
|
||||
|
||||
namespace Duality {
|
||||
|
||||
class duality_data;
|
||||
|
||||
class dl_interface : public datalog::engine_base {
|
||||
duality_data *_d;
|
||||
datalog::context &m_ctx;
|
||||
|
||||
public:
|
||||
dl_interface(datalog::context& ctx);
|
||||
~dl_interface();
|
||||
|
||||
lbool query(expr* query);
|
||||
|
||||
void cancel();
|
||||
|
||||
void cleanup();
|
||||
|
||||
void display_certificate(std::ostream& out) const;
|
||||
|
||||
void collect_statistics(statistics& st) const;
|
||||
|
||||
void reset_statistics();
|
||||
|
||||
expr_ref get_answer();
|
||||
|
||||
unsigned get_num_levels(func_decl* pred);
|
||||
|
||||
expr_ref get_cover_delta(int level, func_decl* pred);
|
||||
|
||||
void add_cover(int level, func_decl* pred, expr* property);
|
||||
|
||||
void updt_params();
|
||||
|
||||
model_ref get_model();
|
||||
|
||||
proof_ref get_proof();
|
||||
|
||||
duality_data *dd(){return _d;}
|
||||
|
||||
private:
|
||||
void display_certificate_non_const(std::ostream& out);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -454,6 +454,44 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief fixedpoint-push command.
|
||||
*/
|
||||
class dl_push_cmd : public cmd {
|
||||
ref<dl_context> m_dl_ctx;
|
||||
public:
|
||||
dl_push_cmd(dl_context * dl_ctx):
|
||||
cmd("fixedpoint-push"),
|
||||
m_dl_ctx(dl_ctx)
|
||||
{}
|
||||
|
||||
virtual char const * get_usage() const { return ""; }
|
||||
virtual char const * get_descr(cmd_context & ctx) const { return "push the fixedpoint context"; }
|
||||
virtual unsigned get_arity() const { return 0; }
|
||||
virtual void execute(cmd_context & ctx) {
|
||||
m_dl_ctx->push();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief fixedpoint-pop command.
|
||||
*/
|
||||
class dl_pop_cmd : public cmd {
|
||||
ref<dl_context> m_dl_ctx;
|
||||
public:
|
||||
dl_pop_cmd(dl_context * dl_ctx):
|
||||
cmd("fixedpoint-pop"),
|
||||
m_dl_ctx(dl_ctx)
|
||||
{}
|
||||
|
||||
virtual char const * get_usage() const { return ""; }
|
||||
virtual char const * get_descr(cmd_context & ctx) const { return "pop the fixedpoint context"; }
|
||||
virtual unsigned get_arity() const { return 0; }
|
||||
virtual void execute(cmd_context & ctx) {
|
||||
m_dl_ctx->pop();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_cmds) {
|
||||
dl_context * dl_ctx = alloc(dl_context, ctx, collected_cmds);
|
||||
|
@ -461,6 +499,13 @@ static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_c
|
|||
ctx.insert(alloc(dl_query_cmd, dl_ctx));
|
||||
ctx.insert(alloc(dl_declare_rel_cmd, dl_ctx));
|
||||
ctx.insert(alloc(dl_declare_var_cmd, dl_ctx));
|
||||
// #ifndef _EXTERNAL_RELEASE
|
||||
// TODO: we need these!
|
||||
#if 1
|
||||
ctx.insert(alloc(dl_push_cmd, dl_ctx)); // not exposed to keep command-extensions simple.
|
||||
ctx.insert(alloc(dl_pop_cmd, dl_ctx));
|
||||
#endif
|
||||
// #endif
|
||||
}
|
||||
|
||||
void install_dl_cmds(cmd_context & ctx) {
|
||||
|
|
|
@ -22,6 +22,7 @@ Revision History:
|
|||
#include "tab_context.h"
|
||||
#include "rel_context.h"
|
||||
#include "pdr_dl_interface.h"
|
||||
#include "duality_dl_interface.h"
|
||||
|
||||
namespace datalog {
|
||||
register_engine::register_engine(): m_ctx(0) {}
|
||||
|
@ -40,6 +41,8 @@ namespace datalog {
|
|||
return alloc(tab, *m_ctx);
|
||||
case CLP_ENGINE:
|
||||
return alloc(clp, *m_ctx);
|
||||
case DUALITY_ENGINE:
|
||||
return alloc(Duality::dl_interface, *m_ctx);
|
||||
case LAST_ENGINE:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
|
|
|
@ -1125,9 +1125,7 @@ namespace pdr {
|
|||
n->mk_instantiate(r0, r1, binding);
|
||||
proof_ref p1(m), p2(m);
|
||||
p1 = r0->get_proof();
|
||||
if (!p1) {
|
||||
r0->display(dctx, std::cout);
|
||||
}
|
||||
IF_VERBOSE(0, if (!p1) r0->display(dctx, verbose_stream()););
|
||||
SASSERT(p1);
|
||||
pfs[0] = p1;
|
||||
rls[0] = r1;
|
||||
|
|
|
@ -19,6 +19,7 @@ Revision History:
|
|||
|
||||
#include "dl_mk_array_blast.h"
|
||||
#include "qe_util.h"
|
||||
#include "scoped_proof.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
|
@ -270,7 +271,7 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
|
||||
expr_ref fml2(m), body(m), head(m);
|
||||
expr_ref fml1(m), fml2(m), body(m), head(m);
|
||||
body = m.mk_and(new_conjs.size(), new_conjs.c_ptr());
|
||||
head = r.get_head();
|
||||
sub(body);
|
||||
|
@ -287,9 +288,17 @@ namespace datalog {
|
|||
proof_ref p(m);
|
||||
rule_set new_rules(m_ctx);
|
||||
rm.mk_rule(fml2, p, new_rules, r.name());
|
||||
|
||||
|
||||
rule_ref new_rule(rm);
|
||||
if (m_simplifier.transform_rule(new_rules.last(), new_rule)) {
|
||||
if (r.get_proof()) {
|
||||
scoped_proof _sc(m);
|
||||
r.to_formula(fml1);
|
||||
p = m.mk_rewrite(fml1, fml2);
|
||||
p = m.mk_modus_ponens(r.get_proof(), p);
|
||||
new_rule->set_proof(m, p);
|
||||
}
|
||||
rules.add_rule(new_rule.get());
|
||||
rm.mk_rule_rewrite_proof(r, *new_rule.get());
|
||||
TRACE("dl", new_rule->display(m_ctx, tout << "new rule\n"););
|
||||
|
|
|
@ -25,6 +25,7 @@ Revision History:
|
|||
#include "filter_model_converter.h"
|
||||
#include "dl_mk_interp_tail_simplifier.h"
|
||||
#include "fixedpoint_params.hpp"
|
||||
#include "scoped_proof.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
|
@ -268,7 +269,8 @@ namespace datalog {
|
|||
r->to_formula(fml);
|
||||
if (blast(r, fml)) {
|
||||
proof_ref pr(m);
|
||||
if (m_context.generate_proof_trace()) {
|
||||
if (r->get_proof()) {
|
||||
scoped_proof _sc(m);
|
||||
pr = m.mk_asserted(fml); // loses original proof of r.
|
||||
}
|
||||
// TODO add logic for pc:
|
||||
|
|
|
@ -341,7 +341,6 @@ namespace datalog {
|
|||
}
|
||||
head = mk_head(source, *result, r.get_head(), cnt);
|
||||
fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), head);
|
||||
rule_ref_vector added_rules(rm);
|
||||
proof_ref pr(m);
|
||||
rm.mk_rule(fml, pr, *result);
|
||||
TRACE("dl", result->last()->display(m_ctx, tout););
|
||||
|
|
|
@ -527,6 +527,9 @@ namespace datalog {
|
|||
|
||||
|
||||
bool mk_rule_inliner::do_eager_inlining(rule * r, rule_set const& rules, rule_ref& res) {
|
||||
if (r->has_negation()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SASSERT(rules.is_closed());
|
||||
const rule_stratifier& strat = rules.get_stratifier();
|
||||
|
|
|
@ -416,6 +416,9 @@ namespace opt {
|
|||
if (m_engine == symbol("wpm2")) {
|
||||
return wpm2_solve();
|
||||
}
|
||||
if (m_engine == symbol("wpm2b")) {
|
||||
return wpm2b_solve();
|
||||
}
|
||||
return incremental_solve();
|
||||
}
|
||||
|
||||
|
@ -664,12 +667,6 @@ namespace opt {
|
|||
m_lower = m_upper = rational::zero();
|
||||
obj_map<expr, unsigned> ans_index;
|
||||
|
||||
#ifdef WPM2b
|
||||
// change from CP'13
|
||||
for (unsigned i = 0; i < s.get_num_assertions(); ++i) {
|
||||
al.push_back(s.get_assertion(i));
|
||||
}
|
||||
#endif
|
||||
vector<rational> amk;
|
||||
vector<uint_set> sc;
|
||||
for (unsigned i = 0; i < m_soft.size(); ++i) {
|
||||
|
@ -758,10 +755,7 @@ namespace opt {
|
|||
}
|
||||
}
|
||||
rational k;
|
||||
std::cout << "new bound";
|
||||
is_sat = new_bound(al, ws, bs, k);
|
||||
std::cout << " " << k << "\n";
|
||||
std::cout.flush();
|
||||
if (is_sat != l_true) {
|
||||
return is_sat;
|
||||
}
|
||||
|
@ -783,6 +777,177 @@ namespace opt {
|
|||
amk.push_back(k);
|
||||
}
|
||||
}
|
||||
|
||||
// Version from CP'13
|
||||
lbool wpm2b_solve() {
|
||||
solver::scoped_push _s(s);
|
||||
pb_util u(m);
|
||||
app_ref fml(m), a(m), b(m), c(m);
|
||||
expr_ref val(m);
|
||||
expr_ref_vector block(m), ans(m), am(m), soft(m);
|
||||
m_lower = m_upper = rational::zero();
|
||||
obj_map<expr, unsigned> ans_index;
|
||||
|
||||
vector<rational> amk;
|
||||
vector<uint_set> sc; // vector of indices used in at last constraints
|
||||
expr_ref_vector al(m); // vector of at least constraints.
|
||||
rational wmax;
|
||||
for (unsigned i = 0; i < m_soft.size(); ++i) {
|
||||
rational w = m_weights[i];
|
||||
m_upper += w;
|
||||
if (wmax < w) wmax = w;
|
||||
b = m.mk_fresh_const("b", m.mk_bool_sort());
|
||||
expr* bb = b;
|
||||
s.mc().insert(b->get_decl());
|
||||
a = m.mk_fresh_const("a", m.mk_bool_sort());
|
||||
s.mc().insert(a->get_decl());
|
||||
ans.push_back(a);
|
||||
ans_index.insert(a, i);
|
||||
soft.push_back(0); // assert soft constraints lazily.
|
||||
|
||||
c = m.mk_fresh_const("c", m.mk_bool_sort());
|
||||
s.mc().insert(c->get_decl());
|
||||
fml = m.mk_implies(c, u.mk_le(1,&w,&bb,rational(0)));
|
||||
s.assert_expr(fml);
|
||||
|
||||
sc.push_back(uint_set());
|
||||
sc.back().insert(i);
|
||||
am.push_back(c);
|
||||
|
||||
al.push_back(u.mk_ge(1,&w,&bb,rational(0)));
|
||||
s.assert_expr(al.back());
|
||||
|
||||
amk.push_back(rational(0));
|
||||
}
|
||||
++wmax;
|
||||
|
||||
while (true) {
|
||||
enable_soft(soft, block, ans, wmax);
|
||||
expr_ref_vector asms(m);
|
||||
asms.append(ans);
|
||||
asms.append(am);
|
||||
lbool is_sat = s.check_sat(asms.size(), asms.c_ptr());
|
||||
if (m_cancel && is_sat != l_false) {
|
||||
is_sat = l_undef;
|
||||
}
|
||||
if (is_sat == l_undef) {
|
||||
return l_undef;
|
||||
}
|
||||
if (is_sat == l_true && wmax.is_zero()) {
|
||||
s.get_model(m_model);
|
||||
m_upper = m_lower;
|
||||
for (unsigned i = 0; i < block.size(); ++i) {
|
||||
VERIFY(m_model->eval(block[i].get(), val));
|
||||
m_assignment[i] = m.is_false(val);
|
||||
}
|
||||
return l_true;
|
||||
}
|
||||
if (is_sat == l_true) {
|
||||
rational W(0);
|
||||
for (unsigned i = 0; i < m_weights.size(); ++i) {
|
||||
if (m_weights[i] < wmax) W += m_weights[i];
|
||||
}
|
||||
harden(am, W);
|
||||
wmax = decrease(wmax);
|
||||
continue;
|
||||
}
|
||||
SASSERT(is_sat == l_false);
|
||||
ptr_vector<expr> core;
|
||||
s.get_unsat_core(core);
|
||||
if (core.empty()) {
|
||||
return l_false;
|
||||
}
|
||||
uint_set A;
|
||||
for (unsigned i = 0; i < core.size(); ++i) {
|
||||
unsigned j;
|
||||
if (ans_index.find(core[i], j) && soft[j].get()) {
|
||||
A.insert(j);
|
||||
}
|
||||
}
|
||||
if (A.empty()) {
|
||||
return l_false;
|
||||
}
|
||||
uint_set B;
|
||||
for (unsigned i = 0; i < sc.size(); ++i) {
|
||||
uint_set t(sc[i]);
|
||||
t &= A;
|
||||
if (!t.empty()) {
|
||||
B |= sc[i];
|
||||
m_lower -= amk[i];
|
||||
sc[i] = sc.back();
|
||||
sc.pop_back();
|
||||
am[i] = am.back();
|
||||
am.pop_back();
|
||||
amk[i] = amk.back();
|
||||
amk.pop_back();
|
||||
--i;
|
||||
}
|
||||
}
|
||||
vector<rational> ws;
|
||||
expr_ref_vector bs(m);
|
||||
for (unsigned i = 0; i < m_soft.size(); ++i) {
|
||||
if (B.contains(i)) {
|
||||
ws.push_back(m_weights[i]);
|
||||
bs.push_back(block[i].get());
|
||||
}
|
||||
}
|
||||
rational k;
|
||||
|
||||
expr_ref_vector al2(al);
|
||||
for (unsigned i = 0; i < s.get_num_assertions(); ++i) {
|
||||
al2.push_back(s.get_assertion(i));
|
||||
}
|
||||
is_sat = new_bound(al2, ws, bs, k);
|
||||
if (is_sat != l_true) {
|
||||
return is_sat;
|
||||
}
|
||||
m_lower += k;
|
||||
expr_ref B_le_k(m), B_ge_k(m);
|
||||
B_le_k = u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k);
|
||||
B_ge_k = u.mk_ge(ws.size(), ws.c_ptr(), bs.c_ptr(), k);
|
||||
s.assert_expr(B_ge_k);
|
||||
al.push_back(B_ge_k);
|
||||
IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2 lower bound: " << m_lower << ")\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "New lower bound: " << B_ge_k << "\n";);
|
||||
|
||||
c = m.mk_fresh_const("c", m.mk_bool_sort());
|
||||
s.mc().insert(c->get_decl());
|
||||
fml = m.mk_implies(c, B_le_k);
|
||||
s.assert_expr(fml);
|
||||
sc.push_back(B);
|
||||
am.push_back(c);
|
||||
amk.push_back(k);
|
||||
}
|
||||
}
|
||||
|
||||
void harden(expr_ref_vector& am, rational const& W) {
|
||||
// TBD
|
||||
}
|
||||
|
||||
rational decrease(rational const& wmax) {
|
||||
rational wmin(0);
|
||||
for (unsigned i = 0; i < m_weights.size(); ++i) {
|
||||
rational w = m_weights[i];
|
||||
if (w < wmax && wmin < w) wmin = w;
|
||||
}
|
||||
return wmin;
|
||||
}
|
||||
|
||||
|
||||
// enable soft constraints that have reached wmax.
|
||||
void enable_soft(expr_ref_vector& soft,
|
||||
expr_ref_vector const& block,
|
||||
expr_ref_vector const& ans,
|
||||
rational wmax) {
|
||||
for (unsigned i = 0; i < m_soft.size(); ++i) {
|
||||
rational w = m_weights[i];
|
||||
if (w >= wmax && !soft[i].get()) {
|
||||
soft[i] = m.mk_or(m_soft[i].get(), block[i], m.mk_not(ans[i]));
|
||||
s.assert_expr(soft[i].get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lbool new_bound(expr_ref_vector const& al,
|
||||
vector<rational> const& ws,
|
||||
|
|
|
@ -9,7 +9,7 @@ Abstract:
|
|||
|
||||
SAT simplification procedures that use a "full" occurrence list:
|
||||
Subsumption, Blocked Clause Removal, Variable Elimination, ...
|
||||
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
|
@ -54,21 +54,21 @@ namespace sat {
|
|||
m_use_list[l2.index()].erase(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
simplifier::simplifier(solver & _s, params_ref const & p):
|
||||
s(_s),
|
||||
m_num_calls(0) {
|
||||
updt_params(p);
|
||||
reset_statistics();
|
||||
}
|
||||
|
||||
|
||||
simplifier::~simplifier() {
|
||||
}
|
||||
|
||||
inline watch_list & simplifier::get_wlist(literal l) { return s.get_wlist(l); }
|
||||
|
||||
inline watch_list const & simplifier::get_wlist(literal l) const { return s.get_wlist(l); }
|
||||
|
||||
|
||||
inline bool simplifier::is_external(bool_var v) const { return s.is_external(v); }
|
||||
|
||||
inline bool simplifier::was_eliminated(bool_var v) const { return s.was_eliminated(v); }
|
||||
|
@ -78,7 +78,7 @@ namespace sat {
|
|||
lbool simplifier::value(literal l) const { return s.value(l); }
|
||||
|
||||
inline void simplifier::checkpoint() { s.checkpoint(); }
|
||||
|
||||
|
||||
void simplifier::register_clauses(clause_vector & cs) {
|
||||
std::stable_sort(cs.begin(), cs.end(), size_lt());
|
||||
clause_vector::iterator it = cs.begin();
|
||||
|
@ -117,7 +117,7 @@ namespace sat {
|
|||
SASSERT(s.get_wlist(~l1).contains(watched(l2, learned)));
|
||||
s.get_wlist(~l1).erase(watched(l2, learned));
|
||||
}
|
||||
|
||||
|
||||
void simplifier::init_visited() {
|
||||
m_visited.reset();
|
||||
m_visited.resize(2*s.num_vars(), false);
|
||||
|
@ -155,7 +155,7 @@ namespace sat {
|
|||
|
||||
if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls))
|
||||
elim_blocked_clauses();
|
||||
|
||||
|
||||
if (!learned)
|
||||
m_num_calls++;
|
||||
|
||||
|
@ -180,6 +180,7 @@ namespace sat {
|
|||
bool vars_eliminated = m_num_elim_vars > old_num_elim_vars;
|
||||
|
||||
if (!m_need_cleanup) {
|
||||
TRACE("after_simplifier", tout << "skipping cleanup...\n";);
|
||||
if (vars_eliminated) {
|
||||
// must remove learned clauses with eliminated variables
|
||||
cleanup_clauses(s.m_learned, true, true, learned_in_use_lists);
|
||||
|
@ -189,6 +190,7 @@ namespace sat {
|
|||
free_memory();
|
||||
return;
|
||||
}
|
||||
TRACE("after_simplifier", tout << "cleanning watches...\n";);
|
||||
cleanup_watches();
|
||||
cleanup_clauses(s.m_learned, true, vars_eliminated, learned_in_use_lists);
|
||||
cleanup_clauses(s.m_clauses, false, vars_eliminated, true);
|
||||
|
@ -234,7 +236,7 @@ namespace sat {
|
|||
s.del_clause(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (learned && vars_eliminated) {
|
||||
unsigned sz = c.size();
|
||||
unsigned i;
|
||||
|
@ -293,7 +295,7 @@ namespace sat {
|
|||
mark_visited(c[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void simplifier::unmark_all(clause const & c) {
|
||||
unsigned sz = c.size();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
|
@ -325,7 +327,7 @@ namespace sat {
|
|||
*/
|
||||
bool simplifier::subsumes1(clause const & c1, clause const & c2, literal & l) {
|
||||
unsigned sz2 = c2.size();
|
||||
for (unsigned i = 0; i < sz2; i++)
|
||||
for (unsigned i = 0; i < sz2; i++)
|
||||
mark_visited(c2[i]);
|
||||
|
||||
bool r = true;
|
||||
|
@ -344,7 +346,7 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < sz2; i++)
|
||||
for (unsigned i = 0; i < sz2; i++)
|
||||
unmark_visited(c2[i]);
|
||||
return r;
|
||||
}
|
||||
|
@ -353,7 +355,7 @@ namespace sat {
|
|||
\brief Return the clauses subsumed by c1 and the clauses that can be subsumed resolved using c1.
|
||||
The collections is populated using the use list of target.
|
||||
*/
|
||||
void simplifier::collect_subsumed1_core(clause const & c1, clause_vector & out, literal_vector & out_lits,
|
||||
void simplifier::collect_subsumed1_core(clause const & c1, clause_vector & out, literal_vector & out_lits,
|
||||
literal target) {
|
||||
clause_use_list const & cs = m_use_list.get(target);
|
||||
clause_use_list::iterator it = cs.mk_iterator();
|
||||
|
@ -362,7 +364,7 @@ namespace sat {
|
|||
CTRACE("resolution_bug", c2.was_removed(), tout << "clause has been removed:\n" << c2 << "\n";);
|
||||
SASSERT(!c2.was_removed());
|
||||
if (&c2 != &c1 &&
|
||||
c1.size() <= c2.size() &&
|
||||
c1.size() <= c2.size() &&
|
||||
approx_subset(c1.approx(), c2.approx())) {
|
||||
m_sub_counter -= c1.size() + c2.size();
|
||||
literal l;
|
||||
|
@ -373,7 +375,7 @@ namespace sat {
|
|||
}
|
||||
it.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the clauses subsumed by c1 and the clauses that can be subsumed resolved using c1.
|
||||
|
@ -400,12 +402,12 @@ namespace sat {
|
|||
if (*l_it == null_literal) {
|
||||
// c2 was subsumed
|
||||
if (c1.is_learned() && !c2.is_learned())
|
||||
c1.unset_learned();
|
||||
c1.unset_learned();
|
||||
TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";);
|
||||
remove_clause(c2);
|
||||
m_num_subsumed++;
|
||||
}
|
||||
else {
|
||||
else if (!c2.was_removed()) {
|
||||
// subsumption resolution
|
||||
TRACE("subsumption_resolution", tout << c1 << " sub-ref(" << *l_it << ") " << c2 << "\n";);
|
||||
elim_lit(c2, *l_it);
|
||||
|
@ -447,9 +449,9 @@ namespace sat {
|
|||
*/
|
||||
bool simplifier::subsumes0(clause const & c1, clause const & c2) {
|
||||
unsigned sz2 = c2.size();
|
||||
for (unsigned i = 0; i < sz2; i++)
|
||||
for (unsigned i = 0; i < sz2; i++)
|
||||
mark_visited(c2[i]);
|
||||
|
||||
|
||||
bool r = true;
|
||||
unsigned sz1 = c1.size();
|
||||
for (unsigned i = 0; i < sz1; i++) {
|
||||
|
@ -459,12 +461,12 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < sz2; i++)
|
||||
for (unsigned i = 0; i < sz2; i++)
|
||||
unmark_visited(c2[i]);
|
||||
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Collect the clauses subsumed by c1 (using the occurrence list of target).
|
||||
*/
|
||||
|
@ -475,7 +477,7 @@ namespace sat {
|
|||
clause & c2 = it.curr();
|
||||
SASSERT(!c2.was_removed());
|
||||
if (&c2 != &c1 &&
|
||||
c1.size() <= c2.size() &&
|
||||
c1.size() <= c2.size() &&
|
||||
approx_subset(c1.approx(), c2.approx())) {
|
||||
m_sub_counter -= c1.size() + c2.size();
|
||||
if (subsumes0(c1, c2)) {
|
||||
|
@ -485,7 +487,7 @@ namespace sat {
|
|||
it.next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Collect the clauses subsumed by c1
|
||||
*/
|
||||
|
@ -493,8 +495,8 @@ namespace sat {
|
|||
literal l = get_min_occ_var0(c1);
|
||||
collect_subsumed0_core(c1, out, l);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Perform backward subsumption using c1.
|
||||
*/
|
||||
|
@ -507,16 +509,16 @@ namespace sat {
|
|||
clause & c2 = *(*it);
|
||||
// c2 was subsumed
|
||||
if (c1.is_learned() && !c2.is_learned())
|
||||
c1.unset_learned();
|
||||
c1.unset_learned();
|
||||
TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";);
|
||||
remove_clause(c2);
|
||||
m_num_subsumed++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Eliminate false literals from c, and update occurrence lists
|
||||
|
||||
|
||||
Return true if the clause is satisfied
|
||||
*/
|
||||
bool simplifier::cleanup_clause(clause & c, bool in_use_list) {
|
||||
|
@ -666,7 +668,7 @@ namespace sat {
|
|||
back_subsumption1(c);
|
||||
if (w.is_learned() && !c.is_learned()) {
|
||||
SASSERT(wlist[j] == w);
|
||||
TRACE("mark_not_learned_bug",
|
||||
TRACE("mark_not_learned_bug",
|
||||
tout << "marking as not learned: " << l2 << " " << wlist[j].is_learned() << "\n";);
|
||||
wlist[j].mark_not_learned();
|
||||
mark_as_not_learned_core(get_wlist(~l2), l);
|
||||
|
@ -735,7 +737,7 @@ namespace sat {
|
|||
continue;
|
||||
}
|
||||
if (it2->get_literal() == last_lit) {
|
||||
TRACE("subsumption", tout << "eliminating: " << ~to_literal(l_idx)
|
||||
TRACE("subsumption", tout << "eliminating: " << ~to_literal(l_idx)
|
||||
<< " " << it2->get_literal() << "\n";);
|
||||
elim++;
|
||||
}
|
||||
|
@ -762,12 +764,12 @@ namespace sat {
|
|||
m_num_sub_res(s.m_num_sub_res) {
|
||||
m_watch.start();
|
||||
}
|
||||
|
||||
|
||||
~subsumption_report() {
|
||||
m_watch.stop();
|
||||
IF_VERBOSE(SAT_VB_LVL,
|
||||
IF_VERBOSE(SAT_VB_LVL,
|
||||
verbose_stream() << " (sat-subsumer :subsumed "
|
||||
<< (m_simplifier.m_num_subsumed - m_num_subsumed)
|
||||
<< (m_simplifier.m_num_subsumed - m_num_subsumed)
|
||||
<< " :subsumption-resolution " << (m_simplifier.m_num_sub_res - m_num_sub_res)
|
||||
<< " :threshold " << m_simplifier.m_sub_counter
|
||||
<< mem_stat()
|
||||
|
@ -847,12 +849,12 @@ namespace sat {
|
|||
vector<watch_list> const & m_watches;
|
||||
public:
|
||||
literal_lt(use_list const & l, vector<watch_list> const & ws):m_use_list(l), m_watches(ws) {}
|
||||
|
||||
|
||||
unsigned weight(unsigned l_idx) const {
|
||||
return 2*m_use_list.get(~to_literal(l_idx)).size() + m_watches[l_idx].size();
|
||||
}
|
||||
|
||||
bool operator()(unsigned l_idx1, unsigned l_idx2) const {
|
||||
|
||||
bool operator()(unsigned l_idx1, unsigned l_idx2) const {
|
||||
return weight(l_idx1) < weight(l_idx2);
|
||||
}
|
||||
};
|
||||
|
@ -861,9 +863,9 @@ namespace sat {
|
|||
heap<literal_lt> m_queue;
|
||||
public:
|
||||
queue(use_list const & l, vector<watch_list> const & ws):m_queue(128, literal_lt(l, ws)) {}
|
||||
void insert(literal l) {
|
||||
void insert(literal l) {
|
||||
unsigned idx = l.index();
|
||||
m_queue.reserve(idx + 1);
|
||||
m_queue.reserve(idx + 1);
|
||||
SASSERT(!m_queue.contains(idx));
|
||||
m_queue.insert(idx);
|
||||
}
|
||||
|
@ -877,14 +879,14 @@ namespace sat {
|
|||
literal next() { SASSERT(!empty()); return to_literal(m_queue.erase_min()); }
|
||||
bool empty() const { return m_queue.empty(); }
|
||||
};
|
||||
|
||||
|
||||
simplifier & s;
|
||||
int m_counter;
|
||||
model_converter & mc;
|
||||
queue m_queue;
|
||||
clause_vector m_to_remove;
|
||||
|
||||
blocked_clause_elim(simplifier & _s, unsigned limit, model_converter & _mc, use_list & l,
|
||||
blocked_clause_elim(simplifier & _s, unsigned limit, model_converter & _mc, use_list & l,
|
||||
vector<watch_list> & wlist):
|
||||
s(_s),
|
||||
m_counter(limit),
|
||||
|
@ -946,7 +948,7 @@ namespace sat {
|
|||
clause_vector::iterator it = m_to_remove.begin();
|
||||
clause_vector::iterator end = m_to_remove.end();
|
||||
for (; it != end; ++it) {
|
||||
s.remove_clause(*(*it));
|
||||
s.remove_clause(*(*it));
|
||||
}
|
||||
}
|
||||
{
|
||||
|
@ -1025,12 +1027,12 @@ namespace sat {
|
|||
m_num_blocked_clauses(s.m_num_blocked_clauses) {
|
||||
m_watch.start();
|
||||
}
|
||||
|
||||
|
||||
~blocked_cls_report() {
|
||||
m_watch.stop();
|
||||
IF_VERBOSE(SAT_VB_LVL,
|
||||
IF_VERBOSE(SAT_VB_LVL,
|
||||
verbose_stream() << " (sat-blocked-clauses :elim-blocked-clauses "
|
||||
<< (m_simplifier.m_num_blocked_clauses - m_num_blocked_clauses)
|
||||
<< (m_simplifier.m_num_blocked_clauses - m_num_blocked_clauses)
|
||||
<< mem_stat()
|
||||
<< " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
|
||||
}
|
||||
|
@ -1062,8 +1064,8 @@ namespace sat {
|
|||
unsigned num_neg = m_use_list.get(neg_l).size();
|
||||
unsigned num_bin_pos = get_num_non_learned_bin(pos_l);
|
||||
unsigned num_bin_neg = get_num_non_learned_bin(neg_l);
|
||||
unsigned cost = 2 * num_pos * num_neg + num_pos * num_bin_neg + num_neg * num_bin_pos;
|
||||
CTRACE("elim_vars_detail", cost == 0, tout << v << " num_pos: " << num_pos << " num_neg: " << num_neg << " num_bin_pos: " << num_bin_pos
|
||||
unsigned cost = 2 * num_pos * num_neg + num_pos * num_bin_neg + num_neg * num_bin_pos;
|
||||
CTRACE("elim_vars_detail", cost == 0, tout << v << " num_pos: " << num_pos << " num_neg: " << num_neg << " num_bin_pos: " << num_bin_pos
|
||||
<< " num_bin_neg: " << num_bin_neg << " cost: " << cost << "\n";);
|
||||
return cost;
|
||||
}
|
||||
|
@ -1071,7 +1073,7 @@ namespace sat {
|
|||
typedef std::pair<bool_var, unsigned> bool_var_and_cost;
|
||||
|
||||
struct bool_var_and_cost_lt {
|
||||
bool operator()(bool_var_and_cost const & p1, bool_var_and_cost const & p2) const { return p1.second < p2.second; }
|
||||
bool operator()(bool_var_and_cost const & p1, bool_var_and_cost const & p2) const { return p1.second < p2.second; }
|
||||
};
|
||||
|
||||
void simplifier::order_vars_for_elim(bool_var_vector & r) {
|
||||
|
@ -1104,7 +1106,7 @@ namespace sat {
|
|||
r.push_back(it2->first);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Collect clauses and binary clauses containing l.
|
||||
*/
|
||||
|
@ -1116,7 +1118,7 @@ namespace sat {
|
|||
SASSERT(r.back().size() == it.curr().size());
|
||||
it.next();
|
||||
}
|
||||
|
||||
|
||||
watch_list & wlist = get_wlist(~l);
|
||||
watch_list::iterator it2 = wlist.begin();
|
||||
watch_list::iterator end2 = wlist.end();
|
||||
|
@ -1129,7 +1131,7 @@ namespace sat {
|
|||
}
|
||||
|
||||
/**
|
||||
\brief Resolve clauses c1 and c2.
|
||||
\brief Resolve clauses c1 and c2.
|
||||
c1 must contain l.
|
||||
c2 must contain ~l.
|
||||
Store result in r.
|
||||
|
@ -1149,7 +1151,7 @@ namespace sat {
|
|||
m_visited[l2.index()] = true;
|
||||
r.push_back(l2);
|
||||
}
|
||||
|
||||
|
||||
literal not_l = ~l;
|
||||
sz = c2.size();
|
||||
m_elim_counter -= sz;
|
||||
|
@ -1164,7 +1166,7 @@ namespace sat {
|
|||
if (!m_visited[l2.index()])
|
||||
r.push_back(l2);
|
||||
}
|
||||
|
||||
|
||||
sz = c1.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
literal l2 = c1[i];
|
||||
|
@ -1200,7 +1202,7 @@ namespace sat {
|
|||
break;
|
||||
}
|
||||
}
|
||||
CTRACE("resolve_bug", it2 == end2,
|
||||
CTRACE("resolve_bug", it2 == end2,
|
||||
tout << ~l1 << " -> ";
|
||||
display(tout, s.m_cls_allocator, wlist1); tout << "\n" << ~l2 << " -> ";
|
||||
display(tout, s.m_cls_allocator, wlist2); tout << "\n";);
|
||||
|
@ -1262,7 +1264,7 @@ namespace sat {
|
|||
TRACE("resolution_bug", tout << "processing: " << v << "\n";);
|
||||
if (value(v) != l_undef)
|
||||
return false;
|
||||
|
||||
|
||||
literal pos_l(v, false);
|
||||
literal neg_l(v, true);
|
||||
unsigned num_bin_pos = get_num_non_learned_bin(pos_l);
|
||||
|
@ -1274,12 +1276,12 @@ namespace sat {
|
|||
m_elim_counter -= num_pos + num_neg;
|
||||
|
||||
TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << "\n";);
|
||||
|
||||
|
||||
if (num_pos >= m_res_occ_cutoff && num_neg >= m_res_occ_cutoff)
|
||||
return false;
|
||||
|
||||
unsigned before_lits = num_bin_pos*2 + num_bin_neg*2;
|
||||
|
||||
|
||||
{
|
||||
clause_use_list::iterator it = pos_occs.mk_iterator();
|
||||
while (!it.at_end()) {
|
||||
|
@ -1287,7 +1289,7 @@ namespace sat {
|
|||
it.next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
clause_use_list::iterator it2 = neg_occs.mk_iterator();
|
||||
while (!it2.at_end()) {
|
||||
|
@ -1297,23 +1299,23 @@ namespace sat {
|
|||
}
|
||||
|
||||
TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << " before_lits: " << before_lits << "\n";);
|
||||
|
||||
|
||||
if (num_pos >= m_res_occ_cutoff3 && num_neg >= m_res_occ_cutoff3 && before_lits > m_res_lit_cutoff3 && s.m_clauses.size() > m_res_cls_cutoff2)
|
||||
return false;
|
||||
if (num_pos >= m_res_occ_cutoff2 && num_neg >= m_res_occ_cutoff2 && before_lits > m_res_lit_cutoff2 &&
|
||||
if (num_pos >= m_res_occ_cutoff2 && num_neg >= m_res_occ_cutoff2 && before_lits > m_res_lit_cutoff2 &&
|
||||
s.m_clauses.size() > m_res_cls_cutoff1 && s.m_clauses.size() <= m_res_cls_cutoff2)
|
||||
return false;
|
||||
if (num_pos >= m_res_occ_cutoff1 && num_neg >= m_res_occ_cutoff1 && before_lits > m_res_lit_cutoff1 &&
|
||||
if (num_pos >= m_res_occ_cutoff1 && num_neg >= m_res_occ_cutoff1 && before_lits > m_res_lit_cutoff1 &&
|
||||
s.m_clauses.size() <= m_res_cls_cutoff1)
|
||||
return false;
|
||||
|
||||
|
||||
m_pos_cls.reset();
|
||||
m_neg_cls.reset();
|
||||
collect_clauses(pos_l, m_pos_cls);
|
||||
collect_clauses(neg_l, m_neg_cls);
|
||||
|
||||
|
||||
m_elim_counter -= num_pos * num_neg + before_lits;
|
||||
|
||||
|
||||
TRACE("resolution_detail", tout << "collecting number of after_clauses\n";);
|
||||
unsigned before_clauses = num_pos + num_neg;
|
||||
unsigned after_clauses = 0;
|
||||
|
@ -1350,7 +1352,7 @@ namespace sat {
|
|||
neg_occs.reset();
|
||||
|
||||
m_elim_counter -= num_pos * num_neg + before_lits;
|
||||
|
||||
|
||||
it1 = m_pos_cls.begin();
|
||||
end1 = m_pos_cls.end();
|
||||
for (; it1 != end1; ++it1) {
|
||||
|
@ -1393,7 +1395,7 @@ namespace sat {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1406,10 +1408,10 @@ namespace sat {
|
|||
m_num_elim_vars(s.m_num_elim_vars) {
|
||||
m_watch.start();
|
||||
}
|
||||
|
||||
|
||||
~elim_var_report() {
|
||||
m_watch.stop();
|
||||
IF_VERBOSE(SAT_VB_LVL,
|
||||
IF_VERBOSE(SAT_VB_LVL,
|
||||
verbose_stream() << " (sat-resolution :elim-bool-vars "
|
||||
<< (m_simplifier.m_num_elim_vars - m_num_elim_vars)
|
||||
<< " :threshold " << m_simplifier.m_elim_counter
|
||||
|
@ -1417,12 +1419,12 @@ namespace sat {
|
|||
<< " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void simplifier::elim_vars() {
|
||||
elim_var_report rpt(*this);
|
||||
bool_var_vector vars;
|
||||
order_vars_for_elim(vars);
|
||||
|
||||
|
||||
bool_var_vector::iterator it = vars.begin();
|
||||
bool_var_vector::iterator end = vars.end();
|
||||
for (; it != end; ++it) {
|
||||
|
@ -1463,7 +1465,7 @@ namespace sat {
|
|||
void simplifier::collect_param_descrs(param_descrs & r) {
|
||||
sat_simplifier_params::collect_param_descrs(r);
|
||||
}
|
||||
|
||||
|
||||
void simplifier::collect_statistics(statistics & st) {
|
||||
st.update("subsumed", m_num_subsumed);
|
||||
st.update("subsumption resolution", m_num_sub_res);
|
||||
|
@ -1471,7 +1473,7 @@ namespace sat {
|
|||
st.update("elim bool vars", m_num_elim_vars);
|
||||
st.update("elim blocked clauses", m_num_blocked_clauses);
|
||||
}
|
||||
|
||||
|
||||
void simplifier::reset_statistics() {
|
||||
m_num_blocked_clauses = 0;
|
||||
m_num_subsumed = 0;
|
||||
|
|
|
@ -27,7 +27,7 @@ Revision History:
|
|||
// define to create a copy of the solver before starting the search
|
||||
// useful for checking models
|
||||
// #define CLONE_BEFORE_SOLVING
|
||||
|
||||
|
||||
namespace sat {
|
||||
|
||||
solver::solver(params_ref const & p, extension * ext):
|
||||
|
@ -103,7 +103,7 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Variable & Clause creation
|
||||
|
@ -312,7 +312,7 @@ namespace sat {
|
|||
/**
|
||||
\brief Select a watch literal starting the search at the given position.
|
||||
This method is only used for clauses created during the search.
|
||||
|
||||
|
||||
I use the following rules to select a watch literal.
|
||||
|
||||
1- select a literal l in idx >= starting_at such that value(l) = l_true,
|
||||
|
@ -329,7 +329,7 @@ namespace sat {
|
|||
lvl(l) >= lvl(l')
|
||||
|
||||
Without rule 3, boolean propagation is incomplete, that is, it may miss possible propagations.
|
||||
|
||||
|
||||
\remark The method select_lemma_watch_lit is used to select the watch literal for regular learned clauses.
|
||||
*/
|
||||
unsigned solver::select_watch_lit(clause const & cls, unsigned starting_at) const {
|
||||
|
@ -443,7 +443,7 @@ namespace sat {
|
|||
erase_clause_watch(get_wlist(~c[0]), cls_off);
|
||||
erase_clause_watch(get_wlist(~c[1]), cls_off);
|
||||
}
|
||||
|
||||
|
||||
void solver::dettach_ter_clause(clause & c) {
|
||||
erase_ternary_watch(get_wlist(~c[0]), c[1], c[2]);
|
||||
erase_ternary_watch(get_wlist(~c[1]), c[0], c[2]);
|
||||
|
@ -498,10 +498,10 @@ namespace sat {
|
|||
unsigned sz = c.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
switch (value(c[i])) {
|
||||
case l_true:
|
||||
case l_true:
|
||||
return l_true;
|
||||
case l_undef:
|
||||
found_undef = true;
|
||||
case l_undef:
|
||||
found_undef = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -515,7 +515,7 @@ namespace sat {
|
|||
// Propagation
|
||||
//
|
||||
// -----------------------
|
||||
|
||||
|
||||
bool solver::propagate_core(bool update) {
|
||||
if (m_inconsistent)
|
||||
return false;
|
||||
|
@ -545,7 +545,7 @@ namespace sat {
|
|||
}
|
||||
for (; it != end; ++it) {
|
||||
switch (it->get_kind()) {
|
||||
case watched::BINARY:
|
||||
case watched::BINARY:
|
||||
l1 = it->get_literal();
|
||||
switch (value(l1)) {
|
||||
case l_false:
|
||||
|
@ -585,15 +585,30 @@ namespace sat {
|
|||
break;
|
||||
case watched::CLAUSE: {
|
||||
if (value(it->get_blocked_literal()) == l_true) {
|
||||
TRACE("propagate_clause_bug", tout << "blocked literal " << it->get_blocked_literal() << "\n";
|
||||
clause_offset cls_off = it->get_clause_offset();
|
||||
clause & c = *(m_cls_allocator.get_clause(cls_off));
|
||||
tout << c << "\n";);
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
break;
|
||||
}
|
||||
clause_offset cls_off = it->get_clause_offset();
|
||||
clause & c = *(m_cls_allocator.get_clause(cls_off));
|
||||
TRACE("propagate_clause_bug", tout << "processing... " << c << "\nwas_removed: " << c.was_removed() << "\n";);
|
||||
if (c[0] == not_l)
|
||||
std::swap(c[0], c[1]);
|
||||
CTRACE("propagate_bug", c[1] != not_l, tout << "l: " << l << " " << c << "\n";);
|
||||
if (c.was_removed() || c[1] != not_l) {
|
||||
// Remark: this method may be invoked when the watch lists are not in a consistent state,
|
||||
// and may contain dead/removed clauses, or clauses with removed literals.
|
||||
// See: method propagate_unit at sat_simplifier.cpp
|
||||
// So, we must check whether the clause was marked for deletion, or
|
||||
// c[1] != not_l
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
break;
|
||||
}
|
||||
SASSERT(c[1] == not_l);
|
||||
if (value(c[0]) == l_true) {
|
||||
it2->set_clause(c[0], cls_off);
|
||||
|
@ -694,7 +709,7 @@ namespace sat {
|
|||
m_conflicts_since_restart = 0;
|
||||
m_restart_threshold = m_config.m_restart_initial;
|
||||
}
|
||||
|
||||
|
||||
// iff3_finder(*this)();
|
||||
simplify_problem();
|
||||
|
||||
|
@ -705,10 +720,10 @@ namespace sat {
|
|||
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"abort: max-conflicts = 0\"\n";);
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
|
||||
while (true) {
|
||||
SASSERT(!inconsistent());
|
||||
|
||||
|
||||
lbool r = bounded_search();
|
||||
if (r != l_undef)
|
||||
return r;
|
||||
|
@ -717,7 +732,7 @@ namespace sat {
|
|||
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"abort: max-conflicts = " << m_conflicts << "\"\n";);
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
|
||||
restart();
|
||||
if (m_conflicts >= m_next_simplify) {
|
||||
simplify_problem();
|
||||
|
@ -735,7 +750,7 @@ namespace sat {
|
|||
|
||||
bool_var solver::next_var() {
|
||||
bool_var next;
|
||||
|
||||
|
||||
if (m_rand() < static_cast<int>(m_config.m_random_freq * random_gen::max_value())) {
|
||||
if (num_vars() == 0)
|
||||
return null_bool_var;
|
||||
|
@ -744,16 +759,16 @@ namespace sat {
|
|||
if (value(next) == l_undef && !was_eliminated(next))
|
||||
return next;
|
||||
}
|
||||
|
||||
|
||||
while (!m_case_split_queue.empty()) {
|
||||
next = m_case_split_queue.next_var();
|
||||
if (value(next) == l_undef && !was_eliminated(next))
|
||||
return next;
|
||||
}
|
||||
|
||||
|
||||
return null_bool_var;
|
||||
}
|
||||
|
||||
|
||||
bool solver::decide() {
|
||||
bool_var next = next_var();
|
||||
if (next == null_bool_var)
|
||||
|
@ -761,7 +776,7 @@ namespace sat {
|
|||
push();
|
||||
m_stats.m_decision++;
|
||||
lbool phase = m_ext ? m_ext->get_phase(next) : l_undef;
|
||||
|
||||
|
||||
if (phase == l_undef) {
|
||||
switch (m_config.m_phase) {
|
||||
case PS_ALWAYS_TRUE:
|
||||
|
@ -785,7 +800,7 @@ namespace sat {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SASSERT(phase != l_undef);
|
||||
literal next_lit(next, phase == l_false);
|
||||
assign(next_lit, justification());
|
||||
|
@ -808,23 +823,23 @@ namespace sat {
|
|||
return l_undef;
|
||||
if (scope_lvl() == 0) {
|
||||
cleanup(); // cleaner may propagate frozen clauses
|
||||
if (inconsistent())
|
||||
if (inconsistent())
|
||||
return l_false;
|
||||
gc();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gc();
|
||||
|
||||
if (!decide()) {
|
||||
if (m_ext) {
|
||||
switch (m_ext->check()) {
|
||||
case CR_DONE:
|
||||
case CR_DONE:
|
||||
mk_model();
|
||||
return l_true;
|
||||
case CR_CONTINUE:
|
||||
case CR_CONTINUE:
|
||||
break;
|
||||
case CR_GIVEUP:
|
||||
case CR_GIVEUP:
|
||||
throw abort_solver();
|
||||
}
|
||||
}
|
||||
|
@ -850,23 +865,23 @@ namespace sat {
|
|||
m_stopwatch.reset();
|
||||
m_stopwatch.start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Apply all simplifications.
|
||||
*/
|
||||
void solver::simplify_problem() {
|
||||
SASSERT(scope_lvl() == 0);
|
||||
|
||||
|
||||
m_cleaner();
|
||||
CASSERT("sat_simplify_bug", check_invariant());
|
||||
|
||||
|
||||
m_scc();
|
||||
CASSERT("sat_simplify_bug", check_invariant());
|
||||
|
||||
m_simplifier(false);
|
||||
|
||||
m_simplifier(false);
|
||||
CASSERT("sat_simplify_bug", check_invariant());
|
||||
CASSERT("sat_missed_prop", check_missed_propagation());
|
||||
|
||||
|
||||
if (!m_learned.empty()) {
|
||||
m_simplifier(true);
|
||||
CASSERT("sat_missed_prop", check_missed_propagation());
|
||||
|
@ -879,11 +894,11 @@ namespace sat {
|
|||
m_probing();
|
||||
CASSERT("sat_missed_prop", check_missed_propagation());
|
||||
CASSERT("sat_simplify_bug", check_invariant());
|
||||
|
||||
|
||||
m_asymm_branch();
|
||||
CASSERT("sat_missed_prop", check_missed_propagation());
|
||||
CASSERT("sat_simplify_bug", check_invariant());
|
||||
|
||||
|
||||
if (m_ext) {
|
||||
m_ext->clauses_modifed();
|
||||
m_ext->simplify();
|
||||
|
@ -957,7 +972,7 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!m_mc.check_model(m))
|
||||
if (!m_mc.check_model(m))
|
||||
ok = false;
|
||||
CTRACE("sat_model_bug", !ok, tout << m << "\n";);
|
||||
return ok;
|
||||
|
@ -965,9 +980,9 @@ namespace sat {
|
|||
|
||||
void solver::restart() {
|
||||
m_stats.m_restart++;
|
||||
IF_VERBOSE(1,
|
||||
IF_VERBOSE(1,
|
||||
verbose_stream() << "(sat-restart :conflicts " << m_stats.m_conflict << " :decisions " << m_stats.m_decision
|
||||
<< " :restarts " << m_stats.m_restart << mk_stat(*this)
|
||||
<< " :restarts " << m_stats.m_restart << mk_stat(*this)
|
||||
<< " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";);
|
||||
IF_VERBOSE(30, display_status(verbose_stream()););
|
||||
pop(scope_lvl());
|
||||
|
@ -992,9 +1007,9 @@ namespace sat {
|
|||
// GC
|
||||
//
|
||||
// -----------------------
|
||||
|
||||
|
||||
void solver::gc() {
|
||||
if (m_conflicts_since_gc <= m_gc_threshold)
|
||||
if (m_conflicts_since_gc <= m_gc_threshold)
|
||||
return;
|
||||
CASSERT("sat_gc_bug", check_invariant());
|
||||
switch (m_config.m_gc_strategy) {
|
||||
|
@ -1074,7 +1089,7 @@ namespace sat {
|
|||
std::stable_sort(m_learned.begin(), m_learned.end(), glue_lt());
|
||||
gc_half("glue");
|
||||
}
|
||||
|
||||
|
||||
void solver::gc_psm() {
|
||||
save_psm();
|
||||
std::stable_sort(m_learned.begin(), m_learned.end(), psm_lt());
|
||||
|
@ -1135,8 +1150,8 @@ namespace sat {
|
|||
void solver::gc_dyn_psm() {
|
||||
// To do gc at scope_lvl() > 0, I will need to use the reinitialization stack, or live with the fact
|
||||
// that I may miss some propagations for reactivated clauses.
|
||||
SASSERT(scope_lvl() == 0);
|
||||
// compute
|
||||
SASSERT(scope_lvl() == 0);
|
||||
// compute
|
||||
// d_tk
|
||||
unsigned h = 0;
|
||||
unsigned V_tk = 0;
|
||||
|
@ -1153,7 +1168,7 @@ namespace sat {
|
|||
double d_tk = V_tk == 0 ? static_cast<double>(num_vars() + 1) : static_cast<double>(h)/static_cast<double>(V_tk);
|
||||
if (d_tk < m_min_d_tk)
|
||||
m_min_d_tk = d_tk;
|
||||
TRACE("sat_frozen", tout << "m_min_d_tk: " << m_min_d_tk << "\n";);
|
||||
TRACE("sat_frozen", tout << "m_min_d_tk: " << m_min_d_tk << "\n";);
|
||||
unsigned frozen = 0;
|
||||
unsigned deleted = 0;
|
||||
unsigned activated = 0;
|
||||
|
@ -1219,15 +1234,15 @@ namespace sat {
|
|||
++it2;
|
||||
}
|
||||
m_learned.set_end(it2);
|
||||
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat-gc :d_tk " << d_tk << " :min-d_tk " << m_min_d_tk <<
|
||||
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat-gc :d_tk " << d_tk << " :min-d_tk " << m_min_d_tk <<
|
||||
" :frozen " << frozen << " :activated " << activated << " :deleted " << deleted << ")\n";);
|
||||
}
|
||||
|
||||
|
||||
// return true if should keep the clause, and false if we should delete it.
|
||||
bool solver::activate_frozen_clause(clause & c) {
|
||||
bool solver::activate_frozen_clause(clause & c) {
|
||||
TRACE("sat_gc", tout << "reactivating:\n" << c << "\n";);
|
||||
SASSERT(scope_lvl() == 0);
|
||||
// do some cleanup
|
||||
// do some cleanup
|
||||
unsigned sz = c.size();
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
|
@ -1291,13 +1306,13 @@ namespace sat {
|
|||
bool solver::resolve_conflict() {
|
||||
while (true) {
|
||||
bool r = resolve_conflict_core();
|
||||
CASSERT("sat_check_marks", check_marks());
|
||||
// after pop, clauses are reinitialized, this may trigger another conflict.
|
||||
if (!r)
|
||||
if (!r)
|
||||
return false;
|
||||
if (!inconsistent())
|
||||
return true;
|
||||
}
|
||||
CASSERT("sat_check_marks", check_marks());
|
||||
}
|
||||
|
||||
bool solver::resolve_conflict_core() {
|
||||
|
@ -1312,7 +1327,7 @@ namespace sat {
|
|||
if (m_conflict_lvl == 0)
|
||||
return false;
|
||||
m_lemma.reset();
|
||||
|
||||
|
||||
forget_phase_of_vars(m_conflict_lvl);
|
||||
|
||||
unsigned idx = skip_literals_above_conflict_level();
|
||||
|
@ -1324,10 +1339,10 @@ namespace sat {
|
|||
TRACE("sat_conflict", tout << "not_l: " << m_not_l << "\n";);
|
||||
process_antecedent(m_not_l, num_marks);
|
||||
}
|
||||
|
||||
|
||||
literal consequent = m_not_l;
|
||||
justification js = m_conflict;
|
||||
|
||||
|
||||
do {
|
||||
TRACE("sat_conflict_detail", tout << "processing consequent: " << consequent << "\n";
|
||||
tout << "num_marks: " << num_marks << ", js kind: " << js.get_kind() << "\n";);
|
||||
|
@ -1363,7 +1378,7 @@ namespace sat {
|
|||
fill_ext_antecedents(consequent, js);
|
||||
literal_vector::iterator it = m_ext_antecedents.begin();
|
||||
literal_vector::iterator end = m_ext_antecedents.end();
|
||||
for (; it != end; ++it)
|
||||
for (; it != end; ++it)
|
||||
process_antecedent(*it, num_marks);
|
||||
break;
|
||||
}
|
||||
|
@ -1371,10 +1386,10 @@ namespace sat {
|
|||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
while (true) {
|
||||
literal l = m_trail[idx];
|
||||
if (is_marked(l.var()))
|
||||
if (is_marked(l.var()))
|
||||
break;
|
||||
SASSERT(idx > 0);
|
||||
idx--;
|
||||
|
@ -1387,9 +1402,9 @@ namespace sat {
|
|||
idx--;
|
||||
num_marks--;
|
||||
reset_mark(c_var);
|
||||
}
|
||||
}
|
||||
while (num_marks > 0);
|
||||
|
||||
|
||||
m_lemma[0] = ~consequent;
|
||||
TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";);
|
||||
|
||||
|
@ -1400,7 +1415,9 @@ namespace sat {
|
|||
dyn_sub_res();
|
||||
TRACE("sat_lemma", tout << "new lemma (after minimization) size: " << m_lemma.size() << "\n" << m_lemma << "\n";);
|
||||
}
|
||||
|
||||
else
|
||||
reset_lemma_var_marks();
|
||||
|
||||
literal_vector::iterator it = m_lemma.begin();
|
||||
literal_vector::iterator end = m_lemma.end();
|
||||
unsigned new_scope_lvl = 0;
|
||||
|
@ -1431,10 +1448,10 @@ namespace sat {
|
|||
return 0;
|
||||
|
||||
unsigned r = 0;
|
||||
|
||||
|
||||
if (consequent != null_literal)
|
||||
r = lvl(consequent);
|
||||
|
||||
|
||||
switch (js.get_kind()) {
|
||||
case justification::NONE:
|
||||
break;
|
||||
|
@ -1467,7 +1484,7 @@ namespace sat {
|
|||
fill_ext_antecedents(consequent, js);
|
||||
literal_vector::iterator it = m_ext_antecedents.begin();
|
||||
literal_vector::iterator end = m_ext_antecedents.end();
|
||||
for (; it != end; ++it)
|
||||
for (; it != end; ++it)
|
||||
r = std::max(r, lvl(*it));
|
||||
break;
|
||||
}
|
||||
|
@ -1496,7 +1513,7 @@ namespace sat {
|
|||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
void solver::process_antecedent(literal antecedent, unsigned & num_marks) {
|
||||
bool_var var = antecedent.var();
|
||||
unsigned var_lvl = lvl(var);
|
||||
|
@ -1510,7 +1527,7 @@ namespace sat {
|
|||
m_lemma.push_back(~antecedent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief js is an external justification. Collect its antecedents and store at m_ext_antecedents.
|
||||
*/
|
||||
|
@ -1577,7 +1594,7 @@ namespace sat {
|
|||
unsigned var_lvl = lvl(var);
|
||||
if (!is_marked(var) && var_lvl > 0) {
|
||||
if (m_lvl_set.may_contain(var_lvl)) {
|
||||
mark(var);
|
||||
mark(var);
|
||||
m_unmark.push_back(var);
|
||||
m_lemma_min_stack.push_back(var);
|
||||
}
|
||||
|
@ -1589,17 +1606,17 @@ namespace sat {
|
|||
}
|
||||
|
||||
/**
|
||||
\brief Return true if lit is implied by other marked literals
|
||||
and/or literals assigned at the base level.
|
||||
The set lvl_set is used as an optimization.
|
||||
\brief Return true if lit is implied by other marked literals
|
||||
and/or literals assigned at the base level.
|
||||
The set lvl_set is used as an optimization.
|
||||
The idea is to stop the recursive search with a failure
|
||||
as soon as we find a literal assigned in a level that is not in lvl_set.
|
||||
as soon as we find a literal assigned in a level that is not in lvl_set.
|
||||
*/
|
||||
bool solver::implied_by_marked(literal lit) {
|
||||
m_lemma_min_stack.reset(); // avoid recursive function
|
||||
m_lemma_min_stack.push_back(lit.var());
|
||||
unsigned old_size = m_unmark.size();
|
||||
|
||||
|
||||
while (!m_lemma_min_stack.empty()) {
|
||||
bool_var var = m_lemma_min_stack.back();
|
||||
m_lemma_min_stack.pop_back();
|
||||
|
@ -1700,7 +1717,7 @@ namespace sat {
|
|||
void solver::minimize_lemma() {
|
||||
m_unmark.reset();
|
||||
updt_lemma_lvl_set();
|
||||
|
||||
|
||||
unsigned sz = m_lemma.size();
|
||||
unsigned i = 1; // the first literal is the FUIP
|
||||
unsigned j = 1;
|
||||
|
@ -1716,12 +1733,12 @@ namespace sat {
|
|||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
reset_unmark(0);
|
||||
m_lemma.shrink(j);
|
||||
m_stats.m_minimized_lits += sz - j;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Reset the mark of the variables in the current lemma.
|
||||
*/
|
||||
|
@ -1741,17 +1758,17 @@ namespace sat {
|
|||
Only binary and ternary clauses are used.
|
||||
*/
|
||||
void solver::dyn_sub_res() {
|
||||
unsigned sz = m_lemma.size();
|
||||
unsigned sz = m_lemma.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
mark_lit(m_lemma[i]);
|
||||
}
|
||||
|
||||
|
||||
literal l0 = m_lemma[0];
|
||||
// l0 is the FUIP, and we never remove the FUIP.
|
||||
//
|
||||
//
|
||||
// In the following loop, we use unmark_lit(l) to remove a
|
||||
// literal from m_lemma.
|
||||
|
||||
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
literal l = m_lemma[i];
|
||||
if (!is_marked_lit(l))
|
||||
|
@ -1763,8 +1780,8 @@ namespace sat {
|
|||
for (; it != end; ++it) {
|
||||
// In this for-loop, the conditions l0 != ~l2 and l0 != ~l3
|
||||
// are not really needed if the solver does not miss unit propagations.
|
||||
// However, we add them anyway because we don't want to rely on this
|
||||
// property of the propagator.
|
||||
// However, we add them anyway because we don't want to rely on this
|
||||
// property of the propagator.
|
||||
// For example, if this property is relaxed in the future, then the code
|
||||
// without the conditions l0 != ~l2 and l0 != ~l3 may remove the FUIP
|
||||
if (it->is_binary_clause()) {
|
||||
|
@ -1810,10 +1827,10 @@ namespace sat {
|
|||
// p1 \/ ~p2
|
||||
// p2 \/ ~p3
|
||||
// p3 \/ ~p4
|
||||
// q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
|
||||
// q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
|
||||
// ~q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
|
||||
// ~q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
|
||||
// q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
|
||||
// q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
|
||||
// ~q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
|
||||
// ~q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
|
||||
// ...
|
||||
//
|
||||
// 2. Now suppose we learned the lemma
|
||||
|
@ -1824,15 +1841,15 @@ namespace sat {
|
|||
// That is, l \/ l2 is an implied clause. Note that probing does not add
|
||||
// this clause to the clause database (there are too many).
|
||||
//
|
||||
// 4. Lemma (*) is deleted (garbage collected).
|
||||
// 4. Lemma (*) is deleted (garbage collected).
|
||||
//
|
||||
// 5. l is decided to be false, p1, p2, p3 and p4 are propagated using BCP,
|
||||
// but l2 is not since the lemma (*) was deleted.
|
||||
//
|
||||
//
|
||||
// Probing module still "knows" that l \/ l2 is valid binary clause
|
||||
//
|
||||
//
|
||||
// 6. A new lemma is created where ~l2 is the FUIP and the lemma also contains l.
|
||||
// If we remove l0 != ~l2 may try to delete the FUIP.
|
||||
// If we remove l0 != ~l2 may try to delete the FUIP.
|
||||
if (is_marked_lit(~l2) && l0 != ~l2) {
|
||||
// eliminate ~l2 from lemma because we have the clause l \/ l2
|
||||
unmark_lit(~l2);
|
||||
|
@ -1843,7 +1860,7 @@ namespace sat {
|
|||
|
||||
// can't eliminat FUIP
|
||||
SASSERT(is_marked_lit(m_lemma[0]));
|
||||
|
||||
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
literal l = m_lemma[i];
|
||||
|
@ -1855,7 +1872,7 @@ namespace sat {
|
|||
}
|
||||
|
||||
m_stats.m_dyn_sub_res += sz - j;
|
||||
|
||||
|
||||
SASSERT(j >= 1);
|
||||
m_lemma.shrink(j);
|
||||
}
|
||||
|
@ -1948,7 +1965,7 @@ namespace sat {
|
|||
// Misc
|
||||
//
|
||||
// -----------------------
|
||||
|
||||
|
||||
void solver::updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_config.updt_params(p);
|
||||
|
@ -1970,8 +1987,8 @@ namespace sat {
|
|||
void solver::set_cancel(bool f) {
|
||||
m_cancel = f;
|
||||
}
|
||||
|
||||
void solver::collect_statistics(statistics & st) {
|
||||
|
||||
void solver::collect_statistics(statistics & st) {
|
||||
m_stats.collect_statistics(st);
|
||||
m_cleaner.collect_statistics(st);
|
||||
m_simplifier.collect_statistics(st);
|
||||
|
@ -2066,7 +2083,7 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void solver::display_units(std::ostream & out) const {
|
||||
unsigned end = scope_lvl() == 0 ? m_trail.size() : m_scopes[0].m_trail_lim;
|
||||
for (unsigned i = 0; i < end; i++) {
|
||||
|
@ -2220,26 +2237,26 @@ namespace sat {
|
|||
// Simplification
|
||||
//
|
||||
// -----------------------
|
||||
void solver::cleanup() {
|
||||
if (scope_lvl() > 0 || inconsistent())
|
||||
return;
|
||||
void solver::cleanup() {
|
||||
if (scope_lvl() > 0 || inconsistent())
|
||||
return;
|
||||
if (m_cleaner() && m_ext)
|
||||
m_ext->clauses_modifed();
|
||||
}
|
||||
|
||||
void solver::simplify(bool learned) {
|
||||
if (scope_lvl() > 0 || inconsistent())
|
||||
return;
|
||||
m_simplifier(learned);
|
||||
m_simplifier.free_memory();
|
||||
void solver::simplify(bool learned) {
|
||||
if (scope_lvl() > 0 || inconsistent())
|
||||
return;
|
||||
m_simplifier(learned);
|
||||
m_simplifier.free_memory();
|
||||
if (m_ext)
|
||||
m_ext->clauses_modifed();
|
||||
}
|
||||
|
||||
unsigned solver::scc_bin() {
|
||||
if (scope_lvl() > 0 || inconsistent())
|
||||
return 0;
|
||||
unsigned r = m_scc();
|
||||
unsigned solver::scc_bin() {
|
||||
if (scope_lvl() > 0 || inconsistent())
|
||||
return 0;
|
||||
unsigned r = m_scc();
|
||||
if (r > 0 && m_ext)
|
||||
m_ext->clauses_modifed();
|
||||
return r;
|
||||
|
@ -2313,10 +2330,10 @@ namespace sat {
|
|||
out << " :inconsistent " << (m_inconsistent ? "true" : "false") << "\n";
|
||||
out << " :vars " << num_vars() << "\n";
|
||||
out << " :elim-vars " << num_elim << "\n";
|
||||
out << " :lits " << num_lits << "\n";
|
||||
out << " :lits " << num_lits << "\n";
|
||||
out << " :assigned " << m_trail.size() << "\n";
|
||||
out << " :binary-clauses " << num_bin << "\n";
|
||||
out << " :ternary-clauses " << num_ter << "\n";
|
||||
out << " :binary-clauses " << num_bin << "\n";
|
||||
out << " :ternary-clauses " << num_ter << "\n";
|
||||
out << " :clauses " << num_cls << "\n";
|
||||
out << " :del-clause " << m_stats.m_del_clause << "\n";
|
||||
out << " :avg-clause-size " << (total_cls == 0 ? 0.0 : static_cast<double>(num_lits) / static_cast<double>(total_cls)) << "\n";
|
||||
|
|
|
@ -30,6 +30,7 @@ Revision History:
|
|||
#include"polynomial_cmds.h"
|
||||
#include"subpaving_cmds.h"
|
||||
#include"smt_strategic_solver.h"
|
||||
#include"smt_solver.h"
|
||||
|
||||
extern bool g_display_statistics;
|
||||
extern void display_config();
|
||||
|
@ -106,6 +107,7 @@ unsigned read_smtlib2_commands(char const * file_name) {
|
|||
cmd_context ctx;
|
||||
|
||||
ctx.set_solver_factory(mk_smt_strategic_solver_factory());
|
||||
ctx.set_interpolating_solver_factory(mk_smt_solver_factory());
|
||||
|
||||
install_dl_cmds(ctx);
|
||||
install_dbg_cmds(ctx);
|
||||
|
|
|
@ -27,6 +27,7 @@ void qi_params::updt_params(params_ref const & _p) {
|
|||
m_mbqi_max_iterations = p.mbqi_max_iterations();
|
||||
m_mbqi_trace = p.mbqi_trace();
|
||||
m_mbqi_force_template = p.mbqi_force_template();
|
||||
m_mbqi_id = p.mbqi_id();
|
||||
m_qi_profile = p.qi_profile();
|
||||
m_qi_profile_freq = p.qi_profile_freq();
|
||||
m_qi_max_instances = p.qi_max_instances();
|
||||
|
|
|
@ -51,6 +51,7 @@ struct qi_params {
|
|||
unsigned m_mbqi_max_iterations;
|
||||
bool m_mbqi_trace;
|
||||
unsigned m_mbqi_force_template;
|
||||
const char * m_mbqi_id;
|
||||
|
||||
qi_params(params_ref const & p = params_ref()):
|
||||
/*
|
||||
|
@ -97,7 +98,9 @@ struct qi_params {
|
|||
m_mbqi_max_cexs_incr(1),
|
||||
m_mbqi_max_iterations(1000),
|
||||
m_mbqi_trace(false),
|
||||
m_mbqi_force_template(10) {
|
||||
m_mbqi_force_template(10),
|
||||
m_mbqi_id(0)
|
||||
{
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ void smt_params::updt_local_params(params_ref const & _p) {
|
|||
m_arith_pivot_strategy = ARITH_PIVOT_GREATEST_ERROR;
|
||||
else if (_p.get_bool("arith.least_error_pivot", false))
|
||||
m_arith_pivot_strategy = ARITH_PIVOT_LEAST_ERROR;
|
||||
theory_array_params::updt_params(_p);
|
||||
}
|
||||
|
||||
void smt_params::updt_params(params_ref const & p) {
|
||||
|
@ -48,6 +49,7 @@ void smt_params::updt_params(params_ref const & p) {
|
|||
theory_arith_params::updt_params(p);
|
||||
theory_bv_params::updt_params(p);
|
||||
theory_pb_params::updt_params(p);
|
||||
// theory_array_params::updt_params(p);
|
||||
updt_local_params(p);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ def_module_params(module_name='smt',
|
|||
('mbqi.max_iterations', UINT, 1000, 'maximum number of rounds of MBQI'),
|
||||
('mbqi.trace', BOOL, False, 'generate tracing messages for Model Based Quantifier Instantiation (MBQI). It will display a message before every round of MBQI, and the quantifiers that were not satisfied'),
|
||||
('mbqi.force_template', UINT, 10, 'some quantifiers can be used as templates for building interpretations for functions. Z3 uses heuristics to decide whether a quantifier will be used as a template or not. Quantifiers with weight >= mbqi.force_template are forced to be used as a template'),
|
||||
('mbqi.id', STRING, '', 'Only use model-based instantiation for quantifiers with id\'s beginning with string'),
|
||||
('qi.profile', BOOL, False, 'profile quantifier instantiation'),
|
||||
('qi.profile_freq', UINT, UINT_MAX, 'how frequent results are reported by qi.profile'),
|
||||
('qi.max_instances', UINT, UINT_MAX, 'maximum number of quantifier instantiations'),
|
||||
|
@ -44,5 +45,7 @@ def_module_params(module_name='smt',
|
|||
('arith.ignore_int', BOOL, False, 'treat integer variables as real'),
|
||||
('pb.conflict_frequency', UINT, 0, 'conflict frequency for Pseudo-Boolean theory'),
|
||||
('pb.learn_complements', BOOL, True, 'learn complement literals for Pseudo-Boolean theory'),
|
||||
('pb.enable_compilation', BOOL, True, 'enable compilation into sorting circuits for Pseudo-Boolean')))
|
||||
|
||||
('pb.enable_compilation', BOOL, True, 'enable compilation into sorting circuits for Pseudo-Boolean'),
|
||||
('array.weak', BOOL, False, 'weak array theory'),
|
||||
('array.extensional', BOOL, True, 'extensional array theory')
|
||||
))
|
||||
|
|
28
src/smt/params/theory_array_params.cpp
Normal file
28
src/smt/params/theory_array_params.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
theory_array_params.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-05-06.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"theory_array_params.h"
|
||||
#include"smt_params_helper.hpp"
|
||||
|
||||
void theory_array_params::updt_params(params_ref const & _p) {
|
||||
smt_params_helper p(_p);
|
||||
m_array_weak = p.array_weak();
|
||||
m_array_extensional = p.array_extensional();
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +51,9 @@ struct theory_array_params : public array_simplifier_params {
|
|||
m_array_lazy_ieq_delay(10) {
|
||||
}
|
||||
|
||||
|
||||
void updt_params(params_ref const & _p);
|
||||
|
||||
#if 0
|
||||
void register_params(ini_params & p) {
|
||||
p.register_int_param("array_solver", 0, 3, reinterpret_cast<int&>(m_array_mode), "0 - no array, 1 - simple, 2 - model based, 3 - full");
|
||||
|
|
|
@ -322,6 +322,7 @@ namespace smt {
|
|||
|
||||
for (; it != end; ++it) {
|
||||
quantifier * q = *it;
|
||||
if(!m_qm->mbqi_enabled(q)) continue;
|
||||
if (m_context->is_relevant(q) && m_context->get_assignment(q) == l_true) {
|
||||
if (m_params.m_mbqi_trace && q->get_qid() != symbol::null) {
|
||||
verbose_stream() << "(smt.mbqi :checking " << q->get_qid() << ")\n";
|
||||
|
|
|
@ -335,6 +335,10 @@ namespace smt {
|
|||
return m_imp->m_plugin->model_based();
|
||||
}
|
||||
|
||||
bool quantifier_manager::mbqi_enabled(quantifier *q) const {
|
||||
return m_imp->m_plugin->mbqi_enabled(q);
|
||||
}
|
||||
|
||||
void quantifier_manager::adjust_model(proto_model * m) {
|
||||
m_imp->m_plugin->adjust_model(m);
|
||||
}
|
||||
|
@ -434,10 +438,24 @@ namespace smt {
|
|||
|
||||
virtual bool model_based() const { return m_fparams->m_mbqi; }
|
||||
|
||||
virtual bool mbqi_enabled(quantifier *q) const {
|
||||
if(!m_fparams->m_mbqi_id) return true;
|
||||
const symbol &s = q->get_qid();
|
||||
unsigned len = strlen(m_fparams->m_mbqi_id);
|
||||
if(s == symbol::null || s.is_numerical())
|
||||
return len == 0;
|
||||
return strncmp(s.bare_str(),m_fparams->m_mbqi_id,static_cast<unsigned>(len)) == 0;
|
||||
}
|
||||
|
||||
/* Quantifier id's must begin with the prefix specified by
|
||||
parameter mbqi.id to be instantiated with MBQI. The default
|
||||
value is the empty string, so all quantifiers are
|
||||
instantiated.
|
||||
*/
|
||||
virtual void add(quantifier * q) {
|
||||
if (m_fparams->m_mbqi) {
|
||||
m_model_finder->register_quantifier(q);
|
||||
}
|
||||
if (m_fparams->m_mbqi && mbqi_enabled(q)) {
|
||||
m_model_finder->register_quantifier(q);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void del(quantifier * q) {
|
||||
|
|
|
@ -75,6 +75,7 @@ namespace smt {
|
|||
};
|
||||
|
||||
bool model_based() const;
|
||||
bool mbqi_enabled(quantifier *q) const; // can mbqi instantiate this quantifier?
|
||||
void adjust_model(proto_model * m);
|
||||
check_model_result check_model(proto_model * m, obj_map<enode, app *> const & root2value);
|
||||
|
||||
|
@ -144,6 +145,11 @@ namespace smt {
|
|||
*/
|
||||
virtual bool model_based() const = 0;
|
||||
|
||||
/**
|
||||
\brief Is "model based" instantiate allowed to instantiate this quantifier?
|
||||
*/
|
||||
virtual bool mbqi_enabled(quantifier *q) const {return true;}
|
||||
|
||||
/**
|
||||
\brief Give a change to the plugin to adjust the interpretation of unintepreted functions.
|
||||
It can basically change the "else" of each uninterpreted function.
|
||||
|
|
|
@ -50,7 +50,7 @@ class factor_tactic : public tactic {
|
|||
return args[0];
|
||||
return m_util.mk_mul(sz, args);
|
||||
}
|
||||
|
||||
|
||||
expr * mk_zero_for(expr * arg) {
|
||||
return m_util.mk_numeral(rational(0), m_util.is_int(arg));
|
||||
}
|
||||
|
@ -92,10 +92,10 @@ class factor_tactic : public tactic {
|
|||
return k;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// p1^{2*k1} * p2^{2*k2 + 1} >=< 0
|
||||
// -->
|
||||
// (p1^2)*p2 >=<0
|
||||
// (p1^2)*p2 >=<0
|
||||
void mk_comp(decl_kind k, polynomial::factors const & fs, expr_ref & result) {
|
||||
SASSERT(k == OP_LT || k == OP_GT || k == OP_LE || k == OP_GE);
|
||||
expr_ref_buffer args(m);
|
||||
|
@ -127,7 +127,7 @@ class factor_tactic : public tactic {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Strict case
|
||||
// p1^{2*k1} * p2^{2*k2 + 1} >< 0
|
||||
// -->
|
||||
|
@ -158,11 +158,11 @@ class factor_tactic : public tactic {
|
|||
args.push_back(m.mk_app(m_util.get_family_id(), k, mk_mul(odd_factors.size(), odd_factors.c_ptr()), mk_zero_for(odd_factors[0])));
|
||||
}
|
||||
SASSERT(!args.empty());
|
||||
if (args.size() == 1)
|
||||
if (args.size() == 1)
|
||||
result = args[0];
|
||||
else if (strict)
|
||||
result = m.mk_and(args.size(), args.c_ptr());
|
||||
else
|
||||
else
|
||||
result = m.mk_or(args.size(), args.c_ptr());
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ class factor_tactic : public tactic {
|
|||
scoped_mpz d2(m_qm);
|
||||
m_expr2poly.to_polynomial(lhs, p1, d1);
|
||||
m_expr2poly.to_polynomial(rhs, p2, d2);
|
||||
TRACE("factor_tactic_bug",
|
||||
TRACE("factor_tactic_bug",
|
||||
tout << "lhs: " << mk_ismt2_pp(lhs, m) << "\n";
|
||||
tout << "p1: " << p1 << "\n";
|
||||
tout << "d1: " << d1 << "\n";
|
||||
|
@ -195,18 +195,18 @@ class factor_tactic : public tactic {
|
|||
SASSERT(fs.distinct_factors() > 0);
|
||||
TRACE("factor_tactic_bug", tout << "factors:\n"; fs.display(tout); tout << "\n";);
|
||||
if (fs.distinct_factors() == 1 && fs.get_degree(0) == 1)
|
||||
return BR_FAILED;
|
||||
return BR_FAILED;
|
||||
if (m.is_eq(f)) {
|
||||
if (m_split_factors)
|
||||
mk_split_eq(fs, result);
|
||||
else
|
||||
else
|
||||
mk_eq(fs, result);
|
||||
}
|
||||
else {
|
||||
decl_kind k = f->get_decl_kind();
|
||||
if (m_qm.is_neg(fs.get_constant()))
|
||||
k = flip(k);
|
||||
|
||||
|
||||
if (m_split_factors)
|
||||
mk_split_comp(k, fs, result);
|
||||
else
|
||||
|
@ -215,10 +215,10 @@ class factor_tactic : public tactic {
|
|||
return BR_DONE;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (num != 2)
|
||||
return BR_FAILED;
|
||||
if (m.is_eq(f) && (m_util.is_arith_expr(args[0]) || m_util.is_arith_expr(args[1])))
|
||||
if (m.is_eq(f) && (m_util.is_arith_expr(args[0]) || m_util.is_arith_expr(args[1])) && (!m.is_bool(args[0])))
|
||||
return factor(f, args[0], args[1], result);
|
||||
if (f->get_family_id() != m_util.get_family_id())
|
||||
return BR_FAILED;
|
||||
|
@ -232,10 +232,10 @@ class factor_tactic : public tactic {
|
|||
return BR_FAILED;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct rw : public rewriter_tpl<rw_cfg> {
|
||||
rw_cfg m_cfg;
|
||||
|
||||
|
||||
rw(ast_manager & m, params_ref const & p):
|
||||
rewriter_tpl<rw_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m, p) {
|
||||
|
@ -245,24 +245,24 @@ class factor_tactic : public tactic {
|
|||
struct imp {
|
||||
ast_manager & m;
|
||||
rw m_rw;
|
||||
|
||||
|
||||
imp(ast_manager & _m, params_ref const & p):
|
||||
m(_m),
|
||||
m_rw(m, p) {
|
||||
}
|
||||
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_rw.set_cancel(f);
|
||||
m_rw.cfg().m_pm.set_cancel(f);
|
||||
}
|
||||
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_rw.cfg().updt_params(p);
|
||||
}
|
||||
|
||||
void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
|
||||
void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(g->is_well_sorted());
|
||||
|
@ -288,7 +288,7 @@ class factor_tactic : public tactic {
|
|||
SASSERT(g->is_well_sorted());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
public:
|
||||
|
@ -300,7 +300,7 @@ public:
|
|||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(factor_tactic, m, m_params);
|
||||
}
|
||||
|
||||
|
||||
virtual ~factor_tactic() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
@ -311,14 +311,14 @@ public:
|
|||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
r.insert("split_factors", CPK_BOOL,
|
||||
r.insert("split_factors", CPK_BOOL,
|
||||
"(default: true) apply simplifications such as (= (* p1 p2) 0) --> (or (= p1 0) (= p2 0)).");
|
||||
polynomial::factor_params::get_param_descrs(r);
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
try {
|
||||
|
@ -331,7 +331,7 @@ public:
|
|||
throw tactic_exception(ex.msg());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void cleanup() {
|
||||
ast_manager & m = m_imp->m;
|
||||
imp * d = m_imp;
|
||||
|
|
|
@ -480,7 +480,10 @@ private:
|
|||
break;
|
||||
}
|
||||
|
||||
SASSERT (i < sz);
|
||||
if (i >= sz) {
|
||||
// [Christoph]: In this case, all the m_a are equal to m_c.
|
||||
return;
|
||||
}
|
||||
|
||||
// copy lits [0, i) to m_clause
|
||||
for (unsigned j = 0; j < i; j++)
|
||||
|
@ -500,6 +503,7 @@ private:
|
|||
}
|
||||
|
||||
void mk_pbc(polynomial & m_p, numeral & m_c, expr_ref & r, bool enable_split) {
|
||||
TRACE("mk_pbc", display(tout, m_p, m_c); );
|
||||
if (m_c.is_nonpos()) {
|
||||
// constraint is equivalent to true.
|
||||
r = m.mk_true();
|
||||
|
@ -507,7 +511,7 @@ private:
|
|||
}
|
||||
polynomial::iterator it = m_p.begin();
|
||||
polynomial::iterator end = m_p.end();
|
||||
numeral a_gcd = it->m_a;
|
||||
numeral a_gcd = (it->m_a > m_c) ? m_c : it->m_a;
|
||||
for (; it != end; ++it) {
|
||||
if (it->m_a > m_c)
|
||||
it->m_a = m_c; // trimming coefficients
|
||||
|
@ -520,6 +524,7 @@ private:
|
|||
it->m_a /= a_gcd;
|
||||
m_c = ceil(m_c/a_gcd);
|
||||
}
|
||||
TRACE("mk_pbc", tout << "GCD = " << a_gcd << "; Normalized: "; display(tout, m_p, m_c); tout << "\n"; );
|
||||
it = m_p.begin();
|
||||
numeral a_sum;
|
||||
for (; it != end; ++it) {
|
||||
|
|
|
@ -140,7 +140,7 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) {
|
|||
s_sig = m_bv_util.mk_sort(sbits-1);
|
||||
s_exp = m_bv_util.mk_sort(ebits);
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
std::string p("fpa2bv");
|
||||
std::string name = f->get_name().str();
|
||||
|
||||
|
@ -271,7 +271,7 @@ void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) {
|
|||
SASSERT(is_rm_sort(f->get_range()));
|
||||
|
||||
result = m.mk_fresh_const(
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
"fpa2bv_rm"
|
||||
#else
|
||||
0
|
||||
|
@ -1588,8 +1588,7 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr *
|
|||
v2 = x;
|
||||
|
||||
unsigned ebits = m_util.get_ebits(f->get_range());
|
||||
unsigned sbits = m_util.get_sbits(f->get_range());
|
||||
SASSERT(ebits < sbits);
|
||||
unsigned sbits = m_util.get_sbits(f->get_range());
|
||||
|
||||
expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m);
|
||||
unpack(x, a_sgn, a_sig, a_exp, a_lz, true);
|
||||
|
@ -1619,9 +1618,22 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr *
|
|||
expr_ref shift(m), r_shifted(m), l_shifted(m);
|
||||
shift = m_bv_util.mk_bv_sub(m_bv_util.mk_numeral(sbits-1, ebits+1),
|
||||
m_bv_util.mk_sign_extend(1, a_exp));
|
||||
r_shifted = m_bv_util.mk_bv_lshr(a_sig, m_bv_util.mk_zero_extend(sbits-ebits-1, shift));
|
||||
if (sbits > (ebits+1))
|
||||
r_shifted = m_bv_util.mk_bv_lshr(a_sig, m_bv_util.mk_zero_extend(sbits-(ebits+1), shift));
|
||||
else if (sbits < (ebits+1))
|
||||
r_shifted = m_bv_util.mk_extract(ebits, ebits-sbits+1, m_bv_util.mk_bv_lshr(m_bv_util.mk_zero_extend(ebits+1-sbits, a_sig), shift));
|
||||
else // sbits == ebits+1
|
||||
r_shifted = m_bv_util.mk_bv_lshr(a_sig, shift);
|
||||
SASSERT(is_well_sorted(m, r_shifted));
|
||||
SASSERT(m_bv_util.get_bv_size(r_shifted) == sbits);
|
||||
l_shifted = m_bv_util.mk_bv_shl(r_shifted, m_bv_util.mk_zero_extend(sbits-ebits-1, shift));
|
||||
|
||||
if (sbits > (ebits+1))
|
||||
l_shifted = m_bv_util.mk_bv_shl(r_shifted, m_bv_util.mk_zero_extend(sbits-(ebits+1), shift));
|
||||
else if (sbits < (ebits+1))
|
||||
l_shifted = m_bv_util.mk_extract(ebits, ebits-sbits+1, m_bv_util.mk_bv_shl(m_bv_util.mk_zero_extend(ebits+1-sbits, r_shifted), shift));
|
||||
else // sbits == ebits+1
|
||||
l_shifted = m_bv_util.mk_bv_shl(r_shifted, shift);
|
||||
SASSERT(is_well_sorted(m, l_shifted));
|
||||
SASSERT(m_bv_util.get_bv_size(l_shifted) == sbits);
|
||||
|
||||
res_sig = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1),
|
||||
|
@ -1825,146 +1837,158 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a
|
|||
mk_triple(args[0], args[1], args[2], result);
|
||||
}
|
||||
else if (num == 2 && is_app(args[1]) && m_util.is_float(m.get_sort(args[1]))) {
|
||||
// We also support float to float conversion
|
||||
// We also support float to float conversion
|
||||
sort * s = f->get_range();
|
||||
expr_ref rm(m), x(m);
|
||||
rm = args[0];
|
||||
x = args[1];
|
||||
|
||||
expr_ref c1(m), c2(m), c3(m), c4(m), c5(m);
|
||||
expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m);
|
||||
expr_ref one1(m);
|
||||
|
||||
one1 = m_bv_util.mk_numeral(1, 1);
|
||||
expr_ref ninf(m), pinf(m);
|
||||
mk_plus_inf(f, pinf);
|
||||
mk_minus_inf(f, ninf);
|
||||
|
||||
// NaN -> NaN
|
||||
mk_is_nan(x, c1);
|
||||
mk_nan(f, v1);
|
||||
|
||||
// +0 -> +0
|
||||
mk_is_pzero(x, c2);
|
||||
mk_pzero(f, v2);
|
||||
|
||||
// -0 -> -0
|
||||
mk_is_nzero(x, c3);
|
||||
mk_nzero(f, v3);
|
||||
|
||||
// +oo -> +oo
|
||||
mk_is_pinf(x, c4);
|
||||
v4 = pinf;
|
||||
|
||||
// -oo -> -oo
|
||||
mk_is_ninf(x, c5);
|
||||
v5 = ninf;
|
||||
|
||||
// otherwise: the actual conversion with rounding.
|
||||
sort * s = f->get_range();
|
||||
expr_ref sgn(m), sig(m), exp(m), lz(m);
|
||||
unpack(x, sgn, sig, exp, lz, true);
|
||||
|
||||
dbg_decouple("fpa2bv_to_float_x_sig", sig);
|
||||
dbg_decouple("fpa2bv_to_float_x_exp", exp);
|
||||
dbg_decouple("fpa2bv_to_float_lz", lz);
|
||||
|
||||
expr_ref res_sgn(m), res_sig(m), res_exp(m);
|
||||
|
||||
res_sgn = sgn;
|
||||
|
||||
unsigned from_sbits = m_util.get_sbits(m.get_sort(args[1]));
|
||||
unsigned from_ebits = m_util.get_ebits(m.get_sort(args[1]));
|
||||
unsigned from_sbits = m_util.get_sbits(m.get_sort(x));
|
||||
unsigned from_ebits = m_util.get_ebits(m.get_sort(x));
|
||||
unsigned to_sbits = m_util.get_sbits(s);
|
||||
unsigned to_ebits = m_util.get_ebits(s);
|
||||
|
||||
SASSERT(m_bv_util.get_bv_size(sgn) == 1);
|
||||
SASSERT(m_bv_util.get_bv_size(sig) == from_sbits);
|
||||
SASSERT(m_bv_util.get_bv_size(exp) == from_ebits);
|
||||
SASSERT(m_bv_util.get_bv_size(lz) == from_ebits);
|
||||
if (from_sbits == to_sbits && from_ebits == to_ebits)
|
||||
result = x;
|
||||
else {
|
||||
expr_ref c1(m), c2(m), c3(m), c4(m), c5(m);
|
||||
expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m);
|
||||
expr_ref one1(m);
|
||||
|
||||
if (from_sbits < (to_sbits + 3))
|
||||
{
|
||||
// make sure that sig has at least to_sbits + 3
|
||||
res_sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, to_sbits+3-from_sbits));
|
||||
}
|
||||
else if (from_sbits > (to_sbits + 3))
|
||||
{
|
||||
// collapse the extra bits into a sticky bit.
|
||||
expr_ref sticky(m), low(m), high(m);
|
||||
low = m_bv_util.mk_extract(from_sbits - to_sbits - 3, 0, sig);
|
||||
high = m_bv_util.mk_extract(from_sbits - 1, from_sbits - to_sbits - 2, sig);
|
||||
sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low.get());
|
||||
res_sig = m_bv_util.mk_concat(high, sticky);
|
||||
}
|
||||
else
|
||||
res_sig = sig;
|
||||
one1 = m_bv_util.mk_numeral(1, 1);
|
||||
expr_ref ninf(m), pinf(m);
|
||||
mk_plus_inf(f, pinf);
|
||||
mk_minus_inf(f, ninf);
|
||||
|
||||
res_sig = m_bv_util.mk_zero_extend(1, res_sig); // extra zero in the front for the rounder.
|
||||
unsigned sig_sz = m_bv_util.get_bv_size(res_sig);
|
||||
SASSERT(sig_sz == to_sbits+4);
|
||||
// NaN -> NaN
|
||||
mk_is_nan(x, c1);
|
||||
mk_nan(f, v1);
|
||||
|
||||
expr_ref exponent_overflow(m);
|
||||
exponent_overflow = m.mk_false();
|
||||
// +0 -> +0
|
||||
mk_is_pzero(x, c2);
|
||||
mk_pzero(f, v2);
|
||||
|
||||
if (from_ebits < (to_ebits + 2))
|
||||
{
|
||||
res_exp = m_bv_util.mk_sign_extend(to_ebits-from_ebits+2, exp);
|
||||
}
|
||||
else if (from_ebits > (to_ebits + 2))
|
||||
{
|
||||
expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), h_or_eq(m), h_and_eq(m);
|
||||
expr_ref no_ovf(m), zero1(m), s_is_one(m), s_is_zero(m);
|
||||
high = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, exp);
|
||||
low = m_bv_util.mk_extract(to_ebits+1, 0, exp);
|
||||
lows = m_bv_util.mk_extract(to_ebits+1, to_ebits+1, low);
|
||||
// -0 -> -0
|
||||
mk_is_nzero(x, c3);
|
||||
mk_nzero(f, v3);
|
||||
|
||||
// +oo -> +oo
|
||||
mk_is_pinf(x, c4);
|
||||
v4 = pinf;
|
||||
|
||||
// -oo -> -oo
|
||||
mk_is_ninf(x, c5);
|
||||
v5 = ninf;
|
||||
|
||||
high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high.get());
|
||||
high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high.get());
|
||||
// otherwise: the actual conversion with rounding.
|
||||
expr_ref sgn(m), sig(m), exp(m), lz(m);
|
||||
unpack(x, sgn, sig, exp, lz, true);
|
||||
|
||||
zero1 = m_bv_util.mk_numeral(0, 1);
|
||||
m_simp.mk_eq(high_red_and, one1, h_and_eq);
|
||||
m_simp.mk_eq(high_red_or, zero1, h_or_eq);
|
||||
m_simp.mk_eq(lows, zero1, s_is_zero);
|
||||
m_simp.mk_eq(lows, one1, s_is_one);
|
||||
dbg_decouple("fpa2bv_to_float_x_sig", sig);
|
||||
dbg_decouple("fpa2bv_to_float_x_exp", exp);
|
||||
dbg_decouple("fpa2bv_to_float_lz", lz);
|
||||
|
||||
expr_ref res_sgn(m), res_sig(m), res_exp(m);
|
||||
|
||||
res_sgn = sgn;
|
||||
|
||||
SASSERT(m_bv_util.get_bv_size(sgn) == 1);
|
||||
SASSERT(m_bv_util.get_bv_size(sig) == from_sbits);
|
||||
SASSERT(m_bv_util.get_bv_size(exp) == from_ebits);
|
||||
SASSERT(m_bv_util.get_bv_size(lz) == from_ebits);
|
||||
|
||||
if (from_sbits < (to_sbits + 3))
|
||||
{
|
||||
// make sure that sig has at least to_sbits + 3
|
||||
res_sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, to_sbits+3-from_sbits));
|
||||
}
|
||||
else if (from_sbits > (to_sbits + 3))
|
||||
{
|
||||
// collapse the extra bits into a sticky bit.
|
||||
expr_ref sticky(m), low(m), high(m);
|
||||
low = m_bv_util.mk_extract(from_sbits - to_sbits - 3, 0, sig);
|
||||
high = m_bv_util.mk_extract(from_sbits - 1, from_sbits - to_sbits - 2, sig);
|
||||
sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low.get());
|
||||
res_sig = m_bv_util.mk_concat(high, sticky);
|
||||
}
|
||||
else
|
||||
res_sig = sig;
|
||||
|
||||
res_sig = m_bv_util.mk_zero_extend(1, res_sig); // extra zero in the front for the rounder.
|
||||
unsigned sig_sz = m_bv_util.get_bv_size(res_sig);
|
||||
SASSERT(sig_sz == to_sbits+4);
|
||||
|
||||
expr_ref exponent_overflow(m);
|
||||
exponent_overflow = m.mk_false();
|
||||
|
||||
if (from_ebits < (to_ebits + 2))
|
||||
{
|
||||
res_exp = m_bv_util.mk_sign_extend(to_ebits-from_ebits+2, exp);
|
||||
|
||||
// subtract lz for subnormal numbers.
|
||||
expr_ref lz_ext(m);
|
||||
lz_ext = m_bv_util.mk_zero_extend(to_ebits-from_ebits+2, lz);
|
||||
res_exp = m_bv_util.mk_bv_sub(res_exp, lz_ext);
|
||||
}
|
||||
else if (from_ebits > (to_ebits + 2))
|
||||
{
|
||||
expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), h_or_eq(m), h_and_eq(m);
|
||||
expr_ref no_ovf(m), zero1(m), s_is_one(m), s_is_zero(m);
|
||||
high = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, exp);
|
||||
low = m_bv_util.mk_extract(to_ebits+1, 0, exp);
|
||||
lows = m_bv_util.mk_extract(to_ebits+1, to_ebits+1, low);
|
||||
|
||||
expr_ref c2(m);
|
||||
m_simp.mk_ite(h_or_eq, s_is_one, m.mk_false(), c2);
|
||||
m_simp.mk_ite(h_and_eq, s_is_zero, c2, exponent_overflow);
|
||||
high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high.get());
|
||||
high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high.get());
|
||||
|
||||
zero1 = m_bv_util.mk_numeral(0, 1);
|
||||
m_simp.mk_eq(high_red_and, one1, h_and_eq);
|
||||
m_simp.mk_eq(high_red_or, zero1, h_or_eq);
|
||||
m_simp.mk_eq(lows, zero1, s_is_zero);
|
||||
m_simp.mk_eq(lows, one1, s_is_one);
|
||||
|
||||
// Note: Upon overflow, we _could_ try to shift the significand around...
|
||||
expr_ref c2(m);
|
||||
m_simp.mk_ite(h_or_eq, s_is_one, m.mk_false(), c2);
|
||||
m_simp.mk_ite(h_and_eq, s_is_zero, c2, exponent_overflow);
|
||||
|
||||
// Note: Upon overflow, we _could_ try to shift the significand around...
|
||||
|
||||
res_exp = low;
|
||||
}
|
||||
else
|
||||
res_exp = exp;
|
||||
// subtract lz for subnormal numbers.
|
||||
expr_ref lz_ext(m), lz_rest(m), lz_redor(m), lz_redor_bool(m);
|
||||
lz_ext = m_bv_util.mk_extract(to_ebits+1, 0, lz);
|
||||
lz_rest = m_bv_util.mk_extract(from_ebits-1, to_ebits+2, lz);
|
||||
lz_redor = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, lz_rest.get());
|
||||
m_simp.mk_eq(lz_redor, one1, lz_redor_bool);
|
||||
m_simp.mk_or(exponent_overflow, lz_redor_bool, exponent_overflow);
|
||||
|
||||
// subtract lz for subnormal numbers.
|
||||
expr_ref lz_ext(m);
|
||||
lz_ext = m_bv_util.mk_zero_extend(to_ebits-from_ebits+2, lz);
|
||||
res_exp = m_bv_util.mk_bv_sub(res_exp, lz_ext);
|
||||
SASSERT(m_bv_util.get_bv_size(res_exp) == to_ebits+2);
|
||||
res_exp = m_bv_util.mk_bv_sub(low, lz_ext);
|
||||
}
|
||||
else // from_ebits == (to_ebits + 2)
|
||||
res_exp = m_bv_util.mk_bv_sub(exp, lz);
|
||||
|
||||
dbg_decouple("fpa2bv_to_float_res_sig", res_sig);
|
||||
dbg_decouple("fpa2bv_to_float_res_exp", res_exp);
|
||||
SASSERT(m_bv_util.get_bv_size(res_exp) == to_ebits+2);
|
||||
SASSERT(is_well_sorted(m, res_exp));
|
||||
|
||||
expr_ref rounded(m);
|
||||
round(s, rm, res_sgn, res_sig, res_exp, rounded);
|
||||
|
||||
dbg_decouple("fpa2bv_to_float_res_sig", res_sig);
|
||||
dbg_decouple("fpa2bv_to_float_res_exp", res_exp);
|
||||
|
||||
expr_ref is_neg(m), sig_inf(m);
|
||||
m_simp.mk_eq(sgn, one1, is_neg);
|
||||
mk_ite(is_neg, ninf, pinf, sig_inf);
|
||||
expr_ref rounded(m);
|
||||
round(s, rm, res_sgn, res_sig, res_exp, rounded);
|
||||
|
||||
expr_ref is_neg(m), sig_inf(m);
|
||||
m_simp.mk_eq(sgn, one1, is_neg);
|
||||
mk_ite(is_neg, ninf, pinf, sig_inf);
|
||||
|
||||
dbg_decouple("fpa2bv_to_float_exp_ovf", exponent_overflow);
|
||||
dbg_decouple("fpa2bv_to_float_exp_ovf", exponent_overflow);
|
||||
mk_ite(exponent_overflow, sig_inf, rounded, v6);
|
||||
|
||||
mk_ite(exponent_overflow, sig_inf, rounded, v6);
|
||||
|
||||
// And finally, we tie them together.
|
||||
mk_ite(c5, v5, v6, result);
|
||||
mk_ite(c4, v4, result, result);
|
||||
mk_ite(c3, v3, result, result);
|
||||
mk_ite(c2, v2, result, result);
|
||||
mk_ite(c1, v1, result, result);
|
||||
// And finally, we tie them together.
|
||||
mk_ite(c5, v5, v6, result);
|
||||
mk_ite(c4, v4, result, result);
|
||||
mk_ite(c3, v3, result, result);
|
||||
mk_ite(c2, v2, result, result);
|
||||
mk_ite(c1, v1, result, result);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// .. other than that, we only support rationals for asFloat
|
||||
|
@ -2167,14 +2191,14 @@ void fpa2bv_converter::mk_bot_exp(unsigned sz, expr_ref & result) {
|
|||
}
|
||||
|
||||
void fpa2bv_converter::mk_min_exp(unsigned ebits, expr_ref & result) {
|
||||
SASSERT(ebits > 0);
|
||||
SASSERT(ebits >= 2);
|
||||
const mpz & z = m_mpf_manager.m_powers2.m1(ebits-1, true);
|
||||
result = m_bv_util.mk_numeral(z + mpz(1), ebits);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_max_exp(unsigned ebits, expr_ref & result) {
|
||||
SASSERT(ebits > 0);
|
||||
result = m_bv_util.mk_numeral(m_mpf_manager.m_powers2.m1(ebits-1, false), ebits);
|
||||
SASSERT(ebits >= 2);
|
||||
result = m_bv_util.mk_numeral(m_mpf_manager.m_powers2.m1(ebits-1, false), ebits);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_leading_zeros(expr * e, unsigned max_bits, expr_ref & result) {
|
||||
|
@ -2220,14 +2244,14 @@ void fpa2bv_converter::mk_bias(expr * e, expr_ref & result) {
|
|||
unsigned ebits = m_bv_util.get_bv_size(e);
|
||||
SASSERT(ebits >= 2);
|
||||
|
||||
expr_ref mask(m);
|
||||
mask = m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits);
|
||||
result = m_bv_util.mk_bv_add(e, mask);
|
||||
expr_ref bias(m);
|
||||
bias = m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits);
|
||||
result = m_bv_util.mk_bv_add(e, bias);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_unbias(expr * e, expr_ref & result) {
|
||||
unsigned ebits = m_bv_util.get_bv_size(e);
|
||||
SASSERT(ebits >= 2);
|
||||
SASSERT(ebits >= 3);
|
||||
|
||||
expr_ref e_plus_one(m);
|
||||
e_plus_one = m_bv_util.mk_bv_add(e, m_bv_util.mk_numeral(1, ebits));
|
||||
|
@ -2263,6 +2287,7 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref
|
|||
|
||||
expr_ref denormal_sig(m), denormal_exp(m);
|
||||
denormal_sig = m_bv_util.mk_zero_extend(1, sig);
|
||||
SASSERT(ebits >= 3); // Note: when ebits=2 there is no 1-exponent, so mk_unbias will produce a 0.
|
||||
denormal_exp = m_bv_util.mk_numeral(1, ebits);
|
||||
mk_unbias(denormal_exp, denormal_exp);
|
||||
dbg_decouple("fpa2bv_unpack_denormal_exp", denormal_exp);
|
||||
|
@ -2345,7 +2370,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result)
|
|||
}
|
||||
|
||||
void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) {
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
return;
|
||||
// CMW: This works only for quantifier-free formulas.
|
||||
expr_ref new_e(m);
|
||||
|
@ -2436,13 +2461,12 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
|
|||
t = m_bv_util.mk_bv_add(exp, m_bv_util.mk_numeral(1, ebits+2));
|
||||
t = m_bv_util.mk_bv_sub(t, lz);
|
||||
t = m_bv_util.mk_bv_sub(t, m_bv_util.mk_sign_extend(2, e_min));
|
||||
expr_ref TINY(m);
|
||||
dbg_decouple("fpa2bv_rnd_t", t);
|
||||
expr_ref TINY(m);
|
||||
TINY = m_bv_util.mk_sle(t, m_bv_util.mk_numeral((unsigned)-1, ebits+2));
|
||||
|
||||
TRACE("fpa2bv_dbg", tout << "TINY = " << mk_ismt2_pp(TINY, m) << std::endl;);
|
||||
SASSERT(is_well_sorted(m, TINY));
|
||||
|
||||
dbg_decouple("fpa2bv_rnd_TINY", TINY);
|
||||
TRACE("fpa2bv_dbg", tout << "TINY = " << mk_ismt2_pp(TINY, m) << std::endl;);
|
||||
SASSERT(is_well_sorted(m, TINY));
|
||||
|
||||
expr_ref beta(m);
|
||||
beta = m_bv_util.mk_bv_add(m_bv_util.mk_bv_sub(exp, lz), m_bv_util.mk_numeral(1, ebits+2));
|
||||
|
@ -2455,7 +2479,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
|
|||
dbg_decouple("fpa2bv_rnd_e_min", e_min);
|
||||
dbg_decouple("fpa2bv_rnd_e_max", e_max);
|
||||
|
||||
expr_ref sigma(m), sigma_add(m), e_min_p2(m);
|
||||
expr_ref sigma(m), sigma_add(m);
|
||||
sigma_add = m_bv_util.mk_bv_sub(exp, m_bv_util.mk_sign_extend(2, e_min));
|
||||
sigma_add = m_bv_util.mk_bv_add(sigma_add, m_bv_util.mk_numeral(1, ebits+2));
|
||||
m_simp.mk_ite(TINY, sigma_add, lz, sigma);
|
||||
|
@ -2477,9 +2501,10 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
|
|||
rs_sig(m), ls_sig(m), big_sh_sig(m), sigma_le_cap(m);
|
||||
sigma_neg = m_bv_util.mk_bv_neg(sigma);
|
||||
sigma_cap = m_bv_util.mk_numeral(sbits+2, sigma_size);
|
||||
sigma_le_cap = m_bv_util.mk_sle(sigma_neg, sigma_cap);
|
||||
sigma_le_cap = m_bv_util.mk_ule(sigma_neg, sigma_cap);
|
||||
m_simp.mk_ite(sigma_le_cap, sigma_neg, sigma_cap, sigma_neg_capped);
|
||||
dbg_decouple("fpa2bv_rnd_sigma_neg", sigma_neg);
|
||||
dbg_decouple("fpa2bv_rnd_sigma_cap", sigma_cap);
|
||||
dbg_decouple("fpa2bv_rnd_sigma_neg_capped", sigma_neg_capped);
|
||||
sigma_lt_zero = m_bv_util.mk_sle(sigma, m_bv_util.mk_numeral((unsigned)-1, sigma_size));
|
||||
dbg_decouple("fpa2bv_rnd_sigma_lt_zero", sigma_lt_zero);
|
||||
|
|
|
@ -255,7 +255,8 @@ void goal::get_formulas(ptr_vector<expr> & result) {
|
|||
}
|
||||
|
||||
void goal::update(unsigned i, expr * f, proof * pr, expr_dependency * d) {
|
||||
SASSERT(proofs_enabled() == (pr != 0 && !m().is_undef_proof(pr)));
|
||||
// KLM: don't know why this assertion is no longer true
|
||||
// SASSERT(proofs_enabled() == (pr != 0 && !m().is_undef_proof(pr)));
|
||||
if (m_inconsistent)
|
||||
return;
|
||||
if (proofs_enabled()) {
|
||||
|
|
|
@ -189,14 +189,14 @@ class sls_tactic : public tactic {
|
|||
bool what_if(goal_ref const & g, func_decl * fd, const unsigned & fd_inx, const mpz & temp,
|
||||
double & best_score, unsigned & best_const, mpz & best_value) {
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
mpz old_value;
|
||||
m_mpz_manager.set(old_value, m_tracker.get_value(fd));
|
||||
#endif
|
||||
|
||||
double r = incremental_score(g, fd, temp);
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
TRACE("sls_whatif", tout << "WHAT IF " << fd->get_name() << " WERE " << m_mpz_manager.to_string(temp) <<
|
||||
" --> " << r << std::endl; );
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) {
|
|||
simp2_p.set_bool("push_ite_bv", false);
|
||||
simp2_p.set_bool("local_ctx", true);
|
||||
simp2_p.set_uint("local_ctx_limit", 10000000);
|
||||
simp2_p.set_bool("flat", true); // required by som
|
||||
simp2_p.set_bool("hoist_mul", false); // required by som
|
||||
|
||||
params_ref local_ctx_p = p;
|
||||
local_ctx_p.set_bool("local_ctx", true);
|
||||
|
|
|
@ -57,6 +57,11 @@ public:
|
|||
m_free_ids.finalize();
|
||||
}
|
||||
|
||||
unsigned show_hash(){
|
||||
unsigned h = string_hash((char *)&m_free_ids[0],m_free_ids.size()*sizeof(unsigned),17);
|
||||
return hash_u_u(h,m_next_id);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return N if the range of ids generated by this module is in the set [0..N)
|
||||
*/
|
||||
|
|
|
@ -360,6 +360,8 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode
|
|||
mk_inf(ebits, sbits, x.sign, o);
|
||||
else if (is_zero(x))
|
||||
mk_zero(ebits, sbits, x.sign, o);
|
||||
else if (x.ebits == ebits && x.sbits == sbits)
|
||||
set(o, x);
|
||||
else {
|
||||
set(o, x);
|
||||
unpack(o, true);
|
||||
|
@ -1378,12 +1380,12 @@ bool mpf_manager::has_top_exp(mpf const & x) {
|
|||
}
|
||||
|
||||
mpf_exp_t mpf_manager::mk_bot_exp(unsigned ebits) {
|
||||
SASSERT(ebits > 0);
|
||||
SASSERT(ebits >= 2);
|
||||
return m_mpz_manager.get_int64(m_powers2.m1(ebits-1, true));
|
||||
}
|
||||
|
||||
mpf_exp_t mpf_manager::mk_top_exp(unsigned ebits) {
|
||||
SASSERT(ebits > 0);
|
||||
SASSERT(ebits >= 2);
|
||||
return m_mpz_manager.get_int64(m_powers2(ebits-1));
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ mpn_manager static_mpn_manager;
|
|||
const mpn_digit mpn_manager::zero = 0;
|
||||
|
||||
mpn_manager::mpn_manager() {
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
trace_enabled=true;
|
||||
#endif
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ int mpn_manager::compare(mpn_digit const * a, size_t const lnga,
|
|||
mpn_digit const * b, size_t const lngb) const {
|
||||
int res = 0;
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
if (trace_enabled)
|
||||
STRACE("mpn", tout << "[mpn] "; );
|
||||
#endif
|
||||
|
@ -60,7 +60,7 @@ int mpn_manager::compare(mpn_digit const * a, size_t const lnga,
|
|||
res = -1;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
if (trace_enabled)
|
||||
STRACE("mpn", tout << ((res == 1) ? " > " : (res == -1) ? " < " : " == "); );
|
||||
#endif
|
||||
|
@ -212,7 +212,7 @@ bool mpn_manager::div(mpn_digit const * numer, size_t const lnum,
|
|||
trace(numer, lnum, denom, lden, "%");
|
||||
trace_nl(rem, lden);
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
mpn_sbuffer temp(lnum+1, 0);
|
||||
mul(quot, lnum-lden+1, denom, lden, temp.c_ptr());
|
||||
size_t real_size;
|
||||
|
@ -340,7 +340,7 @@ bool mpn_manager::div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom,
|
|||
// Replace numer[j+n]...numer[j] with
|
||||
// numer[j+n]...numer[j] - q * (denom[n-1]...denom[0])
|
||||
mpn_digit q_hat_small = (mpn_digit)q_hat;
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
trace_enabled = false;
|
||||
#endif
|
||||
mul(&q_hat_small, 1, denom.c_ptr(), n, t_ms.c_ptr());
|
||||
|
@ -354,7 +354,7 @@ bool mpn_manager::div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom,
|
|||
for (size_t i = 0; i < n+1; i++)
|
||||
numer[j+i] = t_ab[i];
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
trace_enabled = true;
|
||||
#endif
|
||||
STRACE("mpn_div", tout << "q_hat=" << q_hat << " r_hat=" << r_hat;
|
||||
|
@ -416,7 +416,7 @@ void mpn_manager::display_raw(std::ostream & out, mpn_digit const * a, size_t co
|
|||
void mpn_manager::trace(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb,
|
||||
const char * op) const {
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
if (trace_enabled)
|
||||
STRACE("mpn", tout << "[mpn] " << to_string(a, lnga, char_buf, sizeof(char_buf));
|
||||
tout << " " << op << " " << to_string(b, lngb, char_buf, sizeof(char_buf));
|
||||
|
@ -425,14 +425,14 @@ void mpn_manager::trace(mpn_digit const * a, size_t const lnga,
|
|||
}
|
||||
|
||||
void mpn_manager::trace(mpn_digit const * a, size_t const lnga) const {
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
if (trace_enabled)
|
||||
STRACE("mpn", tout << to_string(a, lnga, char_buf, sizeof(char_buf)); );
|
||||
#endif
|
||||
}
|
||||
|
||||
void mpn_manager::trace_nl(mpn_digit const * a, size_t const lnga) const {
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
if (trace_enabled)
|
||||
STRACE("mpn", tout << to_string(a, lnga, char_buf, sizeof(char_buf)) << std::endl; );
|
||||
#endif
|
||||
|
|
|
@ -101,7 +101,7 @@ private:
|
|||
bool div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom,
|
||||
mpn_digit * quot, mpn_digit * rem);
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
mutable char char_buf[4096];
|
||||
bool trace_enabled;
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue