diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 704756072..6faeb3edc 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -1155,6 +1155,30 @@ static void parse_example() { // expr b = c.parse_string("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))"); } +void mk_model_example() { + context c; + + // construct empty model + model m(c); + + // create constants "a", "b" and get their func_decl + expr a = c.int_const("a"); + expr b = c.int_const("b"); + func_decl a_decl = a.decl(); + func_decl b_decl = b.decl(); + + // create numerals to be used in model + expr zero_numeral = c.int_val(0); + expr one_numeral = c.int_val(1); + + // add assignment to model + m.add_const_interp(a_decl, zero_numeral); + m.add_const_interp(b_decl, one_numeral); + + // evaluate a + b < 2 in the model + std::cout << m.eval(a + b < 2)<< std::endl; +} + int main() { @@ -1202,6 +1226,7 @@ int main() { sudoku_example(); std::cout << "\n"; consequence_example(); std::cout << "\n"; parse_example(); std::cout << "\n"; + mk_model_example(); std::cout << "\n"; std::cout << "done\n"; } catch (exception & ex) { diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index a6937f293..14e403826 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -1754,7 +1754,6 @@ void parser_example5() { err: printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e)); if (ctx != NULL) { - printf("Error message: '%s'.\n",Z3_get_parser_error(ctx)); del_solver(ctx, s); Z3_del_context(ctx); } diff --git a/scripts/mk_project.py b/scripts/mk_project.py index dada93069..ca62f5c5f 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -54,6 +54,8 @@ 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','nlsat','tactic','nlsat_tactic'], 'qe') + add_lib('sat_solver', ['solver', 'core_tactics', 'aig_tactic', 'bv_tactics', 'arith_tactics', 'sat_tactic'], 'sat/sat_solver') + add_lib('fd_solver', ['core_tactics', 'arith_tactics', 'sat_solver'], 'tactic/fd_solver') add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base') add_lib('dataflow', ['muz'], 'muz/dataflow') add_lib('transforms', ['muz', 'hilbert', 'dataflow'], 'muz/transforms') @@ -61,14 +63,13 @@ def init_project_def(): add_lib('spacer', ['muz', 'transforms', 'arith_tactics', 'smt_tactic'], 'muz/spacer') add_lib('clp', ['muz', 'transforms'], 'muz/clp') add_lib('tab', ['muz', 'transforms'], 'muz/tab') - add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') add_lib('ddnf', ['muz', 'transforms', 'rel'], 'muz/ddnf') + add_lib('bmc', ['muz', 'transforms', 'fd_solver'], 'muz/bmc') add_lib('fp', ['muz', 'clp', 'tab', 'rel', 'bmc', 'ddnf', 'spacer'], 'muz/fp') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') - add_lib('sat_solver', ['solver', 'core_tactics', 'aig_tactic', 'bv_tactics', 'arith_tactics', 'sat_tactic'], 'sat/sat_solver') add_lib('smtlogic_tactics', ['ackermannization', 'sat_solver', 'arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics') add_lib('fpa_tactics', ['fpa', 'core_tactics', 'bv_tactics', 'sat_tactic', 'smt_tactic', 'arith_tactics', 'smtlogic_tactics'], 'tactic/fpa') - add_lib('portfolio', ['smtlogic_tactics', 'sat_solver', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') + add_lib('portfolio', ['smtlogic_tactics', 'sat_solver', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'fd_solver', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('opt', ['smt', 'smtlogic_tactics', 'sls_tactic', 'sat_solver'], 'opt') API_files = ['z3_api.h', 'z3_ast_containers.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_fixedpoint.h', 'z3_optimization.h', 'z3_fpa.h', 'z3_spacer.h'] add_lib('api', ['portfolio', 'realclosure', 'opt'], @@ -89,6 +90,7 @@ def init_project_def(): set_z3py_dir('api/python') add_python(_libz3Component) add_python_install(_libz3Component) + add_js() # Examples add_cpp_example('cpp_example', 'c++') add_cpp_example('z3_tptp', 'tptp') diff --git a/scripts/mk_util.py b/scripts/mk_util.py index d51735255..770e118ee 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -82,6 +82,7 @@ VS_ARM = False LINUX_X64 = True ONLY_MAKEFILES = False Z3PY_SRC_DIR=None +Z3JS_SRC_DIR=None VS_PROJ = False TRACE = False PYTHON_ENABLED=False @@ -89,6 +90,7 @@ DOTNET_ENABLED=False DOTNET_KEY_FILE=getenv("Z3_DOTNET_KEY_FILE", None) JAVA_ENABLED=False ML_ENABLED=False +JS_ENABLED=False PYTHON_INSTALL_ENABLED=False STATIC_LIB=False STATIC_BIN=False @@ -654,6 +656,7 @@ def display_help(exit_code): print(" --dotnet-key= sign the .NET assembly using the private key in .") print(" --java generate Java bindings.") print(" --ml generate OCaml bindings.") + print(" --js generate JScript bindings.") print(" --python generate Python bindings.") print(" --staticlib build Z3 static library.") print(" --staticbin build a statically linked Z3 binary.") @@ -687,14 +690,14 @@ 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, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED + global DOTNET_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, JS_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED global LINUX_X64, SLOW_OPTIMIZE, USE_OMP, LOG_SYNC global GUARD_CF, ALWAYS_DYNAMIC_BASE try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', ['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', - 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', + 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js', 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'noomp', 'pypkgdir=', 'python', 'staticbin', 'log-sync']) except: print("ERROR: Invalid command line option") @@ -755,6 +758,8 @@ def parse_options(): GIT_DESCRIBE = True elif opt in ('', '--ml'): ML_ENABLED = True + elif opt == "--js": + JS_ENABLED = True elif opt in ('', '--noomp'): USE_OMP = False elif opt in ('', '--log-sync'): @@ -817,6 +822,16 @@ def set_build_dir(d): BUILD_DIR = norm_path(d) REV_BUILD_DIR = reverse_path(d) +def set_z3js_dir(p): + global SRC_DIR, Z3JS_SRC_DIR + p = norm_path(p) + full = os.path.join(SRC_DIR, p) + if not os.path.exists(full): + raise MKException("Python bindings directory '%s' does not exist" % full) + Z3JS_SRC_DIR = full + if VERBOSE: + print("Js bindings directory was detected.") + def set_z3py_dir(p): global SRC_DIR, Z3PY_SRC_DIR p = norm_path(p) @@ -852,6 +867,10 @@ def get_components(): def get_z3py_dir(): return Z3PY_SRC_DIR +# Return directory where the js bindings are located +def get_z3js_dir(): + return Z3JS_SRC_DIR + # Return true if in verbose mode def is_verbose(): return VERBOSE @@ -862,6 +881,9 @@ def is_java_enabled(): def is_ml_enabled(): return ML_ENABLED +def is_js_enabled(): + return JS_ENABLED + def is_dotnet_enabled(): return DOTNET_ENABLED @@ -1411,6 +1433,22 @@ class DLLComponent(Component): shutil.copy('%s.a' % os.path.join(build_path, self.dll_name), '%s.a' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) +class JsComponent(Component): + def __init__(self): + Component.__init__(self, "js", None, []) + + def main_component(self): + return False + + def mk_win_dist(self, build_path, dist_path): + return + + def mk_unix_dist(self, build_path, dist_path): + return + + def mk_makefile(self, out): + return + class PythonComponent(Component): def __init__(self, name, libz3Component): assert isinstance(libz3Component, DLLComponent) @@ -2320,6 +2358,9 @@ def add_python(libz3Component): name = 'python' reg_component(name, PythonComponent(name, libz3Component)) +def add_js(): + reg_component('js', JsComponent()) + def add_python_install(libz3Component): name = 'python_install' reg_component(name, PythonInstallComponent(name, libz3Component)) @@ -2949,6 +2990,9 @@ def mk_bindings(api_files): ml_output_dir = None if is_ml_enabled(): ml_output_dir = get_component('ml').src_dir + if is_js_enabled(): + set_z3js_dir("api/js") + js_output_dir = get_component('js').src_dir # Get the update_api module to do the work for us update_api.generate_files(api_files=new_api_files, api_output_dir=get_component('api').src_dir, @@ -2956,6 +3000,7 @@ def mk_bindings(api_files): dotnet_output_dir=dotnet_output_dir, java_output_dir=java_output_dir, java_package_name=java_package_name, + js_output_dir=get_z3js_dir(), ml_output_dir=ml_output_dir, ml_src_dir=ml_output_dir ) diff --git a/scripts/update_api.py b/scripts/update_api.py index b082c96e1..917df94a2 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -311,7 +311,7 @@ def display_args_to_z3(params): core_py.write("a%s" % i) i = i + 1 -NULLWrapped = [ 'Z3_mk_context', 'Z3_mk_context_rc', 'Z3_mk_interpolation_context' ] +NULLWrapped = [ 'Z3_mk_context', 'Z3_mk_context_rc' ] Unwrapped = [ 'Z3_del_context', 'Z3_get_error_code' ] def mk_py_wrappers(): @@ -741,6 +741,59 @@ def mk_java(java_dir, package_name): if mk_util.is_verbose(): print("Generated '%s'" % java_nativef) + +Type2Napi = { VOID : '', VOID_PTR : '', INT : 'number', UINT : 'number', INT64 : 'number', UINT64 : 'number', DOUBLE : 'number', + FLOAT : 'number', STRING : 'string', STRING_PTR : 'array', + BOOL : 'number', SYMBOL : 'external', PRINT_MODE : 'number', ERROR_CODE : 'number' } + +def type2napi(t): + try: + return Type2Napi[t] + except: + return "external" + +Type2NapiBuilder = { VOID : '', VOID_PTR : '', INT : 'int32', UINT : 'uint32', INT64 : 'int64', UINT64 : 'uint64', DOUBLE : 'double', + FLOAT : 'float', STRING : 'string', STRING_PTR : 'array', + BOOL : 'bool', SYMBOL : 'external', PRINT_MODE : 'int32', ERROR_CODE : 'int32' } + +def type2napibuilder(t): + try: + return Type2NapiBuilder[t] + except: + return "external" + + +def mk_js(js_output_dir): + with open(os.path.join(js_output_dir, "z3.json"), 'w') as ous: + ous.write("{\n") + ous.write(" \"api\": [\n") + for name, result, params in _dotnet_decls: + ous.write(" {\n") + ous.write(" \"name\": \"%s\",\n" % name) + ous.write(" \"c_type\": \"%s\",\n" % Type2Str[result]) + ous.write(" \"napi_type\": \"%s\",\n" % type2napi(result)) + ous.write(" \"arg_list\": [") + first = True + for p in params: + if first: + first = False + ous.write("\n {\n") + else: + ous.write(",\n {\n") + t = param_type(p) + k = t + ous.write(" \"name\": \"%s\",\n" % "") # TBD + ous.write(" \"c_type\": \"%s\",\n" % type2str(t)) + ous.write(" \"napi_type\": \"%s\",\n" % type2napi(t)) + ous.write(" \"napi_builder\": \"%s\"\n" % type2napibuilder(t)) + ous.write( " }") + ous.write("],\n") + ous.write(" \"napi_builder\": \"%s\"\n" % type2napibuilder(result)) + ous.write(" },\n") + ous.write(" ]\n") + ous.write("}\n") + + def mk_log_header(file, name, params): file.write("void log_%s(" % name) i = 0 @@ -955,9 +1008,9 @@ def def_API(name, result, params): log_c.write(" Au(a%s);\n" % sz) exe_c.write("in.get_uint_array(%s)" % i) elif ty == INT: - log_c.write("U(a%s[i]);" % i) + log_c.write("I(a%s[i]);" % i) log_c.write(" }\n") - log_c.write(" Au(a%s);\n" % sz) + log_c.write(" Ai(a%s);\n" % sz) exe_c.write("in.get_int_array(%s)" % i) elif ty == BOOL: log_c.write("U(a%s[i]);" % i) @@ -1665,6 +1718,7 @@ for v in ('Z3_LIBRARY_PATH', 'PATH', 'PYTHONPATH'): _all_dirs.extend(_default_dirs) +_failures = [] for d in _all_dirs: try: d = os.path.realpath(d) @@ -1673,14 +1727,16 @@ for d in _all_dirs: if os.path.isfile(d): _lib = ctypes.CDLL(d) break - except: + except Exception as e: + _failures += [e] pass if _lib is None: # If all else failed, ask the system to find it. try: _lib = ctypes.CDLL('libz3.%s' % _ext) - except: + except Exception as e: + _failures += [e] pass if _lib is None: @@ -1739,6 +1795,7 @@ def generate_files(api_files, dotnet_output_dir=None, java_output_dir=None, java_package_name=None, + js_output_dir=None, ml_output_dir=None, ml_src_dir=None): """ @@ -1819,6 +1876,9 @@ def generate_files(api_files, assert not ml_src_dir is None mk_ml(ml_src_dir, ml_output_dir) + if js_output_dir: + mk_js(js_output_dir) + def main(args): logging.basicConfig(level=logging.INFO) parser = argparse.ArgumentParser(description=__doc__) @@ -1852,6 +1912,10 @@ def main(args): dest="ml_output_dir", default=None, help="Directory to emit OCaml files. If not specified no files are emitted.") + parser.add_argument("--js_output_dir", + dest="js_output_dir", + default=None, + help="Directory to emit js bindings. If not specified no files are emitted.") pargs = parser.parse_args(args) if pargs.java_output_dir: @@ -1875,6 +1939,7 @@ def main(args): dotnet_output_dir=pargs.dotnet_output_dir, java_output_dir=pargs.java_output_dir, java_package_name=pargs.java_package_name, + js_output_dir=pargs.js_output_dir, ml_output_dir=pargs.ml_output_dir, ml_src_dir=pargs.ml_src_dir) return 0 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7dee4039a..826f87e8c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -91,6 +91,7 @@ add_subdirectory(tactic/ufbv) add_subdirectory(sat/sat_solver) add_subdirectory(tactic/smtlogics) add_subdirectory(tactic/fpa) +add_subdirectory(tactic/fd_solver) add_subdirectory(tactic/portfolio) add_subdirectory(opt) add_subdirectory(api) diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index 47d91209e..1bb1b6a51 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -29,14 +29,14 @@ Notes: #define CHECK_IS_ALGEBRAIC(ARG, RET) { \ if (!Z3_algebraic_is_value_core(c, ARG)) { \ - SET_ERROR_CODE(Z3_INVALID_ARG); \ + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); \ return RET; \ } \ } #define CHECK_IS_ALGEBRAIC_X(ARG, RET) { \ if (!Z3_algebraic_is_value_core(c, ARG)) { \ - SET_ERROR_CODE(Z3_INVALID_ARG); \ + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); \ RETURN_Z3(RET); \ } \ } @@ -196,7 +196,7 @@ extern "C" { CHECK_IS_ALGEBRAIC_X(b, nullptr); if ((is_rational(c, b) && get_rational(c, b).is_zero()) || (!is_rational(c, b) && am(c).is_zero(get_irrational(c, b)))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } BIN_OP(/,div); @@ -211,7 +211,7 @@ extern "C" { if (k % 2 == 0) { if ((is_rational(c, a) && get_rational(c, a).is_neg()) || (!is_rational(c, a) && am(c).is_neg(get_irrational(c, a)))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -360,13 +360,13 @@ extern "C" { expr2polynomial converter(mk_c(c)->m(), pm, nullptr, true); if (!converter.to_polynomial(to_expr(p), _p, d) || static_cast(max_var(_p)) >= n + 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } algebraic_numbers::manager & _am = am(c); scoped_anum_vector as(_am); if (!to_anum_vector(c, n, a, as)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } scoped_anum_vector roots(_am); @@ -396,13 +396,13 @@ extern "C" { expr2polynomial converter(mk_c(c)->m(), pm, nullptr, true); if (!converter.to_polynomial(to_expr(p), _p, d) || static_cast(max_var(_p)) >= n) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } algebraic_numbers::manager & _am = am(c); scoped_anum_vector as(_am); if (!to_anum_vector(c, n, a, as)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } { diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index f245dfd18..f46f56ef2 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -51,7 +51,7 @@ extern "C" { LOG_Z3_mk_real(c, num, den); RESET_ERROR_CODE(); if (den == 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } sort* s = mk_c(c)->m().mk_sort(mk_c(c)->get_arith_fid(), REAL_SORT); @@ -97,7 +97,7 @@ extern "C" { LOG_Z3_mk_sub(c, num_args, args); RESET_ERROR_CODE(); if (num_args == 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } expr* r = to_expr(args[0]); @@ -129,7 +129,7 @@ extern "C" { LOG_Z3_get_algebraic_number_lower(c, a, precision); RESET_ERROR_CODE(); if (!Z3_is_algebraic_number(c, a)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } expr * e = to_expr(a); @@ -147,7 +147,7 @@ extern "C" { LOG_Z3_get_algebraic_number_upper(c, a, precision); RESET_ERROR_CODE(); if (!Z3_is_algebraic_number(c, a)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } expr * e = to_expr(a); @@ -167,7 +167,7 @@ extern "C" { rational val; ast * _a = to_ast(a); if (!is_expr(_a) || !mk_c(c)->autil().is_numeral(to_expr(_a), val)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } expr * r = mk_c(c)->autil().mk_numeral(numerator(val), true); @@ -183,7 +183,7 @@ extern "C" { rational val; ast * _a = to_ast(a); if (!is_expr(_a) || !mk_c(c)->autil().is_numeral(to_expr(_a), val)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } expr * r = mk_c(c)->autil().mk_numeral(denominator(val), true); diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index 31391e218..a9f5d7d70 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -58,7 +58,7 @@ extern "C" { sort * a_ty = m.get_sort(_a); sort * i_ty = m.get_sort(_i); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } sort * domain[2] = {a_ty, i_ty}; @@ -81,7 +81,7 @@ extern "C" { sort * a_ty = m.get_sort(_a); // sort * i_ty = m.get_sort(_i); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } ptr_vector domain; @@ -113,7 +113,7 @@ extern "C" { sort * i_ty = m.get_sort(_i); sort * v_ty = m.get_sort(_v); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } sort * domain[3] = {a_ty, i_ty, v_ty}; @@ -136,7 +136,7 @@ extern "C" { sort * a_ty = m.get_sort(_a); sort * v_ty = m.get_sort(_v); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } ptr_vector domain; @@ -163,7 +163,7 @@ extern "C" { LOG_Z3_mk_map(c, f, n, args); RESET_ERROR_CODE(); if (n == 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ast_manager & m = mk_c(c)->m(); @@ -298,7 +298,7 @@ extern "C" { Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(0).get_ast()); RETURN_Z3(r); } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); Z3_CATCH_RETURN(nullptr); } @@ -314,7 +314,7 @@ extern "C" { Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(n-1).get_ast()); RETURN_Z3(r); } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); Z3_CATCH_RETURN(nullptr); } diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 0753d3ffe..52be66e77 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -48,7 +48,7 @@ extern "C" { LOG_Z3_mk_int_symbol(c, i); RESET_ERROR_CODE(); if (i < 0 || (size_t)i >= (SIZE_MAX >> PTR_ALIGNMENT)) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return nullptr; } Z3_symbol result = of_symbol(symbol(i)); @@ -281,7 +281,7 @@ extern "C" { if (_s.is_numerical()) { return _s.get_num(); } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return -1; Z3_CATCH_RETURN(-1); } @@ -355,7 +355,7 @@ extern "C" { LOG_Z3_get_app_decl(c, a); RESET_ERROR_CODE(); if (!is_app(reinterpret_cast(a))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(of_func_decl(to_app(a)->get_decl())); @@ -371,11 +371,11 @@ extern "C" { LOG_Z3_get_app_arg(c, a, i); RESET_ERROR_CODE(); if (!is_app(reinterpret_cast(a))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } if (i >= to_app(a)->get_num_args()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(of_ast(to_app(a)->get_arg(i))); @@ -384,12 +384,14 @@ extern "C" { Z3_symbol Z3_API Z3_get_decl_name(Z3_context c, Z3_func_decl d) { LOG_Z3_get_decl_name(c, d); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, nullptr); return of_symbol(to_func_decl(d)->get_name()); } unsigned Z3_API Z3_get_decl_num_parameters(Z3_context c, Z3_func_decl d) { LOG_Z3_get_decl_num_parameters(c, d); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, 0); return to_func_decl(d)->get_num_parameters(); } @@ -397,8 +399,9 @@ extern "C" { Z3_TRY; LOG_Z3_get_decl_parameter_kind(c, d, idx); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, Z3_PARAMETER_INT); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return Z3_PARAMETER_INT; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; @@ -429,13 +432,14 @@ extern "C" { Z3_TRY; LOG_Z3_get_decl_int_parameter(c, d, idx); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, 0); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_int()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return p.get_int(); @@ -446,13 +450,14 @@ extern "C" { Z3_TRY; LOG_Z3_get_decl_double_parameter(c, d, idx); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, 0); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_double()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return p.get_double(); @@ -463,13 +468,14 @@ extern "C" { Z3_TRY; LOG_Z3_get_decl_symbol_parameter(c, d, idx); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, 0); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return nullptr; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_symbol()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } return of_symbol(p.get_symbol()); @@ -480,13 +486,14 @@ extern "C" { Z3_TRY; LOG_Z3_get_decl_sort_parameter(c, d, idx); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, 0); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_ast() || !is_sort(p.get_ast())) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(of_sort(to_sort(p.get_ast()))); @@ -497,13 +504,14 @@ extern "C" { Z3_TRY; LOG_Z3_get_decl_ast_parameter(c, d, idx); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, 0); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_ast()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(of_ast(p.get_ast())); @@ -514,13 +522,14 @@ extern "C" { Z3_TRY; LOG_Z3_get_decl_func_decl_parameter(c, d, idx); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, 0); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_ast() || !is_func_decl(p.get_ast())) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(of_func_decl(to_func_decl(p.get_ast()))); @@ -531,13 +540,14 @@ extern "C" { Z3_TRY; LOG_Z3_get_decl_rational_parameter(c, d, idx); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, ""); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return ""; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_rational()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } return mk_c(c)->mk_external_string(p.get_rational().to_string()); @@ -549,6 +559,7 @@ extern "C" { Z3_TRY; LOG_Z3_get_sort_name(c, t); RESET_ERROR_CODE(); + CHECK_VALID_AST(t, nullptr); return of_symbol(to_sort(t)->get_name()); Z3_CATCH_RETURN(nullptr); } @@ -567,6 +578,7 @@ extern "C" { Z3_TRY; LOG_Z3_get_arity(c, d); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, 0); return to_func_decl(d)->get_arity(); Z3_CATCH_RETURN(0); } @@ -575,6 +587,7 @@ extern "C" { Z3_TRY; LOG_Z3_get_domain_size(c, d); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, 0); return to_func_decl(d)->get_arity(); Z3_CATCH_RETURN(0); } @@ -583,8 +596,9 @@ extern "C" { Z3_TRY; LOG_Z3_get_domain(c, d, i); RESET_ERROR_CODE(); + CHECK_VALID_AST(d, 0); if (i >= to_func_decl(d)->get_arity()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } Z3_sort r = of_sort(to_func_decl(d)->get_domain(i)); @@ -740,7 +754,7 @@ extern "C" { case AST_APP: { app* e = to_app(a); if (e->get_num_args() != num_args) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); } else { a = m.mk_app(e->get_decl(), num_args, args); @@ -749,7 +763,7 @@ extern "C" { } case AST_QUANTIFIER: { if (num_args != 1) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); } else { a = m.update_quantifier(to_quantifier(a), args[0]); @@ -779,7 +793,7 @@ extern "C" { expr * r = nullptr; for (unsigned i = 0; i < num_exprs; i++) { if (m.get_sort(from[i]) != m.get_sort(to[i])) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(of_expr(nullptr)); } SASSERT(from[i]->get_ref_count() > 0); @@ -881,7 +895,7 @@ extern "C" { RESET_ERROR_CODE(); func_decl* _d = to_func_decl(d); - if (null_family_id == _d->get_family_id()) { + if (d == nullptr || null_family_id == _d->get_family_id()) { return Z3_OP_UNINTERPRETED; } if (mk_c(c)->get_basic_fid() == _d->get_family_id()) { @@ -1212,14 +1226,14 @@ extern "C" { RESET_ERROR_CODE(); ast* _a = reinterpret_cast(a); if (!_a || _a->get_kind() != AST_VAR) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } var* va = to_var(_a); if (va) { return va->get_idx(); } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; Z3_CATCH_RETURN(0); } @@ -1230,7 +1244,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_VALID_AST(a, nullptr); if (c == target) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } SASSERT(mk_c(c)->m().contains(to_ast(a))); diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index 17dd086b5..44cadc691 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -71,7 +71,7 @@ extern "C" { RESET_ERROR_CODE(); obj_map::obj_map_entry * entry = to_ast_map_ref(m).find_core(to_ast(k)); if (entry == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } else { diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index ae5adecea..5fe19a7d5 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -65,7 +65,7 @@ extern "C" { LOG_Z3_ast_vector_get(c, v, i); RESET_ERROR_CODE(); if (i >= to_ast_vector_ref(v).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } // Remark: Don't need to invoke save_object. @@ -79,7 +79,7 @@ extern "C" { LOG_Z3_ast_vector_set(c, v, i, a); RESET_ERROR_CODE(); if (i >= to_ast_vector_ref(v).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return; } to_ast_vector_ref(v).set(i, to_ast(a)); @@ -107,8 +107,7 @@ extern "C" { LOG_Z3_ast_vector_translate(c, v, t); RESET_ERROR_CODE(); if (c == t) { - SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(nullptr); + RETURN_Z3(v); } ast_translation translator(mk_c(c)->m(), mk_c(t)->m()); Z3_ast_vector_ref * new_v = alloc(Z3_ast_vector_ref, *mk_c(t), mk_c(t)->m()); diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index 1876d930d..bd603aa6d 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -27,9 +27,6 @@ extern "C" { Z3_TRY; LOG_Z3_mk_bv_sort(c, sz); RESET_ERROR_CODE(); - if (sz == 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); - } parameter p(sz); Z3_sort r = of_sort(mk_c(c)->m().mk_sort(mk_c(c)->get_bv_fid(), BV_SORT, 1, &p)); RETURN_Z3(r); @@ -163,7 +160,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ // Not logging this one, since it is just syntax sugar. unsigned sz = Z3_get_bv_sort_size(c, s); if (sz == 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "zero length bit-vector supplied"); return nullptr; } Z3_ast x = Z3_mk_int64(c, 1, s); @@ -393,7 +390,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ if (to_sort(t)->get_family_id() == mk_c(c)->get_bv_fid() && to_sort(t)->get_decl_kind() == BV_SORT) { return to_sort(t)->get_parameter(0).get_int(); } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "sort is not a bit-vector"); return 0; Z3_CATCH_RETURN(0); } diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 295977a06..cc2a13aed 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -144,9 +144,11 @@ namespace api { } } - void context::set_error_code(Z3_error_code err) { + void context::set_error_code(Z3_error_code err, char const* opt_msg) { m_error_code = err; if (err != Z3_OK) { + m_exception_msg.clear(); + if (opt_msg) m_exception_msg = opt_msg; invoke_error_handler(err); } } @@ -159,7 +161,7 @@ namespace api { void context::check_searching() { if (m_searching) { - set_error_code(Z3_INVALID_USAGE); // TBD: error code could be fixed. + set_error_code(Z3_INVALID_USAGE, "cannot use function while searching"); // TBD: error code could be fixed. } } @@ -248,25 +250,24 @@ namespace api { if (ex.has_error_code()) { switch(ex.error_code()) { case ERR_MEMOUT: - set_error_code(Z3_MEMOUT_FAIL); + set_error_code(Z3_MEMOUT_FAIL, nullptr); break; case ERR_PARSER: - set_error_code(Z3_PARSER_ERROR); + set_error_code(Z3_PARSER_ERROR, ex.msg()); break; case ERR_INI_FILE: - set_error_code(Z3_INVALID_ARG); + set_error_code(Z3_INVALID_ARG, nullptr); break; case ERR_OPEN_FILE: - set_error_code(Z3_FILE_ACCESS_ERROR); + set_error_code(Z3_FILE_ACCESS_ERROR, nullptr); break; default: - set_error_code(Z3_INTERNAL_FATAL); + set_error_code(Z3_INTERNAL_FATAL, nullptr); break; } } else { - m_exception_msg = ex.msg(); - set_error_code(Z3_EXCEPTION); + set_error_code(Z3_EXCEPTION, ex.msg()); } } @@ -301,7 +302,7 @@ namespace api { case AST_FUNC_DECL: break; } - set_error_code(Z3_SORT_ERROR); + set_error_code(Z3_SORT_ERROR, nullptr); } } @@ -378,11 +379,13 @@ extern "C" { Z3_TRY; LOG_Z3_dec_ref(c, a); RESET_ERROR_CODE(); - if (to_ast(a)->get_ref_count() == 0) { - SET_ERROR_CODE(Z3_DEC_REF_ERROR); + if (a && to_ast(a)->get_ref_count() == 0) { + SET_ERROR_CODE(Z3_DEC_REF_ERROR, nullptr); return; } - mk_c(c)->m().dec_ref(to_ast(a)); + if (a) { + mk_c(c)->m().dec_ref(to_ast(a)); + } Z3_CATCH; } @@ -440,10 +443,14 @@ extern "C" { } void Z3_API Z3_set_error(Z3_context c, Z3_error_code e) { - SET_ERROR_CODE(e); + SET_ERROR_CODE(e, nullptr); } static char const * _get_error_msg(Z3_context c, Z3_error_code err) { + if (c) { + char const* msg = mk_c(c)->get_exception_msg(); + if (msg && *msg) return msg; + } switch(err) { case Z3_OK: return "ok"; case Z3_SORT_ERROR: return "type error"; @@ -457,7 +464,7 @@ extern "C" { case Z3_INTERNAL_FATAL: return "internal error"; case Z3_INVALID_USAGE: return "invalid usage"; case Z3_DEC_REF_ERROR: return "invalid dec_ref command"; - case Z3_EXCEPTION: return c == nullptr ? "Z3 exception" : mk_c(c)->get_exception_msg(); + case Z3_EXCEPTION: return "Z3 exception"; default: return "unknown"; } } diff --git a/src/api/api_context.h b/src/api/api_context.h index 50e89113d..a6f55d1aa 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -141,7 +141,7 @@ namespace api { Z3_error_code get_error_code() const { return m_error_code; } void reset_error_code(); - void set_error_code(Z3_error_code err); + void set_error_code(Z3_error_code err, char const* opt_msg); void set_error_handler(Z3_error_handler h) { m_error_handler = h; } // Sign an error if solver is searching void check_searching(); @@ -219,14 +219,6 @@ namespace api { // // ------------------------ smt_params & fparams() { return m_fparams; } - - // ------------------------ - // - // Parser interface - // - // ------------------------ - - std::string m_parser_error_buffer; }; @@ -234,14 +226,14 @@ namespace api { inline api::context * mk_c(Z3_context c) { return reinterpret_cast(c); } #define RESET_ERROR_CODE() { mk_c(c)->reset_error_code(); } -#define SET_ERROR_CODE(ERR) { mk_c(c)->set_error_code(ERR); } -#define CHECK_NON_NULL(_p_,_ret_) { if (_p_ == 0) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } -#define CHECK_VALID_AST(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_)) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } +#define SET_ERROR_CODE(ERR, MSG) { mk_c(c)->set_error_code(ERR, MSG); } +#define CHECK_NON_NULL(_p_,_ret_) { if (_p_ == 0) { SET_ERROR_CODE(Z3_INVALID_ARG, "ast is null"); return _ret_; } } +#define CHECK_VALID_AST(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_)) { SET_ERROR_CODE(Z3_INVALID_ARG, "not a valid ast"); return _ret_; } } #define CHECK_SEARCHING(c) mk_c(c)->check_searching(); inline bool is_expr(Z3_ast a) { return is_expr(to_ast(a)); } -#define CHECK_IS_EXPR(_p_, _ret_) { if (_p_ == 0 || !is_expr(_p_)) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } +#define CHECK_IS_EXPR(_p_, _ret_) { if (_p_ == 0 || !is_expr(_p_)) { SET_ERROR_CODE(Z3_INVALID_ARG, "ast is not an expression"); return _ret_; } } inline bool is_bool_expr(Z3_context c, Z3_ast a) { return is_expr(a) && mk_c(c)->m().is_bool(to_expr(a)); } -#define CHECK_FORMULA(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_) || !is_bool_expr(c, _a_)) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } +#define CHECK_FORMULA(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_) || !is_bool_expr(c, _a_)) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return _ret_; } } inline void check_sorts(Z3_context c, ast * n) { mk_c(c)->check_sorts(n); } #endif diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index fd31a65f8..b0a4def55 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -157,7 +157,7 @@ extern "C" { RESET_ERROR_CODE(); sort * r = to_sort(s); if (Z3_get_sort_kind(c, s) != Z3_RELATION_SORT) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "sort should be a relation"); return 0; } return r->get_num_parameters(); @@ -170,18 +170,18 @@ extern "C" { RESET_ERROR_CODE(); sort * r = to_sort(s); if (Z3_get_sort_kind(c, s) != Z3_RELATION_SORT) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "sort should be a relation"); RETURN_Z3(nullptr); } if (col >= r->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } parameter const& p = r->get_parameter(col); if (!p.is_ast() || !is_sort(p.get_ast())) { UNREACHABLE(); warning_msg("Sort parameter expected at %d", col); - SET_ERROR_CODE(Z3_INTERNAL_FATAL); + SET_ERROR_CODE(Z3_INTERNAL_FATAL, "sort parameter expected"); RETURN_Z3(nullptr); } Z3_sort res = of_sort(to_sort(p.get_ast())); @@ -364,7 +364,7 @@ extern "C" { install_dl_collect_cmds(coll, ctx); ctx.set_ignore_check(true); if (!parse_smt2_commands(ctx, s)) { - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, nullptr); return nullptr; } @@ -408,7 +408,7 @@ extern "C" { LOG_Z3_fixedpoint_from_file(c, d, s); std::ifstream is(s); if (!is) { - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(Z3_fixedpoint_from_stream(c, d, is)); diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 799e537ea..0c2544643 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -56,7 +56,7 @@ extern "C" { del_datatype_decl(dt); if (!is_ok) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -118,7 +118,7 @@ extern "C" { del_datatype_decl(dt); if (!is_ok) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -180,7 +180,7 @@ extern "C" { del_datatype_decl(decl); if (!is_ok) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -274,7 +274,7 @@ extern "C" { RESET_ERROR_CODE(); mk_c(c)->reset_last_result(); if (!constr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return; } ast_manager& m = mk_c(c)->m(); @@ -282,7 +282,7 @@ extern "C" { func_decl* f = reinterpret_cast(constr)->m_constructor.get(); if (!f) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return; } if (constructor_decl) { @@ -353,7 +353,7 @@ extern "C" { del_datatype_decl(data); if (!is_ok) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -416,7 +416,7 @@ extern "C" { del_datatype_decls(datas.size(), datas.c_ptr()); if (!ok) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return; } @@ -445,7 +445,7 @@ extern "C" { datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(_t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return dt_util.get_datatype_constructors(_t)->size(); @@ -458,12 +458,12 @@ extern "C" { sort * _t = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(_t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); if (idx >= decls.size()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } func_decl* decl = (decls)[idx]; @@ -488,12 +488,12 @@ extern "C" { datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(_t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); if (idx >= decls.size()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } func_decl* decl = (decls)[idx]; @@ -511,23 +511,23 @@ extern "C" { datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(_t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); if (idx_c >= decls.size()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } func_decl* decl = (decls)[idx_c]; if (decl->get_arity() <= idx_a) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & accs = *dt_util.get_constructor_accessors(decl); SASSERT(accs.size() == decl->get_arity()); if (accs.size() <= idx_a) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } decl = (accs)[idx_a]; @@ -543,7 +543,7 @@ extern "C" { sort * tuple = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(tuple) || dt_util.is_recursive(tuple) || dt_util.get_datatype_num_constructors(tuple) != 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } Z3_func_decl r = get_datatype_sort_constructor_core(c, t, 0); @@ -558,12 +558,12 @@ extern "C" { sort * tuple = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(tuple) || dt_util.is_recursive(tuple) || dt_util.get_datatype_num_constructors(tuple) != 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } ptr_vector const & decls = *dt_util.get_datatype_constructors(tuple); if (decls.size() != 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } ptr_vector const & accs = *dt_util.get_constructor_accessors(decls[0]); @@ -578,17 +578,17 @@ extern "C" { sort * tuple = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(tuple) || dt_util.is_recursive(tuple) || dt_util.get_datatype_num_constructors(tuple) != 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & decls = *dt_util.get_datatype_constructors(tuple); if (decls.size() != 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & accs = *dt_util.get_constructor_accessors((decls)[0]); if (accs.size() <= i) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } func_decl* acc = (accs)[i]; diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 261198354..cdc592527 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -175,7 +175,7 @@ extern "C" { LOG_Z3_mk_fpa_sort(c, ebits, sbits); RESET_ERROR_CODE(); if (ebits < 2 || sbits < 3) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "ebits should be at least 2, sbits at least 3"); } api::context * ctx = mk_c(c); sort * s = ctx->fpautil().mk_float_sort(ebits, sbits); @@ -222,7 +222,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_VALID_AST(s, nullptr); if (!is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -238,7 +238,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_VALID_AST(s, nullptr); if (!is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -255,7 +255,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_VALID_AST(s, nullptr); if (!is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -271,7 +271,7 @@ extern "C" { LOG_Z3_mk_fpa_fp(c, sgn, exp, sig); RESET_ERROR_CODE(); if (!is_bv(c, sgn) || !is_bv(c, exp) || !is_bv(c, sig)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "bv sorts expected for arguments"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -286,7 +286,7 @@ extern "C" { LOG_Z3_mk_fpa_numeral_float(c, v, ty); RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG,"fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -306,7 +306,7 @@ extern "C" { LOG_Z3_mk_fpa_numeral_double(c, v, ty); RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -323,7 +323,7 @@ extern "C" { LOG_Z3_mk_fpa_numeral_int(c, v, ty); RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -343,7 +343,7 @@ extern "C" { LOG_Z3_mk_fpa_numeral_int64_uint64(c, sgn, exp, sig, ty); RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -363,7 +363,7 @@ extern "C" { LOG_Z3_mk_fpa_numeral_int64_uint64(c, sgn, exp, sig, ty); RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -383,7 +383,7 @@ extern "C" { LOG_Z3_mk_fpa_abs(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -398,7 +398,7 @@ extern "C" { LOG_Z3_mk_fpa_neg(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -413,7 +413,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -428,7 +428,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -443,7 +443,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -458,7 +458,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -473,7 +473,7 @@ extern "C" { LOG_Z3_mk_fpa_fma(c, rm, t1, t2, t3); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2) || !is_fp(c, t3)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -488,7 +488,7 @@ extern "C" { LOG_Z3_mk_fpa_sqrt(c, rm, t); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -503,7 +503,7 @@ extern "C" { LOG_Z3_mk_fpa_rem(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -518,7 +518,7 @@ extern "C" { LOG_Z3_mk_fpa_round_to_integral(c, rm, t); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -533,7 +533,7 @@ extern "C" { LOG_Z3_mk_fpa_min(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -548,7 +548,7 @@ extern "C" { LOG_Z3_mk_fpa_max(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -563,7 +563,7 @@ extern "C" { LOG_Z3_mk_fpa_leq(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -578,7 +578,7 @@ extern "C" { LOG_Z3_mk_fpa_lt(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -593,7 +593,7 @@ extern "C" { LOG_Z3_mk_fpa_geq(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -608,7 +608,7 @@ extern "C" { LOG_Z3_mk_fpa_gt(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -623,7 +623,7 @@ extern "C" { LOG_Z3_mk_fpa_eq(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -638,7 +638,7 @@ extern "C" { LOG_Z3_mk_fpa_is_normal(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -653,7 +653,7 @@ extern "C" { LOG_Z3_mk_fpa_is_subnormal(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -668,7 +668,7 @@ extern "C" { LOG_Z3_mk_fpa_is_zero(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -683,7 +683,7 @@ extern "C" { LOG_Z3_mk_fpa_is_infinite(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -698,7 +698,7 @@ extern "C" { LOG_Z3_mk_fpa_is_nan(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -713,7 +713,7 @@ extern "C" { LOG_Z3_mk_fpa_is_negative(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -728,7 +728,7 @@ extern "C" { LOG_Z3_mk_fpa_is_positive(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -744,14 +744,14 @@ extern "C" { LOG_Z3_mk_fpa_to_fp_bv(c, bv, s); RESET_ERROR_CODE(); if (!is_bv(c, bv) || !is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "bv then fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!ctx->bvutil().is_bv(to_expr(bv)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "bv sort the flaot sort expected"); return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(bv)); @@ -769,7 +769,7 @@ extern "C" { if (!fu.is_rm(to_expr(rm)) || !fu.is_float(to_expr(t)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)); @@ -787,7 +787,7 @@ extern "C" { if (!fu.is_rm(to_expr(rm)) || !ctx->autil().is_real(to_expr(t)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)); @@ -805,7 +805,7 @@ extern "C" { if (!fu.is_rm(to_expr(rm)) || !ctx->bvutil().is_bv(to_expr(t)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)); @@ -823,7 +823,7 @@ extern "C" { if (!fu.is_rm(to_expr(rm)) || !ctx->bvutil().is_bv(to_expr(t)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); return nullptr; } expr * a = fu.mk_to_fp_unsigned(to_sort(s), to_expr(rm), to_expr(t)); @@ -837,7 +837,7 @@ extern "C" { LOG_Z3_mk_fpa_to_ubv(c, rm, t, sz); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -852,7 +852,7 @@ extern "C" { LOG_Z3_mk_fpa_to_sbv(c, rm, t, sz); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -867,7 +867,7 @@ extern "C" { LOG_Z3_mk_fpa_to_real(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -884,7 +884,7 @@ extern "C" { CHECK_NON_NULL(s, 0); CHECK_VALID_AST(s, 0); if (!is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(0); } return mk_c(c)->fpautil().get_ebits(to_sort(s)); @@ -898,7 +898,7 @@ extern "C" { CHECK_NON_NULL(s, 0); CHECK_VALID_AST(s, 0); if (!is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(0); } return mk_c(c)->fpautil().get_sbits(to_sort(s)); @@ -912,7 +912,7 @@ extern "C" { CHECK_NON_NULL(t, 0); CHECK_VALID_AST(t, 0); if (sgn == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "sign cannot be a nullpointer"); return 0; } ast_manager & m = mk_c(c)->m(); @@ -921,13 +921,13 @@ extern "C" { fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return 0; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(to_expr(t), val); if (!r || mpfm.is_nan(val)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return 0; } *sgn = mpfm.sgn(val); @@ -948,13 +948,13 @@ extern "C" { api::context * ctx = mk_c(c); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); RETURN_Z3(nullptr); } scoped_mpf val(mpfm); bool r = plugin->is_numeral(to_expr(t), val); if (!r || mpfm.is_nan(val)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return nullptr; } app * a; @@ -981,13 +981,13 @@ extern "C" { SASSERT(plugin != 0); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); RETURN_Z3(nullptr); } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); RETURN_Z3(nullptr); } unsigned sbits = val.get().get_sbits(); @@ -1014,13 +1014,13 @@ extern "C" { SASSERT(plugin != 0); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return ""; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return ""; } unsigned sbits = val.get().get_sbits(); @@ -1042,7 +1042,7 @@ extern "C" { CHECK_NON_NULL(t, 0); CHECK_VALID_AST(t, 0); if (n == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid nullptr argument"); return 0; } ast_manager & m = mk_c(c)->m(); @@ -1053,7 +1053,7 @@ extern "C" { SASSERT(plugin != 0); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; return 0; } @@ -1063,7 +1063,7 @@ extern "C" { if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val)) || !mpzm.is_uint64(z)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; return 0; } @@ -1085,13 +1085,13 @@ extern "C" { SASSERT(plugin != 0); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return ""; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return ""; } unsigned ebits = val.get().get_ebits(); @@ -1120,7 +1120,7 @@ extern "C" { CHECK_NON_NULL(t, 0); CHECK_VALID_AST(t, 0); if (n == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid null argument"); return 0; } ast_manager & m = mk_c(c)->m(); @@ -1130,14 +1130,14 @@ extern "C" { SASSERT(plugin != 0); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; return 0; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; return 0; } @@ -1169,13 +1169,13 @@ extern "C" { fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); RETURN_Z3(nullptr); } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); RETURN_Z3(nullptr); } unsigned ebits = val.get().get_ebits(); @@ -1204,7 +1204,7 @@ extern "C" { CHECK_NON_NULL(t, nullptr); CHECK_VALID_AST(t, nullptr); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -1223,7 +1223,7 @@ extern "C" { !ctx->autil().is_int(to_expr(exp)) || !ctx->autil().is_real(to_expr(sig)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(exp), to_expr(sig)); @@ -1239,7 +1239,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_nan(to_expr(t)); @@ -1253,7 +1253,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_inf(to_expr(t)); @@ -1267,7 +1267,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_zero(to_expr(t)); @@ -1281,7 +1281,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_normal(to_expr(t)); @@ -1295,7 +1295,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_subnormal(to_expr(t)); @@ -1309,7 +1309,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_positive(to_expr(t)); @@ -1323,7 +1323,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_negative(to_expr(t)); diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index ae48a3f6f..cb3bb7478 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -30,7 +30,7 @@ extern "C" { LOG_Z3_mk_goal(c, models, unsat_cores, proofs); RESET_ERROR_CODE(); if (proofs != 0 && !mk_c(c)->m().proofs_enabled()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "proofs are required, but proofs are not enabled on the context"); RETURN_Z3(nullptr); } Z3_goal_ref * g = alloc(Z3_goal_ref, *mk_c(c)); @@ -119,7 +119,7 @@ extern "C" { LOG_Z3_goal_formula(c, g, idx); RESET_ERROR_CODE(); if (idx >= to_goal_ref(g)->size()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } expr * result = to_goal_ref(g)->form(idx); @@ -198,6 +198,10 @@ extern "C" { LOG_Z3_goal_to_dimacs_string(c, g); RESET_ERROR_CODE(); std::ostringstream buffer; + if (!to_goal_ref(g)->is_cnf()) { + SET_ERROR_CODE(Z3_INVALID_ARG, "If this is not what you want, then preprocess by optional bit-blasting and applying tseitin-cnf"); + RETURN_Z3(nullptr); + } to_goal_ref(g)->display_dimacs(buffer); // Hack for removing the trailing '\n' std::string result = buffer.str(); diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 7eb7d2fdd..939cccdca 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -94,7 +94,7 @@ extern "C" { CHECK_NON_NULL(m, nullptr); func_interp * _fi = to_model_ref(m)->get_func_interp(to_func_decl(f)); if (!_fi) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } Z3_func_interp_ref * fi = alloc(Z3_func_interp_ref, *mk_c(c), to_model_ref(m)); @@ -123,7 +123,7 @@ extern "C" { RETURN_Z3(of_func_decl(_m->get_constant(i))); } else { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -142,7 +142,7 @@ extern "C" { CHECK_NON_NULL(m, nullptr); model * _m = to_model_ref(m); if (i >= _m->get_num_functions()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return nullptr; } return of_func_decl(_m->get_function(i)); @@ -187,7 +187,7 @@ extern "C" { LOG_Z3_model_get_sort(c, m, i); RESET_ERROR_CODE(); if (i >= to_model_ref(m)->get_num_uninterpreted_sorts()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } sort * s = to_model_ref(m)->get_uninterpreted_sort(i); @@ -200,15 +200,14 @@ extern "C" { LOG_Z3_model_get_sort_universe(c, m, s); RESET_ERROR_CODE(); if (!to_model_ref(m)->has_uninterpreted_sort(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & universe = to_model_ref(m)->get_universe(to_sort(s)); Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); - unsigned sz = universe.size(); - for (unsigned i = 0; i < sz; i++) { - v->m_ast_vector.push_back(universe[i]); + for (expr * e : universe) { + v->m_ast_vector.push_back(e); } RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(nullptr); @@ -230,7 +229,7 @@ extern "C" { Z3_TRY; LOG_Z3_is_as_array(c, a); RESET_ERROR_CODE(); - return is_expr(to_ast(a)) && is_app_of(to_expr(a), mk_c(c)->get_array_fid(), OP_AS_ARRAY); + return a && is_expr(to_ast(a)) && is_app_of(to_expr(a), mk_c(c)->get_array_fid(), OP_AS_ARRAY); Z3_CATCH_RETURN(Z3_FALSE); } @@ -238,11 +237,11 @@ extern "C" { Z3_TRY; LOG_Z3_get_as_array_func_decl(c, a); RESET_ERROR_CODE(); - if (is_expr(to_ast(a)) && is_app_of(to_expr(a), mk_c(c)->get_array_fid(), OP_AS_ARRAY)) { + if (a && is_expr(to_ast(a)) && is_app_of(to_expr(a), mk_c(c)->get_array_fid(), OP_AS_ARRAY)) { RETURN_Z3(of_func_decl(to_func_decl(to_app(a)->get_decl()->get_parameter(0).get_ast()))); } else { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -252,6 +251,7 @@ extern "C" { Z3_TRY; LOG_Z3_add_func_interp(c, m, f, else_val); RESET_ERROR_CODE(); + CHECK_NON_NULL(f, nullptr); func_decl* d = to_func_decl(f); model* mdl = to_model_ref(m); Z3_func_interp_ref * f_ref = alloc(Z3_func_interp_ref, *mk_c(c), mdl); @@ -268,8 +268,8 @@ extern "C" { LOG_Z3_add_const_interp(c, m, f, a); RESET_ERROR_CODE(); func_decl* d = to_func_decl(f); - if (d->get_arity() != 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + if (!d || d->get_arity() != 0) { + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); } else { model* mdl = to_model_ref(m); @@ -313,7 +313,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_NON_NULL(f, nullptr); if (i >= to_func_interp_ref(f)->num_entries()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } Z3_func_entry_ref * e = alloc(Z3_func_entry_ref, *mk_c(c), to_func_interp(f)->m_model.get()); @@ -364,7 +364,7 @@ extern "C" { func_interp* _fi = to_func_interp_ref(fi); expr* _value = to_expr(value); if (to_ast_vector_ref(args).size() != _fi->get_arity()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return; } // check sorts of value @@ -416,7 +416,7 @@ extern "C" { LOG_Z3_func_entry_get_arg(c, e, i); RESET_ERROR_CODE(); if (i >= to_func_entry(e)->m_func_interp->get_arity()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } expr * r = to_func_entry(e)->m_func_entry->get_arg(i); @@ -434,7 +434,7 @@ extern "C" { if (g) { return g->num_entries(); } - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0; } return 0; @@ -448,7 +448,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_NON_NULL(m, 0); if (j >= get_model_func_num_entries_core(c, m, i)) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0; } Z3_func_decl d = get_model_func_decl_core(c, m, i); diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index de9886571..2891e8cc4 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -26,6 +26,7 @@ Revision History: #include "ast/fpa_decl_plugin.h" bool is_numeral_sort(Z3_context c, Z3_sort ty) { + if (!ty) return false; sort * _ty = to_sort(ty); family_id fid = _ty->get_family_id(); if (fid != mk_c(c)->get_arith_fid() && @@ -40,7 +41,7 @@ bool is_numeral_sort(Z3_context c, Z3_sort ty) { bool check_numeral_sort(Z3_context c, Z3_sort ty) { bool is_num = is_numeral_sort(c, ty); if (!is_num) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); } return is_num; } @@ -55,7 +56,7 @@ extern "C" { RETURN_Z3(nullptr); } if (!n) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } sort * _ty = to_sort(ty); @@ -67,12 +68,11 @@ extern "C" { ('/' == *m) || ('-' == *m) || (' ' == *m) || ('\n' == *m) || ('.' == *m) || ('e' == *m) || - ('E' == *m) || + ('E' == *m) || ('+' == *m) || (is_float && (('p' == *m) || - ('P' == *m) || - ('+' == *m))))) { - SET_ERROR_CODE(Z3_PARSER_ERROR); + ('P' == *m))))) { + SET_ERROR_CODE(Z3_PARSER_ERROR, nullptr); RETURN_Z3(nullptr); } ++m; @@ -145,7 +145,8 @@ extern "C" { Z3_bool Z3_API Z3_is_numeral_ast(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_is_numeral_ast(c, a); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); + CHECK_IS_EXPR(a, Z3_FALSE); expr* e = to_expr(a); return mk_c(c)->autil().is_numeral(e) || @@ -160,11 +161,8 @@ extern "C" { Z3_TRY; // This function is not part of the public API RESET_ERROR_CODE(); + CHECK_IS_EXPR(a, Z3_FALSE); expr* e = to_expr(a); - if (!e) { - SET_ERROR_CODE(Z3_INVALID_ARG); - return Z3_FALSE; - } if (mk_c(c)->autil().is_numeral(e, r)) { return Z3_TRUE; } @@ -187,6 +185,7 @@ extern "C" { // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_string(c, a); RESET_ERROR_CODE(); + CHECK_IS_EXPR(a, ""); rational r; Z3_bool ok = Z3_get_numeral_rational(c, a, r); if (ok == Z3_TRUE) { @@ -221,7 +220,7 @@ extern "C" { return mk_c(c)->mk_external_string(fu.fm().to_string(tmp)); } else { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } } @@ -232,11 +231,8 @@ extern "C" { Z3_TRY; LOG_Z3_get_numeral_decimal_string(c, a, precision); RESET_ERROR_CODE(); + CHECK_IS_EXPR(a, ""); expr* e = to_expr(a); - if (!e) { - SET_ERROR_CODE(Z3_INVALID_ARG); - return ""; - } rational r; arith_util & u = mk_c(c)->autil(); if (u.is_numeral(e, r) && !r.is_int()) { @@ -256,7 +252,7 @@ extern "C" { return mk_c(c)->mk_external_string(r.to_string()); } else { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } Z3_CATCH_RETURN(""); @@ -267,6 +263,7 @@ extern "C" { // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_small(c, a, num, den); RESET_ERROR_CODE(); + CHECK_IS_EXPR(a, Z3_FALSE); rational r; Z3_bool ok = Z3_get_numeral_rational(c, a, r); if (ok == Z3_TRUE) { @@ -281,7 +278,7 @@ extern "C" { return Z3_FALSE; } } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; Z3_CATCH_RETURN(Z3_FALSE); } @@ -292,8 +289,9 @@ extern "C" { // This function invokes Z3_get_numeral_int64, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_int(c, v, i); RESET_ERROR_CODE(); + CHECK_IS_EXPR(v, Z3_FALSE); if (!i) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } int64_t l; @@ -310,8 +308,9 @@ extern "C" { // This function invokes Z3_get_numeral_uint64, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_uint(c, v, u); RESET_ERROR_CODE(); + CHECK_IS_EXPR(v, Z3_FALSE); if (!u) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } uint64_t l; @@ -328,8 +327,9 @@ extern "C" { // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_uint64(c, v, u); RESET_ERROR_CODE(); + CHECK_IS_EXPR(v, Z3_FALSE); if (!u) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } rational r; @@ -348,8 +348,9 @@ extern "C" { // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_int64(c, v, i); RESET_ERROR_CODE(); + CHECK_IS_EXPR(v, Z3_FALSE); if (!i) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } rational r; @@ -367,8 +368,9 @@ extern "C" { // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_rational_int64(c, v, num, den); RESET_ERROR_CODE(); + CHECK_IS_EXPR(v, Z3_FALSE); if (!num || !den) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } rational r; diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 4bb146e39..71f92eeba 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -318,17 +318,15 @@ extern "C" { ctx->set_ignore_check(true); try { if (!parse_smt2_commands(*ctx.get(), s)) { - mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str().c_str()); return; } } catch (z3_exception& e) { errstrm << e.msg(); - mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str().c_str()); return; } diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index d021ed6ad..9d9f5157c 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -171,7 +171,7 @@ extern "C" { LOG_Z3_param_descrs_get_name(c, p, i); RESET_ERROR_CODE(); if (i >= to_param_descrs_ptr(p)->size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } Z3_symbol result = of_symbol(to_param_descrs_ptr(p)->get_param_name(i)); @@ -185,7 +185,7 @@ extern "C" { RESET_ERROR_CODE(); char const* result = to_param_descrs_ptr(p)->get_descr(to_symbol(s)); if (result == nullptr) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } return mk_c(c)->mk_external_string(result); diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index d791dc2a5..b88f273f9 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -30,15 +30,6 @@ Revision History: extern "C" { - - Z3_string Z3_API Z3_get_parser_error(Z3_context c) { - Z3_TRY; - LOG_Z3_get_parser_error(c); - RESET_ERROR_CODE(); - return mk_c(c)->m_parser_error_buffer.c_str(); - Z3_CATCH_RETURN(""); - } - // --------------- // Support for SMTLIB2 @@ -70,16 +61,14 @@ extern "C" { try { if (!parse_smt2_commands(*ctx.get(), is)) { ctx = nullptr; - mk_c(c)->m_parser_error_buffer = errstrm.str(); - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str().c_str()); return of_ast_vector(v); } } catch (z3_exception& e) { errstrm << e.msg(); - mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str().c_str()); return of_ast_vector(v); } ptr_vector::const_iterator it = ctx->begin_assertions(); @@ -118,7 +107,7 @@ extern "C" { LOG_Z3_parse_smtlib2_string(c, file_name, num_sorts, sort_names, sorts, num_decls, decl_names, decls); std::ifstream is(file_name); if (!is) { - SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); + SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR, nullptr); return nullptr; } Z3_ast_vector r = parse_smtlib2_stream(false, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls); @@ -141,15 +130,13 @@ extern "C" { ctx->set_diagnostic_stream(ous); try { if (!parse_smt2_commands(*ctx.get(), is)) { - mk_c(c)->m_parser_error_buffer = ous.str(); - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, ous.str().c_str()); RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); } } catch (z3_exception& e) { if (ous.str().empty()) ous << e.msg(); - mk_c(c)->m_parser_error_buffer = ous.str(); - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, ous.str().c_str()); RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); } RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index 35ece4a59..93a23cb04 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -26,17 +26,6 @@ Notes: #include "util/scoped_timer.h" #include "ast/expr2var.h" -namespace api { - - pmanager::pmanager(reslimit& lim): - m_pm(lim, m_nm) { - } - - pmanager::~pmanager() { - } - -}; - extern "C" { Z3_ast_vector Z3_API Z3_polynomial_subresultants(Z3_context c, Z3_ast p, Z3_ast q, Z3_ast x) { @@ -49,7 +38,7 @@ extern "C" { default_expr2polynomial converter(mk_c(c)->m(), pm); if (!converter.to_polynomial(to_expr(p), _p, d) || !converter.to_polynomial(to_expr(q), _q, d)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); diff --git a/src/api/api_polynomial.h b/src/api/api_polynomial.h index fbb1e7e13..a31f6c2b8 100644 --- a/src/api/api_polynomial.h +++ b/src/api/api_polynomial.h @@ -23,13 +23,13 @@ Notes: namespace api { - class pmanager { + class pmanager final { unsynch_mpz_manager m_nm; polynomial::manager m_pm; // TODO: add support for caching expressions -> polynomial and back public: - pmanager(reslimit& limx); - virtual ~pmanager(); + pmanager(reslimit& lim) : m_pm(lim, m_nm) {} + ~pmanager() {} polynomial::manager & pm() { return m_pm; } }; diff --git a/src/api/api_qe.cpp b/src/api/api_qe.cpp index 92517b02b..94e83144f 100644 --- a/src/api/api_qe.cpp +++ b/src/api/api_qe.cpp @@ -55,7 +55,7 @@ extern "C" app_ref_vector vars(mk_c(c)->m ()); if (!to_apps(num_bounds, bound, vars)) { - SET_ERROR_CODE (Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } @@ -141,7 +141,7 @@ extern "C" for (unsigned i = 0; i < vVars.size (); ++i) { app *a = to_app (vVars.get (i)); if (a->get_kind () != AST_APP) { - SET_ERROR_CODE (Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } vApps.push_back (a); diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index b760760a4..6d6d19d56 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -62,11 +62,11 @@ extern "C" { Z3_TRY; RESET_ERROR_CODE(); if (!mk_c(c)->m().is_bool(to_expr(body))) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return nullptr; } if (num_patterns > 0 && num_no_patterns > 0) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, nullptr); return nullptr; } expr * const* ps = reinterpret_cast(patterns); @@ -77,7 +77,7 @@ extern "C" { pattern_validator v(mk_c(c)->m()); for (unsigned i = 0; i < num_patterns; i++) { if (!v(num_decls, ps[i], 0, 0)) { - SET_ERROR_CODE(Z3_INVALID_PATTERN); + SET_ERROR_CODE(Z3_INVALID_PATTERN, nullptr); return nullptr; } } @@ -154,7 +154,7 @@ extern "C" { RESET_ERROR_CODE(); expr_ref result(mk_c(c)->m()); if (num_decls == 0) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, nullptr); RETURN_Z3(0); } @@ -177,7 +177,7 @@ extern "C" { LOG_Z3_mk_lambda_const(c, num_decls, vars, body); RESET_ERROR_CODE(); if (num_decls == 0) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, nullptr); RETURN_Z3(0); } @@ -220,17 +220,17 @@ extern "C" { svector types; ptr_vector bound_asts; if (num_patterns > 0 && num_no_patterns > 0) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, nullptr); RETURN_Z3(nullptr); } if (num_bound == 0) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "number of bound variables is 0"); RETURN_Z3(nullptr); } for (unsigned i = 0; i < num_bound; ++i) { app* a = to_app(bound[i]); if (a->get_kind() != AST_APP) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } symbol s(to_app(a)->get_decl()->get_name()); @@ -238,7 +238,7 @@ extern "C" { types.push_back(of_sort(mk_c(c)->m().get_sort(a))); bound_asts.push_back(a); if (a->get_family_id() != null_family_id || a->get_num_args() != 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -259,7 +259,7 @@ extern "C" { for (unsigned i = 0; i < num_no_patterns; ++i) { expr_ref result(mk_c(c)->m()); if (!is_app(to_expr(no_patterns[i]))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } app* pat = to_app(to_expr(no_patterns[i])); @@ -323,7 +323,7 @@ extern "C" { RESET_ERROR_CODE(); for (unsigned i = 0; i < num_patterns; ++i) { if (!is_app(to_expr(terms[i]))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -377,7 +377,7 @@ extern "C" { return to_quantifier(_a)->get_weight(); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return 0; } Z3_CATCH_RETURN(0); @@ -392,7 +392,7 @@ extern "C" { return to_quantifier(_a)->get_num_patterns(); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return 0; } Z3_CATCH_RETURN(0); @@ -408,7 +408,7 @@ extern "C" { RETURN_Z3(r); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -424,7 +424,7 @@ extern "C" { return to_quantifier(_a)->get_num_no_patterns(); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return 0; } Z3_CATCH_RETURN(0); @@ -440,7 +440,7 @@ extern "C" { RETURN_Z3(r); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -455,7 +455,7 @@ extern "C" { return of_symbol(to_quantifier(_a)->get_decl_names()[i]); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return nullptr; } Z3_CATCH_RETURN(nullptr); @@ -471,7 +471,7 @@ extern "C" { RETURN_Z3(r); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -487,7 +487,7 @@ extern "C" { RETURN_Z3(r); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -503,7 +503,7 @@ extern "C" { return to_quantifier(_a)->get_num_decls(); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return 0; } Z3_CATCH_RETURN(0); @@ -518,7 +518,7 @@ extern "C" { return _p->get_num_args(); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return 0; } Z3_CATCH_RETURN(0); @@ -534,7 +534,7 @@ extern "C" { RETURN_Z3(r); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); diff --git a/src/api/api_rcf.cpp b/src/api/api_rcf.cpp index 3d65cb1cd..d92ff155b 100644 --- a/src/api/api_rcf.cpp +++ b/src/api/api_rcf.cpp @@ -123,7 +123,7 @@ extern "C" { } if (rz == 0) { // it is the zero polynomial - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } av.shrink(rz); diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 84cfdca32..42979d1ed 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -107,7 +107,7 @@ extern "C" { RESET_ERROR_CODE(); zstring str; if (!mk_c(c)->sutil().str.is_string(to_expr(s), str)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "expression is not a string literal"); return ""; } std::string result = str.encode(); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 1c8d205bc..9ad51aaf4 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -145,10 +145,12 @@ extern "C" { void solver_from_stream(Z3_context c, Z3_solver s, std::istream& is) { scoped_ptr ctx = alloc(cmd_context, false, &(mk_c(c)->m())); ctx->set_ignore_check(true); + std::stringstream errstrm; + ctx->set_regular_stream(errstrm); if (!parse_smt2_commands(*ctx.get(), is)) { ctx = nullptr; - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str().c_str()); return; } @@ -178,7 +180,7 @@ extern "C" { char const* ext = get_extension(file_name); std::ifstream is(file_name); if (!is) { - SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); + SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR, nullptr); } else if (ext && std::string("dimacs") == ext) { ast_manager& m = to_solver_ref(s)->get_manager(); @@ -291,7 +293,7 @@ extern "C" { RESET_ERROR_CODE(); init_solver(c, s); if (n > to_solver_ref(s)->get_scope_level()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return; } if (n > 0) @@ -372,7 +374,7 @@ extern "C" { static Z3_lbool _solver_check(Z3_context c, Z3_solver s, unsigned num_assumptions, Z3_ast const assumptions[]) { for (unsigned i = 0; i < num_assumptions; i++) { if (!is_expr(to_ast(assumptions[i]))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "assumption is not an expression"); return Z3_L_UNDEF; } } @@ -430,7 +432,7 @@ extern "C" { model_ref _m; to_solver_ref(s)->get_model(_m); if (!_m) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "there is no current model"); RETURN_Z3(nullptr); } if (_m) { @@ -450,7 +452,7 @@ extern "C" { init_solver(c, s); proof * p = to_solver_ref(s)->get_proof(); if (!p) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "there is no current proof"); RETURN_Z3(nullptr); } mk_c(c)->save_ast_trail(p); @@ -542,7 +544,7 @@ extern "C" { for (ast* e : __assumptions) { if (!is_expr(e)) { _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "assumption is not an expression"); return Z3_L_UNDEF; } _assumptions.push_back(to_expr(e)); @@ -551,7 +553,7 @@ extern "C" { for (ast* a : __variables) { if (!is_expr(a)) { _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "variable is not an expression"); return Z3_L_UNDEF; } _variables.push_back(to_expr(a)); @@ -593,7 +595,7 @@ extern "C" { expr_ref_vector result(m), vars(m); for (ast* a : to_ast_vector_ref(vs)) { if (!is_expr(a)) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "cube contains a non-expression"); } else { vars.push_back(to_expr(a)); diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index 2e1dac4de..2014d57b8 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.cpp @@ -67,7 +67,7 @@ extern "C" { LOG_Z3_stats_get_key(c, s, idx); RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return ""; } return to_stats_ref(s).get_key(idx); @@ -79,7 +79,7 @@ extern "C" { LOG_Z3_stats_is_uint(c, s, idx); RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return Z3_FALSE; } return to_stats_ref(s).is_uint(idx); @@ -91,7 +91,7 @@ extern "C" { LOG_Z3_stats_is_double(c, s, idx); RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return Z3_FALSE; } return !to_stats_ref(s).is_uint(idx); @@ -103,11 +103,11 @@ extern "C" { LOG_Z3_stats_get_uint_value(c, s, idx); RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0; } if (!to_stats_ref(s).is_uint(idx)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return to_stats_ref(s).get_uint_value(idx); @@ -119,11 +119,11 @@ extern "C" { LOG_Z3_stats_get_double_value(c, s, idx); RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0.0; } if (to_stats_ref(s).is_uint(idx)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0.0; } return to_stats_ref(s).get_double_value(idx); diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 345284fd6..7c0143201 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -52,7 +52,7 @@ extern "C" { RESET_ERROR_CODE(); tactic_cmd * t = mk_c(c)->find_tactic_cmd(symbol(name)); if (t == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } tactic * new_t = t->mk(mk_c(c)->m()); @@ -82,7 +82,7 @@ extern "C" { RESET_ERROR_CODE(); probe_info * p = mk_c(c)->find_probe(symbol(name)); if (p == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } probe * new_p = p->get(); @@ -324,7 +324,7 @@ extern "C" { LOG_Z3_get_tactic_name(c, idx); RESET_ERROR_CODE(); if (idx >= mk_c(c)->num_tactics()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return ""; } return mk_c(c)->get_tactic(idx)->get_name().bare_str(); @@ -344,7 +344,7 @@ extern "C" { LOG_Z3_get_probe_name(c, idx); RESET_ERROR_CODE(); if (idx >= mk_c(c)->num_probes()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return ""; } return mk_c(c)->get_probe(idx)->get_name().bare_str(); @@ -381,7 +381,7 @@ extern "C" { RESET_ERROR_CODE(); tactic_cmd * t = mk_c(c)->find_tactic_cmd(symbol(name)); if (t == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } return t->get_descr(); @@ -394,7 +394,7 @@ extern "C" { RESET_ERROR_CODE(); probe_info * p = mk_c(c)->find_probe(symbol(name)); if (p == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } return p->get_descr(); @@ -504,7 +504,7 @@ extern "C" { LOG_Z3_apply_result_get_subgoal(c, r, i); RESET_ERROR_CODE(); if (i > to_apply_result(r)->m_subgoals.size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } Z3_goal_ref * g = alloc(Z3_goal_ref, *mk_c(c)); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index b68fb2021..e1f263e17 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -167,11 +167,6 @@ namespace z3 { } void check_parser_error() const { - Z3_error_code e = Z3_get_error_code(*this); - if (e != Z3_OK && enable_exceptions()) { - Z3_string s = Z3_get_parser_error(*this); - if (s && *s) Z3_THROW(exception(s)); - } check_error(); } diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 849d1af79..99baaa8e4 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -89,6 +89,15 @@ namespace Microsoft.Z3 } } + /// + /// The i'th argument of the expression. + /// + public Expr Arg(uint i) + { + Contract.Ensures(Contract.Result() != null); + return Expr.Create(Context, Native.Z3_get_app_arg(Context.nCtx, NativeObject, i)); + } + /// /// Update the arguments of the expression using the arguments /// The number of new arguments should coincide with the current number of arguments. @@ -315,6 +324,41 @@ namespace Microsoft.Z3 /// public bool IsImplies { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_IMPLIES; } } + /// + /// Indicates whether the term is at-most + /// + public bool IsAtMost { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PB_AT_MOST; } } + + /// + /// Retrieve bound of at-most + /// + public uint AtMostBound { get { Contract.Requires(IsAtMost); return (uint)FuncDecl.Parameters[0].Int; } } + + /// + /// Indicates whether the term is at-least + /// + public bool IsAtLeast { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PB_AT_LEAST; } } + + /// + /// Retrieve bound of at-least + /// + public uint AtLeastBound { get { Contract.Requires(IsAtLeast); return (uint)FuncDecl.Parameters[0].Int; } } + + /// + /// Indicates whether the term is pbeq + /// + public bool IsPbEq { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PB_EQ; } } + + /// + /// Indicates whether the term is pble + /// + public bool IsPbLe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PB_LE; } } + + /// + /// Indicates whether the term is pbge + /// + public bool IsPbGe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PB_GE; } } + #endregion #region Arithmetic Terms diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs index e2fb7fe5a..102a96ac5 100644 --- a/src/api/dotnet/Fixedpoint.cs +++ b/src/api/dotnet/Fixedpoint.cs @@ -146,7 +146,7 @@ namespace Microsoft.Z3 /// The query is satisfiable if there is an instance of some relation that is non-empty. /// The query is unsatisfiable if there are no derivations satisfying any of the relations. /// - public Status Query(FuncDecl[] relations) + public Status Query(params FuncDecl[] relations) { Contract.Requires(relations != null); Contract.Requires(Contract.ForAll(0, relations.Length, i => relations[i] != null)); @@ -262,7 +262,7 @@ namespace Microsoft.Z3 /// /// Convert benchmark given as set of axioms, rules and queries to a string. /// - public string ToString(BoolExpr[] queries) + public string ToString(params BoolExpr[] queries) { return Native.Z3_fixedpoint_to_string(Context.nCtx, NativeObject, diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 07be64230..57085a09e 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2505,7 +2505,7 @@ public class Context implements AutoCloseable { * with the sorts of the bound variables, {@code names} is an array with the * 'names' of the bound variables, and {@code body} is the body of the * lambda. - * Note that the bound variables are de-Bruijn indices created using {@see #MkBound} + * Note that the bound variables are de-Bruijn indices created using {@link #mkBound} * Z3 applies the convention that the last element in {@code names} and * {@code sorts} refers to the variable with index 0, the second to last element * of {@code names} and {@code sorts} refers to the variable diff --git a/src/api/java/Optimize.java b/src/api/java/Optimize.java index a434b6e9f..c5f8f9449 100644 --- a/src/api/java/Optimize.java +++ b/src/api/java/Optimize.java @@ -314,6 +314,23 @@ public class Optimize extends Z3Object { Native.optimizeFromString(getContext().nCtx(), getNativeObject(), s); } + /** + * The set of asserted formulas. + */ + public BoolExpr[] getAssertions() + { + ASTVector assertions = new ASTVector(getContext(), Native.optimizeGetAssertions(getContext().nCtx(), getNativeObject())); + return assertions.ToBoolExprArray(); + } + + /** + * The set of asserted formulas. + */ + public Expr[] getObjectives() + { + ASTVector objectives = new ASTVector(getContext(), Native.optimizeGetObjectives(getContext().nCtx(), getNativeObject())); + return objectives.ToExprArray(); + } /** * Optimize statistics. diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 24ba59ac2..bce681584 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -6,6 +6,7 @@ import subprocess import multiprocessing import re from setuptools import setup +from distutils.util import get_platform from distutils.errors import LibError from distutils.command.build import build as _build from distutils.command.sdist import sdist as _sdist @@ -45,13 +46,14 @@ def _clean_bins(): shutil.rmtree(HEADERS_DIR, ignore_errors=True) def _z3_version(): + post = os.getenv('Z3_VERSION_SUFFIX', '') fn = os.path.join(SRC_DIR, 'scripts', 'mk_project.py') - if os.path.exists(fn): + if os.path.exists(fn): with open(fn) as f: for line in f: n = re.match(".*set_version\((.*), (.*), (.*), (.*)\).*", line) if not n is None: - return n.group(1) + '.' + n.group(2) + '.' + n.group(3) + '.' + n.group(4) + return n.group(1) + '.' + n.group(2) + '.' + n.group(3) + '.' + n.group(4) + post return "?.?.?.?" def _configure_z3(): @@ -97,7 +99,10 @@ def _copy_bins(): os.mkdir(os.path.join(HEADERS_DIR, 'c++')) shutil.copy(os.path.join(BUILD_DIR, LIBRARY_FILE), LIBS_DIR) shutil.copy(os.path.join(BUILD_DIR, EXECUTABLE_FILE), BINS_DIR) - for fname in ('z3.h', 'z3_v1.h', 'z3_macros.h', 'z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_interp.h', 'z3_fpa.h', os.path.join('c++', 'z3++.h')): + + header_files = [x for x in os.listdir(os.path.join(SRC_DIR, 'src', 'api')) if x.endswith('.h')] + header_files += [os.path.join('c++', x) for x in os.listdir(os.path.join(SRC_DIR, 'src', 'api', 'c++')) if x.endswith('.h')] + for fname in header_files: shutil.copy(os.path.join(SRC_DIR, 'src', 'api', fname), os.path.join(HEADERS_DIR, fname)) def _copy_sources(): @@ -118,6 +123,7 @@ def _copy_sources(): os.mkdir(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python')) os.mkdir(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python', 'z3')) open(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python', 'z3', '.placeholder'), 'w').close() + open(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python', 'z3test.py'), 'w').close() class build(_build): def run(self): @@ -148,14 +154,34 @@ class sdist(_sdist): #try: os.makedirs(os.path.join(ROOT_DIR, 'build')) #except OSError: pass +if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: + idx = sys.argv.index('bdist_wheel') + 1 + sys.argv.insert(idx, '--plat-name') + name = get_platform() + if 'linux' in name: + # linux_* platform tags are disallowed because the python ecosystem is fubar + # linux builds should be built in the centos 5 vm for maximum compatibility + # see https://github.com/pypa/manylinux + # see also https://github.com/angr/angr-dev/blob/master/admin/bdist.py + sys.argv.insert(idx + 1, 'manylinux1_' + platform.machine()) + elif 'mingw' in name: + if platform.architecture()[0] == '64bit': + sys.argv.insert(idx + 1, 'win_amd64') + else: + sys.argv.insert(idx + 1, 'win32') + else: + # https://www.python.org/dev/peps/pep-0425/ + sys.argv.insert(idx + 1, name.replace('.', '_').replace('-', '_')) + + setup( name='z3-solver', version=_z3_version(), description='an efficient SMT solver library', long_description='Z3 is a theorem prover from Microsoft Research with support for bitvectors, booleans, arrays, floating point numbers, strings, and other data types.\n\nFor documentation, please read http://z3prover.github.io/api/html/z3.html\n\nIn the event of technical difficulties related to configuration, compiliation, or installation, please submit issues to https://github.com/angr/angr-z3', author="The Z3 Theorem Prover Project", - maintainer="Andrew Dutcher", - maintainer_email="andrew@andrewdutcher.com", + maintainer="Audrey Dutcher", + maintainer_email="audrey@rhelmot.io", url='https://github.com/Z3Prover/z3', license='MIT License', keywords=['z3', 'smt', 'sat', 'prover', 'theorem'], diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 10198fcc5..0eeeeaecc 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1675,7 +1675,6 @@ def Or(*args): class PatternRef(ExprRef): """Patterns are hints for quantifier instantiation. - See http://rise4fun.com/Z3Py/tutorial/advanced for more details. """ def as_ast(self): return Z3_pattern_to_ast(self.ctx_ref(), self.ast) @@ -1686,8 +1685,6 @@ class PatternRef(ExprRef): def is_pattern(a): """Return `True` if `a` is a Z3 pattern (hint for quantifier instantiation. - See http://rise4fun.com/Z3Py/tutorial/advanced for more details. - >>> f = Function('f', IntSort(), IntSort()) >>> x = Int('x') >>> q = ForAll(x, f(x) == 0, patterns = [ f(x) ]) @@ -1705,8 +1702,6 @@ def is_pattern(a): def MultiPattern(*args): """Create a Z3 multi-pattern using the given expressions `*args` - See http://rise4fun.com/Z3Py/tutorial/advanced for more details. - >>> f = Function('f', IntSort(), IntSort()) >>> g = Function('g', IntSort(), IntSort()) >>> x = Int('x') @@ -1966,8 +1961,6 @@ def ForAll(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]): The parameters `weight`, `qif`, `skid`, `patterns` and `no_patterns` are optional annotations. - See http://rise4fun.com/Z3Py/tutorial/advanced for more details. - >>> f = Function('f', IntSort(), IntSort(), IntSort()) >>> x = Int('x') >>> y = Int('y') @@ -1985,7 +1978,6 @@ def Exists(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]): The parameters `weight`, `qif`, `skid`, `patterns` and `no_patterns` are optional annotations. - See http://rise4fun.com/Z3Py/tutorial/advanced for more details. >>> f = Function('f', IntSort(), IntSort(), IntSort()) >>> x = Int('x') @@ -7241,11 +7233,13 @@ class Optimize(Z3PPObject): def assert_exprs(self, *args): """Assert constraints as background axioms for the optimize solver.""" args = _get_args(args) + s = BoolSort(self.ctx) for arg in args: if isinstance(arg, Goal) or isinstance(arg, AstVector): for f in arg: Z3_optimize_assert(self.ctx.ref(), self.optimize, f.as_ast()) else: + arg = s.cast(arg) Z3_optimize_assert(self.ctx.ref(), self.optimize, arg.as_ast()) def add(self, *args): @@ -8395,11 +8389,6 @@ def _dict2darray(decls, ctx): i = i + 1 return sz, _names, _decls -def _handle_parse_error(ex, ctx): - msg = Z3_get_parser_error(ctx.ref()) - if msg != "": - raise Z3Exception(msg) - raise ex def parse_smt2_string(s, sorts={}, decls={}, ctx=None): """Parse a string in SMT 2.0 format using the given sorts and decls. @@ -8419,10 +8408,7 @@ def parse_smt2_string(s, sorts={}, decls={}, ctx=None): ctx = _get_ctx(ctx) ssz, snames, ssorts = _dict2sarray(sorts, ctx) dsz, dnames, ddecls = _dict2darray(decls, ctx) - try: - return AstVector(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) - except Z3Exception as e: - _handle_parse_error(e, ctx) + return AstVector(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) def parse_smt2_file(f, sorts={}, decls={}, ctx=None): """Parse a file in SMT 2.0 format using the given sorts and decls. @@ -8432,10 +8418,7 @@ def parse_smt2_file(f, sorts={}, decls={}, ctx=None): ctx = _get_ctx(ctx) ssz, snames, ssorts = _dict2sarray(sorts, ctx) dsz, dnames, ddecls = _dict2darray(decls, ctx) - try: - return AstVector(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) - except Z3Exception as e: - _handle_parse_error(e, ctx) + return AstVector(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) ######################################### diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7e12f2fa7..2657e558d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5280,12 +5280,6 @@ extern "C" { Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context, Z3_string str); - /** - \brief Retrieve that last error message information generated from parsing. - - def_API('Z3_get_parser_error', STRING, (_in(CONTEXT), )) - */ - Z3_string Z3_API Z3_get_parser_error(Z3_context c); /*@}*/ /** @name Error Handling */ @@ -5332,11 +5326,6 @@ extern "C" { */ Z3_string Z3_API Z3_get_error_msg(Z3_context c, Z3_error_code err); - /** - \brief Return a string describing the given error code. - Retained function name for backwards compatibility within v4.1 - */ - Z3_string Z3_API Z3_get_error_msg_ex(Z3_context c, Z3_error_code err); /*@}*/ /** @name Miscellaneous */ @@ -5536,6 +5525,11 @@ extern "C" { /** \brief Convert a goal into a DIMACS formatted string. + The goal must be in CNF. You can convert a goal to CNF + by applying the tseitin-cnf tactic. Bit-vectors are not automatically + converted to Booleans either, so the caller intends to + preserve satisfiability, it should apply bit-blasting tactics. + Quantifiers and theory atoms will not be encoded. def_API('Z3_goal_to_dimacs_string', STRING, (_in(CONTEXT), _in(GOAL))) */ diff --git a/src/api/z3_logger.h b/src/api/z3_logger.h index 211601713..8f0eb5371 100644 --- a/src/api/z3_logger.h +++ b/src/api/z3_logger.h @@ -42,6 +42,7 @@ static void __declspec(noinline) Sy(Z3_symbol sym) { } static void __declspec(noinline) Ap(unsigned sz) { *g_z3_log << "p " << sz << "\n"; g_z3_log->flush(); } static void __declspec(noinline) Au(unsigned sz) { *g_z3_log << "u " << sz << "\n"; g_z3_log->flush(); } +static void __declspec(noinline) Ai(unsigned sz) { *g_z3_log << "i " << sz << "\n"; g_z3_log->flush(); } static void __declspec(noinline) Asy(unsigned sz) { *g_z3_log << "s " << sz << "\n"; g_z3_log->flush(); } static void __declspec(noinline) C(unsigned id) { *g_z3_log << "C " << id << "\n"; g_z3_log->flush(); } void __declspec(noinline) _Z3_append_log(char const * msg) { *g_z3_log << "M \"" << ll_escaped(msg) << "\"\n"; g_z3_log->flush(); } diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 0e8297879..8ebac8068 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -78,6 +78,7 @@ struct z3_replayer::imp { std::stringstream strm; strm << "expecting " << kind2string(k) << " at position " << pos << " but got " << kind2string(m_args[pos].m_kind); + TRACE("z3_replayer", tout << strm.str() << "\n";); throw z3_replayer_exception(strm.str().c_str()); } } @@ -186,10 +187,10 @@ struct z3_replayer::imp { sz++; } else { - throw z3_replayer_exception("invalid scaped character"); + throw z3_replayer_exception("invalid escaped character"); } if (val > 255) - throw z3_replayer_exception("invalid scaped character"); + throw z3_replayer_exception("invalid escaped character"); next(); } TRACE("z3_replayer_escape", tout << "val: " << val << "\n";); @@ -497,6 +498,7 @@ struct z3_replayer::imp { case 'p': case 's': case 'u': + case 'i': // push array next(); skip_blank(); read_uint64(); TRACE("z3_replayer", tout << "[" << m_line << "] " << "A " << m_uint64 << "\n";); @@ -504,6 +506,8 @@ struct z3_replayer::imp { push_array(static_cast(m_uint64), OBJECT); else if (c == 's') push_array(static_cast(m_uint64), SYMBOL); + else if (c == 'i') + push_array(static_cast(m_uint64), INT64); else push_array(static_cast(m_uint64), UINT64); break; diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index be3a02019..db3604a99 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -351,6 +351,7 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) { case OP_MUL: return is_real ? m_r_mul_decl : m_i_mul_decl; case OP_DIV: return m_r_div_decl; case OP_IDIV: return m_i_div_decl; + case OP_IDIVIDES: UNREACHABLE(); case OP_REM: return m_i_rem_decl; case OP_MOD: return m_i_mod_decl; case OP_TO_REAL: return m_to_real_decl; @@ -482,6 +483,14 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters m_manager->raise_exception("no arguments supplied to arithmetical operator"); return nullptr; } + if (k == OP_IDIVIDES) { + if (arity != 1 || domain[0] != m_int_decl || num_parameters != 1 || !parameters[0].is_int()) { + m_manager->raise_exception("invalid divides application. Expects integer parameter and one argument of sort integer"); + } + return m_manager->mk_func_decl(symbol("divides"), 1, &m_int_decl, m_manager->mk_bool_sort(), + func_decl_info(m_family_id, k, num_parameters, parameters)); + } + if (m_manager->int_real_coercions() && use_coercion(k)) { return mk_func_decl(fix_kind(k, arity), has_real_arg(arity, domain, m_real_decl)); } @@ -499,6 +508,13 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters m_manager->raise_exception("no arguments supplied to arithmetical operator"); return nullptr; } + if (k == OP_IDIVIDES) { + if (num_args != 1 || m_manager->get_sort(args[0]) != m_int_decl || num_parameters != 1 || !parameters[0].is_int()) { + m_manager->raise_exception("invalid divides application. Expects integer parameter and one argument of sort integer"); + } + return m_manager->mk_func_decl(symbol("divides"), 1, &m_int_decl, m_manager->mk_bool_sort(), + func_decl_info(m_family_id, k, num_parameters, parameters)); + } if (m_manager->int_real_coercions() && use_coercion(k)) { return mk_func_decl(fix_kind(k, num_args), has_real_arg(m_manager, num_args, args, m_real_decl)); } @@ -533,6 +549,8 @@ void arith_decl_plugin::get_op_names(svector& op_names, symbol con op_names.push_back(builtin_name("*",OP_MUL)); op_names.push_back(builtin_name("/",OP_DIV)); op_names.push_back(builtin_name("div",OP_IDIV)); + // clashes with user-defined functions + // op_names.push_back(builtin_name("divides",OP_IDIVIDES)); op_names.push_back(builtin_name("rem",OP_REM)); op_names.push_back(builtin_name("mod",OP_MOD)); op_names.push_back(builtin_name("to_real",OP_TO_REAL)); diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index f5f82b5fd..09f082522 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -46,6 +46,7 @@ enum arith_op_kind { OP_MUL, OP_DIV, OP_IDIV, + OP_IDIVIDES, OP_REM, OP_MOD, OP_TO_REAL, diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index ac7ce156d..11a15492c 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1057,7 +1057,7 @@ sort* basic_decl_plugin::join(sort* s1, sort* s2) { } std::ostringstream buffer; buffer << "Sorts " << mk_pp(s1, *m_manager) << " and " << mk_pp(s2, *m_manager) << " are incompatible"; - throw ast_exception(buffer.str().c_str()); + throw ast_exception(buffer.str()); } @@ -1086,7 +1086,7 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters if (domain[i] != domain[0]) { std::ostringstream buffer; buffer << "Sort mismatch between first argument and argument " << (i+1); - throw ast_exception(buffer.str().c_str()); + throw ast_exception(buffer.str()); } } return m_manager->mk_func_decl(symbol("distinct"), arity, domain, m_bool_sort, info); @@ -1403,6 +1403,7 @@ void ast_manager::init() { inc_ref(m_false); } + template static void mark_array_ref(ast_mark& mark, unsigned sz, T * const * a) { for(unsigned i = 0; i < sz; i++) { @@ -1701,9 +1702,9 @@ ast * ast_manager::register_node_core(ast * n) { SASSERT(m_ast_table.contains(n)); if (is_func_decl(r) && to_func_decl(r)->get_range() != to_func_decl(n)->get_range()) { std::ostringstream buffer; - buffer << "Recycling of declaration for the same name '" << to_func_decl(r)->get_name().str().c_str() << "'" - << " and domain, but different range type is not permitted"; - throw ast_exception(buffer.str().c_str()); + buffer << "Recycling of declaration for the same name '" << to_func_decl(r)->get_name().str() + << "' and domain, but different range type is not permitted"; + throw ast_exception(buffer.str()); } deallocate_node(n, ::get_node_size(n)); return r; @@ -1715,6 +1716,7 @@ ast * ast_manager::register_node_core(ast * n) { n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); + TRACE("ast", tout << "Object " << n->m_id << " was created.\n";); TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";); @@ -1934,8 +1936,7 @@ sort * ast_manager::substitute(sort* s, unsigned n, sort * const * src, sort * c vector ps; bool change = false; sort_ref_vector sorts(*this); - for (unsigned i = 0; i < s->get_num_parameters(); ++i) { - parameter const& p = s->get_parameter(i); + for (parameter const& p : s->parameters()) { if (p.is_ast()) { SASSERT(is_sort(p.get_ast())); change = true; @@ -1992,7 +1993,7 @@ void ast_manager::check_sort(func_decl const * decl, unsigned num_args, expr * c buff << "invalid function application for " << decl->get_name() << ", "; buff << "sort mismatch on argument at position " << (i+1) << ", "; buff << "expected " << mk_pp(expected, m) << " but given " << mk_pp(given, m); - throw ast_exception(buff.str().c_str()); + throw ast_exception(buff.str()); } } } @@ -2008,7 +2009,7 @@ void ast_manager::check_sort(func_decl const * decl, unsigned num_args, expr * c buff << "invalid function application for " << decl->get_name() << ", "; buff << "sort mismatch on argument at position " << (i+1) << ", "; buff << "expected " << mk_pp(expected, m) << " but given " << mk_pp(given, m); - throw ast_exception(buff.str().c_str()); + throw ast_exception(buff.str()); } } } @@ -2170,7 +2171,7 @@ void ast_manager::check_args(func_decl* f, unsigned n, expr* const* es) { << " for function " << mk_pp(f,*this) << " supplied sort is " << mk_pp(actual_sort, *this); - throw ast_exception(buffer.str().c_str()); + throw ast_exception(buffer.str()); } } } @@ -2194,7 +2195,7 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar std::ostringstream buffer; buffer << "Wrong number of arguments (" << num_args << ") passed to function " << mk_pp(decl, *this); - throw ast_exception(buffer.str().c_str()); + throw ast_exception(buffer.str()); } app * r = nullptr; if (num_args == 1 && decl->is_chainable() && decl->get_arity() == 2) { @@ -2330,8 +2331,8 @@ bool ast_manager::is_label_lit(expr const * n, buffer & names) const { return false; } func_decl const * decl = to_app(n)->get_decl(); - for (unsigned i = 0; i < decl->get_num_parameters(); i++) - names.push_back(decl->get_parameter(i).get_symbol()); + for (parameter const& p : decl->parameters()) + names.push_back(p.get_symbol()); return true; } @@ -2370,6 +2371,15 @@ bool ast_manager::is_pattern(expr const * n, ptr_vector &args) { return true; } +static void trace_quant(std::ostream& strm, quantifier* q) { + strm << (is_lambda(q) ? "[mk-lambda]" : "[mk-quant]") + << " #" << q->get_id() << " " << q->get_qid(); + for (unsigned i = 0; i < q->get_num_patterns(); ++i) { + strm << " #" << q->get_pattern(i)->get_id(); + } + strm << " #" << q->get_expr()->get_id() << "\n"; +} + quantifier * ast_manager::mk_quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, int weight , symbol const & qid, symbol const & skid, @@ -2402,12 +2412,7 @@ quantifier * ast_manager::mk_quantifier(quantifier_kind k, unsigned num_decls, s quantifier * r = register_node(new_node); if (m_trace_stream && r == new_node) { - *m_trace_stream << "[mk-quant] #" << r->get_id() << " " << qid; - for (unsigned i = 0; i < num_patterns; ++i) { - *m_trace_stream << " #" << patterns[i]->get_id(); - } - *m_trace_stream << " #" << body->get_id() << "\n"; - + trace_quant(*m_trace_stream, r); } return r; @@ -2421,6 +2426,9 @@ quantifier * ast_manager::mk_lambda(unsigned num_decls, sort * const * decl_sort sort* s = autil.mk_array_sort(num_decls, decl_sorts, ::get_sort(body)); quantifier * new_node = new (mem) quantifier(num_decls, decl_sorts, decl_names, body, s); quantifier * r = register_node(new_node); + if (m_trace_stream && r == new_node) { + trace_quant(*m_trace_stream, r); + } return r; } @@ -2928,8 +2936,8 @@ bool ast_manager::is_quant_inst(expr const* e, expr*& not_q_or_i, ptr_vectorget_arg(0); func_decl* d = to_app(e)->get_decl(); SASSERT(binding.empty()); - for (unsigned i = 0; i < d->get_num_parameters(); ++i) { - binding.push_back(to_expr(d->get_parameter(i).get_ast())); + for (parameter const& p : d->parameters()) { + binding.push_back(to_expr(p.get_ast())); } return true; } diff --git a/src/ast/ast.h b/src/ast/ast.h index aa8669def..89df04961 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -69,7 +69,7 @@ class ast_manager; */ class ast_exception : public default_exception { public: - ast_exception(char const * msg):default_exception(msg) {} + ast_exception(std::string && msg) : default_exception(std::move(msg)) {} }; typedef int family_id; @@ -122,6 +122,7 @@ public: explicit parameter(ast * p): m_kind(PARAM_AST), m_ast(p) {} explicit parameter(symbol const & s): m_kind(PARAM_SYMBOL), m_symbol(s.c_ptr()) {} explicit parameter(rational const & r): m_kind(PARAM_RATIONAL), m_rational(alloc(rational, r)) {} + explicit parameter(rational && r) : m_kind(PARAM_RATIONAL), m_rational(alloc(rational, std::move(r))) {} explicit parameter(double d):m_kind(PARAM_DOUBLE), m_dval(d) {} explicit parameter(const char *s):m_kind(PARAM_SYMBOL), m_symbol(symbol(s).c_ptr()) {} explicit parameter(unsigned ext_id, bool):m_kind(PARAM_EXTERNAL), m_ext_id(ext_id) {} @@ -273,6 +274,14 @@ public: parameter const * get_parameters() const { return m_parameters.begin(); } bool private_parameters() const { return m_private_parameters; } + struct iterator { + decl_info const& d; + iterator(decl_info const& d) : d(d) {} + parameter const* begin() const { return d.get_parameters(); } + parameter const* end() const { return begin() + d.get_num_parameters(); } + }; + iterator parameters() const { return iterator(*this); } + unsigned hash() const; bool operator==(decl_info const & info) const; }; @@ -571,6 +580,16 @@ public: parameter const & get_parameter(unsigned idx) const { return m_info->get_parameter(idx); } parameter const * get_parameters() const { return m_info == nullptr ? nullptr : m_info->get_parameters(); } bool private_parameters() const { return m_info != nullptr && m_info->private_parameters(); } + + struct iterator { + decl const& d; + iterator(decl const& d) : d(d) {} + parameter const* begin() const { return d.get_parameters(); } + parameter const* end() const { return begin() + d.get_num_parameters(); } + }; + iterator parameters() const { return iterator(*this); } + + }; // ----------------------------------- @@ -2401,11 +2420,7 @@ public: } void reset() { - ptr_buffer::iterator it = m_to_unmark.begin(); - ptr_buffer::iterator end = m_to_unmark.end(); - for (; it != end; ++it) { - reset_mark(*it); - } + for (ast* a : m_to_unmark) reset_mark(a); m_to_unmark.reset(); } diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 4869949b7..6bbe3ce13 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -401,7 +401,7 @@ bool bv_decl_plugin::get_int2bv_size(unsigned num_parameters, parameter const * m_manager->raise_exception("int2bv expects one parameter"); return false; } - parameter p(parameters[0]); + const parameter &p = parameters[0]; if (p.is_int()) { result = p.get_int(); return true; @@ -428,7 +428,7 @@ func_decl * bv_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const // After SMT-COMP, I should find all offending modules. // For now, I will just simplify the numeral here. parameter p0(mod(parameters[0].get_rational(), rational::power_of_two(bv_size))); - parameter ps[2] = { p0, parameters[1] }; + parameter ps[2] = { std::move(p0), parameters[1] }; sort * bv = get_bv_sort(bv_size); return m_manager->mk_const_decl(m_bv_sym, bv, func_decl_info(m_family_id, OP_BV_NUM, num_parameters, ps)); } @@ -746,7 +746,7 @@ void bv_decl_plugin::get_op_names(svector & op_names, symbol const expr * bv_decl_plugin::get_some_value(sort * s) { SASSERT(s->is_sort_of(m_family_id, BV_SORT)); unsigned bv_size = s->get_parameter(0).get_int(); - parameter p[2] = { parameter(rational(0)), parameter(static_cast(bv_size)) }; + parameter p[2] = { parameter(rational::zero()), parameter(static_cast(bv_size)) }; return m_manager->mk_app(m_family_id, OP_BV_NUM, 2, p, 0, nullptr); } diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index d3704a84a..284c4df93 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -692,6 +692,7 @@ namespace datatype { } unsigned num_well_founded = 0, id = 0; bool changed; + ptr_vector subsorts; do { changed = false; for (unsigned tid = 0; tid < num_types; tid++) { @@ -701,23 +702,25 @@ namespace datatype { sort* s = sorts[tid]; def const& d = get_def(s); for (constructor const* c : d) { - bool found_nonwf = false; for (accessor const* a : *c) { - if (sort2id.find(a->range(), id) && !well_founded[id]) { - found_nonwf = true; - break; + subsorts.reset(); + get_subsorts(a->range(), subsorts); + for (sort* srt : subsorts) { + if (sort2id.find(srt, id) && !well_founded[id]) { + goto next_constructor; + } } } - if (!found_nonwf) { - changed = true; - well_founded[tid] = true; - num_well_founded++; - break; - } + changed = true; + well_founded[tid] = true; + num_well_founded++; + break; + next_constructor: + ; } } } - while(changed && num_well_founded < num_types); + while (changed && num_well_founded < num_types); return num_well_founded == num_types; } @@ -727,8 +730,7 @@ namespace datatype { void util::get_subsorts(sort* s, ptr_vector& sorts) const { sorts.push_back(s); - for (unsigned i = 0; i < s->get_num_parameters(); ++i) { - parameter const& p = s->get_parameter(i); + for (parameter const& p : s->parameters()) { if (p.is_ast() && is_sort(p.get_ast())) { get_subsorts(to_sort(p.get_ast()), sorts); } diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 17602efcf..fc98c97e7 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -134,13 +134,25 @@ namespace datatype { ~plus() override { m_arg1->dec_ref(); m_arg2->dec_ref(); } size* subst(obj_map& S) override { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); } sort_size eval(obj_map const& S) override { - sort_size s1 = m_arg1->eval(S); - sort_size s2 = m_arg2->eval(S); - if (s1.is_infinite()) return s1; - if (s2.is_infinite()) return s2; - if (s1.is_very_big()) return s1; - if (s2.is_very_big()) return s2; - rational r = rational(s1.size(), rational::ui64()) + rational(s2.size(), rational::ui64()); + rational r(0); + ptr_vector todo; + todo.push_back(m_arg1); + todo.push_back(m_arg2); + while (!todo.empty()) { + size* s = todo.back(); + todo.pop_back(); + plus* p = dynamic_cast(s); + if (p) { + todo.push_back(p->m_arg1); + todo.push_back(p->m_arg2); + } + else { + sort_size sz = s->eval(S); + if (sz.is_infinite()) return sz; + if (sz.is_very_big()) return sz; + r += rational(sz.size(), rational::ui64()); + } + } return sort_size(r); } }; diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index fd6ea43e1..baea760fa 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -192,7 +192,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { expr* t1 = nullptr, *t2 = nullptr; expr* s1 = nullptr, *s2 = nullptr; expr* u1 = nullptr, *u2 = nullptr; - expr* fact = nullptr, *body1 = nullptr, *body2 = nullptr; + expr* fact = nullptr, *body1 = nullptr; expr* l1 = nullptr, *l2 = nullptr, *r1 = nullptr, *r2 = nullptr; func_decl* d1 = nullptr, *d2 = nullptr, *d3 = nullptr; proof* p0 = nullptr, *p1 = nullptr, *p2 = nullptr; @@ -389,14 +389,14 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { match_fact(p, fact) && match_fact(p1, fml) && match_and(fml, terms)) { - for (expr* t : terms) + for (expr* t : terms) if (t == fact) return true; } UNREACHABLE(); return false; } case PR_NOT_OR_ELIM: { - + if (match_proof(p, p1) && match_fact(p, fact) && match_fact(p1, fml) && @@ -605,6 +605,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { bool found = false; for (expr* term2 : terms2) { found = term1 == term2; + if (found) break; } if (!found) { IF_VERBOSE(0, verbose_stream() << "Premise not found:" << mk_pp(term1, m) << "\n";); @@ -738,9 +739,9 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { } if (is_quantifier(e)) { SASSERT(!is_lambda(e)); - q = to_quantifier(e); + q = to_quantifier(e); // TBD check that quantifier is properly instantiated - return is_forall == ::is_forall(q); + return is_forall == ::is_forall(q); } } UNREACHABLE(); @@ -1004,7 +1005,7 @@ bool proof_checker::match_op(expr const* e, decl_kind k, ptr_vector& terms if (e->get_kind() == AST_APP && to_app(e)->get_family_id() == m.get_basic_family_id() && to_app(e)->get_decl_kind() == k) { - for (expr* arg : *to_app(e)) + for (expr* arg : *to_app(e)) terms.push_back(arg); return true; } diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 7a03d84d7..72ce9c761 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -66,6 +66,7 @@ br_status arith_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c SASSERT(num_args == 2); st = mk_div_core(args[0], args[1], result); break; case OP_IDIV: if (num_args == 1) { result = args[0]; st = BR_DONE; break; } SASSERT(num_args == 2); st = mk_idiv_core(args[0], args[1], result); break; + case OP_IDIVIDES: SASSERT(num_args == 1); st = mk_idivides(f->get_parameter(0).get_int(), args[0], result); break; case OP_MOD: SASSERT(num_args == 2); st = mk_mod_core(args[0], args[1], result); break; case OP_REM: SASSERT(num_args == 2); st = mk_rem_core(args[0], args[1], result); break; case OP_UMINUS: SASSERT(num_args == 1); st = mk_uminus(args[0], result); break; @@ -792,6 +793,11 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul return BR_FAILED; } +br_status arith_rewriter::mk_idivides(unsigned k, expr * arg, expr_ref & result) { + result = m().mk_eq(m_util.mk_mod(arg, m_util.mk_int(k)), m_util.mk_int(0)); + return BR_REWRITE2; +} + br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & result) { set_curr_sort(m().get_sort(arg1)); numeral v1, v2; @@ -812,6 +818,28 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu result = m().mk_ite(m().mk_eq(arg1, zero), m_util.mk_idiv(zero, zero), m_util.mk_int(1)); return BR_REWRITE3; } + if (m_util.is_numeral(arg2, v2, is_int) && v2.is_pos() && m_util.is_add(arg1)) { + expr_ref_buffer args(m()); + bool change = false; + rational add(0); + for (expr* arg : *to_app(arg1)) { + rational arg_v; + if (m_util.is_numeral(arg, arg_v) && arg_v.is_pos() && mod(arg_v, v2) != arg_v) { + change = true; + args.push_back(m_util.mk_numeral(mod(arg_v, v2), true)); + add += div(arg_v, v2); + } + else { + args.push_back(arg); + } + } + if (change) { + result = m_util.mk_idiv(m().mk_app(to_app(arg1)->get_decl(), args.size(), args.c_ptr()), arg2); + result = m_util.mk_add(m_util.mk_numeral(add, true), result); + TRACE("div_bug", tout << "mk_div result: " << result << "\n";); + return BR_REWRITE3; + } + } if (divides(arg1, arg2, result)) { return BR_REWRITE_FULL; } @@ -914,9 +942,8 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul } if (arg1 == arg2 && !m_util.is_numeral(arg2)) { - expr_ref zero(m_util.mk_int(0), m()), abs(m()); - mk_abs_core(arg2, abs); - result = m().mk_ite(m().mk_eq(arg2, zero), m_util.mk_mod(zero, zero), abs); + expr_ref zero(m_util.mk_int(0), m()); + result = m().mk_ite(m().mk_eq(arg2, zero), m_util.mk_mod(zero, zero), zero); return BR_DONE; } @@ -927,30 +954,29 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul return BR_DONE; } - // propagate mod inside only if not all arguments are not already mod. + // propagate mod inside only if there is something to reduce. if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos() && (is_add(arg1) || is_mul(arg1))) { TRACE("mod_bug", tout << "mk_mod:\n" << mk_ismt2_pp(arg1, m()) << "\n" << mk_ismt2_pp(arg2, m()) << "\n";); - unsigned num_args = to_app(arg1)->get_num_args(); - unsigned i; - rational arg_v; - for (i = 0; i < num_args; i++) { - expr * arg = to_app(arg1)->get_arg(i); - if (m_util.is_mod(arg)) - continue; - if (m_util.is_numeral(arg, arg_v) && mod(arg_v, v2) == arg_v) - continue; - if (m().is_ite(arg)) - continue; - // found target for rewriting - break; + expr_ref_buffer args(m()); + bool change = false; + for (expr* arg : *to_app(arg1)) { + rational arg_v; + if (m_util.is_numeral(arg, arg_v) && mod(arg_v, v2) != arg_v) { + change = true; + args.push_back(m_util.mk_numeral(mod(arg_v, v2), true)); + } + else if (m_util.is_mod(arg, t1, t2) && t2 == arg2) { + change = true; + args.push_back(t1); + } + else { + args.push_back(arg); + } } - TRACE("mod_bug", tout << "mk_mod target: " << i << "\n";); - if (i == num_args) + if (!change) { return BR_FAILED; // did not find any target for applying simplification - ptr_buffer new_args; - for (unsigned i = 0; i < num_args; i++) - new_args.push_back(m_util.mk_mod(to_app(arg1)->get_arg(i), arg2)); - result = m_util.mk_mod(m().mk_app(to_app(arg1)->get_decl(), new_args.size(), new_args.c_ptr()), arg2); + } + result = m_util.mk_mod(m().mk_app(to_app(arg1)->get_decl(), args.size(), args.c_ptr()), arg2); TRACE("mod_bug", tout << "mk_mod result: " << mk_ismt2_pp(result, m()) << "\n";); return BR_REWRITE3; } diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index 93b6e5ad5..dd7623a9b 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -143,6 +143,7 @@ public: br_status mk_div_core(expr * arg1, expr * arg2, expr_ref & result); br_status mk_idiv_core(expr * arg1, expr * arg2, expr_ref & result); + br_status mk_idivides(unsigned k, expr * arg, expr_ref & result); br_status mk_mod_core(expr * arg1, expr * arg2, expr_ref & result); br_status mk_rem_core(expr * arg1, expr * arg2, expr_ref & result); br_status mk_power_core(expr* arg1, expr* arg2, expr_ref & result); diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index 862d1cdab..fe750acdd 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -89,6 +89,7 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { expr_ref_vector m_out; obj_map m_const2bits; expr_ref_vector m_bindings; + unsigned_vector m_shifts; func_decl_ref_vector m_keys; expr_ref_vector m_values; unsigned_vector m_keyval_lim; @@ -579,19 +580,36 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); } SASSERT(new_bindings.size() == q->get_num_decls()); i = q->get_num_decls(); + unsigned shift = j; + if (!m_shifts.empty()) shift += m_shifts.back(); while (i > 0) { i--; m_bindings.push_back(new_bindings[i]); + m_shifts.push_back(shift); } } return true; } bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { - if (m_blast_quant) { - if (t->get_idx() >= m_bindings.size()) + if (m_blast_quant) { + if (m_bindings.empty()) return false; - result = m_bindings.get(m_bindings.size() - t->get_idx() - 1); + unsigned shift = m_shifts.back(); + if (t->get_idx() >= m_bindings.size()) { + if (shift == 0) + return false; + result = m_manager.mk_var(t->get_idx() + shift, t->get_sort()); + } + else { + unsigned offset = m_bindings.size() - t->get_idx() - 1; + result = m_bindings.get(offset); + shift = shift - m_shifts[offset]; + if (shift > 0) { + var_shifter vs(m_manager); + vs(result, shift, result); + } + } result_pr = nullptr; return true; } @@ -641,6 +659,7 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns); result_pr = nullptr; m_bindings.shrink(old_sz); + m_shifts.shrink(old_sz); return true; } }; diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index d61c906be..d26c55fda 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -613,12 +613,12 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) expr* cond2 = nullptr, *t2 = nullptr, *e2 = nullptr; if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) { - try_ite_value(to_app(t), val, result); + VERIFY(BR_FAILED != try_ite_value(to_app(t), val, result)); result = m().mk_ite(cond, result, m().mk_eq(e, val)); return BR_REWRITE2; } if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) { - try_ite_value(to_app(e), val, result); + VERIFY(BR_FAILED != try_ite_value(to_app(e), val, result)); result = m().mk_ite(cond, m().mk_eq(t, val), result); return BR_REWRITE2; } @@ -640,19 +640,21 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { br_status r = BR_FAILED; - if (m().is_ite(lhs) && m().is_value(rhs)) { - r = try_ite_value(to_app(lhs), to_app(rhs), result); - CTRACE("try_ite_value", r != BR_FAILED, - tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); + + if (m_ite_extra_rules) { + if (m().is_ite(lhs) && m().is_value(rhs)) { + r = try_ite_value(to_app(lhs), to_app(rhs), result); + CTRACE("try_ite_value", r != BR_FAILED, + tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); + } + else if (m().is_ite(rhs) && m().is_value(lhs)) { + r = try_ite_value(to_app(rhs), to_app(lhs), result); + CTRACE("try_ite_value", r != BR_FAILED, + tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); + } + if (r != BR_FAILED) + return r; } - else if (m().is_ite(rhs) && m().is_value(lhs)) { - r = try_ite_value(to_app(rhs), to_app(lhs), result); - CTRACE("try_ite_value", r != BR_FAILED, - tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); - } - if (r != BR_FAILED) - return r; - if (m().is_bool(lhs)) { bool unfolded = false; diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 3862aecae..d1def83a1 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -865,8 +865,8 @@ struct pb2bv_rewriter::imp { // definitions used for sorting network pliteral mk_false() { return m.mk_false(); } pliteral mk_true() { return m.mk_true(); } - pliteral mk_max(pliteral a, pliteral b) { return trail(m.mk_or(a, b)); } - pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } + pliteral mk_max(unsigned n, pliteral const* lits) { return trail(m.mk_or(n, lits)); } + pliteral mk_min(unsigned n, pliteral const* lits) { return trail(m.mk_and(n, lits)); } pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } std::ostream& pp(std::ostream& out, pliteral lit) { return out << mk_ismt2_pp(lit, m); } @@ -889,7 +889,7 @@ struct pb2bv_rewriter::imp { m_keep_cardinality_constraints = f; } - void set_at_most1(sorting_network_encoding enc) { m_sort.cfg().m_encoding = enc; } + void set_cardinality_encoding(sorting_network_encoding enc) { m_sort.cfg().m_encoding = enc; } }; @@ -904,7 +904,7 @@ struct pb2bv_rewriter::imp { card2bv_rewriter_cfg(imp& i, ast_manager & m):m_r(i, m) {} void keep_cardinality_constraints(bool f) { m_r.keep_cardinality_constraints(f); } void set_pb_solver(symbol const& s) { m_r.set_pb_solver(s); } - void set_at_most1(sorting_network_encoding enc) { m_r.set_at_most1(enc); } + void set_cardinality_encoding(sorting_network_encoding enc) { m_r.set_cardinality_encoding(enc); } }; @@ -916,7 +916,7 @@ struct pb2bv_rewriter::imp { m_cfg(i, m) {} void keep_cardinality_constraints(bool f) { m_cfg.keep_cardinality_constraints(f); } void set_pb_solver(symbol const& s) { m_cfg.set_pb_solver(s); } - void set_at_most1(sorting_network_encoding e) { m_cfg.set_at_most1(e); } + void set_cardinality_encoding(sorting_network_encoding e) { m_cfg.set_cardinality_encoding(e); } void rewrite(bool full, expr* e, expr_ref& r, proof_ref& p) { expr_ref ee(e, m()); if (m_cfg.m_r.mk_app(full, e, r)) { @@ -947,15 +947,17 @@ struct pb2bv_rewriter::imp { return gparams::get_module("sat").get_sym("pb.solver", symbol("solver")); } - sorting_network_encoding atmost1_encoding() const { - symbol enc = m_params.get_sym("atmost1_encoding", symbol()); + sorting_network_encoding cardinality_encoding() const { + symbol enc = m_params.get_sym("cardinality.encoding", symbol()); if (enc == symbol()) { - enc = gparams::get_module("sat").get_sym("atmost1_encoding", symbol()); + enc = gparams::get_module("sat").get_sym("cardinality.encoding", symbol()); } - if (enc == symbol("grouped")) return sorting_network_encoding::grouped_at_most_1; - if (enc == symbol("bimander")) return sorting_network_encoding::bimander_at_most_1; - if (enc == symbol("ordered")) return sorting_network_encoding::ordered_at_most_1; - return grouped_at_most_1; + if (enc == symbol("grouped")) return sorting_network_encoding::grouped_at_most; + if (enc == symbol("bimander")) return sorting_network_encoding::bimander_at_most; + if (enc == symbol("ordered")) return sorting_network_encoding::ordered_at_most; + if (enc == symbol("unate")) return sorting_network_encoding::unate_at_most; + if (enc == symbol("circuit")) return sorting_network_encoding::circuit_at_most; + return grouped_at_most; } @@ -973,10 +975,11 @@ struct pb2bv_rewriter::imp { m_params.append(p); m_rw.keep_cardinality_constraints(keep_cardinality()); m_rw.set_pb_solver(pb_solver()); - m_rw.set_at_most1(atmost1_encoding()); + m_rw.set_cardinality_encoding(cardinality_encoding()); } + void collect_param_descrs(param_descrs& r) const { - r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver"); + r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: false) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver"); r.insert("pb.solver", CPK_SYMBOL, "(default: solver) retain pb constraints (don't bit-blast them) and use built-in pb solver"); } diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index af5ef3b0b..84c05d53e 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -1866,6 +1866,52 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve } } +bool seq_rewriter::reduce_contains(expr* a, expr* b, expr_ref_vector& disj) { + m_lhs.reset(); + m_util.str.get_concat(a, m_lhs); + TRACE("seq", tout << expr_ref(a, m()) << " " << expr_ref(b, m()) << "\n";); + zstring s; + for (unsigned i = 0; i < m_lhs.size(); ++i) { + expr* e = m_lhs.get(i); + if (m_util.str.is_empty(e)) { + continue; + } + + if (m_util.str.is_string(e, s)) { + unsigned sz = s.length(); + expr_ref_vector es(m()); + for (unsigned j = 0; j < sz; ++j) { + es.push_back(m_util.str.mk_unit(m_util.str.mk_char(s, j))); + } + es.append(m_lhs.size() - i, m_lhs.c_ptr() + i); + for (unsigned j = 0; j < sz; ++j) { + disj.push_back(m_util.str.mk_prefix(b, m_util.str.mk_concat(es.size() - j, es.c_ptr() + j))); + } + continue; + } + if (m_util.str.is_unit(e)) { + disj.push_back(m_util.str.mk_prefix(b, m_util.str.mk_concat(m_lhs.size() - i, m_lhs.c_ptr() + i))); + continue; + } + + if (m_util.str.is_string(b, s)) { + expr* all = m_util.re.mk_full_seq(m_util.re.mk_re(m().get_sort(b))); + disj.push_back(m_util.re.mk_in_re(m_util.str.mk_concat(m_lhs.size() - i, m_lhs.c_ptr() + i), + m_util.re.mk_concat(all, m_util.re.mk_concat(m_util.re.mk_to_re(b), all)))); + return true; + } + + if (i == 0) { + return false; + } + disj.push_back(m_util.str.mk_contains(m_util.str.mk_concat(m_lhs.size() - i, m_lhs.c_ptr() + i), b)); + return true; + } + disj.push_back(m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b)))); + return true; +} + + expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) { SASSERT(n > 0); ptr_vector bs; diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index c96096c65..f5878b2c2 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -168,6 +168,8 @@ public: bool reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs, bool& change); + bool reduce_contains(expr* a, expr* b, expr_ref_vector& disj); + void add_seqs(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_vector& lhs, expr_ref_vector& rhs); diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index cd8571a95..07c6fd06a 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -363,12 +363,12 @@ bool seq_decl_plugin::is_sort_param(sort* s, unsigned& idx) { bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { if (s == sP) return true; - unsigned i; - if (is_sort_param(sP, i)) { - if (binding.size() <= i) binding.resize(i+1); - if (binding[i] && (binding[i] != s)) return false; - TRACE("seq_verbose", tout << "setting binding @ " << i << " to " << mk_pp(s, *m_manager) << "\n";); - binding[i] = s; + unsigned idx; + if (is_sort_param(sP, idx)) { + if (binding.size() <= idx) binding.resize(idx+1); + if (binding[idx] && (binding[idx] != s)) return false; + TRACE("seq_verbose", tout << "setting binding @ " << idx << " to " << mk_pp(s, *m_manager) << "\n";); + binding[idx] = s; return true; } @@ -376,8 +376,8 @@ bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { if (s->get_family_id() == sP->get_family_id() && s->get_decl_kind() == sP->get_decl_kind() && s->get_num_parameters() == sP->get_num_parameters()) { - for (unsigned i = 0; i < s->get_num_parameters(); ++i) { - parameter const& p = s->get_parameter(i); + for (unsigned i = 0, sz = s->get_num_parameters(); i < sz; ++i) { + parameter const& p = s->get_parameter(i); if (p.is_ast() && is_sort(p.get_ast())) { parameter const& p2 = sP->get_parameter(i); if (!match(binding, to_sort(p.get_ast()), to_sort(p2.get_ast()))) return false; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 585dd0fa6..be3acc261 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1063,7 +1063,7 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg return; } if (num_indices > 0) - throw cmd_exception("invalid use of indexed indentifier, unknown builtin function ", s); + throw cmd_exception("invalid use of indexed identifier, unknown builtin function ", s); expr* _t; if (macros_find(s, num_args, args, _t)) { TRACE("macro_bug", tout << "well_sorted_check_enabled(): " << well_sorted_check_enabled() << "\n"; diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index dc3880674..c0ab1e3e2 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -37,6 +37,7 @@ context_params::context_params() { m_model_compress = true; m_timeout = UINT_MAX; m_rlimit = 0; + m_statistics = false; updt_params(); } @@ -109,6 +110,9 @@ void context_params::set(char const * param, char const * value) { else if (p == "dump_models") { set_bool(m_dump_models, param, value); } + else if (p == "stats") { + set_bool(m_statistics, param, value); + } else if (p == "trace") { set_bool(m_trace, param, value); } @@ -158,6 +162,7 @@ void context_params::updt_params(params_ref const & p) { m_unsat_core = p.get_bool("unsat_core", m_unsat_core); m_debug_ref_count = p.get_bool("debug_ref_count", m_debug_ref_count); m_smtlib2_compliant = p.get_bool("smtlib2_compliant", m_smtlib2_compliant); + m_statistics = p.get_bool("stats", m_statistics); } void context_params::collect_param_descrs(param_descrs & d) { @@ -174,6 +179,8 @@ void context_params::collect_param_descrs(param_descrs & d) { d.insert("dot_proof_file", CPK_STRING, "file in which to output graphical proofs", "proof.dot"); d.insert("debug_ref_count", CPK_BOOL, "debug support for AST reference counting", "false"); d.insert("smtlib2_compliant", CPK_BOOL, "enable/disable SMT-LIB 2.0 compliance", "false"); + d.insert("stats", CPK_BOOL, "enable/disable statistics", "false"); + // statistics are hidden as they are controlled by the /st option. collect_solver_param_descrs(d); } diff --git a/src/cmd_context/context_params.h b/src/cmd_context/context_params.h index 8ca36dfc9..f00d39641 100644 --- a/src/cmd_context/context_params.h +++ b/src/cmd_context/context_params.h @@ -45,6 +45,7 @@ public: bool m_unsat_core; bool m_smtlib2_compliant; // it must be here because it enable/disable the use of coercions in the ast_manager. unsigned m_timeout; + bool m_statistics; unsigned rlimit() const { return m_rlimit; } context_params(); diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 5811811fc..aa4fc5a39 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -2629,17 +2629,15 @@ namespace algebraic_numbers { } else if (a.is_basic()) { mpq const & v = basic_value(a); - scoped_mpz neg_n(qm()); + mpz neg_n; qm().set(neg_n, v.numerator()); qm().neg(neg_n); - unsynch_mpz_manager zmgr; - // FIXME: remove these copies - mpz coeffs[2] = { zmgr.dup(neg_n.get()), zmgr.dup(v.denominator()) }; + mpz coeffs[2] = { std::move(neg_n), qm().dup(v.denominator()) }; out << "("; upm().display(out, 2, coeffs, "#"); out << ", 1)"; // first root of the polynomial d*# - n - zmgr.del(coeffs[0]); - zmgr.del(coeffs[1]); + qm().del(coeffs[0]); + qm().del(coeffs[1]); } else { algebraic_cell * c = a.to_algebraic(); @@ -2679,17 +2677,15 @@ namespace algebraic_numbers { } else if (a.is_basic()) { mpq const & v = basic_value(a); - scoped_mpz neg_n(qm()); + mpz neg_n; qm().set(neg_n, v.numerator()); qm().neg(neg_n); - unsynch_mpz_manager zmgr; - // FIXME: remove these copies - mpz coeffs[2] = { zmgr.dup(neg_n.get()), zmgr.dup(v.denominator()) }; + mpz coeffs[2] = { std::move(neg_n), qm().dup(v.denominator()) }; out << "(root-obj "; upm().display_smt2(out, 2, coeffs, "x"); out << " 1)"; // first root of the polynomial d*# - n - zmgr.del(coeffs[0]); - zmgr.del(coeffs[1]); + qm().del(coeffs[0]); + qm().del(coeffs[1]); } else { algebraic_cell * c = a.to_algebraic(); diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index d1bb90f0c..8a771e07c 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -166,7 +166,7 @@ namespace opt { return true; } -#define PASSERT(_e_) if (!(_e_)) { TRACE("opt", display(tout, r);); SASSERT(_e_); } +#define PASSERT(_e_) if (!(_e_)) { TRACE("opt1", display(tout, r); display(tout);); SASSERT(_e_); } bool model_based_opt::invariant(unsigned index, row const& r) { vector const& vars = r.m_vars; @@ -539,7 +539,7 @@ namespace opt { rational slack = (abs_src_c - rational::one()) * (abs_dst_c - rational::one()); rational dst_val = dst.m_value - x_val*dst_c; rational src_val = src.m_value - x_val*src_c; - rational distance = src_c * dst_val + dst_c * src_val + slack; + rational distance = abs_src_c * dst_val + abs_dst_c * src_val + slack; bool use_case1 = distance.is_nonpos() || abs_src_c.is_one() || abs_dst_c.is_one(); #if 0 @@ -655,7 +655,10 @@ namespace opt { void model_based_opt::normalize(unsigned row_id) { row& r = m_rows[row_id]; - if (r.m_vars.empty()) return; + if (r.m_vars.empty()) { + retire_row(row_id); + return; + } if (r.m_type == t_mod) return; rational g(abs(r.m_vars[0].m_coeff)); bool all_int = g.is_int(); @@ -1085,14 +1088,16 @@ namespace opt { if (D.is_zero()) { throw default_exception("modulo 0 is not defined"); } - TRACE("opt", display(tout << "lcm: " << D << " tableau\n");); + TRACE("opt1", display(tout << "lcm: " << D << " x: v" << x << " tableau\n");); rational val_x = m_var2value[x]; rational u = mod(val_x, D); SASSERT(u.is_nonneg() && u < D); for (unsigned idx : mod_rows) { replace_var(idx, x, u); SASSERT(invariant(idx, m_rows[idx])); + normalize(idx); } + TRACE("opt1", display(tout << "tableau after replace x under mod\n");); // // update inequalities such that u is added to t and // D is multiplied to coefficient of x. @@ -1112,8 +1117,10 @@ namespace opt { // x |-> D*y + u replace_var(row_id, x, D, y, u); visited.insert(row_id); + normalize(row_id); } } + TRACE("opt1", display(tout << "tableau after replace x by y := v" << y << "\n");); def result = project(y, compute_def); if (compute_def) { result = (result * D) + u; diff --git a/src/muz/base/bind_variables.cpp b/src/muz/base/bind_variables.cpp index cbafc57b0..1e918b172 100644 --- a/src/muz/base/bind_variables.cpp +++ b/src/muz/base/bind_variables.cpp @@ -64,7 +64,7 @@ expr_ref bind_variables::abstract(expr* term, cache_t& cache, unsigned scope) { } switch(e->get_kind()) { case AST_VAR: { - SASSERT(to_var(e)->get_idx() < scope); + // SASSERT(to_var(e)->get_idx() >= scope); // mixing bound variables and free is possible for the caller, // but not proper use. // So we assert here even though we don't check for it. diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index d709209e1..0dbeba5b3 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -57,7 +57,8 @@ namespace datalog { m_hnf(m), m_qe(m, params_ref(), false), m_rwr(m), - m_ufproc(m) {} + m_ufproc(m), + m_fd_proc(m) {} void rule_manager::inc_ref(rule * r) { if (r) { @@ -928,6 +929,23 @@ namespace datalog { return exist || univ; } + bool rule_manager::is_finite_domain(rule const& r) const { + m_visited.reset(); + m_fd_proc.reset(); + for (unsigned i = r.get_uninterpreted_tail_size(); i < r.get_tail_size(); ++i) { + for_each_expr_core(m_fd_proc, m_visited, r.get_tail(i)); + } + for (unsigned i = 0; i < r.get_uninterpreted_tail_size(); ++i) { + for (expr* arg : *r.get_tail(i)) { + for_each_expr_core(m_fd_proc, m_visited, arg); + } + } + for (expr* arg : *r.get_head()) { + for_each_expr_core(m_fd_proc, m_visited, arg); + } + return m_fd_proc.is_fd(); + } + bool rule::has_negation() const { for (unsigned i = 0; i < get_uninterpreted_tail_size(); ++i) { if (is_neg_tail(i)) { diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index 102427a4a..7e85199cf 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -92,6 +92,20 @@ namespace datalog { void reset() { m_exist = m_univ = false; } }; + struct fd_finder_proc { + ast_manager& m; + bv_util m_bv; + bool m_is_fd; + fd_finder_proc(ast_manager& m): m(m), m_bv(m), m_is_fd(true) {} + + bool is_fd() const { return m_is_fd; } + bool is_fd(sort* s) { return m.is_bool(s) || m_bv.is_bv_sort(s); } + void operator()(var* n) { m_is_fd &= is_fd(n->get_sort()); } + void operator()(quantifier* ) { m_is_fd = false; } + void operator()(app* n) { m_is_fd &= is_fd(n->get_decl()->get_range()); } + void reset() { m_is_fd = true; } + }; + /** \brief Manager for the \c rule class @@ -117,6 +131,7 @@ namespace datalog { mutable uninterpreted_function_finder_proc m_ufproc; mutable quantifier_finder_proc m_qproc; mutable expr_sparse_mark m_visited; + mutable fd_finder_proc m_fd_proc; // only the context can create a rule_manager @@ -265,6 +280,7 @@ namespace datalog { bool has_uninterpreted_non_predicates(rule const& r, func_decl*& f) const; void has_quantifiers(rule const& r, bool& existential, bool& universal) const; bool has_quantifiers(rule const& r) const; + bool is_finite_domain(rule const& r) const; }; diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index 28abbba41..5114fdca4 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -501,6 +501,14 @@ namespace datalog { } } + bool rule_set::is_finite_domain() const { + for (rule * r : *this) { + if (!get_rule_manager().is_finite_domain(*r)) + return false; + } + return true; + } + void rule_set::display_deps( std::ostream & out ) const { diff --git a/src/muz/base/dl_rule_set.h b/src/muz/base/dl_rule_set.h index 748574d96..736dd8888 100644 --- a/src/muz/base/dl_rule_set.h +++ b/src/muz/base/dl_rule_set.h @@ -253,6 +253,7 @@ namespace datalog { const func_decl_set & get_output_predicates() const { return m_output_preds; } func_decl* get_output_predicate() const { SASSERT(m_output_preds.size() == 1); return *m_output_preds.begin(); } + bool is_finite_domain() const; void display(std::ostream & out) const; diff --git a/src/muz/base/fp_params.pyg b/src/muz/base/fp_params.pyg index ee842d28e..8cee99540 100644 --- a/src/muz/base/fp_params.pyg +++ b/src/muz/base/fp_params.pyg @@ -1,8 +1,7 @@ def_module_params('fp', description='fixedpoint parameters', export=True, - params=(('timeout', UINT, UINT_MAX, 'set timeout'), - ('engine', SYMBOL, 'auto-config', + params=(('engine', SYMBOL, 'auto-config', 'Select: auto-config, datalog, bmc, spacer'), ('datalog.default_table', SYMBOL, 'sparse', 'default table implementation: sparse, hashtable, bitvector, interval'), @@ -84,9 +83,9 @@ def_module_params('fp', ('print_boogie_certificate', BOOL, False, 'print certificate for reachability or non-reachability using a ' + 'format understood by Boogie'), - ('print_statistics', BOOL, False, 'print statistics'), ('print_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), + ('print_statistics', BOOL, False, 'print statistics'), ('tab.selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), ('xform.bit_blast', BOOL, False, diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 5f69e4c37..f804a239a 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -17,22 +17,22 @@ Revision History: --*/ +#include "ast/datatype_decl_plugin.h" +#include "ast/dl_decl_plugin.h" +#include "ast/ast_smt_pp.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/scoped_proof.h" +#include "smt/smt_solver.h" +#include "tactic/fd_solver/fd_solver.h" #include "muz/base/dl_context.h" #include "muz/base/dl_rule_transformer.h" #include "muz/bmc/dl_bmc_engine.h" #include "muz/transforms/dl_mk_slice.h" -#include "smt/smt_kernel.h" -#include "ast/datatype_decl_plugin.h" -#include "ast/dl_decl_plugin.h" -#include "ast/rewriter/bool_rewriter.h" #include "model/model_smt2_pp.h" -#include "ast/ast_smt_pp.h" -#include "ast/well_sorted.h" -#include "ast/rewriter/rewriter_def.h" #include "muz/transforms/dl_transforms.h" #include "muz/transforms/dl_mk_rule_inliner.h" -#include "ast/scoped_proof.h" - #include "muz/base/fp_params.hpp" namespace datalog { @@ -53,7 +53,7 @@ namespace datalog { m_bit_width = 4; lbool res = l_false; while (res == l_false) { - b.m_solver.push(); + b.m_solver->push(); IF_VERBOSE(1, verbose_stream() << "bit_width: " << m_bit_width << "\n";); compile(); b.checkpoint(); @@ -61,12 +61,12 @@ namespace datalog { expr* T = m.mk_const(symbol("T"), mk_index_sort()); expr_ref fml(m.mk_app(q, T), m); b.assert_expr(fml); - res = b.m_solver.check(); + res = b.m_solver->check_sat(0, nullptr); if (res == l_true) { res = get_model(); } - b.m_solver.pop(1); + b.m_solver->pop(1); ++m_bit_width; } return res; @@ -141,10 +141,10 @@ namespace datalog { } void setup() { - b.m_fparams.m_relevancy_lvl = 2; - b.m_fparams.m_model = true; - b.m_fparams.m_model_compact = true; - b.m_fparams.m_mbqi = true; + params_ref p; + p.set_uint("smt.relevancy", 2ul); + p.set_bool("smt.mbqi", true); + b.m_solver->updt_params(p); b.m_rule_trace.reset(); } @@ -252,7 +252,7 @@ namespace datalog { rational num; unsigned level, bv_size; - b.m_solver.get_model(md); + b.m_solver->get_model(md); func_decl* pred = b.m_query_pred; dl_decl_util util(m); T = m.mk_const(symbol("T"), mk_index_sort()); @@ -468,10 +468,9 @@ namespace datalog { } void setup() { - b.m_fparams.m_model = true; - b.m_fparams.m_model_compact = true; - // b.m_fparams.m_mbqi = true; - b.m_fparams.m_relevancy_lvl = 2; + params_ref p; + p.set_uint("smt.relevancy", 2ul); + b.m_solver->updt_params(p); b.m_rule_trace.reset(); } @@ -482,7 +481,7 @@ namespace datalog { q_at_level = m.mk_implies(q, p); b.assert_expr(q_at_level); expr* qr = q.get(); - return b.m_solver.check(1, &qr); + return b.m_solver->check_sat(1, &qr); } proof_ref get_proof(model_ref& md, func_decl* pred, app* prop, unsigned level) { @@ -548,7 +547,7 @@ namespace datalog { scoped_proof _sp(m); expr_ref level_query = compile_query(b.m_query_pred, level); model_ref md; - b.m_solver.get_model(md); + b.m_solver->get_model(md); IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0);); proof_ref pr(m); pr = get_proof(md, b.m_query_pred, to_app(level_query), level); @@ -755,11 +754,10 @@ namespace datalog { m_pred2sort.reset(); m_pinned.reset(); m_sort2pred.reset(); - b.m_fparams.m_relevancy_lvl = 0; - b.m_fparams.m_model = true; - b.m_fparams.m_model_compact = true; - b.m_fparams.m_mbqi = false; - b.m_fparams.m_relevancy_lvl = 2; + params_ref p; + p.set_uint("smt.relevancy", 2ul); + p.set_bool("smt.mbqi", false); + b.m_solver->updt_params(p); b.m_rule_trace.reset(); } @@ -1096,12 +1094,12 @@ namespace datalog { fml = m.mk_app(q, trace.get(), path.get()); b.assert_expr(fml); while (true) { - lbool is_sat = b.m_solver.check(); + lbool is_sat = b.m_solver->check_sat(0, nullptr); model_ref md; if (is_sat == l_false) { return is_sat; } - b.m_solver.get_model(md); + b.m_solver->get_model(md); mk_answer(md, trace, path); return l_true; } @@ -1111,13 +1109,13 @@ namespace datalog { expr_ref trace_val(m), eq(m); trace_val = (*md)(trace); eq = m.mk_eq(trace, trace_val); - b.m_solver.push(); - b.m_solver.assert_expr(eq); - lbool is_sat = b.m_solver.check(); + b.m_solver->push(); + b.m_solver->assert_expr(eq); + lbool is_sat = b.m_solver->check_sat(0, nullptr); if (is_sat != l_false) { - b.m_solver.get_model(md); + b.m_solver->get_model(md); } - b.m_solver.pop(1); + b.m_solver->pop(1); if (is_sat == l_false) { IF_VERBOSE(1, verbose_stream() << "infeasible trace " << mk_pp(trace_val, m) << "\n";); eq = m.mk_not(eq); @@ -1131,8 +1129,8 @@ namespace datalog { trace = (*md)(trace); path = (*md)(path); IF_VERBOSE(2, verbose_stream() << mk_pp(trace, m) << "\n"; - for (unsigned i = 0; i < b.m_solver.size(); ++i) { - verbose_stream() << mk_pp(b.m_solver.get_formula(i), m) << "\n"; + for (unsigned i = 0; i < b.m_solver->get_num_assertions(); ++i) { + verbose_stream() << mk_pp(b.m_solver->get_assertion(i), m) << "\n"; }); scoped_proof _sp(m); proof_ref pr(m); @@ -1183,7 +1181,7 @@ namespace datalog { model_ref md; proof_ref pr(m); rule_unifier unifier(b.m_ctx); - b.m_solver.get_model(md); + b.m_solver->get_model(md); func_decl* pred = b.m_query_pred; SASSERT(m.is_true(md->get_const_interp(to_app(level_query)->get_decl()))); @@ -1283,11 +1281,10 @@ namespace datalog { void setup() { - b.m_fparams.m_relevancy_lvl = 0; - b.m_fparams.m_model = true; - b.m_fparams.m_model_compact = true; - b.m_fparams.m_mbqi = false; - // m_fparams.m_auto_config = false; + params_ref p; + p.set_uint("smt.relevancy", 0ul); + p.set_bool("smt.mbqi", false); + b.m_solver->updt_params(p); b.m_rule_trace.reset(); } @@ -1295,7 +1292,7 @@ namespace datalog { lbool check(unsigned level) { expr_ref level_query = mk_level_predicate(b.m_query_pred, level); expr* q = level_query.get(); - return b.m_solver.check(1, &q); + return b.m_solver->check_sat(1, &q); } expr_ref mk_level_predicate(func_decl* p, unsigned level) { @@ -1428,7 +1425,7 @@ namespace datalog { engine_base(ctx.get_manager(), "bmc"), m_ctx(ctx), m(ctx.get_manager()), - m_solver(m, m_fparams), + m_solver(nullptr), m_rules(ctx), m_query_pred(m), m_answer(m), @@ -1438,7 +1435,7 @@ namespace datalog { bmc::~bmc() {} lbool bmc::query(expr* query) { - m_solver.reset(); + m_solver = nullptr; m_answer = nullptr; m_ctx.ensure_opened(); m_rules.reset(); @@ -1471,6 +1468,7 @@ namespace datalog { IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); + params_ref p; if (m_rules.get_num_rules() == 0) { return l_false; } @@ -1478,18 +1476,25 @@ namespace datalog { return l_false; } - if (is_linear()) { if (m_ctx.get_engine() == QBMC_ENGINE) { + m_solver = mk_smt_solver(m, p, symbol::null); qlinear ql(*this); return ql.check(); } else { + if (m_rules.is_finite_domain()) { + m_solver = mk_fd_solver(m, p); + } + else { + m_solver = mk_smt_solver(m, p, symbol::null); + } linear lin(*this); return lin.check(); } } else { + m_solver = mk_smt_solver(m, p, symbol::null); IF_VERBOSE(0, verbose_stream() << "WARNING: non-linear BMC is highly inefficient\n";); nonlinear nl(*this); return nl.check(); @@ -1498,7 +1503,7 @@ namespace datalog { void bmc::assert_expr(expr* e) { TRACE("bmc", tout << mk_pp(e, m) << "\n";); - m_solver.assert_expr(e); + m_solver->assert_expr(e); } bool bmc::is_linear() const { @@ -1525,11 +1530,11 @@ namespace datalog { } void bmc::collect_statistics(statistics& st) const { - m_solver.collect_statistics(st); + m_solver->collect_statistics(st); } void bmc::reset_statistics() { - m_solver.reset_statistics(); + // m_solver->reset_statistics(); } expr_ref bmc::get_answer() { diff --git a/src/muz/bmc/dl_bmc_engine.h b/src/muz/bmc/dl_bmc_engine.h index a5824fa82..9a7424287 100644 --- a/src/muz/bmc/dl_bmc_engine.h +++ b/src/muz/bmc/dl_bmc_engine.h @@ -22,10 +22,8 @@ Revision History: #include "util/params.h" #include "util/statistics.h" -#include "smt/smt_kernel.h" #include "ast/bv_decl_plugin.h" -#include "smt/params/smt_params.h" - +#include "solver/solver.h" namespace datalog { class context; @@ -33,8 +31,7 @@ namespace datalog { class bmc : public engine_base { context& m_ctx; ast_manager& m; - smt_params m_fparams; - smt::kernel m_solver; + solver_ref m_solver; rule_set m_rules; func_decl_ref m_query_pred; expr_ref m_answer; diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 4605826ba..231dca0d3 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -245,7 +245,8 @@ public: datalog::context& dlctx = m_dl_ctx->dlctx(); set_background(ctx); dlctx.updt_params(m_params); - unsigned timeout = m_dl_ctx->get_params().timeout(); + unsigned timeout = ctx.params().m_timeout; + unsigned rlimit = ctx.params().rlimit(); cancel_eh eh(ctx.m().limit()); bool query_exn = false; lbool status = l_undef; @@ -253,12 +254,14 @@ public: IF_VERBOSE(10, verbose_stream() << "(query)\n";); scoped_ctrl_c ctrlc(eh); scoped_timer timer(timeout, &eh); + scoped_rlimit _rlimit(ctx.m().limit(), rlimit); cmd_context::scoped_watch sw(ctx); try { status = dlctx.rel_query(1, &m_target); } catch (z3_error & ex) { ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl; + print_statistics(ctx); throw ex; } catch (z3_exception& ex) { @@ -352,7 +355,7 @@ private: } void print_statistics(cmd_context& ctx) { - if (m_dl_ctx->get_params().print_statistics()) { + if (ctx.params().m_statistics) { statistics st; datalog::context& dlctx = m_dl_ctx->dlctx(); dlctx.collect_statistics(st); diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 693812a31..f0e86f1a5 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2683,7 +2683,7 @@ lbool context::solve(unsigned from_lvl) if (m_last_result == l_true) { m_stats.m_cex_depth = get_cex_depth (); } - + if (m_params.print_statistics ()) { statistics st; collect_statistics (st); @@ -3063,13 +3063,13 @@ lbool context::solve_core (unsigned from_lvl) IF_VERBOSE(1,verbose_stream() << "Entering level "<< lvl << "\n";); STRACE("spacer_progress", tout << "\n* LEVEL " << lvl << "\n";); - IF_VERBOSE(1, if (m_params.print_statistics ()) { statistics st; collect_statistics (st); }; ); + } // communicate failure to datalog::context if (m_context) { m_context->set_status(datalog::BOUNDED); } diff --git a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp index 47b9e0505..1b633be70 100644 --- a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp +++ b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp @@ -42,26 +42,28 @@ tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & p) { else factor = mk_skip_tactic(); - return and_then(and_then(using_params(mk_simplify_tactic(m, p), - main_p), - using_params(mk_purify_arith_tactic(m, p), - purify_p), - mk_propagate_values_tactic(m, p), - mk_solve_eqs_tactic(m, p), - using_params(mk_purify_arith_tactic(m, p), - purify_p), - mk_elim_uncnstr_tactic(m, p), - mk_elim_term_ite_tactic(m, p)), - and_then(/* mk_degree_shift_tactic(m, p), */ // may affect full dimensionality detection - factor, - mk_solve_eqs_tactic(m, p), - using_params(mk_purify_arith_tactic(m, p), - purify_p), - using_params(mk_simplify_tactic(m, p), - main_p), - mk_tseitin_cnf_core_tactic(m, p), - using_params(mk_simplify_tactic(m, p), - main_p), - mk_nlsat_tactic(m, p))); + return and_then( + mk_report_verbose_tactic("(qfnra-nlsat-tactic)", 10), + and_then(using_params(mk_simplify_tactic(m, p), + main_p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), + mk_propagate_values_tactic(m, p), + mk_solve_eqs_tactic(m, p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), + mk_elim_uncnstr_tactic(m, p), + mk_elim_term_ite_tactic(m, p)), + and_then(/* mk_degree_shift_tactic(m, p), */ // may affect full dimensionality detection + factor, + mk_solve_eqs_tactic(m, p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), + using_params(mk_simplify_tactic(m, p), + main_p), + mk_tseitin_cnf_core_tactic(m, p), + using_params(mk_simplify_tactic(m, p), + main_p), + mk_nlsat_tactic(m, p))); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 566aaa1f6..e5c0bcddb 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1012,8 +1012,7 @@ namespace opt { } } // fix types of objectives: - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective & obj = m_objectives[i]; + for (objective & obj : m_objectives) { expr* t = obj.m_term; switch(obj.m_type) { case O_MINIMIZE: @@ -1189,13 +1188,12 @@ namespace opt { void context::update_bound(bool is_lower) { expr_ref val(m); if (!m_model.get()) return; - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective const& obj = m_objectives[i]; + for (objective const& obj : m_objectives) { rational r; switch(obj.m_type) { case O_MINIMIZE: { val = (*m_model)(obj.m_term); - TRACE("opt", tout << obj.m_term << " " << val << " " << is_numeral(val, r) << "\n";); + TRACE("opt", tout << obj.m_term << " " << val << "\n";); if (is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); TRACE("opt", tout << "adjusted value: " << val << "\n";); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index ca0474314..e61a02d80 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -230,11 +230,14 @@ namespace opt { get_model(m_model); inf_eps val2; m_valid_objectives[i] = true; - TRACE("opt", tout << (has_shared?"has shared":"non-shared") << "\n";); + TRACE("opt", tout << (has_shared?"has shared":"non-shared") << " " << val << "\n";); if (!m_models[i]) { set_model(i); } - if (m_context.get_context().update_model(has_shared)) { + if (!val.is_finite()) { + // skip model updates + } + else if (m_context.get_context().update_model(has_shared)) { if (has_shared && val != current_objective_value(i)) { decrement_value(i, val); } diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 4313cfbec..1fafa12bd 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -124,8 +124,8 @@ namespace opt { // definitions used for sorting network pliteral mk_false() { return m.mk_false(); } pliteral mk_true() { return m.mk_true(); } - pliteral mk_max(pliteral a, pliteral b) { return trail(m.mk_or(a, b)); } - pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } + pliteral mk_max(unsigned n, pliteral const* as) { return trail(m.mk_or(n, as)); } + pliteral mk_min(unsigned n, pliteral const* as) { return trail(m.mk_and(n, as)); } pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } std::ostream& pp(std::ostream& out, pliteral lit) { return out << mk_pp(lit, m); } diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index 21e50182f..f8c519285 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -1301,6 +1301,7 @@ namespace qe { ptr_vector todo; todo.push_back(a); rational k1, k2; + expr* e1 = nullptr, *e2 = nullptr; expr_ref rest(m); while (!todo.empty()) { expr* e = todo.back(); @@ -1319,9 +1320,9 @@ namespace qe { return false; } a = to_app(e); - if (m_util.m_arith.is_mod(e) && - m_util.m_arith.is_numeral(to_app(e)->get_arg(1), k1) && - m_util.get_coeff(contains_x, to_app(e)->get_arg(0), k2, rest)) { + if (m_util.m_arith.is_mod(e, e1, e2) && + m_util.m_arith.is_numeral(e2, k1) && + m_util.get_coeff(contains_x, e1, k2, rest)) { app_ref z(m), z_bv(m); m_util.mk_bounded_var(k1, z_bv, z); m_nested_div_terms.push_back(rest); @@ -1331,10 +1332,9 @@ namespace qe { m_nested_div_z.push_back(z); continue; } - unsigned num_args = a->get_num_args(); - for (unsigned i = 0; i < num_args; ++i) { - todo.push_back(a->get_arg(i)); - } + for (expr* arg : *a) { + todo.push_back(arg); + } } return true; } diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 7dfa35003..b7f0d0d49 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -346,10 +346,50 @@ namespace qe { func_decl_ref_vector no_shared(m); tg1.set_vars(no_shared, false); tg1.add_lits(lits); + arith_util a(m); + expr_ref_vector foreign = tg1.shared_occurrences(a.get_family_id()); + obj_hashtable _foreign; + for (expr* e : foreign) _foreign.insert(e); + vector partition = tg1.get_partition(*mdl); expr_ref_vector diseq = tg1.get_ackerman_disequalities(); lits.append(diseq); - TRACE("qe", tout << "diseq: " << diseq << "\n";); + TRACE("qe", tout << "diseq: " << diseq << "\n"; + tout << "foreign: " << foreign << "\n"; + for (auto const& v : partition) { + tout << "partition: {"; + bool first = true; + for (expr* e : v) { + if (first) first = false; else tout << ", "; + tout << expr_ref(e, m); + } + tout << "}\n"; + } + ); + vector refined_partition; + for (auto & p : partition) { + unsigned j = 0; + for (expr* e : p) { + if (_foreign.contains(e) || + (is_app(e) && m_shared.contains(to_app(e)->get_decl()))) { + p[j++] = e; + } + } + p.shrink(j); + if (!p.empty()) refined_partition.push_back(p); + } + TRACE("qe", + for (auto const& v : refined_partition) { + tout << "partition: {"; + bool first = true; + for (expr* e : v) { + if (first) first = false; else tout << ", "; + tout << expr_ref(e, m); + } + tout << "}\n"; + }); + + arith_project_plugin ap(m); ap.set_check_purified(false); diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 2e81454a0..faa9cfed8 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -99,7 +99,7 @@ namespace qe { m_mark(false), m_mark2(false), m_interpreted(false) { - if (!is_app()) return; + if (!is_app(m_expr)) return; for (expr* e : *to_app(m_expr)) { term* t = app2term[e->get_id()]; t->get_root().m_parents.push_back(this); @@ -151,7 +151,7 @@ namespace qe { unsigned get_id() const { return m_expr->get_id();} - unsigned get_decl_id() const { return is_app() ? get_app()->get_decl()->get_id() : m_expr->get_id(); } + unsigned get_decl_id() const { return is_app(m_expr) ? to_app(m_expr)->get_decl()->get_id() : m_expr->get_id(); } bool is_marked() const {return m_mark;} void set_mark(bool v){m_mark = v;} @@ -159,12 +159,10 @@ namespace qe { void set_mark2(bool v){m_mark2 = v;} // NSB: where is this used? bool is_interpreted() const {return m_interpreted;} - bool is_theory() const { return !is_app() || get_app()->get_family_id() != null_family_id; } + bool is_theory() const { return !is_app(m_expr) || to_app(m_expr)->get_family_id() != null_family_id; } void mark_as_interpreted() {m_interpreted=true;} expr* get_expr() const {return m_expr;} - bool is_app() const {return ::is_app(m_expr);} - app *get_app() const {return is_app() ? to_app(m_expr) : nullptr;} - unsigned get_num_args() const { return is_app() ? get_app()->get_num_args() : 0; } + unsigned get_num_args() const { return is_app(m_expr) ? to_app(m_expr)->get_num_args() : 0; } term &get_root() const {return *m_root;} bool is_root() const {return m_root == this;} @@ -226,7 +224,7 @@ namespace qe { } bool term_graph::is_variable_proc::operator()(const term &t) const { - return (*this)(t.get_app()); + return (*this)(t.get_expr()); } void term_graph::is_variable_proc::set_decls(const func_decl_ref_vector &decls, bool exclude) { @@ -444,7 +442,7 @@ namespace qe { return expr_ref(res, m); } - res = mk_app_core (r.get_app()); + res = mk_app_core (r.get_expr()); m_term2app.insert(r.get_id(), res); return expr_ref(res, m); @@ -463,7 +461,7 @@ namespace qe { SASSERT(t.is_root()); expr_ref rep(mk_app(t), m); for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { - expr* mem = mk_app_core(it->get_app()); + expr* mem = mk_app_core(it->get_expr()); out.push_back (m.mk_eq (rep, mem)); } } @@ -472,9 +470,9 @@ namespace qe { mk_equalities(t, out); for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { - expr* a1 = mk_app_core (it->get_app()); + expr* a1 = mk_app_core (it->get_expr()); for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { - expr* a2 = mk_app_core(it2->get_app()); + expr* a2 = mk_app_core(it2->get_expr()); out.push_back (m.mk_eq (a1, a2)); } } @@ -1000,6 +998,47 @@ namespace qe { reset(); return res; } + + vector get_partition(model& mdl) { + vector result; + expr_ref_vector pinned(m); + obj_map pid; + model::scoped_model_completion _smc(mdl, true); + for (term *t : m_tg.m_terms) { + expr* a = t->get_expr(); + if (!is_app(a)) continue; + if (m.is_bool(a)) continue; + expr_ref val = mdl(a); + unsigned p = 0; + // NB. works for simple domains Integers, Rationals, + // but not for algebraic numerals. + if (!pid.find(val, p)) { + p = pid.size(); + pid.insert(val, p); + pinned.push_back(val); + result.push_back(expr_ref_vector(m)); + } + result[p].push_back(a); + } + return result; + } + + expr_ref_vector shared_occurrences(family_id fid) { + expr_ref_vector result(m); + for (term *t : m_tg.m_terms) { + expr* e = t->get_expr(); + if (m.get_sort(e)->get_family_id() != fid) continue; + for (term * p : term::parents(t->get_root())) { + expr* pe = p->get_expr(); + if (!is_app(pe)) continue; + if (to_app(pe)->get_family_id() == fid) continue; + if (to_app(pe)->get_family_id() == m.get_basic_family_id()) continue; + result.push_back(e); + break; + } + } + return result; + } }; void term_graph::set_vars(func_decl_ref_vector const& decls, bool exclude) { @@ -1033,5 +1072,14 @@ namespace qe { return p.get_ackerman_disequalities(); } + vector term_graph::get_partition(model& mdl) { + term_graph::projector p(*this); + return p.get_partition(mdl); + } + + expr_ref_vector term_graph::shared_occurrences(family_id fid) { + term_graph::projector p(*this); + return p.shared_occurrences(fid); + } } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index 8c02163ab..855a0f2bc 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -122,6 +122,19 @@ namespace qe { */ expr_ref_vector get_ackerman_disequalities(); + /** + * Produce a model-based partition. + */ + vector get_partition(model& mdl); + + /** + * Extract shared occurrences of terms whose sort are + * fid, but appear in a context that is not fid. + * for example f(x + y) produces the shared occurrence + * x + y when f is uninterpreted and x + y has sort Int or Real. + */ + expr_ref_vector shared_occurrences(family_id fid); + }; } diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 930617301..4226b9791 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1976,6 +1976,7 @@ namespace sat { for (unsigned i = 0; !found && i < c.k(); ++i) { found = c[i] == l; } + CTRACE("ba",!found, s().display(tout << l << ":" << c << "\n");); SASSERT(found);); // IF_VERBOSE(0, if (_debug_conflict) verbose_stream() << "ante " << l << " " << c << "\n"); @@ -2591,22 +2592,54 @@ namespace sat { return literal(v, false); } - literal ba_solver::ba_sort::mk_max(literal l1, literal l2) { - VERIFY(l1 != null_literal); - VERIFY(l2 != null_literal); - if (l1 == m_true) return l1; - if (l2 == m_true) return l2; - if (l1 == ~m_true) return l2; - if (l2 == ~m_true) return l1; - literal max = fresh("max"); - s.s().mk_clause(~l1, max); - s.s().mk_clause(~l2, max); - s.s().mk_clause(~max, l1, l2); - return max; + + literal ba_solver::ba_sort::mk_max(unsigned n, literal const* lits) { + m_lits.reset(); + for (unsigned i = 0; i < n; ++i) { + if (lits[i] == m_true) return m_true; + if (lits[i] == ~m_true) continue; + m_lits.push_back(lits[i]); + } + switch (m_lits.size()) { + case 0: + return ~m_true; + case 1: + return m_lits[0]; + default: { + literal max = fresh("max"); + for (unsigned i = 0; i < n; ++i) { + s.s().mk_clause(~m_lits[i], max); + } + m_lits.push_back(~max); + s.s().mk_clause(m_lits.size(), m_lits.c_ptr()); + return max; + } + } } - literal ba_solver::ba_sort::mk_min(literal l1, literal l2) { - return ~mk_max(~l1, ~l2); + literal ba_solver::ba_sort::mk_min(unsigned n, literal const* lits) { + m_lits.reset(); + for (unsigned i = 0; i < n; ++i) { + if (lits[i] == ~m_true) return ~m_true; + if (lits[i] == m_true) continue; + m_lits.push_back(lits[i]); + } + switch (m_lits.size()) { + case 0: + return m_true; + case 1: + return m_lits[0]; + default: { + literal min = fresh("min"); + for (unsigned i = 0; i < n; ++i) { + s.s().mk_clause(~min, m_lits[i]); + m_lits[i] = ~m_lits[i]; + } + m_lits.push_back(min); + s.s().mk_clause(m_lits.size(), m_lits.c_ptr()); + return min; + } + } } void ba_solver::ba_sort::mk_clause(unsigned n, literal const* lits) { diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index e947cee96..bae59f45a 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -255,8 +255,8 @@ namespace sat { pliteral mk_true(); pliteral mk_not(pliteral l); pliteral fresh(char const*); - pliteral mk_max(pliteral l1, pliteral l2); - pliteral mk_min(pliteral l1, pliteral l2); + pliteral mk_min(unsigned, pliteral const* lits); + pliteral mk_max(unsigned, pliteral const* lits); void mk_clause(unsigned n, literal const* lits); std::ostream& pp(std::ostream& out, pliteral l) const; }; diff --git a/src/sat/sat_allocator.h b/src/sat/sat_allocator.h index 06585ebed..e588c8478 100644 --- a/src/sat/sat_allocator.h +++ b/src/sat/sat_allocator.h @@ -23,7 +23,7 @@ Revision History: #include "util/machine.h" class sat_allocator { - static const unsigned CHUNK_SIZE = (1 << 16); + static const unsigned CHUNK_SIZE = (1 << 16) - sizeof(char*); static const unsigned SMALL_OBJ_SIZE = 512; static const unsigned MASK = ((1 << PTR_ALIGNMENT) - 1); static const unsigned NUM_FREE = 1 + (SMALL_OBJ_SIZE >> PTR_ALIGNMENT); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index dd840468e..89776c479 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -43,7 +43,7 @@ def_module_params('sat', ('cardinality.solver', BOOL, True, 'use cardinality solver'), ('pb.solver', SYMBOL, 'solver', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use native solver)'), ('xor.solver', BOOL, False, 'use xor solver'), - ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), + ('cardinality.encoding', SYMBOL, 'grouped', 'encoding used for at-most-k constraints: grouped, bimander, ordered, unate, circuit'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a59dd2b46..7ddc80813 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -17,6 +17,7 @@ Revision History: --*/ + #include #include "sat/sat_solver.h" #include "sat/sat_integrity_checker.h" @@ -298,6 +299,9 @@ namespace sat { if (!c.is_learned()) { m_stats.m_non_learned_generation++; } + if (c.frozen()) { + --m_num_frozen; + } if (m_config.m_drat && !m_drat.is_cleaned(c)) { m_drat.del(c); } @@ -481,9 +485,10 @@ namespace sat { } unsigned some_idx = c.size() >> 1; literal block_lit = c[some_idx]; - DEBUG_CODE(for (auto const& w : m_watches[(~c[0]).index()]) VERIFY(!w.is_clause() || w.get_clause_offset() != cls_off);); - DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) VERIFY(!w.is_clause() || w.get_clause_offset() != cls_off);); - VERIFY(c[0] != c[1]); + VERIFY(!c.frozen()); + DEBUG_CODE(for (auto const& w : m_watches[(~c[0]).index()]) SASSERT(!w.is_clause() || w.get_clause_offset() != cls_off);); + DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) SASSERT(!w.is_clause() || w.get_clause_offset() != cls_off);); + SASSERT(c[0] != c[1]); m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); return reinit; @@ -1547,12 +1552,15 @@ namespace sat { void solver::reinit_assumptions() { if (tracking_assumptions() && at_base_lvl() && !inconsistent()) { TRACE("sat", tout << m_assumptions << "\n";); + if (!propagate(false)) return; push(); - for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { - assign(~m_user_scope_literals[i], justification()); + for (literal lit : m_user_scope_literals) { + if (inconsistent()) break; + assign(~lit, justification()); } - for (unsigned i = 0; !inconsistent() && i < m_assumptions.size(); ++i) { - assign(m_assumptions[i], justification()); + for (literal lit : m_assumptions) { + if (inconsistent()) break; + assign(lit, justification()); } TRACE("sat", for (literal a : m_assumptions) { @@ -2139,7 +2147,6 @@ namespace sat { else { c.inc_inact_rounds(); if (c.inact_rounds() > m_config.m_gc_k) { - m_num_frozen--; del_clause(c); m_stats.m_gc_clause++; deleted++; @@ -2930,7 +2937,7 @@ namespace sat { break; } case justification::EXT_JUSTIFICATION: { - fill_ext_antecedents(m_lemma[i], js); + fill_ext_antecedents(~m_lemma[i], js); for (literal l : m_ext_antecedents) { update_lrb_reasoned(l); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index b44c04604..ad972b2af 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -682,10 +682,10 @@ namespace sat { bool m_deleted; public: scoped_detach(solver& s, clause& c): s(s), c(c), m_deleted(false) { - s.detach_clause(c); + if (!c.frozen()) s.detach_clause(c); } ~scoped_detach() { - if (!m_deleted) s.attach_clause(c); + if (!m_deleted && !c.frozen()) s.attach_clause(c); } void del_clause() { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 8b7e2e63c..ff55598c2 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -483,6 +483,7 @@ public: s2g(m_solver, m_map, m_params, g, m_sat_mc); m_internalized_fmls.reset(); g.get_formulas(m_internalized_fmls); + TRACE("sat", m_solver.display(tout); tout << m_internalized_fmls << "\n";); m_internalized_converted = true; } @@ -529,7 +530,7 @@ private: throw default_exception("generation of proof objects is not supported in this mode"); } SASSERT(!g->proofs_enabled()); - TRACE("sat", g->display(tout);); + TRACE("sat", m_solver.display(tout); g->display(tout);); try { (*m_preprocess)(g, m_subgoals); } @@ -712,23 +713,35 @@ private: m_asms.reset(); unsigned j = 0; sat::literal lit; + sat::literal_set seen; for (unsigned i = 0; i < sz; ++i) { if (dep2asm.find(asms[i], lit)) { SASSERT(lit.var() <= m_solver.num_vars()); - m_asms.push_back(lit); - if (i != j && !m_weights.empty()) { - m_weights[j] = m_weights[i]; + if (!seen.contains(lit)) { + m_asms.push_back(lit); + seen.insert(lit); + if (i != j && !m_weights.empty()) { + m_weights[j] = m_weights[i]; + } + ++j; } - ++j; } } for (unsigned i = 0; i < get_num_assumptions(); ++i) { if (dep2asm.find(get_assumption(i), lit)) { SASSERT(lit.var() <= m_solver.num_vars()); - m_asms.push_back(lit); + if (!seen.contains(lit)) { + m_asms.push_back(lit); + seen.insert(lit); + } } } - + CTRACE("sat", dep2asm.size() != m_asms.size(), + tout << dep2asm.size() << " vs " << m_asms.size() << "\n"; + tout << m_asms << "\n"; + for (auto const& kv : dep2asm) { + tout << mk_pp(kv.m_key, m) << " " << kv.m_value << "\n"; + }); SASSERT(dep2asm.size() == m_asms.size()); } @@ -751,6 +764,7 @@ private: tout << mk_pp(kv.m_key, m) << " |-> " << mk_pp(kv.m_value, m) << "\n"; } tout << "core: "; for (auto c : core) tout << c << " "; tout << "\n"; + m_solver.display(tout); ); m_core.reset(); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 029ddf924..7faa89370 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1167,7 +1167,7 @@ struct sat2goal::imp { } void operator()(sat::solver & s, atom2bool_var const & map, goal & r, ref & mc) { - if (s.inconsistent()) { + if (s.at_base_lvl() && s.inconsistent()) { r.assert_expr(m.mk_false()); return; } diff --git a/src/shell/main.cpp b/src/shell/main.cpp index d367b8ec6..bb1c19b47 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -199,6 +199,7 @@ void parse_cmd_line_args(int argc, char ** argv) { } else if (strcmp(opt_name, "st") == 0) { g_display_statistics = true; + gparams::set("stats", "true"); } else if (strcmp(opt_name, "ist") == 0) { g_display_istatistics = true; @@ -295,7 +296,13 @@ void parse_cmd_line_args(int argc, char ** argv) { int STD_CALL main(int argc, char ** argv) { - try{ +#ifdef DUMP_ARGS + std::cout << "args are: "; + for (int i = 0; i < argc; i++) + std::cout << argv[i] <<" "; + std::cout << std::endl; +#endif + try{ unsigned return_value = 0; memory::initialize(0); memory::exit_when_out_of_memory(true, "ERROR: out of memory"); diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index ea2f50263..00e079989 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -401,7 +401,7 @@ namespace smt { label_hasher & m_lbl_hasher; func_decl * m_root_lbl; unsigned m_num_args; //!< we need this information to avoid the nary *,+ crash bug - unsigned char m_filter_candidates; + bool m_filter_candidates; unsigned m_num_regs; unsigned m_num_choices; instruction * m_root; @@ -531,7 +531,7 @@ namespace smt { } bool filter_candidates() const { - return m_filter_candidates != 0; + return m_filter_candidates; } const instruction * get_root() const { @@ -1847,7 +1847,10 @@ namespace smt { enode * m_n2; enode * m_app; const bind * m_b; - ptr_vector m_used_enodes; + + // equalities used for pattern match. The first element of the tuple gives the argument (or null) of some term that was matched against some higher level + // structure of the trigger, the second element gives the term that argument is replaced with in order to match the trigger. Used for logging purposes only. + vector> m_used_enodes; unsigned m_curr_used_enodes_size; ptr_vector m_pattern_instances; // collect the pattern instances... used for computing min_top_generation and max_top_generation unsigned_vector m_min_top_generation, m_max_top_generation; @@ -1864,11 +1867,11 @@ namespace smt { m_pool.recycle(v); } - void update_max_generation(enode * n) { + void update_max_generation(enode * n, enode * prev) { m_max_generation = std::max(m_max_generation, n->get_generation()); if (m_ast_manager.has_trace_stream()) - m_used_enodes.push_back(n); + m_used_enodes.push_back(std::make_tuple(prev, n)); } // We have to provide the number of expected arguments because we have flat-assoc applications such as +. @@ -1877,7 +1880,7 @@ namespace smt { enode * first = curr; do { if (curr->get_decl() == lbl && curr->is_cgr() && curr->get_num_args() == num_expected_args) { - update_max_generation(curr); + update_max_generation(curr, first); return curr; } curr = curr->get_next(); @@ -1890,7 +1893,7 @@ namespace smt { curr = curr->get_next(); while (curr != first) { if (curr->get_decl() == lbl && curr->is_cgr() && curr->get_num_args() == num_expected_args) { - update_max_generation(curr); + update_max_generation(curr, first); return curr; } curr = curr->get_next(); @@ -1914,7 +1917,7 @@ namespace smt { do { if (n->get_decl() == f && n->get_arg(0)->get_root() == m_args[0]) { - update_max_generation(n); + update_max_generation(n, first); return true; } n = n->get_next(); @@ -1929,7 +1932,7 @@ namespace smt { if (n->get_decl() == f && n->get_arg(0)->get_root() == m_args[0] && n->get_arg(1)->get_root() == m_args[1]) { - update_max_generation(n); + update_max_generation(n, first); return true; } n = n->get_next(); @@ -1949,7 +1952,7 @@ namespace smt { break; } if (i == num_args) { - update_max_generation(n); + update_max_generation(n, first); return true; } } @@ -1975,10 +1978,10 @@ namespace smt { #define INIT_ARGS_SIZE 16 public: - interpreter(context & ctx, mam & m, bool use_filters): + interpreter(context & ctx, mam & ma, bool use_filters): m_context(ctx), m_ast_manager(ctx.get_manager()), - m_mam(m), + m_mam(ma), m_use_filters(use_filters) { m_args.resize(INIT_ARGS_SIZE); } @@ -1999,6 +2002,7 @@ namespace smt { init(t); if (t->filter_candidates()) { for (enode* app : t->get_candidates()) { + TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_owner(), m_ast_manager) << "\n";); if (!app->is_marked() && app->is_cgr()) { if (m_context.resource_limits_exceeded() || !execute_core(t, app)) return; @@ -2196,7 +2200,7 @@ namespace smt { if (bp.m_it == bp.m_end) return nullptr; m_top++; - update_max_generation(*(bp.m_it)); + update_max_generation(*(bp.m_it), nullptr); return *(bp.m_it); } @@ -2277,7 +2281,7 @@ namespace smt { if (m_ast_manager.has_trace_stream()) { m_used_enodes.reset(); - m_used_enodes.push_back(n); + m_used_enodes.push_back(std::make_tuple(nullptr, n)); // null indicates that n was matched against the trigger at the top-level } m_pc = t->get_root(); @@ -2382,6 +2386,10 @@ namespace smt { SASSERT(m_n2 != 0); if (m_n1->get_root() != m_n2->get_root()) goto backtrack; + + // we used the equality m_n1 = m_n2 for the match and need to make sure it ends up in the log + m_used_enodes.push_back(std::make_tuple(m_n1, m_n2)); + m_pc = m_pc->m_next; goto main_loop; @@ -2776,7 +2784,7 @@ namespace smt { m_pattern_instances.pop_back(); m_pattern_instances.push_back(m_app); // continue succeeded - update_max_generation(m_app); + update_max_generation(m_app, nullptr); // null indicates a top-level match TRACE("mam_int", tout << "continue next candidate:\n" << mk_ll_pp(m_app->get_owner(), m_ast_manager);); m_num_args = c->m_num_args; m_oreg = c->m_oreg; @@ -2830,7 +2838,7 @@ namespace smt { mk_tree_trail(ptr_vector & t, unsigned id):m_trees(t), m_lbl_id(id) {} void undo(mam_impl & m) override { dealloc(m_trees[m_lbl_id]); - m_trees[m_lbl_id] = 0; + m_trees[m_lbl_id] = nullptr; } }; @@ -2863,8 +2871,8 @@ namespace smt { app * p = to_app(mp->get_arg(first_idx)); func_decl * lbl = p->get_decl(); unsigned lbl_id = lbl->get_decl_id(); - m_trees.reserve(lbl_id+1, 0); - if (m_trees[lbl_id] == 0) { + m_trees.reserve(lbl_id+1, nullptr); + if (m_trees[lbl_id] == nullptr) { m_trees[lbl_id] = m_compiler.mk_tree(qa, mp, first_idx, false); SASSERT(m_trees[lbl_id]->expected_num_args() == p->get_num_args()); DEBUG_CODE(m_trees[lbl_id]->set_context(m_context);); @@ -2949,7 +2957,7 @@ namespace smt { m_ground_arg(ground_arg), m_pattern_idx(pat_idx), m_child(child) { - SASSERT(ground_arg != 0 || ground_arg_idx == 0); + SASSERT(ground_arg != nullptr || ground_arg_idx == 0); } }; @@ -3216,7 +3224,7 @@ namespace smt { path_tree * mk_path_tree(path * p, quantifier * qa, app * mp) { SASSERT(m_ast_manager.is_pattern(mp)); - SASSERT(p != 0); + SASSERT(p != nullptr); unsigned pat_idx = p->m_pattern_idx; path_tree * head = nullptr; path_tree * curr = nullptr; @@ -3509,9 +3517,7 @@ namespace smt { std::cout << "Avg. " << static_cast(total_sz)/static_cast(counter) << ", Max. " << max_sz << "\n"; #endif - enode_vector::iterator it1 = v->begin(); - enode_vector::iterator end1 = v->end(); - for (; it1 != end1; ++it1) { + for (enode* n : *v) { // Two different kinds of mark are used: // - enode mark field: it is used to mark the already processed parents. // - enode mark2 field: it is used to mark the roots already added to be processed in the next level. @@ -3520,7 +3526,7 @@ namespace smt { // and Z3 may fail to find potential new matches. // // The file regression\acu.sx exposed this problem. - enode * curr_child = (*it1)->get_root(); + enode * curr_child = n->get_root(); if (m_use_filters && curr_child->get_plbls().empty_intersection(filter)) continue; @@ -3584,7 +3590,7 @@ namespace smt { is_eq(curr_tree->m_ground_arg, curr_parent->get_arg(curr_tree->m_ground_arg_idx)) )) { if (curr_tree->m_code) { - TRACE("mam_path_tree", tout << "found candidate\n";); + TRACE("mam_path_tree", tout << "found candidate " << expr_ref(curr_parent->get_owner(), m_ast_manager) << "\n";); add_candidate(curr_tree->m_code, curr_parent); } if (curr_tree->m_first_child) { @@ -3878,7 +3884,7 @@ namespace smt { } #endif - void on_match(quantifier * qa, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, ptr_vector & used_enodes) override { + void on_match(quantifier * qa, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, vector> & used_enodes) override { TRACE("trigger_bug", tout << "found match " << mk_pp(qa, m_ast_manager) << "\n";); #ifdef Z3DEBUG if (m_check_missing_instances) { diff --git a/src/smt/mam.h b/src/smt/mam.h index 635cb30e7..f6b2958c5 100644 --- a/src/smt/mam.h +++ b/src/smt/mam.h @@ -21,6 +21,7 @@ Revision History: #include "ast/ast.h" #include "smt/smt_types.h" +#include namespace smt { /** @@ -57,7 +58,7 @@ namespace smt { virtual void display(std::ostream& out) = 0; - virtual void on_match(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, ptr_vector & used_enodes) = 0; + virtual void on_match(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, vector> & used_enodes) = 0; virtual bool is_shared(enode * n) const = 0; diff --git a/src/smt/old_interval.cpp b/src/smt/old_interval.cpp index da589893b..114f9cf29 100644 --- a/src/smt/old_interval.cpp +++ b/src/smt/old_interval.cpp @@ -561,15 +561,24 @@ interval & interval::operator/=(interval const & other) { TRACE("interval", other.display_with_dependencies(tout);); if (other.m_lower.is_pos() || (other.m_lower.is_zero() && other.m_lower_open)) { // other.lower > 0 + // x in ([0, 0] / [other.lo, other.up]), for other.lo > 0 + // <=> + // x >= 0: because y*x >= 0 & y > 0 + // x <= 0: because y*x <= 0 & y > 0 m_lower_dep = join(m_lower_dep, other.m_lower_dep); m_upper_dep = join(m_upper_dep, other.m_lower_dep); } else { // assertion must hold since !other.contains_zero() - SASSERT(other.m_upper.is_neg() || (other.m_upper.is_zero() && other.m_upper_open)); + SASSERT(other.m_upper.is_neg() || (other.m_upper.is_zero() && other.m_upper_open)); // other.upper < 0 - m_lower_dep = join(m_lower_dep, other.m_upper_dep); - m_upper_dep = join(m_upper_dep, other.m_upper_dep); + // x in ([0, 0] / [other.lo, other.up]), for up < 0 + // <=> + // x >= 0: because y*x <= 0 & y < 0 + // x <= 0: because y*x >= 0 & y < 0 + v_dependency* lower_dep = m_lower_dep; + m_lower_dep = join(m_upper_dep, other.m_upper_dep); + m_upper_dep = join(lower_dep, other.m_upper_dep); } return *this; } diff --git a/src/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index 9d09b4c38..fe7cc6060 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -19,7 +19,7 @@ Revision History: #ifndef THEORY_ARITH_PARAMS_H_ #define THEORY_ARITH_PARAMS_H_ -#include +#include #include "util/params.h" enum arith_solver_id { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index ac6482b95..f275b0ebf 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -51,6 +51,7 @@ namespace smt { m_relevancy_propagator(mk_relevancy_propagator(*this)), m_random(p.m_random_seed), m_flushing(false), + m_lemma_id(0), m_progress_callback(nullptr), m_next_progress_sample(0), m_fingerprints(m, m_region), @@ -227,7 +228,6 @@ namespace smt { } void context::copy_plugins(context& src, context& dst) { - // copy theory plugins for (theory* old_th : src.m_theory_set) { theory * new_th = old_th->mk_fresh(&dst); @@ -235,8 +235,8 @@ namespace smt { } } - context * context::mk_fresh(symbol const * l, smt_params * p) { - context * new_ctx = alloc(context, m_manager, p == nullptr ? m_fparams : *p); + context * context::mk_fresh(symbol const * l, smt_params * p, params_ref const& pa) { + context * new_ctx = alloc(context, m_manager, p ? *p : m_fparams, pa); new_ctx->set_logic(l == nullptr ? m_setup.get_logic() : *l); copy_plugins(*this, *new_ctx); return new_ctx; @@ -562,6 +562,7 @@ namespace smt { invert_trans(n1); n1->m_trans.m_target = n2; n1->m_trans.m_justification = js; + n1->m_proof_logged_status = smt::logged_status::NOT_LOGGED; SASSERT(r1->trans_reaches(n1)); // --------------- // r1 -> .. -> n1 -> n2 -> ... -> r2 @@ -741,12 +742,14 @@ namespace smt { eq_justification js = n->m_trans.m_justification; prev->m_trans.m_target = nullptr; prev->m_trans.m_justification = null_eq_justification; + prev->m_proof_logged_status = smt::logged_status::NOT_LOGGED; while (curr != nullptr) { SASSERT(prev->trans_reaches(n)); enode * new_curr = curr->m_trans.m_target; eq_justification new_js = curr->m_trans.m_justification; curr->m_trans.m_target = prev; curr->m_trans.m_justification = js; + curr->m_proof_logged_status = smt::logged_status::NOT_LOGGED; prev = curr; js = new_js; curr = new_curr; @@ -1040,6 +1043,7 @@ namespace smt { SASSERT(r1->trans_reaches(n1)); n1->m_trans.m_target = nullptr; n1->m_trans.m_justification = null_eq_justification; + n1->m_proof_logged_status = smt::logged_status::NOT_LOGGED; invert_trans(r1); // --------------- // n1 -> ... -> r1 @@ -1346,18 +1350,9 @@ namespace smt { \remark The method assign_eq adds a new entry on this queue. */ bool context::propagate_eqs() { - for (unsigned i = 0; i < m_eq_propagation_queue.size(); i++) { + TRACE("add_eq", tout << m_eq_propagation_queue.size() << "\n";); + for (unsigned i = 0; i < m_eq_propagation_queue.size() && !get_cancel_flag(); i++) { new_eq & entry = m_eq_propagation_queue[i]; -#if 0 - static unsigned counter1 = 0; - static unsigned counter2 = 0; - if (entry.m_lhs->is_eq() || entry.m_rhs->is_eq()) - counter1++; - else - counter2++; - if ((counter1 + counter2) % 10000 == 0) - std::cout << counter1 << " " << counter2 << "\n"; -#endif add_eq(entry.m_lhs, entry.m_rhs, entry.m_justification); if (inconsistent()) return false; @@ -1371,7 +1366,7 @@ namespace smt { */ bool context::propagate_atoms() { SASSERT(!inconsistent()); - for (unsigned i = 0; i < m_atom_propagation_queue.size(); i++) { + for (unsigned i = 0; i < m_atom_propagation_queue.size() && !get_cancel_flag(); i++) { SASSERT(!inconsistent()); literal l = m_atom_propagation_queue[i]; bool_var v = l.var(); @@ -1553,16 +1548,17 @@ namespace smt { lbool context::get_assignment(expr * n) const { if (m_manager.is_false(n)) return l_false; - if (m_manager.is_not(n)) - return ~get_assignment_core(to_app(n)->get_arg(0)); + expr* arg = nullptr; + if (m_manager.is_not(n, arg)) + return ~get_assignment_core(arg); return get_assignment_core(n); } lbool context::find_assignment(expr * n) const { if (m_manager.is_false(n)) return l_false; - if (m_manager.is_not(n)) { - expr * arg = to_app(n)->get_arg(0); + expr* arg = nullptr; + if (m_manager.is_not(n, arg)) { if (b_internalized(arg)) return ~get_assignment_core(arg); return l_undef; @@ -1747,6 +1743,10 @@ namespace smt { return false; if (!propagate_eqs()) return false; + if (get_cancel_flag()) { + m_qhead = qhead; + return true; + } propagate_th_eqs(); propagate_th_diseqs(); if (inconsistent()) @@ -1786,7 +1786,7 @@ namespace smt { } bool context::add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, expr* def, unsigned max_generation, - unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes) { + unsigned min_top_generation, unsigned max_top_generation, vector> & used_enodes) { return m_qmanager->add_instance(q, pat, num_bindings, bindings, def, max_generation, min_top_generation, max_top_generation, used_enodes); } @@ -2877,6 +2877,7 @@ namespace smt { void context::push() { TRACE("trigger_bug", tout << "context::push()\n";); + scoped_suspend_rlimit _suspend_cancel(m_manager.limit()); pop_to_base_lvl(); setup_context(false); bool was_consistent = !inconsistent(); @@ -3182,6 +3183,7 @@ namespace smt { if (m_tmp_clauses.empty()) return l_true; for (auto & tmp_clause : m_tmp_clauses) { literal_vector& lits = tmp_clause.second; + literal unassigned = null_literal; for (literal l : lits) { switch (get_assignment(l)) { case l_false: @@ -3189,13 +3191,17 @@ namespace smt { case l_true: goto next_clause; default: - shuffle(lits.size(), lits.c_ptr(), m_random); - push_scope(); - assign(l, b_justification::mk_axiom(), true); - return l_undef; + unassigned = l; } } + if (unassigned != null_literal) { + shuffle(lits.size(), lits.c_ptr(), m_random); + push_scope(); + assign(unassigned, b_justification::mk_axiom(), true); + return l_undef; + } + if (lits.size() == 1) { set_conflict(b_justification(), ~lits[0]); } @@ -3254,6 +3260,7 @@ namespace smt { } void context::reset_assumptions() { + TRACE("unsat_core_bug", tout << "reset " << m_assumptions << "\n";); for (literal lit : m_assumptions) get_bdata(lit.var()).m_assumption = false; m_assumptions.reset(); @@ -4096,9 +4103,7 @@ namespace smt { } SASSERT(!inconsistent()); - unsigned sz = m_b_internalized_stack.size(); - for (unsigned i = 0; i < sz; i++) { - expr * curr = m_b_internalized_stack.get(i); + for (expr * curr : m_b_internalized_stack) { if (is_relevant(curr) && get_assignment(curr) == l_true) { // if curr is a label literal, then its tags will be copied to result. m_manager.is_label_lit(curr, result); @@ -4114,9 +4119,7 @@ namespace smt { void context::get_relevant_labeled_literals(bool at_lbls, expr_ref_vector & result) { SASSERT(!inconsistent()); buffer lbls; - unsigned sz = m_b_internalized_stack.size(); - for (unsigned i = 0; i < sz; i++) { - expr * curr = m_b_internalized_stack.get(i); + for (expr * curr : m_b_internalized_stack) { if (is_relevant(curr) && get_assignment(curr) == l_true) { lbls.reset(); if (m_manager.is_label_lit(curr, lbls)) { diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 4f7c8073e..ff92f6f95 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -49,6 +49,7 @@ Revision History: #include "util/timer.h" #include "util/statistics.h" #include "solver/progress_callback.h" +#include // there is a significant space overhead with allocating 1000+ contexts in // the case that each context only references a few expressions. @@ -87,6 +88,7 @@ namespace smt { scoped_ptr m_relevancy_propagator; random_gen m_random; bool m_flushing; // (debug support) true when flushing + mutable unsigned m_lemma_id; progress_callback * m_progress_callback; unsigned m_next_progress_sample; @@ -489,7 +491,7 @@ namespace smt { } bool tracking_assumptions() const { - return m_search_lvl > m_base_lvl; + return !m_assumptions.empty() && m_search_lvl > m_base_lvl; } expr * bool_var2expr(bool_var v) const { @@ -970,7 +972,7 @@ namespace smt { bool contains_instance(quantifier * q, unsigned num_bindings, enode * const * bindings); bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, expr* def, unsigned max_generation, - unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes); + unsigned min_top_generation, unsigned max_top_generation, vector> & used_enodes /*gives the equalities used for the pattern match, see mam.cpp for more info*/); void set_global_generation(unsigned generation) { m_generation = generation; } @@ -1009,6 +1011,7 @@ namespace smt { void push_eq(enode * lhs, enode * rhs, eq_justification const & js) { SASSERT(lhs != rhs); + SASSERT(lhs->get_root() != rhs->get_root()); m_eq_propagation_queue.push_back(new_eq(lhs, rhs, js)); } @@ -1317,12 +1320,12 @@ namespace smt { void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, literal consequent = false_literal, symbol const& logic = symbol::null) const; - void display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, literal consequent = false_literal, symbol const& logic = symbol::null) const; + unsigned display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, literal consequent = false_literal, symbol const& logic = symbol::null) const; void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs, literal consequent = false_literal, symbol const& logic = symbol::null) const; - void display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, + unsigned display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs, literal consequent = false_literal, symbol const& logic = symbol::null) const; @@ -1490,7 +1493,7 @@ namespace smt { If l == 0, then the logic of this context is used in the new context. If p == 0, then this->m_params is used */ - context * mk_fresh(symbol const * l = nullptr, smt_params * p = nullptr); + context * mk_fresh(symbol const * l = nullptr, smt_params * smtp = nullptr, params_ref const & p = params_ref()); static void copy(context& src, context& dst); diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 29c624bb2..2a46fd07f 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -419,23 +419,16 @@ namespace smt { visitor.collect(fmls); visitor.display_decls(out); visitor.display_asserts(out, fmls, true); + out << "(check-sat)\n"; } - static unsigned g_lemma_id = 0; - -#define BUFFER_SZ 128 - - void context::display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, literal consequent, symbol const& logic) const { - char buffer[BUFFER_SZ]; -#ifdef _WINDOWS - sprintf_s(buffer, BUFFER_SZ, "lemma_%d.smt2", g_lemma_id); -#else - sprintf(buffer, "lemma_%d.smt2", g_lemma_id); -#endif - std::ofstream out(buffer); + unsigned context::display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, literal consequent, symbol const& logic) const { + std::stringstream strm; + strm << "lemma_" << (++m_lemma_id) << ".smt2"; + std::ofstream out(strm.str()); display_lemma_as_smt_problem(out, num_antecedents, antecedents, consequent, logic); out.close(); - g_lemma_id++; + return m_lemma_id; } void context::display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, @@ -464,21 +457,18 @@ namespace smt { visitor.collect(fmls); visitor.display_decls(out); visitor.display_asserts(out, fmls, true); + out << "(check-sat)\n"; } - void context::display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, + unsigned context::display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, unsigned num_eq_antecedents, enode_pair const * eq_antecedents, literal consequent, symbol const& logic) const { - char buffer[BUFFER_SZ]; -#ifdef _WINDOWS - sprintf_s(buffer, BUFFER_SZ, "lemma_%d.smt2", g_lemma_id); -#else - sprintf(buffer, "lemma_%d.smt2", g_lemma_id); -#endif - std::ofstream out(buffer); + std::stringstream strm; + strm << "lemma_" << (++m_lemma_id) << ".smt2"; + std::ofstream out(strm.str()); display_lemma_as_smt_problem(out, num_antecedents, antecedents, num_eq_antecedents, eq_antecedents, consequent, logic); out.close(); - g_lemma_id++; + return m_lemma_id; } /** @@ -577,7 +567,7 @@ namespace smt { case b_justification::BIN_CLAUSE: { literal l2 = j.get_literal(); out << "bin-clause "; - display_literal_verbose(out, l2); + display_literal(out, l2); break; } case b_justification::CLAUSE: { @@ -590,7 +580,7 @@ namespace smt { out << "justification " << j.get_justification()->get_from_theory() << ": "; literal_vector lits; const_cast(*m_conflict_resolution).justification2literals(j.get_justification(), lits); - display_literals_verbose(out, lits); + display_literals(out, lits); break; } default: diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index e09e83f6b..ca646974d 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -47,6 +47,7 @@ namespace smt { n->m_cgc_enabled = cgc_enabled; n->m_iscope_lvl = iscope_lvl; n->m_lbl_hash = -1; + n->m_proof_logged_status = smt::logged_status::NOT_LOGGED; unsigned num_args = n->get_num_args(); for (unsigned i = 0; i < num_args; i++) { enode * arg = app2enode[owner->get_arg(i)->get_id()]; diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 6c8d156b4..61fed786b 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -38,6 +38,15 @@ namespace smt { } }; + /** + \brief Indicates whether the proof for membership in an equivalence class is already logged. + */ + enum logged_status { + NOT_LOGGED, //!< Proof is not logged or logged information is not up-to-date. + BEING_LOGGED, //!< We are currently in the process of logging all relevant information. This is used to prevent looping when logging congruence steps. + LOGGED //!< Proof is logged and logged information is still up-to-date. + }; + /** \ brief Use sparse maps in SMT solver. Define this to use hash maps rather than vectors over ast @@ -105,6 +114,7 @@ namespace smt { enode_vector m_parents; //!< Parent enodes of the equivalence class. theory_var_list m_th_var_list; //!< List of theories that 'care' about this enode. trans_justification m_trans; //!< A justification for the enode being equal to its root. + logged_status m_proof_logged_status; //!< Indicates that the proof for the enode being equal to its root is in the log. signed char m_lbl_hash; //!< It is different from -1, if enode is used in a pattern approx_set m_lbls; approx_set m_plbls; @@ -113,6 +123,7 @@ namespace smt { friend class context; friend class euf_manager; friend class conflict_resolution; + friend class quantifier_manager; theory_var_list * get_th_var_list() { @@ -361,6 +372,10 @@ namespace smt { theory_var get_th_var(theory_id th_id) const; + trans_justification get_trans_justification() { + return m_trans; + } + unsigned get_generation() const { return m_generation; } diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index ae023078a..1414cb522 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -678,8 +678,18 @@ namespace smt { push_trail(set_merge_tf_trail(n)); n->m_merge_tf = true; lbool val = get_assignment(v); - if (val != l_undef) - push_eq(n, val == l_true ? m_true_enode : m_false_enode, eq_justification(literal(v, val == l_false))); + switch (val) { + case l_undef: + break; + case l_true: + if (n->get_root() != m_true_enode->get_root()) + push_eq(n, m_true_enode, eq_justification(literal(v, false))); + break; + case l_false: + if (n->get_root() != m_false_enode->get_root()) + push_eq(n, m_false_enode, eq_justification(literal(v, true))); + break; + } } } diff --git a/src/smt/smt_literal.h b/src/smt/smt_literal.h index 7f554d740..598335cff 100644 --- a/src/smt/smt_literal.h +++ b/src/smt/smt_literal.h @@ -103,7 +103,7 @@ namespace smt { void display_compact(std::ostream & out, unsigned num_lits, literal const * lits, expr * const * bool_var2expr_map); - void display_verbose(std::ostream & out, ast_manager& m, unsigned num_lits, literal const * lits, expr * const * bool_var2expr_map, char const* sep = " "); + void display_verbose(std::ostream & out, ast_manager& m, unsigned num_lits, literal const * lits, expr * const * bool_var2expr_map, char const* sep = "\n"); template void neg_literals(unsigned num_lits, literal const * lits, T & result) { diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 06dd04846..0fea4d13d 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -33,6 +33,7 @@ Revision History: #include "smt/smt_context.h" #include "smt/smt_model_finder.h" #include "model/model_pp.h" +#include namespace smt { @@ -383,10 +384,13 @@ namespace smt { m_fparams = alloc(smt_params, m_context->get_fparams()); m_fparams->m_relevancy_lvl = 0; // no relevancy since the model checking problems are quantifier free m_fparams->m_case_split_strategy = CS_ACTIVITY; // avoid warning messages about smt.case_split >= 3. + m_fparams->m_arith_dump_lemmas = false; } if (!m_aux_context) { symbol logic; - m_aux_context = m_context->mk_fresh(&logic, m_fparams.get()); + params_ref p; + p.set_bool("arith.dump_lemmas", false); + m_aux_context = m_context->mk_fresh(&logic, m_fparams.get(), p); } } @@ -518,7 +522,7 @@ namespace smt { void model_checker::assert_new_instances() { TRACE("model_checker_bug_detail", tout << "assert_new_instances, inconsistent: " << m_context->inconsistent() << "\n";); ptr_buffer bindings; - ptr_vector dummy; + vector> dummy; for (instance const& inst : m_new_instances) { quantifier * q = inst.m_q; if (m_context->b_internalized(q)) { diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 5417785d6..a4b3029e2 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -28,6 +28,15 @@ Revision History: namespace smt { + void fresh_value_proc::get_dependencies(buffer& result) { + result.push_back(model_value_dependency(m_value)); + } + + std::ostream& operator<<(std::ostream& out, model_value_dependency const& src) { + if (src.is_fresh_value()) return out << "fresh!" << src.get_value()->get_idx(); + else return out << "#" << src.get_enode()->get_owner_id(); + } + model_generator::model_generator(ast_manager & m): m_manager(m), m_context(nullptr), @@ -161,20 +170,20 @@ namespace smt { source2color & colors, obj_hashtable & already_traversed, svector & todo) { + if (src.is_fresh_value()) { - // there is an implicit dependency between a fresh value stub of sort S and the root enodes of sort S that are not associated with fresh values. + // there is an implicit dependency between a fresh value stub of + // sort S and the root enodes of sort S that are not associated with fresh values. + // sort * s = src.get_value()->get_sort(); if (already_traversed.contains(s)) return true; bool visited = true; - unsigned sz = roots.size(); - for (unsigned i = 0; i < sz; i++) { - enode * r = roots[i]; + for (enode * r : roots) { if (m_manager.get_sort(r->get_owner()) != s) continue; SASSERT(r == r->get_root()); - model_value_proc * proc = nullptr; - root2proc.find(r, proc); + model_value_proc * proc = root2proc[r]; SASSERT(proc); if (proc->is_fresh()) continue; // r is associated with a fresh value... @@ -192,17 +201,12 @@ namespace smt { enode * n = src.get_enode(); SASSERT(n == n->get_root()); bool visited = true; - model_value_proc * proc = nullptr; - root2proc.find(n, proc); - SASSERT(proc); + model_value_proc * proc = root2proc[n]; buffer dependencies; proc->get_dependencies(dependencies); for (model_value_dependency const& dep : dependencies) { visit_child(dep, colors, todo, visited); - TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " -> "; - if (dep.is_fresh_value()) tout << "fresh!" << dep.get_value()->get_idx(); - else tout << "#" << dep.get_enode()->get_owner_id(); - tout << "\n";); + TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " -> " << dep << " already visited: " << visited << "\n";); } return visited; } @@ -215,9 +219,7 @@ namespace smt { svector & todo, svector & sorted_sources) { TRACE("mg_top_sort", tout << "process source, is_fresh: " << src.is_fresh_value() << " "; - if (src.is_fresh_value()) tout << "fresh!" << src.get_value()->get_idx(); - else tout << "#" << src.get_enode()->get_owner_id(); - tout << ", todo.size(): " << todo.size() << "\n";); + tout << src << ", todo.size(): " << todo.size() << "\n";); int color = get_color(colors, src); SASSERT(color != Grey); if (color == Black) @@ -227,17 +229,16 @@ namespace smt { while (!todo.empty()) { source curr = todo.back(); TRACE("mg_top_sort", tout << "current source, is_fresh: " << curr.is_fresh_value() << " "; - if (curr.is_fresh_value()) tout << "fresh!" << curr.get_value()->get_idx(); - else tout << "#" << curr.get_enode()->get_owner_id(); - tout << ", todo.size(): " << todo.size() << "\n";); + tout << curr << ", todo.size(): " << todo.size() << "\n";); switch (get_color(colors, curr)) { case White: set_color(colors, curr, Grey); visit_children(curr, roots, root2proc, colors, already_traversed, todo); break; case Grey: - SASSERT(visit_children(curr, roots, root2proc, colors, already_traversed, todo)); + // SASSERT(visit_children(curr, roots, root2proc, colors, already_traversed, todo)); set_color(colors, curr, Black); + TRACE("mg_top_sort", tout << "append " << curr << "\n";); sorted_sources.push_back(curr); break; case Black: @@ -266,18 +267,15 @@ namespace smt { // topological sort // traverse all extra fresh values... - unsigned sz = m_extra_fresh_values.size(); - for (unsigned i = 0; i < sz; i++) { - extra_fresh_value * f = m_extra_fresh_values[i]; + for (extra_fresh_value * f : m_extra_fresh_values) { process_source(source(f), roots, root2proc, colors, already_traversed, todo, sorted_sources); } // traverse all enodes that are associated with fresh values... - sz = roots.size(); + unsigned sz = roots.size(); for (unsigned i = 0; i < sz; i++) { enode * r = roots[i]; - model_value_proc * proc = nullptr; - root2proc.find(r, proc); + model_value_proc * proc = root2proc[r]; SASSERT(proc); if (!proc->is_fresh()) continue; @@ -303,43 +301,38 @@ namespace smt { TRACE("sorted_sources", for (source const& curr : sources) { if (curr.is_fresh_value()) { - tout << "fresh!" << curr.get_value()->get_idx() << " " << mk_pp(curr.get_value()->get_sort(), m_manager) << "\n"; + tout << curr << " " << mk_pp(curr.get_value()->get_sort(), m_manager) << "\n"; } else { enode * n = curr.get_enode(); SASSERT(n->get_root() == n); sort * s = m_manager.get_sort(n->get_owner()); - tout << "#" << n->get_owner_id() << " " << mk_pp(s, m_manager); - model_value_proc * proc = 0; - root2proc.find(n, proc); - SASSERT(proc); - tout << " is_fresh: " << proc->is_fresh() << "\n"; + tout << curr << " " << mk_pp(s, m_manager); + tout << " is_fresh: " << root2proc[n]->is_fresh() << "\n"; } }); for (source const& curr : sources) { if (curr.is_fresh_value()) { sort * s = curr.get_value()->get_sort(); - TRACE("model_fresh_bug", tout << "mk fresh!" << curr.get_value()->get_idx() << " : " << mk_pp(s, m_manager) << "\n";); + TRACE("model_fresh_bug", tout << curr << " : " << mk_pp(s, m_manager) << "\n";); expr * val = m_model->get_fresh_value(s); - TRACE("model_fresh_bug", tout << "mk fresh!" << curr.get_value()->get_idx() << " := #" << (val == 0 ? UINT_MAX : val->get_id()) << "\n";); + TRACE("model_fresh_bug", tout << curr << " := #" << (val == nullptr ? UINT_MAX : val->get_id()) << "\n";); m_asts.push_back(val); curr.get_value()->set_value(val); } else { enode * n = curr.get_enode(); SASSERT(n->get_root() == n); - TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << "\n";); + TRACE("mg_top_sort", tout << curr << "\n";); dependencies.reset(); dependency_values.reset(); - model_value_proc * proc = nullptr; - VERIFY(root2proc.find(n, proc)); + model_value_proc * proc = root2proc[n]; SASSERT(proc); proc->get_dependencies(dependencies); for (model_value_dependency const& d : dependencies) { if (d.is_fresh_value()) { CTRACE("mg_top_sort", !d.get_value()->get_value(), - tout << "#" << n->get_owner_id() << " -> "; - tout << "fresh!" << d.get_value()->get_idx() << "\n";); + tout << "#" << n->get_owner_id() << " -> " << d << "\n";); SASSERT(d.get_value()->get_value()); dependency_values.push_back(d.get_value()->get_value()); } @@ -445,8 +438,7 @@ namespace smt { } } - extra_fresh_value * model_generator::mk_extra_fresh_value(sort * s) { - SASSERT(s->is_infinite()); + extra_fresh_value * model_generator::mk_extra_fresh_value(sort * s) { extra_fresh_value * r = alloc(extra_fresh_value, s, m_fresh_idx); m_fresh_idx++; m_extra_fresh_values.push_back(r); diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index 7466b8877..1f69eb324 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -100,14 +100,16 @@ namespace smt { extra_fresh_value * m_value; //!< When m_fresh == true, contains the sort of the fresh value }; public: - model_value_dependency():m_fresh(true), m_value(nullptr) {} - model_value_dependency(enode * n):m_fresh(false), m_enode(n->get_root()) {} - model_value_dependency(extra_fresh_value * v):m_fresh(true), m_value(v) {} + model_value_dependency():m_fresh(true), m_value(nullptr) { } + explicit model_value_dependency(enode * n):m_fresh(false), m_enode(n->get_root()) {} + explicit model_value_dependency(extra_fresh_value * v) :m_fresh(true), m_value(v) { SASSERT(v); } bool is_fresh_value() const { return m_fresh; } enode * get_enode() const { SASSERT(!is_fresh_value()); return m_enode; } extra_fresh_value * get_value() const { SASSERT(is_fresh_value()); return m_value; } }; + std::ostream& operator<<(std::ostream& out, model_value_dependency const& d); + typedef model_value_dependency source; struct source_hash_proc { @@ -166,7 +168,7 @@ namespace smt { extra_fresh_value * m_value; public: fresh_value_proc(extra_fresh_value * v):m_value(v) {} - void get_dependencies(buffer & result) override { result.push_back(m_value); } + void get_dependencies(buffer & result) override; app * mk_value(model_generator & m, ptr_vector & values) override { return to_app(values[0]); } bool is_fresh() const override { return true; } }; diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 48c59003c..885157ab3 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -104,6 +104,90 @@ namespace smt { return m_plugin->is_shared(n); } + /** + \brief Ensures that all relevant proof steps to explain why the enode is equal to the root of its + equivalence class are in the log and up-to-date. + */ + void log_justification_to_root(std::ostream & log, enode *en) { + enode *root = en->get_root(); + for (enode *it = en; it != root; it = it->get_trans_justification().m_target) { + if (it->m_proof_logged_status == smt::logged_status::NOT_LOGGED) { + it->m_proof_logged_status = smt::logged_status::BEING_LOGGED; + log_single_justification(log, it); + it->m_proof_logged_status = smt::logged_status::LOGGED; + } else if (it->m_proof_logged_status != smt::logged_status::BEING_LOGGED && it->get_trans_justification().m_justification.get_kind() == smt::eq_justification::kind::CONGRUENCE) { + + // When the justification of an argument changes m_proof_logged_status is not reset => We need to check if the proofs of all arguments are logged. + it->m_proof_logged_status = smt::logged_status::BEING_LOGGED; + const unsigned num_args = it->get_num_args(); + enode *target = it->get_trans_justification().m_target; + + for (unsigned i = 0; i < num_args; ++i) { + log_justification_to_root(log, it->get_arg(i)); + log_justification_to_root(log, target->get_arg(i)); + } + it->m_proof_logged_status = smt::logged_status::LOGGED; + } + } + if (root->m_proof_logged_status == smt::logged_status::NOT_LOGGED) { + log << "[eq-expl] #" << root->get_owner_id() << " root\n"; + root->m_proof_logged_status = smt::logged_status::LOGGED; + } + } + + /** + \brief Logs a single equality explanation step and, if necessary, recursively calls log_justification_to_root to log + equalities needed by the step (e.g. argument equalities for congruence steps). + */ + void log_single_justification(std::ostream & out, enode *en) { + smt::literal lit; + unsigned num_args; + enode *target = en->get_trans_justification().m_target; + theory_id th_id; + + switch (en->get_trans_justification().m_justification.get_kind()) { + case smt::eq_justification::kind::EQUATION: + lit = en->get_trans_justification().m_justification.get_literal(); + out << "[eq-expl] #" << en->get_owner_id() << " lit #" << m_context.bool_var2expr(lit.var())->get_id() << " ; #" << target->get_owner_id() << "\n"; + break; + case smt::eq_justification::kind::AXIOM: + out << "[eq-expl] #" << en->get_owner_id() << " ax ; #" << target->get_owner_id() << "\n"; + break; + case smt::eq_justification::kind::CONGRUENCE: + if (!en->get_trans_justification().m_justification.used_commutativity()) { + num_args = en->get_num_args(); + + for (unsigned i = 0; i < num_args; ++i) { + log_justification_to_root(out, en->get_arg(i)); + log_justification_to_root(out, target->get_arg(i)); + } + + out << "[eq-expl] #" << en->get_owner_id() << " cg"; + for (unsigned i = 0; i < num_args; ++i) { + out << " (#" << en->get_arg(i)->get_owner_id() << " #" << target->get_arg(i)->get_owner_id() << ")"; + } + out << " ; #" << target->get_owner_id() << "\n"; + + break; + } else { + out << "[eq-expl] #" << en->get_owner_id() << " nyi ; #" << target->get_owner_id() << "\n"; + break; + } + case smt::eq_justification::kind::JUSTIFICATION: + th_id = en->get_trans_justification().m_justification.get_justification()->get_from_theory(); + if (th_id != null_theory_id) { + symbol const theory = m().get_family_name(th_id); + out << "[eq-expl] #" << en->get_owner_id() << " th " << theory.str() << " ; #" << target->get_owner_id() << "\n"; + } else { + out << "[eq-expl] #" << en->get_owner_id() << " unknown ; #" << target->get_owner_id() << "\n"; + } + break; + default: + out << "[eq-expl] #" << en->get_owner_id() << " unknown ; #" << target->get_owner_id() << "\n"; + break; + } + } + bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, @@ -111,7 +195,7 @@ namespace smt { unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, - ptr_vector & used_enodes) { + vector> & used_enodes) { max_generation = std::max(max_generation, get_generation(q)); if (m_num_instances > m_params.m_qi_max_instances) { return false; @@ -121,15 +205,39 @@ namespace smt { if (f) { if (has_trace_stream()) { std::ostream & out = trace_stream(); - out << "[new-match] " << static_cast(f) << " #" << q->get_id(); + + // In the term produced by the quantifier instantiation the root of the equivalence class of the terms bound to the quantified variables + // is used. We need to make sure that all of these equalities appear in the log. + for (unsigned i = 0; i < num_bindings; ++i) { + log_justification_to_root(out, bindings[i]); + } + + for (auto n : used_enodes) { + enode *orig = std::get<0>(n); + enode *substituted = std::get<1>(n); + if (orig != nullptr) { + log_justification_to_root(out, orig); + log_justification_to_root(out, substituted); + } + } + + // At this point all relevant equalities for the match are logged. + out << "[new-match] " << static_cast(f) << " #" << q->get_id() << " #" << pat->get_id(); for (unsigned i = 0; i < num_bindings; i++) { // I don't want to use mk_pp because it creates expressions for pretty printing. // This nasty side-effect may change the behavior of Z3. out << " #" << bindings[i]->get_owner_id(); } out << " ;"; - for (enode* n : used_enodes) - out << " #" << n->get_owner_id(); + for (auto n : used_enodes) { + enode *orig = std::get<0>(n); + enode *substituted = std::get<1>(n); + if (orig == nullptr) + out << " #" << substituted->get_owner_id(); + else { + out << " (#" << orig->get_owner_id() << " #" << substituted->get_owner_id() << ")"; + } + } out << "\n"; } m_qi_queue.insert(f, pat, max_generation, min_top_generation, max_top_generation); // TODO @@ -296,12 +404,12 @@ namespace smt { unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, - ptr_vector & used_enodes) { + vector> & used_enodes) { return m_imp->add_instance(q, pat, num_bindings, bindings, def, max_generation, min_top_generation, max_generation, used_enodes); } bool quantifier_manager::add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, expr* def, unsigned generation) { - ptr_vector tmp; + vector> tmp; return add_instance(q, nullptr, num_bindings, bindings, def, generation, generation, generation, tmp); } diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index dde7ec2c4..4f14c6853 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -23,6 +23,7 @@ Revision History: #include "util/statistics.h" #include "util/params.h" #include "smt/smt_types.h" +#include class proto_model; struct smt_params; @@ -58,7 +59,7 @@ namespace smt { unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, - ptr_vector & used_enodes); + vector> & used_enodes /*gives the equalities used for the pattern match, see mam.cpp for more info*/); bool add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, expr* def, unsigned generation = 0); void init_search_eh(); diff --git a/src/smt/smt_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index 85c0ca183..14719c140 100644 --- a/src/smt/smt_quick_checker.cpp +++ b/src/smt/smt_quick_checker.cpp @@ -19,6 +19,7 @@ Revision History: #include "smt/smt_context.h" #include "smt/smt_quick_checker.h" #include "ast/ast_pp.h" +#include namespace smt { @@ -197,7 +198,7 @@ namespace smt { } bool quick_checker::process_candidates(quantifier * q, bool unsat) { - ptr_vector empty_used_enodes; + vector> empty_used_enodes; buffer szs; buffer it; for (unsigned i = 0; i < m_num_bindings; i++) { diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index ca3c01189..9e38fef69 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -492,7 +492,7 @@ namespace smt { m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; - m_params.m_nnf_cnf = false; + m_params.m_nnf_cnf = false; setup_lra_arith(); } @@ -627,9 +627,6 @@ namespace smt { m_params.m_phase_selection = PS_CACHING_CONSERVATIVE2; m_params.m_random_initial_activity = IA_ZERO; } - // if (st.m_num_arith_ineqs == st.m_num_diff_ineqs && st.m_num_arith_eqs == st.m_num_diff_eqs && st.arith_k_sum_is_small()) - // m_context.register_plugin(new smt::theory_si_arith(m_manager, m_params)); - // else setup_i_arith(); setup_arrays(); } @@ -654,7 +651,7 @@ namespace smt { // m_params.m_ng_lift_ite = LI_FULL; TRACE("setup", tout << "max_eager_multipatterns: " << m_params.m_qi_max_eager_multipatterns << "\n";); - setup_i_arith(); + m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); setup_arrays(); } @@ -777,7 +774,11 @@ namespace smt { IF_VERBOSE(1000, st.display_primitive(verbose_stream());); bool fixnum = st.arith_k_sum_is_small() && m_params.m_arith_fixnum; bool int_only = !st.m_has_rational && !st.m_has_real && m_params.m_arith_int_only; - switch(m_params.m_arith_mode) { + auto mode = m_params.m_arith_mode; + if (m_logic == "QF_LIA") { + mode = AS_NEW_ARITH; + } + switch(mode) { case AS_NO_ARITH: m_context.register_plugin(alloc(smt::theory_dummy, m_manager.mk_family_id("arith"), "no arithmetic")); break; @@ -828,7 +829,10 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); break; case AS_NEW_ARITH: - setup_lra_arith(); + if (st.m_num_non_linear != 0) + m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); + else + setup_lra_arith(); break; default: m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); @@ -990,7 +994,7 @@ namespace smt { } if (st.num_theories() == 2 && st.has_uf() && is_arith(st)) { - if (!st.m_has_real) + if (!st.m_has_real && st.m_num_non_linear == 0) setup_QF_UFLIA(st); else if (!st.m_has_int && st.m_num_non_linear == 0) setup_QF_UFLRA(); diff --git a/src/smt/smt_theory.cpp b/src/smt/smt_theory.cpp index b5ad68adc..63c6d7417 100644 --- a/src/smt/smt_theory.cpp +++ b/src/smt/smt_theory.cpp @@ -123,7 +123,7 @@ namespace smt { context & ctx = get_context(); app * eq = ctx.mk_eq_atom(a, b); TRACE("mk_var_bug", tout << "mk_eq: " << eq->get_id() << " " << a->get_id() << " " << b->get_id() << "\n"; - tout << mk_ll_pp(a, get_manager()) << "\n" << mk_ll_pp(b, get_manager());); + tout << mk_ll_pp(a, get_manager()) << "\n" << mk_ll_pp(b, get_manager());); ctx.internalize(eq, gate_ctx); return ctx.get_literal(eq); } diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index daf285a54..9526637e9 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -731,35 +731,34 @@ namespace smt { template void theory_arith::derived_bound::push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) { + TRACE("arith", tout << m_lits << " " << m_eqs.size() << "\n";); if (proofs_enabled) { - for (unsigned i = 0; i < m_lits.size(); ++i) { - a.push_lit(m_lits[i], coeff, proofs_enabled); - } - for (unsigned i = 0; i < m_eqs.size(); ++i) { - a.push_eq(m_eqs[i], coeff, proofs_enabled); - } + for (literal l : m_lits) + a.push_lit(l, coeff, proofs_enabled); + for (auto const& e : m_eqs) + a.push_eq(e, coeff, proofs_enabled); } else { a.append(m_lits.size(), m_lits.c_ptr()); - a.append(m_eqs.size(), m_eqs.c_ptr()); + a.append(m_eqs.size(), m_eqs.c_ptr()); } } template void theory_arith::derived_bound::display(theory_arith const& th, std::ostream& out) const { - out << "v" << bound::get_var() << " " << bound::get_bound_kind() << " " << bound::get_value(); - ast_manager& m = th.get_manager(); - for (unsigned i = 0; i < m_eqs.size(); ++i) { - enode* a = m_eqs[i].first; - enode* b = m_eqs[i].second; + out << "v" << bound::get_var() << " " << bound::get_bound_kind() << " " << bound::get_value() << "\n"; + out << "expr: " << mk_pp(th.var2expr(bound::get_var()), m) << "\n"; + + for (auto const& e : m_eqs) { + enode* a = e.first; + enode* b = e.second; out << " "; out << "#" << a->get_owner_id() << " " << mk_pp(a->get_owner(), m) << " = " - << "#" << b->get_owner_id() << " " << mk_pp(b->get_owner(), m); + << "#" << b->get_owner_id() << " " << mk_pp(b->get_owner(), m) << "\n"; } - for (unsigned i = 0; i < m_lits.size(); ++i) { - literal l = m_lits[i]; - out << " " << l << ":"; th.get_context().display_detailed_literal(out, l); + for (literal l : m_lits) { + out << l << ":"; th.get_context().display_detailed_literal(out, l) << "\n"; } } @@ -882,13 +881,10 @@ namespace smt { } TRACE("derived_bound", tout << "explanation:\n"; - literal_vector::const_iterator it1 = new_bound->m_lits.begin(); - literal_vector::const_iterator end1 = new_bound->m_lits.end(); - for (; it1 != end1; ++it1) tout << *it1 << " "; + for (literal l : new_bound->m_lits) tout << l << " "; tout << " "; - eq_vector::const_iterator it2 = new_bound->m_eqs.begin(); - eq_vector::const_iterator end2 = new_bound->m_eqs.end(); - for (; it2 != end2; ++it2) tout << "#" << it2->first->get_owner_id() << "=#" << it2->second->get_owner_id() << " "; + for (auto const& e : new_bound->m_eqs) + tout << "#" << e.first->get_owner_id() << "=#" << e.second->get_owner_id() << " "; tout << "\n";); DEBUG_CODE(CTRACE("derived_bound", k != val, tout << "k: " << k << ", k_norm: " << k_norm << ", val: " << val << "\n";);); SASSERT(k == val); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index cbd41f08c..54f61a09a 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1708,7 +1708,7 @@ namespace smt { template theory* theory_arith::mk_fresh(context* new_ctx) { - return alloc(theory_arith, new_ctx->get_manager(), m_params); + return alloc(theory_arith, new_ctx->get_manager(), new_ctx->get_fparams()); } template @@ -1853,10 +1853,7 @@ namespace smt { void theory_arith::restore_assignment() { CASSERT("arith", valid_row_assignment()); TRACE("restore_assignment_bug", tout << "START restore_assignment...\n";); - typename svector::iterator it = m_update_trail_stack.begin(); - typename svector::iterator end = m_update_trail_stack.end(); - for(; it != end; ++it) { - theory_var v = *it; + for (theory_var v : m_update_trail_stack) { TRACE("restore_assignment_bug", tout << "restoring v" << v << " <- " << m_old_value[v] << "\n";); SASSERT(!is_quasi_base(v)); SASSERT(m_in_update_trail_stack.contains(v)); @@ -2237,11 +2234,7 @@ namespace smt { theory_var best = null_theory_var; inf_numeral best_error; inf_numeral curr_error; - typename var_heap::iterator it = m_to_patch.begin(); - typename var_heap::iterator end = m_to_patch.end(); - //unsigned n = 0; - for (; it != end; ++it) { - theory_var v = *it; + for (theory_var v : m_to_patch) { if (below_lower(v)) curr_error = lower(v)->get_value() - get_value(v); else if (above_upper(v)) @@ -2391,10 +2384,11 @@ namespace smt { TRACE("sign_row_conflict", tout << "v" << x_i << " is_below: " << is_below << " delta: " << delta << "\n"; display_var(tout, x_i); tout << "is_below_lower: " << below_lower(x_i) << ", is_above_upper: " << above_upper(x_i) << "\n"; + display_row(tout, r, true); + display_row(tout, r, false); ante.display(tout);); set_conflict(ante, ante, "farkas"); - // display_bounds_in_smtlib(); } // ----------------------------------- @@ -2535,10 +2529,9 @@ namespace smt { antecedents ante(*this); b1->push_justification(ante, numeral(1), coeffs_enabled()); b2->push_justification(ante, numeral(1), coeffs_enabled()); - - set_conflict(ante, ante, "farkas"); TRACE("arith_conflict", tout << "bound conflict v" << b1->get_var() << "\n"; tout << "bounds: " << b1 << " " << b2 << "\n";); + set_conflict(ante, ante, "farkas"); } // ----------------------------------- @@ -2771,8 +2764,10 @@ namespace smt { template void theory_arith::explain_bound(row const & r, int idx, bool is_lower, inf_numeral & delta, antecedents& ante) { SASSERT(delta >= inf_numeral::zero()); - if (!relax_bounds() && (!ante.lits().empty() || !ante.eqs().empty())) + TRACE("arith_conflict", tout << "relax: " << relax_bounds() << " lits: " << ante.lits().size() << " eqs: " << ante.eqs().size() << " idx: " << idx << "\n";); + if (!relax_bounds() && (!ante.lits().empty() || !ante.eqs().empty())) { return; + } context & ctx = get_context(); row_entry const & entry = r[idx]; numeral coeff = entry.m_coeff; @@ -2790,9 +2785,11 @@ namespace smt { if (!it->is_dead() && idx != idx2) { bound * b = get_bound(it->m_var, is_lower ? it->m_coeff.is_pos() : it->m_coeff.is_neg()); SASSERT(b); - if (!b->has_justification()) + if (!b->has_justification()) { continue; + } if (!relax_bounds() || delta.is_zero()) { + TRACE("propagate_bounds", tout << "push justification: v" << it->m_var << "\n";); b->push_justification(ante, it->m_coeff, coeffs_enabled()); continue; } @@ -2821,10 +2818,7 @@ namespace smt { inf_numeral k_2 = k_1; atom * new_atom = nullptr; atoms const & as = m_var_occs[it->m_var]; - typename atoms::const_iterator it = as.begin(); - typename atoms::const_iterator end = as.end(); - for (; it != end; ++it) { - atom * a = *it; + for (atom * a : as) { if (a == b) continue; bool_var bv = a->get_bool_var(); @@ -2880,10 +2874,7 @@ namespace smt { atoms const & as = m_var_occs[v]; inf_numeral const & epsilon = get_epsilon(v); inf_numeral delta; - typename atoms::const_iterator it = as.begin(); - typename atoms::const_iterator end = as.end(); - for (; it != end; ++it) { - atom * a = *it; + for (atom* a : as) { bool_var bv = a->get_bool_var(); literal l(bv); if (get_context().get_assignment(bv) == l_undef) { @@ -2954,6 +2945,7 @@ namespace smt { TRACE("arith", ante.display(tout) << " --> "; ctx.display_detailed_literal(tout, l); tout << "\n";); ctx.display_lemma_as_smt_problem(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), l); + } } @@ -2972,12 +2964,13 @@ namespace smt { context & ctx = get_context(); antecedents ante(*this); explain_bound(r, idx, is_lower, delta, ante); - dump_lemmas(l, ante); TRACE("propagate_bounds", ante.display(tout) << " --> "; ctx.display_detailed_literal(tout, l); tout << "\n";); + dump_lemmas(l, ante); + if (ante.lits().size() < small_lemma_size() && ante.eqs().empty()) { literal_vector & lits = m_tmp_literal_vector2; lits.reset(); @@ -3060,14 +3053,14 @@ namespace smt { template void theory_arith::set_conflict(antecedents const& ante, antecedents& bounds, char const* proof_rule) { - dump_lemmas(false_literal, ante); set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), bounds, proof_rule); + dump_lemmas(false_literal, ante); } template void theory_arith::set_conflict(derived_bound const& ante, antecedents& bounds, char const* proof_rule) { - dump_lemmas(false_literal, ante); set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), bounds, proof_rule); + dump_lemmas(false_literal, ante); } template diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index ba6648dac..c27d3b44a 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -58,7 +58,6 @@ namespace smt { void theory_arith::mark_var(theory_var v, svector & vars, var_set & already_found) { if (already_found.contains(v)) return; - TRACE("non_linear", tout << "marking: v" << v << "\n";); already_found.insert(v); vars.push_back(v); } @@ -71,8 +70,7 @@ namespace smt { if (is_pure_monomial(v)) { expr * n = var2expr(v); SASSERT(m_util.is_mul(n)); - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) { - expr * curr = to_app(n)->get_arg(i); + for (expr * curr : *to_app(n)) { theory_var v = expr2var(curr); SASSERT(v != null_theory_var); mark_var(v, vars, already_found); @@ -118,22 +116,19 @@ namespace smt { var_set already_found; row_set already_visited_rows; context & ctx = get_context(); - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (theory_var v : m_nl_monomials) { expr * n = var2expr(v); if (ctx.is_relevant(n)) mark_var(v, vars, already_found); } - for (unsigned idx = 0; idx < vars.size(); idx++) { - TRACE("non_linear", tout << "marking dependents of: v" << vars[idx] << "\n";); - mark_dependents(vars[idx], vars, already_found, already_visited_rows); + // NB: vars changes inside of loop + for (unsigned idx = 0; idx < vars.size(); ++idx) { + theory_var v = vars[idx]; + TRACE("non_linear", tout << "marking dependents of: v" << v << "\n";); + mark_dependents(v, vars, already_found, already_visited_rows); } TRACE("non_linear", tout << "variables in non linear cluster:\n"; - svector::const_iterator it = vars.begin(); - svector::const_iterator end = vars.end(); - for (; it != end; ++it) tout << "v" << *it << " "; + for (theory_var v : vars) tout << "v" << v << " "; tout << "\n";); } @@ -227,9 +222,8 @@ namespace smt { SASSERT(!m_util.is_numeral(m)); if (m_util.is_mul(m)) { unsigned num_vars = 0; - expr * var = nullptr; - for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { - expr * curr = to_app(m)->get_arg(i); + expr * var = nullptr; + for (expr * curr : *to_app(m)) { if (var != curr) { num_vars++; var = curr; @@ -254,9 +248,7 @@ namespace smt { unsigned curr_idx = 0; expr * var = nullptr; unsigned power = 0; - unsigned j; - for (j = 0; j < to_app(m)->get_num_args(); j++) { - expr * arg = to_app(m)->get_arg(j); + for (expr * arg : *to_app(m)) { if (var == nullptr) { var = arg; power = 1; @@ -360,6 +352,7 @@ namespace smt { template interval theory_arith::evaluate_as_interval(expr * n) { expr* arg; + rational val; TRACE("nl_evaluate", tout << "evaluating: " << mk_bounded_pp(n, get_manager(), 10) << "\n";); if (has_var(n)) { TRACE("nl_evaluate", tout << "n has a variable associated with it\n";); @@ -370,8 +363,8 @@ namespace smt { else if (m_util.is_add(n)) { TRACE("nl_evaluate", tout << "is add\n";); interval r(m_dep_manager, rational(0)); - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) { - r += evaluate_as_interval(to_app(n)->get_arg(i)); + for (expr* arg : *to_app(n)) { + r += evaluate_as_interval(arg); } TRACE("cross_nested_eval_bug", display_nested_form(tout, n); tout << "\ninterval: " << r << "\n";); return r; @@ -388,31 +381,28 @@ namespace smt { it.expt(power); r *= it; } - TRACE("cross_nested_eval_bug", display_nested_form(tout, n); tout << "\ninterval: " << r << "\n";); + TRACE("nl_evaluate", display_nested_form(tout, n); tout << "\ninterval: " << r << "\n";); return r; } else if (m_util.is_to_real(n, arg)) { return evaluate_as_interval(arg); } + else if (m_util.is_numeral(n, val)) { + TRACE("nl_evaluate", tout << "is numeral\n";); + return interval(m_dep_manager, val); + } else { - rational val; - if (m_util.is_numeral(n, val)) { - TRACE("nl_evaluate", tout << "is numeral\n";); - return interval(m_dep_manager, val); - } - else { - TRACE("nl_evaluate", tout << "is unknown\n";); - return interval(m_dep_manager); - } + TRACE("nl_evaluate", tout << "is unknown\n";); + return interval(m_dep_manager); } } template - void theory_arith::display_monomial(std::ostream & out, expr * m) const { + void theory_arith::display_monomial(std::ostream & out, expr * n) const { bool first = true; - unsigned num_vars = get_num_vars_in_monomial(m); + unsigned num_vars = get_num_vars_in_monomial(n); for (unsigned i = 0; i < num_vars; i++) { - var_power_pair p = get_var_and_degree(m, i); + var_power_pair p = get_var_and_degree(n, i); SASSERT(p.first != 0); if (first) first = false; else out << " * "; out << mk_bounded_pp(p.first, get_manager()) << "^" << p.second; @@ -425,10 +415,8 @@ namespace smt { m_dep_manager.linearize(dep, bounds); m_tmp_lit_set.reset(); m_tmp_eq_set.reset(); - ptr_vector::const_iterator it = bounds.begin(); - ptr_vector::const_iterator end = bounds.end(); - for (; it != end; ++it) { - bound * b = static_cast(*it); + for (void* _b : bounds) { + bound * b = static_cast(_b); accumulate_justification(*b, new_bound, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); } } @@ -544,21 +532,19 @@ namespace smt { the method returns without doing anything. */ template - bool theory_arith::propagate_nl_downward(expr * m, unsigned i) { - SASSERT(is_pure_monomial(m)); - SASSERT(i < get_num_vars_in_monomial(m)); - var_power_pair p = get_var_and_degree(m, i); + bool theory_arith::propagate_nl_downward(expr * n, unsigned i) { + SASSERT(is_pure_monomial(n)); + SASSERT(i < get_num_vars_in_monomial(n)); + var_power_pair p = get_var_and_degree(n, i); expr * v = p.first; unsigned power = p.second; - TRACE("propagate_nl_downward", tout << "m: " << mk_ismt2_pp(m, get_manager()) << "\nv: " << mk_ismt2_pp(v, get_manager()) << - "\npower: " << power << "\n";); if (power != 1) return false; // TODO: remove, when the n-th root is implemented in interval. - unsigned num_vars = get_num_vars_in_monomial(m); + unsigned num_vars = get_num_vars_in_monomial(n); interval other_bounds(m_dep_manager, rational(1)); // TODO: the following code can be improved it is quadratic on the degree of the monomial. for (unsigned i = 0; i < num_vars; i++) { - var_power_pair p = get_var_and_degree(m, i); + var_power_pair p = get_var_and_degree(n, i); if (p.first == v) continue; expr * var = p.first; @@ -567,7 +553,13 @@ namespace smt { } if (other_bounds.contains_zero()) return false; // interval division requires that divisor doesn't contain 0. - interval r = mk_interval_for(m); + interval r = mk_interval_for(n); + TRACE("nl_arith_bug", tout << "m: " << mk_ismt2_pp(n, get_manager()) << "\nv: " << mk_ismt2_pp(v, get_manager()) << + "\npower: " << power << "\n"; + tout << "num_vars: " << num_vars << "\n"; + display_interval(tout << "monomial bounds\n", r); + display_interval(tout << "other bounds\n", other_bounds); + ); r /= other_bounds; return update_bounds_using_interval(v, r); } @@ -907,7 +899,6 @@ namespace smt { } TRACE("non_linear_bug", tout << "enode: " << get_context().get_enode(rhs) << " enode_id: " << get_context().get_enode(rhs)->get_owner_id() << "\n";); theory_var new_v = expr2var(rhs); - TRACE("non_linear_bug", ctx.display(tout);); SASSERT(new_v != null_theory_var); new_lower = alloc(derived_bound, new_v, inf_numeral(0), B_LOWER); new_upper = alloc(derived_bound, new_v, inf_numeral(0), B_UPPER); @@ -953,19 +944,17 @@ namespace smt { } accumulate_justification(*l, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); - TRACE("non_linear", - for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) { - ctx.display_detailed_literal(tout, new_lower->m_lits[j]); - tout << " "; + TRACE("non_linear", + for (literal l : new_lower->m_lits) { + ctx.display_detailed_literal(tout, l) << " "; } tout << "\n";); accumulate_justification(*u, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); TRACE("non_linear", - for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) { - ctx.display_detailed_literal(tout, new_lower->m_lits[j]); - tout << " "; + for (literal l : new_lower->m_lits) { + ctx.display_detailed_literal(tout, l) << " "; } tout << "\n";); @@ -977,9 +966,8 @@ namespace smt { TRACE("non_linear", new_lower->display(*this, tout << "lower: "); tout << "\n"; new_upper->display(*this, tout << "upper: "); tout << "\n"; - for (unsigned j = 0; j < new_upper->m_lits.size(); ++j) { - ctx.display_detailed_literal(tout, new_upper->m_lits[j]); - tout << " "; + for (literal lit : new_upper->m_lits) { + ctx.display_detailed_literal(tout, lit) << " "; } tout << "\n";); @@ -1123,14 +1111,14 @@ namespace smt { continue; if (is_pure_monomial(v)) { expr * m = var2expr(v); - for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { - theory_var curr = expr2var(to_app(m)->get_arg(i)); + for (expr* arg : *to_app(m)) { + theory_var curr = expr2var(arg); if (m_tmp_var_set.contains(curr)) return true; } SASSERT(m == var2expr(v)); - for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { - theory_var curr = expr2var(to_app(m)->get_arg(i)); + for (expr* arg : *to_app(m)) { + theory_var curr = expr2var(arg); if (!is_fixed(curr)) m_tmp_var_set.insert(curr); } @@ -1936,10 +1924,7 @@ namespace smt { derived_bound b(null_theory_var, inf_numeral(0), B_LOWER); dependency2new_bound(d, b); set_conflict(b, ante, "arith_nl"); - TRACE("non_linear", - for (unsigned i = 0; i < b.m_lits.size(); ++i) { - tout << b.m_lits[i] << " "; - }); + TRACE("non_linear", for (literal lit : b.m_lits) tout << lit << " "; tout << "\n";); } /** @@ -2387,7 +2372,7 @@ namespace smt { elim_quasi_base_rows(); move_non_base_vars_to_bounds(); - TRACE("non_linear", tout << "processing non linear constraints...\n"; get_context().display(tout);); + TRACE("non_linear_verbose", tout << "processing non linear constraints...\n"; get_context().display(tout);); if (!make_feasible()) { TRACE("non_linear", tout << "failed to move variables to bounds.\n";); failed(); diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index 6579856a4..59d386292 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -391,19 +391,19 @@ namespace smt { void theory_arith::display_vars(std::ostream & out) const { out << "vars:\n"; int n = get_num_vars(); - int inf_vars = 0; - int int_inf_vars = 0; - for (theory_var v = 0; v < n; v++) { - if ((lower(v) && lower(v)->get_value() > get_value(v)) - || (upper(v) && upper(v)->get_value() < get_value(v))) - inf_vars++; - if (is_int(v) && !get_value(v).is_int()) - int_inf_vars++; - } - out << "infeasibles = " << inf_vars << " int_inf = " << int_inf_vars << std::endl; - for (theory_var v = 0; v < n; v++) { - display_var(out, v); - } + int inf_vars = 0; + int int_inf_vars = 0; + for (theory_var v = 0; v < n; v++) { + if ((lower(v) && lower(v)->get_value() > get_value(v)) + || (upper(v) && upper(v)->get_value() < get_value(v))) + inf_vars++; + if (is_int(v) && !get_value(v).is_int()) + int_inf_vars++; + } + out << "infeasibles = " << inf_vars << " int_inf = " << int_inf_vars << std::endl; + for (theory_var v = 0; v < n; v++) { + display_var(out, v); + } } template @@ -418,9 +418,9 @@ namespace smt { th.get_context().display_literals_verbose(out, lits().size(), lits().c_ptr()); if (!lits().empty()) out << "\n"; ast_manager& m = th.get_manager(); - for (unsigned i = 0; i < m_eqs.size(); ++i) { - out << mk_pp(m_eqs[i].first->get_owner(), m) << " "; - out << mk_pp(m_eqs[i].second->get_owner(), m) << "\n"; + for (auto const& e : m_eqs) { + out << mk_pp(e.first->get_owner(), m) << " "; + out << mk_pp(e.second->get_owner(), m) << "\n"; } return out; } @@ -431,27 +431,24 @@ namespace smt { m_dep_manager.linearize(dep, bounds); m_tmp_lit_set.reset(); m_tmp_eq_set.reset(); - ptr_vector::const_iterator it = bounds.begin(); - ptr_vector::const_iterator end = bounds.end(); - for (; it != end; ++it) { - bound * b = static_cast(*it); - out << " "; - b->display(*this, out); + for (void *_b : bounds) { + bound * b = static_cast(_b); + b->display(*this, out << "\n"); } } template void theory_arith::display_interval(std::ostream & out, interval const& i) { i.display(out); - display_deps(out << " lo:", i.get_lower_dependencies()); - display_deps(out << " hi:", i.get_upper_dependencies()); + display_deps(out << "\nlo:", i.get_lower_dependencies()); + display_deps(out << "\nhi:", i.get_upper_dependencies()); } template void theory_arith::display_atoms(std::ostream & out) const { out << "atoms:\n"; - for (unsigned i = 0; i < m_atoms.size(); i++) - display_atom(out, m_atoms[i], false); + for (atom * a : m_atoms) + display_atom(out, a, false); } template diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 873d1692d..33207d15a 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -138,9 +138,9 @@ namespace smt { void theory_bv::process_args(app * n) { context & ctx = get_context(); - unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) - ctx.internalize(n->get_arg(i), false); + for (expr* arg : *n) { + ctx.internalize(arg, false); + } } enode * theory_bv::mk_enode(app * n) { @@ -185,11 +185,9 @@ namespace smt { void theory_bv::get_bits(theory_var v, expr_ref_vector & r) { context & ctx = get_context(); literal_vector & bits = m_bits[v]; - literal_vector::const_iterator it = bits.begin(); - literal_vector::const_iterator end = bits.end(); - for (; it != end; ++it) { + for (literal lit : bits) { expr_ref l(get_manager()); - ctx.literal2expr(*it, l); + ctx.literal2expr(lit, l); r.push_back(l); } } @@ -358,18 +356,16 @@ namespace smt { void mark_bits(conflict_resolution & cr, literal_vector const & bits) { context & ctx = cr.get_context(); - literal_vector::const_iterator it = bits.begin(); - literal_vector::const_iterator end = bits.end(); - for (; it != end; ++it) { - if (it->var() != true_bool_var) { - if (ctx.get_assignment(*it) == l_true) - cr.mark_literal(*it); + for (literal lit : bits) { + if (lit.var() != true_bool_var) { + if (ctx.get_assignment(lit) == l_true) + cr.mark_literal(lit); else - cr.mark_literal(~(*it)); + cr.mark_literal(~lit); } } } - + void get_proof(conflict_resolution & cr, literal l, ptr_buffer & prs, bool & visited) { if (l.var() == true_bool_var) return; @@ -489,7 +485,7 @@ namespace smt { } } - bool theory_bv::get_fixed_value(theory_var v, numeral & result) const { + bool theory_bv::get_fixed_value(theory_var v, numeral & result) const { context & ctx = get_context(); result.reset(); literal_vector const & bits = m_bits[v]; @@ -830,10 +826,9 @@ namespace smt { while (i > 0) { i--; theory_var arg = get_arg_var(e, i); - literal_vector::const_iterator it = m_bits[arg].begin(); - literal_vector::const_iterator end = m_bits[arg].end(); - for (; it != end; ++it) - add_bit(v, *it); + for (literal lit : m_bits[arg]) { + add_bit(v, lit); + } } find_wpos(v); } @@ -855,6 +850,8 @@ namespace smt { } bool theory_bv::internalize_term(app * term) { + scoped_suspend_rlimit _suspend_cancel(get_manager().limit()); + try { SASSERT(term->get_family_id() == get_family_id()); TRACE("bv", tout << "internalizing term: " << mk_bounded_pp(term, get_manager()) << "\n";); if (approximate_term(term)) { @@ -912,6 +909,11 @@ namespace smt { UNREACHABLE(); return false; } + } + catch (z3_exception& ex) { + IF_VERBOSE(1, verbose_stream() << "internalize_term: " << ex.msg() << "\n";); + throw; + } } #define MK_NO_OVFL(NAME, OP) \ @@ -1097,8 +1099,7 @@ namespace smt { void theory_bv::apply_sort_cnstr(enode * n, sort * s) { if (!is_attached_to_var(n) && !approximate_term(n->get_owner())) { - theory_var v = mk_var(n); - mk_bits(v); + mk_bits(mk_var(n)); } } @@ -1308,10 +1309,9 @@ namespace smt { theory_var v = e->get_th_var(get_id()); if (v != null_theory_var) { literal_vector & bits = m_bits[v]; - literal_vector::iterator it = bits.begin(); - literal_vector::iterator end = bits.end(); - for (; it != end; ++it) - ctx.mark_as_relevant(*it); + for (literal lit : bits) { + ctx.mark_as_relevant(lit); + } } } } @@ -1463,35 +1463,27 @@ namespace smt { SASSERT(bv_size == get_bv_size(r2)); m_merge_aux[0].reserve(bv_size+1, null_theory_var); m_merge_aux[1].reserve(bv_size+1, null_theory_var); -#define RESET_MERGET_AUX() { \ - zero_one_bits::iterator it = bits1.begin(); \ - zero_one_bits::iterator end = bits1.end(); \ - for (; it != end; ++it) \ - m_merge_aux[it->m_is_true][it->m_idx] = null_theory_var; \ - } + +#define RESET_MERGET_AUX() for (auto & zo : bits1) m_merge_aux[zo.m_is_true][zo.m_idx] = null_theory_var; + DEBUG_CODE(for (unsigned i = 0; i < bv_size; i++) { SASSERT(m_merge_aux[0][i] == null_theory_var || m_merge_aux[1][i] == null_theory_var); }); // save info about bits1 - zero_one_bits::iterator it = bits1.begin(); - zero_one_bits::iterator end = bits1.end(); - for (; it != end; ++it) - m_merge_aux[it->m_is_true][it->m_idx] = it->m_owner; + for (auto & zo : bits1) m_merge_aux[zo.m_is_true][zo.m_idx] = zo.m_owner; // check if bits2 is consistent with bits1, and copy new bits to bits1 - it = bits2.begin(); - end = bits2.end(); - for (; it != end; ++it) { - theory_var v2 = it->m_owner; - theory_var v1 = m_merge_aux[!it->m_is_true][it->m_idx]; + for (auto & zo : bits2) { + theory_var v2 = zo.m_owner; + theory_var v1 = m_merge_aux[!zo.m_is_true][zo.m_idx]; if (v1 != null_theory_var) { // conflict was detected ... v1 and v2 have complementary bits - SASSERT(m_bits[v1][it->m_idx] == ~(m_bits[v2][it->m_idx])); + SASSERT(m_bits[v1][zo.m_idx] == ~(m_bits[v2][zo.m_idx])); SASSERT(m_bits[v1].size() == m_bits[v2].size()); - mk_new_diseq_axiom(v1, v2, it->m_idx); + mk_new_diseq_axiom(v1, v2, zo.m_idx); RESET_MERGET_AUX(); return false; } - if (m_merge_aux[it->m_is_true][it->m_idx] == null_theory_var) { + if (m_merge_aux[zo.m_is_true][zo.m_idx] == null_theory_var) { // copy missing variable to bits1 - bits1.push_back(*it); + bits1.push_back(zo); } } // reset m_merge_aux vector @@ -1614,11 +1606,9 @@ namespace smt { out << std::right << ", bits:"; context & ctx = get_context(); literal_vector const & bits = m_bits[v]; - literal_vector::const_iterator it = bits.begin(); - literal_vector::const_iterator end = bits.end(); - for (; it != end; ++it) { + for (literal lit : bits) { out << " "; - ctx.display_literal(out, *it); + ctx.display_literal(out, lit); } numeral val; if (get_fixed_value(v, val)) @@ -1668,7 +1658,7 @@ namespace smt { } #ifdef Z3DEBUG - bool theory_bv::check_assignment(theory_var v) const { + bool theory_bv::check_assignment(theory_var v) { context & ctx = get_context(); if (!is_root(v)) return true; @@ -1709,7 +1699,7 @@ namespace smt { \remark The method does nothing if v is not the root of the equivalence class. */ - bool theory_bv::check_zero_one_bits(theory_var v) const { + bool theory_bv::check_zero_one_bits(theory_var v) { if (get_context().inconsistent()) return true; // property is only valid if the context is not in a conflict. if (is_root(v) && is_bv(v)) { @@ -1740,19 +1730,17 @@ namespace smt { SASSERT(_bits.size() == num_bits); svector already_found; already_found.resize(bv_sz, false); - zero_one_bits::const_iterator it = _bits.begin(); - zero_one_bits::const_iterator end = _bits.end(); - for (; it != end; ++it) { - SASSERT(find(it->m_owner) == v); - SASSERT(bits[it->m_is_true][it->m_idx]); - SASSERT(!already_found[it->m_idx]); - already_found[it->m_idx] = true; + for (auto & zo : _bits) { + SASSERT(find(zo.m_owner) == v); + SASSERT(bits[zo.m_is_true][zo.m_idx]); + SASSERT(!already_found[zo.m_idx]); + already_found[zo.m_idx] = true; } } return true; } - bool theory_bv::check_invariant() const { + bool theory_bv::check_invariant() { unsigned num = get_num_vars(); for (unsigned v = 0; v < num; v++) { check_assignment(v); diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index f2e0f5bed..23644c6fd 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -266,9 +266,9 @@ namespace smt { #ifdef Z3DEBUG - bool check_assignment(theory_var v) const; - bool check_invariant() const; - bool check_zero_one_bits(theory_var v) const; + bool check_assignment(theory_var v); + bool check_invariant(); + bool check_zero_one_bits(theory_var v); #endif }; }; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 6b8d7a47d..267412da6 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -298,13 +298,15 @@ class theory_lra::imp { void init_solver() { if (m_solver) return; - lp_params lp(ctx().get_params()); - m_solver = alloc(lp::lar_solver); + + reset_variable_values(); m_theory_var2var_index.reset(); + m_solver = alloc(lp::lar_solver); + lp_params lp(ctx().get_params()); m_solver->settings().set_resource_limit(m_resource_limit); m_solver->settings().simplex_strategy() = static_cast(lp.simplex_strategy()); - reset_variable_values(); m_solver->settings().bound_propagation() = BP_NONE != propagation_mode(); + m_solver->settings().m_enable_hnf = lp.enable_hnf(); m_solver->set_track_pivoted_rows(lp.bprop_on_pivoted_rows()); // todo : do not use m_arith_branch_cut_ratio for deciding on cheap cuts @@ -514,7 +516,7 @@ class theory_lra::imp { rational r1; v = mk_var(t); svector vars; - ptr_vector todo; + ptr_buffer todo; todo.push_back(t); while (!todo.empty()) { expr* n = todo.back(); @@ -534,7 +536,7 @@ class theory_lra::imp { vars.push_back(get_var_index(mk_var(n))); } } - TRACE("arith", tout << mk_pp(t, m) << " " << _has_var << "\n";); + TRACE("arith", tout << "v" << v << "(" << get_var_index(v) << ") := " << mk_pp(t, m) << " " << _has_var << "\n";); if (!_has_var) { ensure_nra(); m_nra->add_monomial(get_var_index(v), vars.size(), vars.c_ptr()); @@ -1118,7 +1120,7 @@ public: (v != null_theory_var) && (v < static_cast(m_theory_var2var_index.size())) && (UINT_MAX != m_theory_var2var_index[v]) && - !m_variable_values.empty(); + (!m_variable_values.empty() || m_solver->is_term(m_theory_var2var_index[v])); } bool can_get_bound(theory_var v) const { @@ -1163,12 +1165,22 @@ public: } rational get_value(theory_var v) const { - if (!can_get_value(v)) return rational::zero(); + + if (v == null_theory_var || + v >= static_cast(m_theory_var2var_index.size())) { + TRACE("arith", tout << "Variable v" << v << " not internalized\n";); + return rational::zero(); + } + lp::var_index vi = m_theory_var2var_index[v]; if (m_variable_values.count(vi) > 0) return m_variable_values[vi]; - SASSERT (m_solver->is_term(vi)); + if (!m_solver->is_term(vi)) { + TRACE("arith", tout << "not a term v" << v << "\n";); + return rational::zero(); + } + m_todo_terms.push_back(std::make_pair(vi, rational::one())); rational result(0); while (!m_todo_terms.empty()) { @@ -1178,12 +1190,12 @@ public: if (m_solver->is_term(wi)) { const lp::lar_term& term = m_solver->get_term(wi); result += term.m_v * coeff; - for (const auto & i : term.m_coeffs) { - if (m_variable_values.count(i.first) > 0) { - result += m_variable_values[i.first] * coeff * i.second; + for (const auto & i : term) { + if (m_variable_values.count(i.var()) > 0) { + result += m_variable_values[i.var()] * coeff * i.coeff(); } else { - m_todo_terms.push_back(std::make_pair(i.first, coeff * i.second)); + m_todo_terms.push_back(std::make_pair(i.var(), coeff * i.coeff())); } } } @@ -1199,6 +1211,7 @@ public: if (!m.canceled() && m_solver.get() && th.get_num_vars() > 0) { reset_variable_values(); m_solver->get_model(m_variable_values); + TRACE("arith", display(tout);); } } @@ -1360,20 +1373,42 @@ public: // create a bound atom representing term >= k is lower_bound is true, and term <= k if it is false app_ref mk_bound(lp::lar_term const& term, rational const& k, bool lower_bound) { - app_ref t = mk_term(term, k.is_int()); + bool is_int = k.is_int(); + rational offset = -k; + u_map coeffs; + term2coeffs(term, coeffs, rational::one(), offset); + offset.neg(); + if (is_int) { + // 3x + 6y >= 5 -> x + 3y >= 5/3, then x + 3y >= 2 + // 3x + 6y <= 5 -> x + 3y <= 1 + + rational g = gcd_reduce(coeffs); + if (!g.is_one()) { + if (lower_bound) { + offset = div(offset + g - rational::one(), g); + } + else { + offset = div(offset, g); + } + } + } + if (!coeffs.empty() && coeffs.begin()->m_value.is_neg()) { + offset.neg(); + lower_bound = !lower_bound; + for (auto& kv : coeffs) kv.m_value.neg(); + } + app_ref atom(m); + app_ref t = coeffs2app(coeffs, rational::zero(), is_int); if (lower_bound) { - atom = a.mk_ge(t, a.mk_numeral(k, k.is_int())); + atom = a.mk_ge(t, a.mk_numeral(offset, is_int)); } else { - atom = a.mk_le(t, a.mk_numeral(k, k.is_int())); + atom = a.mk_le(t, a.mk_numeral(offset, is_int)); } - expr_ref atom1(m); - proof_ref atomp(m); - ctx().get_rewriter()(atom, atom1, atomp); - atom = to_app(atom1); - TRACE("arith", tout << atom << "\n"; - m_solver->print_term(term, tout << "bound atom: "); tout << " <= " << k << "\n";); + + TRACE("arith", tout << t << ": " << atom << "\n"; + m_solver->print_term(term, tout << "bound atom: "); tout << (lower_bound?" >= ":" <= ") << k << "\n";); ctx().internalize(atom, true); ctx().mark_as_relevant(atom.get()); return atom; @@ -1392,6 +1427,7 @@ public: case lp::lia_move::sat: return l_true; case lp::lia_move::branch: { + TRACE("arith", tout << "branch\n";); app_ref b = mk_bound(term, k, !upper); // branch on term >= k + 1 // branch on term <= k @@ -1401,6 +1437,7 @@ public: return l_false; } case lp::lia_move::cut: { + TRACE("arith", tout << "cut\n";); ++m_stats.m_gomory_cuts; // m_explanation implies term <= k app_ref b = mk_bound(term, k, !upper); @@ -1444,7 +1481,7 @@ public: } if (!m_nra) return l_true; if (!m_nra->need_check()) return l_true; - m_a1 = 0; m_a2 = 0; + m_a1 = nullptr; m_a2 = nullptr; lbool r = m_nra->check(m_explanation); m_a1 = alloc(scoped_anum, m_nra->am()); m_a2 = alloc(scoped_anum, m_nra->am()); @@ -1499,10 +1536,7 @@ public: } } else { - enode_vector::const_iterator it = r->begin_parents(); - enode_vector::const_iterator end = r->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : r->get_const_parents()) { if (is_underspecified(parent->get_owner())) { return true; } @@ -1703,6 +1737,7 @@ public: void assign(literal lit) { // SASSERT(validate_assign(lit)); + dump_assign(lit); if (m_core.size() < small_lemma_size() && m_eqs.empty()) { m_core2.reset(); for (auto const& c : m_core) { @@ -1773,12 +1808,11 @@ public: lp_api::bound* lo_inf = end, *lo_sup = end; lp_api::bound* hi_inf = end, *hi_sup = end; - for (unsigned i = 0; i < bounds.size(); ++i) { - lp_api::bound& other = *bounds[i]; - if (&other == &b) continue; - if (b.get_bv() == other.get_bv()) continue; - lp_api::bound_kind kind2 = other.get_bound_kind(); - rational const& k2 = other.get_value(); + for (lp_api::bound* other : bounds) { + if (other == &b) continue; + if (b.get_bv() == other->get_bv()) continue; + lp_api::bound_kind kind2 = other->get_bound_kind(); + rational const& k2 = other->get_value(); if (k1 == k2 && kind1 == kind2) { // the bounds are equivalent. continue; @@ -1788,20 +1822,20 @@ public: if (kind2 == lp_api::lower_t) { if (k2 < k1) { if (lo_inf == end || k2 > lo_inf->get_value()) { - lo_inf = &other; + lo_inf = other; } } else if (lo_sup == end || k2 < lo_sup->get_value()) { - lo_sup = &other; + lo_sup = other; } } else if (k2 < k1) { if (hi_inf == end || k2 > hi_inf->get_value()) { - hi_inf = &other; + hi_inf = other; } } else if (hi_sup == end || k2 < hi_sup->get_value()) { - hi_sup = &other; + hi_sup = other; } } if (lo_inf != end) mk_bound_axiom(b, *lo_inf); @@ -2119,8 +2153,8 @@ public: vi = m_todo_vars.back(); m_todo_vars.pop_back(); lp::lar_term const& term = m_solver->get_term(vi); - for (auto const& coeff : term.m_coeffs) { - lp::var_index wi = coeff.first; + for (auto const& coeff : term) { + lp::var_index wi = coeff.var(); if (m_solver->is_term(wi)) { m_todo_vars.push_back(wi); } @@ -2527,6 +2561,7 @@ public: } } // SASSERT(validate_conflict()); + dump_conflict(); ctx().set_conflict( ctx().mk_justification( ext_theory_conflict_justification( @@ -2570,19 +2605,23 @@ public: m_todo_terms.push_back(std::make_pair(vi, rational::one())); + TRACE("arith", tout << "v" << v << " := w" << vi << "\n"; + m_solver->print_term(m_solver->get_term(vi), tout); tout << "\n";); + m_nra->am().set(r, 0); while (!m_todo_terms.empty()) { rational wcoeff = m_todo_terms.back().second; - // lp::var_index wi = m_todo_terms.back().first; // todo : got a warning "wi is not used" + vi = m_todo_terms.back().first; m_todo_terms.pop_back(); lp::lar_term const& term = m_solver->get_term(vi); + TRACE("arith", m_solver->print_term(term, tout); tout << "\n";); scoped_anum r1(m_nra->am()); rational c1 = term.m_v * wcoeff; m_nra->am().set(r1, c1.to_mpq()); m_nra->am().add(r, r1, r); - for (auto const coeff : term.m_coeffs) { - lp::var_index wi = coeff.first; - c1 = coeff.second * wcoeff; + for (auto const & arg : term) { + lp::var_index wi = m_solver->local2external(arg.var()); + c1 = arg.coeff() * wcoeff; if (m_solver->is_term(wi)) { m_todo_terms.push_back(std::make_pair(wi, c1)); } @@ -2612,6 +2651,8 @@ public: } else { rational r = get_value(v); + TRACE("arith", tout << "v" << v << " := " << r << "\n";); + SASSERT(!a.is_int(o) || r.is_int()); if (a.is_int(o) && !r.is_int()) r = floor(r); return alloc(expr_wrapper_proc, m_factory->mk_value(r, m.get_sort(o))); } @@ -2684,10 +2725,14 @@ public: } }; - bool validate_conflict() { + void dump_conflict() { if (dump_lemmas()) { - ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), false_literal); + unsigned id = ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), false_literal); + (void)id; } + } + + bool validate_conflict() { if (m_arith_params.m_arith_mode != AS_NEW_ARITH) return true; scoped_arith_mode _sa(ctx().get_fparams()); context nctx(m, ctx().get_fparams(), ctx().get_params()); @@ -2699,10 +2744,14 @@ public: return result; } - bool validate_assign(literal lit) { + void dump_assign(literal lit) { if (dump_lemmas()) { - ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); + unsigned id = ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); + (void)id; } + } + + bool validate_assign(literal lit) { if (m_arith_params.m_arith_mode != AS_NEW_ARITH) return true; scoped_arith_mode _sa(ctx().get_fparams()); context nctx(m, ctx().get_fparams(), ctx().get_params()); @@ -2728,13 +2777,13 @@ public: } void add_background(context& nctx) { - for (unsigned i = 0; i < m_core.size(); ++i) { + for (literal c : m_core) { expr_ref tmp(m); - ctx().literal2expr(m_core[i], tmp); + ctx().literal2expr(c, tmp); nctx.assert_expr(tmp); } - for (unsigned i = 0; i < m_eqs.size(); ++i) { - nctx.assert_expr(m.mk_eq(m_eqs[i].first->get_owner(), m_eqs[i].second->get_owner())); + for (auto const& eq : m_eqs) { + nctx.assert_expr(m.mk_eq(eq.first->get_owner(), eq.second->get_owner())); } } @@ -2753,20 +2802,22 @@ public: lp::var_index vi = m_theory_var2var_index[v]; st = m_solver->maximize_term(vi, term_max); } + TRACE("arith", display(tout << st << " v" << v << "\n");); switch (st) { case lp::lp_status::OPTIMAL: { - inf_rational val(term_max.x, term_max.y); + init_variable_values(); + inf_rational val = get_value(v); + // inf_rational val(term_max.x, term_max.y); blocker = mk_gt(v); return inf_eps(rational::zero(), val); } case lp::lp_status::FEASIBLE: { - inf_rational val(term_max.x, term_max.y); - // todo , TODO , not sure what happens here + inf_rational val = get_value(v); + blocker = mk_gt(v); return inf_eps(rational::zero(), val); } default: SASSERT(st == lp::lp_status::UNBOUNDED); - TRACE("arith", tout << "Unbounded v" << v << "\n";); has_shared = false; blocker = m.mk_false(); return inf_eps(rational::one(), inf_rational()); @@ -2802,29 +2853,48 @@ public: } theory_var add_objective(app* term) { + TRACE("opt", tout << expr_ref(term, m) << "\n";); return internalize_def(term); } - app_ref mk_term(lp::lar_term const& term, bool is_int) { - expr_ref_vector args(m); + void term2coeffs(lp::lar_term const& term, u_map& coeffs, rational const& coeff, rational& offset) { for (const auto & ti : term) { theory_var w; if (m_solver->is_term(ti.var())) { - w = m_term_index2theory_var[m_solver->adjust_term_index(ti.var())]; + //w = m_term_index2theory_var.get(m_solver->adjust_term_index(ti.var()), null_theory_var); + //if (w == null_theory_var) // if extracing expressions directly from nested term + lp::lar_term const& term1 = m_solver->get_term(ti.var()); + rational coeff2 = coeff * ti.coeff(); + term2coeffs(term1, coeffs, coeff2, offset); + continue; } else { w = m_var_index2theory_var[ti.var()]; } + rational c0(0); + coeffs.find(w, c0); + coeffs.insert(w, c0 + ti.coeff() * coeff); + } + offset += coeff * term.m_v; + } + + app_ref coeffs2app(u_map const& coeffs, rational const& offset, bool is_int) { + expr_ref_vector args(m); + for (auto const& kv : coeffs) { + theory_var w = kv.m_key; expr* o = get_enode(w)->get_owner(); - if (ti.coeff().is_one()) { + if (kv.m_value.is_zero()) { + // continue + } + else if (kv.m_value.is_one()) { args.push_back(o); } else { - args.push_back(a.mk_mul(a.mk_numeral(ti.coeff(), is_int), o)); + args.push_back(a.mk_mul(a.mk_numeral(kv.m_value, is_int), o)); } } - if (!term.m_v.is_zero()) { - args.push_back(a.mk_numeral(term.m_v, is_int)); + if (!offset.is_zero()) { + args.push_back(a.mk_numeral(offset, is_int)); } switch (args.size()) { case 0: @@ -2836,6 +2906,26 @@ public: } } + app_ref mk_term(lp::lar_term const& term, bool is_int) { + u_map coeffs; + rational offset; + term2coeffs(term, coeffs, rational::one(), offset); + return coeffs2app(coeffs, offset, is_int); + } + + rational gcd_reduce(u_map& coeffs) { + rational g(0); + for (auto const& kv : coeffs) { + g = gcd(g, kv.m_value); + } + if (!g.is_one() && !g.is_zero()) { + for (auto& kv : coeffs) { + kv.m_value /= g; + } + } + return g; + } + app_ref mk_obj(theory_var v) { lp::var_index vi = m_theory_var2var_index[v]; bool is_int = a.is_int(get_enode(v)->get_owner()); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index ed0481938..e389c819e 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1429,23 +1429,27 @@ namespace smt { return literal(ctx.mk_bool_var(y)); } - literal mk_max(literal a, literal b) { - if (a == b) return a; - expr_ref t1(m), t2(m), t3(m); - ctx.literal2expr(a, t1); - ctx.literal2expr(b, t2); - t3 = m.mk_or(t1, t2); - bool_var v = ctx.b_internalized(t3)?ctx.get_bool_var(t3):ctx.mk_bool_var(t3); + literal mk_max(unsigned n, literal const* lits) { + expr_ref_vector es(m); + expr_ref tmp(m); + for (unsigned i = 0; i < n; ++i) { + ctx.literal2expr(lits[i], tmp); + es.push_back(tmp); + } + tmp = m.mk_or(es.size(), es.c_ptr()); + bool_var v = ctx.b_internalized(tmp)?ctx.get_bool_var(tmp):ctx.mk_bool_var(tmp); return literal(v); } - - literal mk_min(literal a, literal b) { - if (a == b) return a; - expr_ref t1(m), t2(m), t3(m); - ctx.literal2expr(a, t1); - ctx.literal2expr(b, t2); - t3 = m.mk_and(t1, t2); - bool_var v = ctx.b_internalized(t3)?ctx.get_bool_var(t3):ctx.mk_bool_var(t3); + + literal mk_min(unsigned n, literal const* lits) { + expr_ref_vector es(m); + expr_ref tmp(m); + for (unsigned i = 0; i < n; ++i) { + ctx.literal2expr(lits[i], tmp); + es.push_back(tmp); + } + tmp = m.mk_and(es.size(), es.c_ptr()); + bool_var v = ctx.b_internalized(tmp)?ctx.get_bool_var(tmp):ctx.mk_bool_var(tmp); return literal(v); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 48d4ddcc0..b00c1565c 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -367,7 +367,7 @@ bool theory_seq::branch_binary_variable(eq const& e) { return false; } ptr_vector xs, ys; - expr* x, *y; + expr_ref x(m), y(m); bool is_binary = is_binary_eq(e.ls(), e.rs(), x, xs, ys, y); if (!is_binary) { is_binary = is_binary_eq(e.rs(), e.ls(), x, xs, ys, y); @@ -630,7 +630,7 @@ bool theory_seq::branch_ternary_variable_base( // Equation is of the form x ++ xs = y1 ++ ys ++ y2 where xs, ys are units. bool theory_seq::branch_ternary_variable(eq const& e, bool flag1) { expr_ref_vector xs(m), ys(m); - expr* x = nullptr, *y1 = nullptr, *y2 = nullptr; + expr_ref x(m), y1(m), y2(m); bool is_ternary = is_ternary_eq(e.ls(), e.rs(), x, xs, y1, ys, y2, flag1); if (!is_ternary) { is_ternary = is_ternary_eq(e.rs(), e.ls(), x, xs, y1, ys, y2, flag1); @@ -746,7 +746,7 @@ bool theory_seq::branch_ternary_variable_base2(dependency* dep, unsigned_vector // Equation is of the form xs ++ x = y1 ++ ys ++ y2 where xs, ys are units. bool theory_seq::branch_ternary_variable2(eq const& e, bool flag1) { expr_ref_vector xs(m), ys(m); - expr* x = nullptr, *y1 = nullptr, *y2 = nullptr; + expr_ref x(m), y1(m), y2(m); bool is_ternary = is_ternary_eq2(e.ls(), e.rs(), xs, x, y1, ys, y2, flag1); if (!is_ternary) { is_ternary = is_ternary_eq2(e.rs(), e.ls(), xs, x, y1, ys, y2, flag1); @@ -823,7 +823,7 @@ bool theory_seq::branch_quat_variable() { // Equation is of the form x1 ++ xs ++ x2 = y1 ++ ys ++ y2 where xs, ys are units. bool theory_seq::branch_quat_variable(eq const& e) { expr_ref_vector xs(m), ys(m); - expr* x1_l = nullptr, *x2 = nullptr, *y1_l = nullptr, *y2 = nullptr; + expr_ref x1_l(m), x2(m), y1_l(m), y2(m); bool is_quat = is_quat_eq(e.ls(), e.rs(), x1_l, xs, x2, y1_l, ys, y2); if (!is_quat) { return false; @@ -889,38 +889,35 @@ bool theory_seq::branch_quat_variable(eq const& e) { return true; } -void theory_seq::len_offset(expr* const& e, rational val) { +void theory_seq::len_offset(expr* e, rational val) { context & ctx = get_context(); expr *l1 = nullptr, *l2 = nullptr, *l21 = nullptr, *l22 = nullptr; rational fact; if (m_autil.is_add(e, l1, l2) && m_autil.is_mul(l2, l21, l22) && - m_autil.is_numeral(l21, fact) && fact.is_minus_one()) { + m_autil.is_numeral(l21, fact) && fact.is_minus_one()) { if (ctx.e_internalized(l1) && ctx.e_internalized(l22)) { enode* r1 = ctx.get_enode(l1)->get_root(), *n1 = r1; enode* r2 = ctx.get_enode(l22)->get_root(), *n2 = r2; expr *e1 = nullptr, *e2 = nullptr; do { - if (!m_util.str.is_length(n1->get_owner(), e1)) - n1 = n1->get_next(); - else + if (m_util.str.is_length(n1->get_owner(), e1)) break; + n1 = n1->get_next(); } while (n1 != r1); do { - if (!m_util.str.is_length(n2->get_owner(), e2)) - n2 = n2->get_next(); - else + if (m_util.str.is_length(n2->get_owner(), e2)) break; + n2 = n2->get_next(); } while (n2 != r2); + obj_map tmp; if (m_util.str.is_length(n1->get_owner(), e1) - && m_util.str.is_length(n2->get_owner(), e2)) { - obj_map tmp; - m_len_offset.find(r1, tmp); + && m_util.str.is_length(n2->get_owner(), e2) && + m_len_offset.find(r1, tmp)) { tmp.insert(r2, val.get_int32()); m_len_offset.insert(r1, tmp); - TRACE("seq", tout << "a length pair: " << mk_pp(e1, m) - << ", " << mk_pp(e2, m) << "\n";); + TRACE("seq", tout << "a length pair: " << mk_pp(e1, m) << ", " << mk_pp(e2, m) << "\n";); return; } } @@ -1083,8 +1080,8 @@ void theory_seq::find_max_eq_len(expr_ref_vector const& ls, expr_ref_vector cons } // TODO: propagate length offsets for last vars -bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector const& rs, unsigned const& idx, - dependency*& deps, expr_ref_vector & res) { +bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector const& rs, unsigned idx, + dependency*& deps, expr_ref_vector & res) { context& ctx = get_context(); if (ls.empty() || rs.empty()) @@ -1307,32 +1304,34 @@ bool theory_seq::len_based_split(eq const& e) { y12 = mk_concat(Z, y12); } } - else - lenY11 = m_util.str.mk_length(y11); + else { + lenY11 = m_util.str.mk_length(y11); + } dependency* dep = e.dep(); literal_vector lits; literal lit1 = mk_eq(lenX11, lenY11, false); + if (ctx.get_assignment(lit1) != l_true) { + return false; + } lits.push_back(lit1); - if (ls.size()>=2 && rs.size()>=2 && (ls.size()>2 || rs.size()>2)) { + if (ls.size() >= 2 && rs.size() >= 2 && (ls.size() > 2 || rs.size() > 2)) { expr_ref len1(m_autil.mk_int(0),m), len2(m_autil.mk_int(0),m); for (unsigned i = 2; i < ls.size(); ++i) len1 = mk_add(len1, m_util.str.mk_length(ls[i])); for (unsigned i = 2; i < rs.size(); ++i) len2 = mk_add(len2, m_util.str.mk_length(rs[i])); - bool flag = false; + literal lit2; if (!m_autil.is_numeral(len1) && !m_autil.is_numeral(len2)) { - literal lit2 = mk_eq(len1, len2, false); - flag = ctx.get_assignment(lit2) == l_true; + lit2 = mk_eq(len1, len2, false); } else { expr_ref eq_len(m.mk_eq(len1, len2), m); - flag = ctx.find_assignment(eq_len) == l_true; + lit2 = mk_literal(eq_len); } - if (flag) { - literal lit2 = mk_eq(len1, len2, false); + if (ctx.get_assignment(lit2) == l_true) { lits.push_back(lit2); TRACE("seq", tout << mk_pp(len1, m) << " = " << mk_pp(len2, m) << "\n";); expr_ref lhs(m), rhs(m); @@ -2263,6 +2262,7 @@ bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependenc SASSERT(lhs.size() == rhs.size()); m_seq_rewrite.add_seqs(ls, rs, lhs, rhs); if (lhs.empty()) { + TRACE("seq", tout << "solved\n";); return true; } TRACE("seq", @@ -2412,6 +2412,7 @@ bool theory_seq::solve_eqs(unsigned i) { m_eqs.pop_back(); change = true; } + TRACE("seq", display_equations(tout);); } return change || m_new_propagation || ctx.inconsistent(); } @@ -2430,6 +2431,7 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de display_deps(tout, deps); ); if (!ctx.inconsistent() && simplify_eq(ls, rs, deps)) { + TRACE("seq", tout << "simplified\n";); return true; } TRACE("seq", tout << ls << " = " << rs << "\n";); @@ -2465,6 +2467,7 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de if (!updated) { m_eqs.push_back(eq(m_eq_id++, ls, rs, deps)); } + TRACE("seq", tout << "simplified\n";); return true; } return false; @@ -2484,7 +2487,7 @@ bool theory_seq::propagate_max_length(expr* l, expr* r, dependency* deps) { return false; } -bool theory_seq::is_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr*& x, ptr_vector& xs, ptr_vector& ys, expr*& y) { +bool theory_seq::is_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x, ptr_vector& xs, ptr_vector& ys, expr_ref& y) { if (ls.size() > 1 && is_var(ls[0]) && rs.size() > 1 && is_var(rs.back())) { xs.reset(); @@ -2505,7 +2508,7 @@ bool theory_seq::is_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& } bool theory_seq::is_quat_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, -expr*& x1, expr_ref_vector& xs, expr*& x2, expr*& y1, expr_ref_vector& ys, expr*& y2) { + expr_ref& x1, expr_ref_vector& xs, expr_ref& x2, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2) { if (ls.size() > 1 && is_var(ls[0]) && is_var(ls.back()) && rs.size() > 1 && is_var(rs[0]) && is_var(rs.back())) { unsigned l_start = 1; @@ -2548,7 +2551,7 @@ expr*& x1, expr_ref_vector& xs, expr*& x2, expr*& y1, expr_ref_vector& ys, expr* } bool theory_seq::is_ternary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, -expr*& x, expr_ref_vector& xs, expr*& y1, expr_ref_vector& ys, expr*& y2, bool flag1) { + expr_ref& x, expr_ref_vector& xs, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1) { if (ls.size() > 1 && (is_var(ls[0]) || flag1) && rs.size() > 1 && is_var(rs[0]) && is_var(rs.back())) { unsigned l_start = ls.size()-1; @@ -2586,7 +2589,7 @@ expr*& x, expr_ref_vector& xs, expr*& y1, expr_ref_vector& ys, expr*& y2, bool f } bool theory_seq::is_ternary_eq2(expr_ref_vector const& ls, expr_ref_vector const& rs, - expr_ref_vector& xs, expr*& x, expr*& y1, expr_ref_vector& ys, expr*& y2, bool flag1) { + expr_ref_vector& xs, expr_ref& x, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1) { if (ls.size() > 1 && (is_var(ls.back()) || flag1) && rs.size() > 1 && is_var(rs[0]) && is_var(rs.back())) { unsigned l_start = 0; @@ -2748,7 +2751,7 @@ bool theory_seq::reduce_length(unsigned i, unsigned j, bool front, expr_ref_vect bool theory_seq::solve_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep) { context& ctx = get_context(); ptr_vector xs, ys; - expr* x, *y; + expr_ref x(m), y(m); bool is_binary = is_binary_eq(ls, rs, x, xs, ys, y); if (!is_binary) { is_binary = is_binary_eq(rs, ls, x, xs, ys, y); @@ -2771,49 +2774,36 @@ bool theory_seq::solve_binary_eq(expr_ref_vector const& ls, expr_ref_vector cons UNREACHABLE(); return false; } - unsigned sz = xs.size(); - literal_vector conflict; - for (unsigned offset = 0; offset < sz; ++offset) { - bool has_conflict = false; - for (unsigned j = 0; !has_conflict && j < sz; ++j) { - unsigned j1 = (offset + j) % sz; - if (xs[j] == ys[j1]) continue; - literal eq = mk_eq(xs[j], ys[j1], false); - switch (ctx.get_assignment(eq)) { - case l_false: - conflict.push_back(~eq); - has_conflict = true; - break; - case l_undef: { - enode* n1 = ensure_enode(xs[j]); - enode* n2 = ensure_enode(ys[j1]); - if (n1->get_root() == n2->get_root()) { - break; - } - ctx.mark_as_relevant(eq); - if (sz == 1) { - propagate_lit(dep, 0, nullptr, eq); - return true; - } - m_new_propagation = true; - break; - } - case l_true: - break; - } - } - if (!has_conflict) { - TRACE("seq", tout << "offset: " << offset << " equality "; - for (unsigned j = 0; j < sz; ++j) { - tout << mk_pp(xs[j], m) << " = " << mk_pp(ys[(offset+j) % sz], m) << "; "; - } - tout << "\n";); - // current equalities can work when solving x ++ xs = ys ++ y + + // Equation is of the form x ++ xs = ys ++ x + // where |xs| = |ys| are units of same length + // then xs is a wrap-around of ys + // x ++ ab = ba ++ x + // + if (xs.size() == 1) { + enode* n1 = ensure_enode(xs[0]); + enode* n2 = ensure_enode(ys[0]); + if (n1->get_root() == n2->get_root()) { return false; } + literal eq = mk_eq(xs[0], ys[0], false); + switch (ctx.get_assignment(eq)) { + case l_false: { + literal_vector conflict; + conflict.push_back(~eq); + TRACE("seq", tout << conflict << "\n";); + set_conflict(dep, conflict); + break; + } + case l_true: + break; + case l_undef: + ctx.mark_as_relevant(eq); + propagate_lit(dep, 0, nullptr, eq); + m_new_propagation = true; + break; + } } - TRACE("seq", tout << conflict << "\n";); - set_conflict(dep, conflict); return false; } @@ -4582,7 +4572,6 @@ bool theory_seq::lower_bound(expr* _e, rational& lo) const { if (thi && thi->get_lower(ctx.get_enode(e), _lo)) break; theory_lra* thr = get_th_arith(ctx, afid, e); if (thr && thr->get_lower(ctx.get_enode(e), _lo)) break; - TRACE("seq", tout << "no lower bound " << mk_pp(_e, m) << "\n";); return false; } while (false); @@ -4640,7 +4629,6 @@ bool theory_seq::upper_bound(expr* _e, rational& hi) const { if (thi && thi->get_upper(ctx.get_enode(e), _hi)) break; theory_lra* thr = get_th_arith(ctx, afid, e); if (thr && thr->get_upper(ctx.get_enode(e), _hi)) break; - TRACE("seq", tout << "no upper bound " << mk_pp(_e, m) << "\n";); return false; } while (false); @@ -5163,7 +5151,22 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { } } else if (m_util.str.is_contains(e, e1, e2)) { - if (is_true) { + expr_ref_vector disj(m); + // disabled pending regression on issue 1196 + if (false && m_seq_rewrite.reduce_contains(e1, e2, disj)) { + literal_vector lits; + literal lit = mk_literal(e); + lits.push_back(~lit); + for (expr* d : disj) { + lits.push_back(mk_literal(d)); + } + ++m_stats.m_add_axiom; + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + for (expr* d : disj) { + add_axiom(lit, ~mk_literal(d)); + } + } + else if (is_true) { expr_ref f1 = mk_skolem(m_indexof_left, e1, e2); expr_ref f2 = mk_skolem(m_indexof_right, e1, e2); f = mk_concat(f1, e2, f2); @@ -5236,6 +5239,7 @@ void theory_seq::new_eq_eh(theory_var v1, theory_var v2) { } void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) { + TRACE("seq", tout << expr_ref(n1->get_owner(), m) << " = " << expr_ref(n2->get_owner(), m) << "\n";); if (n1 != n2 && m_util.is_seq(n1->get_owner())) { theory_var v1 = n1->get_th_var(get_id()); theory_var v2 = n2->get_th_var(get_id()); @@ -5263,9 +5267,10 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) { void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { enode* n1 = get_enode(v1); - enode* n2 = get_enode(v2); + enode* n2 = get_enode(v2); expr_ref e1(n1->get_owner(), m); expr_ref e2(n2->get_owner(), m); + SASSERT(n1->get_root() != n2->get_root()); m_exclude.update(e1, e2); expr_ref eq(m.mk_eq(e1, e2), m); TRACE("seq", tout << "new disequality " << get_context().get_scope_level() << ": " << eq << "\n";); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index abb202884..fbefaede2 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -375,13 +375,13 @@ namespace smt { void init_model(expr_ref_vector const& es); - void len_offset(expr* const& e, rational val); + void len_offset(expr* e, rational val); void prop_arith_to_len_offset(); int find_fst_non_empty_idx(expr_ref_vector const& x) const; expr* find_fst_non_empty_var(expr_ref_vector const& x) const; void find_max_eq_len(expr_ref_vector const& ls, expr_ref_vector const& rs); bool has_len_offset(expr_ref_vector const& ls, expr_ref_vector const& rs, int & diff); - bool find_better_rep(expr_ref_vector const& ls, expr_ref_vector const& rs, unsigned const& idx, dependency*& deps, expr_ref_vector & res); + bool find_better_rep(expr_ref_vector const& ls, expr_ref_vector const& rs, unsigned idx, dependency*& deps, expr_ref_vector & res); // final check bool simplify_and_solve_eqs(); // solve unitary equalities @@ -427,10 +427,10 @@ namespace smt { bool simplify_eq(expr_ref_vector& l, expr_ref_vector& r, dependency* dep); bool solve_unit_eq(expr* l, expr* r, dependency* dep); bool solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep); - bool is_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, expr*& x, ptr_vector& xunits, ptr_vector& yunits, expr*& y); - bool is_quat_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr*& x1, expr_ref_vector& xs, expr*& x2, expr*& y1, expr_ref_vector& ys, expr*& y2); - bool is_ternary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr*& x, expr_ref_vector& xs, expr*& y1, expr_ref_vector& ys, expr*& y2, bool flag1); - bool is_ternary_eq2(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_vector& xs, expr*& x, expr*& y1, expr_ref_vector& ys, expr*& y2, bool flag1); + bool is_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, expr_ref& x, ptr_vector& xunits, ptr_vector& yunits, expr_ref& y); + bool is_quat_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x1, expr_ref_vector& xs, expr_ref& x2, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2); + bool is_ternary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x, expr_ref_vector& xs, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1); + bool is_ternary_eq2(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_vector& xs, expr_ref& x, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1); bool solve_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep); bool propagate_max_length(expr* l, expr* r, dependency* dep); diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index ad166d425..61094c29c 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -186,10 +186,12 @@ public: void push() override { switch_inc_mode(); m_solver1->push(); - m_solver2->push(); + m_solver2->push(); + TRACE("pop", tout << "push\n";); } void pop(unsigned n) override { + TRACE("pop", tout << n << "\n";); switch_inc_mode(); m_solver1->pop(n); m_solver2->pop(n); diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index db745597c..41853b19a 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -90,9 +90,9 @@ void solver_na2as::push() { void solver_na2as::pop(unsigned n) { if (n > 0) { - pop_core(n); unsigned lvl = m_scopes.size(); - SASSERT(n <= lvl); + n = std::min(lvl, n); + pop_core(n); unsigned new_lvl = lvl - n; restore_assumptions(m_scopes[new_lvl]); m_scopes.shrink(new_lvl); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 135d402e6..cf0c6f9bc 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -122,9 +122,12 @@ void tactic2solver::assert_expr_core(expr * t) { void tactic2solver::push_core() { m_scopes.push_back(m_assertions.size()); m_result = nullptr; + TRACE("pop", tout << m_scopes.size() << "\n";); } void tactic2solver::pop_core(unsigned n) { + TRACE("pop", tout << m_scopes.size() << " " << n << "\n";); + n = std::min(m_scopes.size(), n); unsigned new_lvl = m_scopes.size() - n; unsigned old_sz = m_scopes[new_lvl]; m_assertions.shrink(old_sz); @@ -142,9 +145,8 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass m_tactic->updt_params(get_params()); // parameters are allowed to overwrite logic. goal_ref g = alloc(goal, m, m_produce_proofs, m_produce_models, m_produce_unsat_cores); - unsigned sz = m_assertions.size(); - for (unsigned i = 0; i < sz; i++) { - g->assert_expr(m_assertions.get(i)); + for (expr* e : m_assertions) { + g->assert_expr(e); } for (unsigned i = 0; i < num_assumptions; i++) { proof_ref pr(m.mk_asserted(assumptions[i]), m); @@ -169,7 +171,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass m_result->set_status(l_undef); if (reason_unknown != "") m_result->m_unknown = reason_unknown; - if (num_assumptions == 0) { + if (num_assumptions == 0 && m_scopes.empty()) { m_assertions.reset(); g->get_formulas(m_assertions); } diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 97649cc2f..65b8d8bf3 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -80,10 +80,10 @@ public: } expr_ref_vector fmls(m); rw2.flush_side_constraints(fmls); - for (unsigned i = 0; !g->inconsistent() && i < fmls.size(); ++i) { - g->assert_expr(fmls[i].get()); + for (expr* e : fmls) { + g->assert_expr(e); } - + func_decl_ref_vector const& fns = rw2.fresh_constants(); if (!fns.empty()) { generic_model_converter* filter = alloc(generic_model_converter, m, "card2bv"); diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index 36ee89a1b..2e090755b 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -127,6 +127,42 @@ public: } }; +struct has_nlmul { + struct found {}; + ast_manager& m; + arith_util a; + has_nlmul(ast_manager& m):m(m), a(m) {} + + void throw_found(expr* e) { + TRACE("probe", tout << expr_ref(e, m) << ": " << sort_ref(m.get_sort(e), m) << "\n";); + throw found(); + } + + void operator()(var *) { } + + void operator()(quantifier *) { } + + void operator()(app * n) { + family_id fid = n->get_family_id(); + if (fid == a.get_family_id()) { + switch (n->get_decl_kind()) { + case OP_MUL: + if (n->get_num_args() != 2 || !a.is_numeral(n->get_arg(0))) + throw_found(n); + break; + case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: + if (!a.is_numeral(n->get_arg(1))) + throw_found(n); + break; + case OP_POWER: + throw_found(n); + default: + break; + } + } + } +}; + probe * mk_arith_avg_degree_probe() { return alloc(arith_degree_probe, true); } @@ -441,13 +477,13 @@ struct is_non_nira_functor { if (m_linear) { if (n->get_num_args() != 2) throw_found(n); - if (!u.is_numeral(n->get_arg(0))) + if (!u.is_numeral(n->get_arg(0)) && !u.is_numeral(n->get_arg(1))) throw_found(n); } return; case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: if (m_linear && !u.is_numeral(n->get_arg(1))) - throw_found(n); + throw_found(n); return; case OP_IS_INT: if (m_real) @@ -478,27 +514,27 @@ struct is_non_nira_functor { static bool is_qfnia(goal const & g) { is_non_nira_functor p(g.m(), true, false, false, false); - return !test(g, p); + return !test(g, p) && test(g); } static bool is_qfnra(goal const & g) { is_non_nira_functor p(g.m(), false, true, false, false); - return !test(g, p); + return !test(g, p) && test(g); } static bool is_nia(goal const & g) { is_non_nira_functor p(g.m(), true, false, true, false); - return !test(g, p); + return !test(g, p) && test(g); } static bool is_nra(goal const & g) { is_non_nira_functor p(g.m(), false, true, true, false); - return !test(g, p); + return !test(g, p) && test(g); } static bool is_nira(goal const & g) { is_non_nira_functor p(g.m(), true, true, true, false); - return !test(g, p); + return !test(g, p) && test(g); } static bool is_lra(goal const & g) { @@ -560,12 +596,16 @@ struct is_non_qfufnra_functor { } return; case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: - if (!u.is_numeral(n->get_arg(1))) + if (!u.is_numeral(n->get_arg(1))) { + TRACE("arith", tout << "non-linear " << expr_ref(n, m) << "\n";); throw_found(); + } return; case OP_POWER: - if (!u.is_numeral(n->get_arg(1))) + if (!u.is_numeral(n->get_arg(1))) { + TRACE("arith", tout << "non-linear " << expr_ref(n, m) << "\n";); throw_found(); + } m_has_nonlinear = true; return; case OP_IS_INT: @@ -574,6 +614,7 @@ struct is_non_qfufnra_functor { throw_found(); return; default: + TRACE("arith", tout << "non-linear " << expr_ref(n, m) << "\n";); throw_found(); } } diff --git a/src/tactic/fd_solver/CMakeLists.txt b/src/tactic/fd_solver/CMakeLists.txt new file mode 100644 index 000000000..67567d19d --- /dev/null +++ b/src/tactic/fd_solver/CMakeLists.txt @@ -0,0 +1,11 @@ +z3_add_component(fd_solver + SOURCES + bounded_int2bv_solver.cpp + enum2bv_solver.cpp + fd_solver.cpp + pb2bv_solver.cpp + COMPONENT_DEPENDENCIES + sat_solver + TACTIC_HEADERS + fd_solver.h +) diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp similarity index 99% rename from src/tactic/portfolio/bounded_int2bv_solver.cpp rename to src/tactic/fd_solver/bounded_int2bv_solver.cpp index 6389ed739..8791a6282 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -16,8 +16,7 @@ Author: Notes: --*/ - -#include "tactic/portfolio/bounded_int2bv_solver.h" +#include "tactic/fd_solver/bounded_int2bv_solver.h" #include "solver/solver_na2as.h" #include "tactic/tactic.h" #include "ast/rewriter/pb2bv_rewriter.h" diff --git a/src/tactic/portfolio/bounded_int2bv_solver.h b/src/tactic/fd_solver/bounded_int2bv_solver.h similarity index 100% rename from src/tactic/portfolio/bounded_int2bv_solver.h rename to src/tactic/fd_solver/bounded_int2bv_solver.h diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp similarity index 99% rename from src/tactic/portfolio/enum2bv_solver.cpp rename to src/tactic/fd_solver/enum2bv_solver.cpp index 29c6aeb39..a864d9631 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -26,9 +26,9 @@ Notes: #include "model/model_smt2_pp.h" #include "tactic/tactic.h" #include "tactic/generic_model_converter.h" -#include "tactic/portfolio/enum2bv_solver.h" #include "solver/solver_na2as.h" #include "ast/rewriter/enum2bv_rewriter.h" +#include "tactic/fd_solver/enum2bv_solver.h" class enum2bv_solver : public solver_na2as { ast_manager& m; diff --git a/src/tactic/portfolio/enum2bv_solver.h b/src/tactic/fd_solver/enum2bv_solver.h similarity index 100% rename from src/tactic/portfolio/enum2bv_solver.h rename to src/tactic/fd_solver/enum2bv_solver.h diff --git a/src/tactic/portfolio/fd_solver.cpp b/src/tactic/fd_solver/fd_solver.cpp similarity index 83% rename from src/tactic/portfolio/fd_solver.cpp rename to src/tactic/fd_solver/fd_solver.cpp index b0d95baee..2af30b089 100644 --- a/src/tactic/portfolio/fd_solver.cpp +++ b/src/tactic/fd_solver/fd_solver.cpp @@ -17,12 +17,12 @@ Notes: --*/ -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" #include "tactic/tactic.h" #include "sat/sat_solver/inc_sat_solver.h" -#include "tactic/portfolio/enum2bv_solver.h" -#include "tactic/portfolio/pb2bv_solver.h" -#include "tactic/portfolio/bounded_int2bv_solver.h" +#include "tactic/fd_solver/enum2bv_solver.h" +#include "tactic/fd_solver/pb2bv_solver.h" +#include "tactic/fd_solver/bounded_int2bv_solver.h" #include "solver/solver2tactic.h" #include "solver/parallel_tactic.h" #include "solver/parallel_params.hpp" diff --git a/src/tactic/portfolio/fd_solver.h b/src/tactic/fd_solver/fd_solver.h similarity index 100% rename from src/tactic/portfolio/fd_solver.h rename to src/tactic/fd_solver/fd_solver.h diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp similarity index 98% rename from src/tactic/portfolio/pb2bv_solver.cpp rename to src/tactic/fd_solver/pb2bv_solver.cpp index 60ca6a5dc..fd4fb8e73 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -16,14 +16,15 @@ Notes: --*/ +#include "util/statistics.h" #include "ast/ast_pp.h" +#include "ast/rewriter/pb2bv_rewriter.h" +#include "ast/rewriter/th_rewriter.h" #include "model/model_smt2_pp.h" -#include "tactic/portfolio/pb2bv_solver.h" #include "tactic/tactic.h" #include "tactic/generic_model_converter.h" #include "solver/solver_na2as.h" -#include "ast/rewriter/pb2bv_rewriter.h" -#include "ast/rewriter/th_rewriter.h" +#include "tactic/fd_solver/pb2bv_solver.h" class pb2bv_solver : public solver_na2as { ast_manager& m; diff --git a/src/tactic/portfolio/pb2bv_solver.h b/src/tactic/fd_solver/pb2bv_solver.h similarity index 100% rename from src/tactic/portfolio/pb2bv_solver.h rename to src/tactic/fd_solver/pb2bv_solver.h diff --git a/src/tactic/fpa/qffplra_tactic.cpp b/src/tactic/fpa/qffplra_tactic.cpp index 947a41111..605232772 100644 --- a/src/tactic/fpa/qffplra_tactic.cpp +++ b/src/tactic/fpa/qffplra_tactic.cpp @@ -26,6 +26,23 @@ tactic * mk_qffplra_tactic(ast_manager & m, params_ref const & p) { return st; } +struct is_fpa_function { + struct found {}; + ast_manager & m; + fpa_util fu; + + is_fpa_function(ast_manager & _m) : m(_m), fu(m) {} + + void operator()(var *) { } + + void operator()(quantifier *) { } + + void operator()(app * n) { + if (n->get_family_id() == fu.get_family_id()) + throw found(); + } +}; + struct is_non_qffplra_predicate { struct found {}; ast_manager & m; @@ -61,7 +78,9 @@ struct is_non_qffplra_predicate { class is_qffplra_probe : public probe { public: result operator()(goal const & g) override { - return !test(g); + return + test(g) && + !test(g); } ~is_qffplra_probe() override {} diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index d5d2ee558..dfe63e29a 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -716,3 +716,33 @@ bool is_equal(goal const & s1, goal const & s2) { SASSERT(num1 >= num2); return num1 == num2; } + +bool goal::is_cnf() const { + for (unsigned i = 0; i < size(); i++) { + expr * f = form(i); + if (m_manager.is_or(f)) { + for (expr* lit : *to_app(f)) { + if (!is_literal(lit)) { + return false; + } + } + return true; + } + if (!is_literal(f)) { + return false; + } + } + return true; +} + +bool goal::is_literal(expr* f) const { + m_manager.is_not(f, f); + if (!is_app(f)) return false; + if (to_app(f)->get_family_id() == m_manager.get_basic_family_id()) { + for (expr* arg : *to_app(f)) + if (m_manager.is_bool(arg)) { + return false; + } + } + return true; +} diff --git a/src/tactic/goal.h b/src/tactic/goal.h index 2d91bc67f..4125fab99 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -77,7 +77,7 @@ protected: unsigned get_not_idx(expr * f) const; void shrink(unsigned j); void reset_core(); - + bool is_literal(expr* f) const; public: goal(ast_manager & m, bool models_enabled = true, bool core_enabled = false); @@ -159,6 +159,8 @@ public: void set(model_converter* m) { m_mc = m; } void set(proof_converter* p) { m_pc = p; } + bool is_cnf() const; + goal * translate(ast_translation & translator) const; }; diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index 2b714cc2c..0913bf7f0 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -1,10 +1,6 @@ z3_add_component(portfolio SOURCES - bounded_int2bv_solver.cpp default_tactic.cpp - enum2bv_solver.cpp - fd_solver.cpp - pb2bv_solver.cpp smt_strategic_solver.cpp solver2lookahead.cpp COMPONENT_DEPENDENCIES @@ -17,7 +13,7 @@ z3_add_component(portfolio smtlogic_tactics subpaving_tactic ufbv_tactic + fd_solver TACTIC_HEADERS default_tactic.h - fd_solver.h ) diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 7f71114f4..3e479524e 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -31,7 +31,7 @@ Notes: #include "tactic/fpa/qffplra_tactic.h" #include "tactic/smtlogics/qfaufbv_tactic.h" #include "tactic/smtlogics/qfauflia_tactic.h" -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index b8ba2f59d..6718eb13f 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -33,7 +33,7 @@ Notes: #include "tactic/smtlogics/qfidl_tactic.h" #include "tactic/smtlogics/nra_tactic.h" #include "tactic/portfolio/default_tactic.h" -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" #include "tactic/ufbv/ufbv_tactic.h" #include "tactic/fpa/qffp_tactic.h" #include "muz/fp/horn_tactic.h" diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index bc93b4e7b..a8ad95319 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -89,14 +89,6 @@ static tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat params_ref solver_p; solver_p.set_bool("preprocess", false); // preprocessor of smt::context is not needed. - params_ref no_flat_p; - no_flat_p.set_bool("flat", false); - - params_ref ctx_simp_p; - ctx_simp_p.set_uint("max_depth", 32); - ctx_simp_p.set_uint("max_steps", 50000000); - - params_ref big_aig_p; big_aig_p.set_bool("aig_per_assertion", false); diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index 46b766bd4..eed4e4425 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -60,6 +60,7 @@ probe * mk_is_quasi_pb_probe() { // Create SMT solver that does not use cuts static tactic * mk_no_cut_smt_tactic(unsigned rs) { params_ref solver_p; + solver_p.set_sym(symbol("smt.logic"), symbol("QF_LIA")); // force smt_setup to use the new solver solver_p.set_uint("arith.branch_cut_ratio", 10000000); solver_p.set_uint("random_seed", rs); return annotate_tactic("no-cut-smt-tactic", using_params(mk_smt_tactic_using(false), solver_p)); @@ -209,15 +210,8 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { params_ref quasi_pb_p; quasi_pb_p.set_uint("lia2pb_max_bits", 64); - params_ref no_cut_p; - no_cut_p.set_uint("arith.branch_cut_ratio", 10000000); - - tactic * st = using_params(and_then(preamble_st, -#if 0 - mk_smt_tactic()), -#else or_else(mk_ilp_model_finder_tactic(m), mk_pb_tactic(m), and_then(fail_if_not(mk_is_quasi_pb_probe()), @@ -225,7 +219,6 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { mk_fail_if_undecided_tactic()), mk_bounded_tactic(m), mk_smt_tactic())), -#endif main_p); diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 2ef49229a..b92e08006 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -110,9 +110,11 @@ static tactic * mk_qfnia_smt_solver(ast_manager& m, params_ref const& p) { tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { - return and_then(mk_qfnia_premable(m, p), - or_else(mk_qfnia_sat_solver(m, p), - try_for(mk_qfnia_smt_solver(m, p), 2000), - mk_qfnia_nlsat_solver(m, p), - mk_qfnia_smt_solver(m, p))); + return and_then( + mk_report_verbose_tactic("(qfnia-tactic)", 10), + mk_qfnia_premable(m, p), + or_else(mk_qfnia_sat_solver(m, p), + try_for(mk_qfnia_smt_solver(m, p), 2000), + mk_qfnia_nlsat_solver(m, p), + mk_qfnia_smt_solver(m, p))); } diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 767b07b6d..0e5124d58 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -11,7 +11,7 @@ Copyright (c) 2016 Microsoft Corporation #include "tactic/bv/dt2bv_tactic.h" #include "tactic/tactic.h" #include "model/model_smt2_pp.h" -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { return expr_ref(m.mk_const(symbol(name), s), m); diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index e5375a0df..6e418fe68 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -320,7 +320,6 @@ void test_small_lu(lp_settings & settings) { auto columns_to_replace = l.get_set_of_columns_to_replace_for_add_last_rows(heading); l.add_last_rows_to_B(heading, columns_to_replace); - std::cout << "here" << std::endl; lp_assert(l.is_correct(basis)); } diff --git a/src/test/pb2bv.cpp b/src/test/pb2bv.cpp index d58bf61ee..493d81bb7 100644 --- a/src/test/pb2bv.cpp +++ b/src/test/pb2bv.cpp @@ -16,7 +16,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/ast_util.h" #include "ast/pb_decl_plugin.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" #include "solver/solver.h" static void test1() { diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index f5c415c04..2470df528 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -134,16 +134,12 @@ void test_sorting3() { for (unsigned i = 0; i < 7; ++i) { in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); } - for (unsigned i = 0; i < in.size(); ++i) { - std::cout << mk_pp(in[i].get(), m) << "\n"; - } + for (expr* e : in) std::cout << mk_pp(e, m) << "\n"; ast_ext aext(m); sorting_network sn(aext); sn(in, out); std::cout << "size: " << out.size() << "\n"; - for (unsigned i = 0; i < out.size(); ++i) { - std::cout << mk_pp(out[i].get(), m) << "\n"; - } + for (expr* e : out) std::cout << mk_pp(e, m) << "\n"; } @@ -162,10 +158,12 @@ struct ast_ext2 { pliteral mk_false() { return m.mk_false(); } pliteral mk_true() { return m.mk_true(); } - pliteral mk_max(pliteral a, pliteral b) { - return trail(m.mk_or(a, b)); + pliteral mk_max(unsigned n, pliteral const* lits) { + return trail(m.mk_or(n, lits)); + } + pliteral mk_min(unsigned n, pliteral const* lits) { + return trail(m.mk_and(n, lits)); } - pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } @@ -199,8 +197,8 @@ static void test_eq1(unsigned n, sorting_network_encoding enc) { // equality: solver.push(); result1 = sn.eq(true, 1, in.size(), in.c_ptr()); - for (expr* cl : ext.m_clauses) { - solver.assert_expr(cl); + for (expr* cls : ext.m_clauses) { + solver.assert_expr(cls); } expr_ref_vector ors(m); for (unsigned i = 0; i < n; ++i) { @@ -245,12 +243,15 @@ static void test_sorting_eq(unsigned n, unsigned k, sorting_network_encoding enc std::cout << "eq " << k << " out of " << n << " for encoding " << enc << "\n"; solver.push(); result = sn.eq(false, k, in.size(), in.c_ptr()); - std::cout << result << "\n" << ext.m_clauses << "\n"; solver.assert_expr(result); for (expr* cl : ext.m_clauses) { solver.assert_expr(cl); } lbool res = solver.check(); + if (res != l_true) { + std::cout << res << "\n"; + solver.display(std::cout); + } ENSURE(res == l_true); solver.push(); @@ -258,6 +259,9 @@ static void test_sorting_eq(unsigned n, unsigned k, sorting_network_encoding enc solver.assert_expr(in[i].get()); } res = solver.check(); + if (res != l_true) { + std::cout << result << "\n" << ext.m_clauses << "\n"; + } ENSURE(res == l_true); solver.assert_expr(in[k].get()); res = solver.check(); @@ -295,16 +299,26 @@ static void test_sorting_le(unsigned n, unsigned k, sorting_network_encoding enc solver.push(); result = sn.le(false, k, in.size(), in.c_ptr()); solver.assert_expr(result); - for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { - solver.assert_expr(ext.m_clauses[i].get()); + for (expr* cls : ext.m_clauses) { + solver.assert_expr(cls); } lbool res = solver.check(); + if (res != l_true) { + std::cout << res << "\n"; + solver.display(std::cout); + std::cout << "clauses: " << ext.m_clauses << "\n"; + std::cout << "result: " << result << "\n"; + } ENSURE(res == l_true); for (unsigned i = 0; i < k; ++i) { solver.assert_expr(in[i].get()); } res = solver.check(); + if (res != l_true) { + std::cout << res << "\n"; + solver.display(std::cout); + } ENSURE(res == l_true); solver.assert_expr(in[k].get()); res = solver.check(); @@ -343,8 +357,8 @@ void test_sorting_ge(unsigned n, unsigned k, sorting_network_encoding enc) { solver.push(); result = sn.ge(false, k, in.size(), in.c_ptr()); solver.assert_expr(result); - for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { - solver.assert_expr(ext.m_clauses[i].get()); + for (expr* cls : ext.m_clauses) { + solver.assert_expr(cls); } lbool res = solver.check(); ENSURE(res == l_true); @@ -407,13 +421,13 @@ void test_at_most_1(unsigned n, bool full, sorting_network_encoding enc) { std::cout << "clauses: " << ext.m_clauses << "\n-----\n"; - std::cout << "encoded: " << result1 << "\n"; - std::cout << "naive: " << result2 << "\n"; + //std::cout << "encoded: " << result1 << "\n"; + //std::cout << "naive: " << result2 << "\n"; smt_params fp; smt::kernel solver(m, fp); - for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { - solver.assert_expr(ext.m_clauses[i].get()); + for (expr* cls : ext.m_clauses) { + solver.assert_expr(cls); } if (full) { solver.push(); @@ -481,8 +495,8 @@ static void test_at_most1(sorting_network_encoding enc) { sn.cfg().m_encoding = enc; expr_ref result(m); result = sn.le(true, 1, in.size(), in.c_ptr()); - std::cout << result << "\n"; - std::cout << ext.m_clauses << "\n"; + //std::cout << result << "\n"; + //std::cout << ext.m_clauses << "\n"; } static void test_sorting5(sorting_network_encoding enc) { @@ -509,9 +523,11 @@ static void tst_sorting_network(sorting_network_encoding enc) { } void tst_sorting_network() { - tst_sorting_network(sorting_network_encoding::ordered_at_most_1); - tst_sorting_network(sorting_network_encoding::grouped_at_most_1); - tst_sorting_network(sorting_network_encoding::bimander_at_most_1); + tst_sorting_network(sorting_network_encoding::unate_at_most); + tst_sorting_network(sorting_network_encoding::circuit_at_most); + tst_sorting_network(sorting_network_encoding::ordered_at_most); + tst_sorting_network(sorting_network_encoding::grouped_at_most); + tst_sorting_network(sorting_network_encoding::bimander_at_most); test_sorting1(); test_sorting2(); test_sorting3(); diff --git a/src/util/approx_nat.h b/src/util/approx_nat.h index b5e1edb8f..354ead92b 100644 --- a/src/util/approx_nat.h +++ b/src/util/approx_nat.h @@ -21,7 +21,7 @@ Notes: #define APPROX_NAT_H_ #include -#include +#include class approx_nat { unsigned m_value; diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index f9f0a0797..78b7f15aa 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include +#include #include "util/bit_vector.h" #include "util/trace.h" diff --git a/src/util/cooperate.cpp b/src/util/cooperate.cpp index 2b2e7958e..df8f67968 100644 --- a/src/util/cooperate.cpp +++ b/src/util/cooperate.cpp @@ -16,6 +16,8 @@ Author: Notes: --*/ + +#ifndef _NO_OMP_ #include "util/cooperate.h" #include "util/trace.h" #include "util/debug.h" @@ -36,7 +38,7 @@ struct cooperation_lock { } }; -cooperation_lock g_lock; +static cooperation_lock g_lock; bool cooperation_ctx::g_cooperate = false; @@ -59,29 +61,4 @@ void cooperation_ctx::checkpoint(char const * task) { } } -cooperation_section::cooperation_section() { - SASSERT(!cooperation_ctx::enabled()); - SASSERT(!omp_in_parallel()); - cooperation_ctx::g_cooperate = true; -} - -cooperation_section::~cooperation_section() { - SASSERT(cooperation_ctx::enabled()); - cooperation_ctx::g_cooperate = false; -} - -init_task::init_task(char const * task) { - SASSERT(cooperation_ctx::enabled()); - SASSERT(omp_in_parallel()); - cooperation_ctx::checkpoint(task); -} - -init_task::~init_task() { - int tid = omp_get_thread_num(); - if (g_lock.m_owner_thread == tid) { - g_lock.m_owner_thread = -1; - omp_unset_nest_lock(&(g_lock.m_lock)); - } -} - - +#endif diff --git a/src/util/cooperate.h b/src/util/cooperate.h index af2cff55c..6220c4c51 100644 --- a/src/util/cooperate.h +++ b/src/util/cooperate.h @@ -19,10 +19,9 @@ Notes: #ifndef COOPERATE_H_ #define COOPERATE_H_ -class cooperation_section; +#ifndef _NO_OMP_ class cooperation_ctx { - friend class cooperation_section; static bool g_cooperate; public: static bool enabled() { return g_cooperate; } @@ -33,18 +32,8 @@ inline void cooperate(char const * task) { if (cooperation_ctx::enabled()) cooperation_ctx::checkpoint(task); } -// must be declared before "#pragma parallel" to enable cooperation -class cooperation_section { -public: - cooperation_section(); - ~cooperation_section(); -}; - -// must be first declaration inside "#pragma parallel for" -class init_task { -public: - init_task(char const * task); - ~init_task(); -}; +#else +inline void cooperate(char const *) {} +#endif #endif diff --git a/src/util/fixed_bit_vector.cpp b/src/util/fixed_bit_vector.cpp index aafc58404..e227aa524 100644 --- a/src/util/fixed_bit_vector.cpp +++ b/src/util/fixed_bit_vector.cpp @@ -19,7 +19,7 @@ Revision History: --*/ -#include +#include #include "util/fixed_bit_vector.h" #include "util/trace.h" #include "util/hash.h" diff --git a/src/util/hashtable.h b/src/util/hashtable.h index 420e48949..55866065e 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -19,9 +19,9 @@ Revision History: #ifndef HASHTABLE_H_ #define HASHTABLE_H_ #include "util/debug.h" -#include +#include #include "util/util.h" -#include +#include #include "util/memory_manager.h" #include "util/hash.h" #include "util/vector.h" diff --git a/src/util/lp/binary_heap_priority_queue.h b/src/util/lp/binary_heap_priority_queue.h index 9a71fc01e..018d154ab 100644 --- a/src/util/lp/binary_heap_priority_queue.h +++ b/src/util/lp/binary_heap_priority_queue.h @@ -78,8 +78,6 @@ public: lp_assert(m_heap_size > 0); return m_heap[1]; } -#ifdef Z3DEBUG void print(std::ostream & out); -#endif }; } diff --git a/src/util/lp/binary_heap_priority_queue_def.h b/src/util/lp/binary_heap_priority_queue_def.h index 8a39ecdfa..232959c83 100644 --- a/src/util/lp/binary_heap_priority_queue_def.h +++ b/src/util/lp/binary_heap_priority_queue_def.h @@ -194,7 +194,6 @@ template unsigned binary_heap_priority_queue::dequeue() { m_heap_inverse[ret] = -1; return ret; } -#ifdef Z3DEBUG template void binary_heap_priority_queue::print(std::ostream & out) { vector index; vector prs; @@ -210,5 +209,4 @@ template void binary_heap_priority_queue::print(std::ostream & o for (int i = 0; i < index.size(); i++) enqueue(index[i], prs[i]); } -#endif } diff --git a/src/util/lp/bound_analyzer_on_row.h b/src/util/lp/bound_analyzer_on_row.h index 196551f20..549c8e5ce 100644 --- a/src/util/lp/bound_analyzer_on_row.h +++ b/src/util/lp/bound_analyzer_on_row.h @@ -29,65 +29,7 @@ Revision History: namespace lp { template // C plays a role of a container class bound_analyzer_on_row { - struct term_with_basis_col { - const C & m_row; - unsigned m_bj; - struct ival { - unsigned m_var; - const mpq & m_coeff; - ival(unsigned var, const mpq & val) : m_var(var), m_coeff(val) { - } - unsigned var() const { return m_var;} - const mpq & coeff() const { return m_coeff; } - }; - - term_with_basis_col(const C& row, unsigned bj) : m_row(row), m_bj(bj) {} - struct const_iterator { - // fields - typename C::const_iterator m_it; - unsigned m_bj; - - - //typedefs - - - typedef const_iterator self_type; - typedef ival value_type; - typedef ival reference; - typedef int difference_type; - typedef std::forward_iterator_tag iterator_category; - - reference operator*() const { - if (m_bj == static_cast(-1)) - return ival((*m_it).var(), (*m_it).coeff()); - return ival(m_bj, - 1); - } - self_type operator++() { self_type i = *this; operator++(1); return i; } - - self_type operator++(int) { - if (m_bj == static_cast(-1)) - m_it++; - else - m_bj = static_cast(-1); - return *this; - } - - // constructor - const_iterator(const typename C::const_iterator& it, unsigned bj) : - m_it(it), - m_bj(bj) - {} - bool operator==(const self_type &other) const { - return m_it == other.m_it && m_bj == other.m_bj ; - } - bool operator!=(const self_type &other) const { return !(*this == other); } - }; - const_iterator begin() const { - return const_iterator( m_row.begin(), m_bj); - } - const_iterator end() const { return const_iterator(m_row.end(), m_bj); } - }; - term_with_basis_col m_row; + const C& m_row; bound_propagator & m_bp; unsigned m_row_or_term_index; int m_column_of_u; // index of an unlimited from above monoid @@ -105,7 +47,7 @@ public : bound_propagator & bp ) : - m_row(it, bj), + m_row(it), m_bp(bp), m_row_or_term_index(row_or_term_index), m_column_of_u(-1), diff --git a/src/util/lp/core_solver_pretty_printer_def.h b/src/util/lp/core_solver_pretty_printer_def.h index 58ffbb481..dcf3e0a11 100644 --- a/src/util/lp/core_solver_pretty_printer_def.h +++ b/src/util/lp/core_solver_pretty_printer_def.h @@ -100,7 +100,7 @@ template void core_solver_pretty_printer::init_m_ for (unsigned column = 0; column < ncols(); column++) { vector t(nrows(), zero_of_type()); for (const auto & c : m_core_solver.m_A.m_columns[column]){ - t[c.m_i] = m_core_solver.m_A.get_val(c); + t[c.var()] = m_core_solver.m_A.get_val(c); } string name = m_core_solver.column_name(column); diff --git a/src/util/lp/general_matrix.h b/src/util/lp/general_matrix.h index 715f2cb08..1c643161a 100644 --- a/src/util/lp/general_matrix.h +++ b/src/util/lp/general_matrix.h @@ -71,7 +71,6 @@ public: ref_row operator[](unsigned i) { return ref_row(*this, m_data[adjust_row(i)]); } ref_row_const operator[](unsigned i) const { return ref_row_const(*this, m_data[adjust_row(i)]); } -#ifdef Z3DEBUG void print(std::ostream & out, unsigned blanks = 0) const { unsigned m = row_count(); unsigned n = column_count(); @@ -96,8 +95,6 @@ public: print_matrix(m.m_data, out, blanks); } -#endif - void clear() { m_data.clear(); } bool row_is_initialized_correctly(const vector& row) { @@ -108,12 +105,12 @@ public: } template - void init_row_from_container(int i, const T & c, std::function column_fix) { + void init_row_from_container(int i, const T & c, std::function column_fix, const mpq& sign) { auto & row = m_data[adjust_row(i)]; lp_assert(row_is_initialized_correctly(row)); for (const auto & p : c) { unsigned j = adjust_column(column_fix(p.var())); - row[j] = p.coeff(); + row[j] = sign * p.coeff(); } } diff --git a/src/util/lp/hnf.h b/src/util/lp/hnf.h index 3cdeac466..8edce39e0 100644 --- a/src/util/lp/hnf.h +++ b/src/util/lp/hnf.h @@ -317,7 +317,6 @@ class hnf { } void handle_column_ij_in_row_i(unsigned i, unsigned j) { - lp_assert(is_correct_modulo()); const mpq& aii = m_H[i][i]; const mpq& aij = m_H[i][j]; mpq p,q,r; @@ -342,7 +341,7 @@ class hnf { // from the left multiply_U_reverse_from_left_by(i, j, aii_over_r, aij_over_r, -q, p); - lp_assert(is_correct_modulo()); + CASSERT("hnf_test", is_correct_modulo()); } @@ -402,8 +401,6 @@ class hnf { } void process_row(unsigned i) { - - lp_assert(is_correct_modulo()); for (unsigned j = i + 1; j < m_n; j++) { process_row_column(i, j); } @@ -414,7 +411,7 @@ class hnf { if (is_neg(m_H[i][i])) switch_sign_for_column(i); work_on_columns_less_than_i_in_the_triangle(i); - lp_assert(is_correct_modulo()); + CASSERT("hnf_test", is_correct_modulo()); } void calculate() { @@ -604,7 +601,7 @@ public: #ifdef Z3DEBUG prepare_U_and_U_reverse(); calculate(); - lp_assert(is_correct_final()); + CASSERT("hnf_test", is_correct_final()); #endif calculate_by_modulo(); #ifdef Z3DEBUG diff --git a/src/util/lp/hnf_cutter.h b/src/util/lp/hnf_cutter.h index 90cdd5a6d..3f9038651 100644 --- a/src/util/lp/hnf_cutter.h +++ b/src/util/lp/hnf_cutter.h @@ -29,6 +29,7 @@ class hnf_cutter { var_register m_var_register; general_matrix m_A; vector m_terms; + vector m_terms_upper; svector m_constraints_for_explanation; vector m_right_sides; lp_settings & m_settings; @@ -54,15 +55,22 @@ public: // m_A will be filled from scratch in init_matrix_A m_var_register.clear(); m_terms.clear(); + m_terms_upper.clear(); m_constraints_for_explanation.clear(); m_right_sides.clear(); m_abs_max = zero_of_type(); m_overflow = false; } - void add_term(const lar_term* t, const mpq &rs, constraint_index ci) { + void add_term(const lar_term* t, const mpq &rs, constraint_index ci, bool upper_bound) { m_terms.push_back(t); - m_right_sides.push_back(rs); + m_terms_upper.push_back(upper_bound); + if (upper_bound) + m_right_sides.push_back(rs); + else + m_right_sides.push_back(-rs); + m_constraints_for_explanation.push_back(ci); + for (const auto &p : *t) { m_var_register.add_var(p.var()); mpq t = abs(ceil(p.coeff())); @@ -76,7 +84,8 @@ public: } void initialize_row(unsigned i) { - m_A.init_row_from_container(i, * m_terms[i], [this](unsigned j) { return m_var_register.add_var(j);}); + mpq sign = m_terms_upper[i]? one_of_type(): - one_of_type(); + m_A.init_row_from_container(i, * m_terms[i], [this](unsigned j) { return m_var_register.add_var(j);}, sign); } void init_matrix_A() { @@ -162,8 +171,7 @@ public: vector transform_to_local_columns(const vector & x) const { vector ret; for (unsigned j = 0; j < vars().size(); j++) { - lp_assert(is_zero(x[m_var_register.local_to_external(j)].y)); - ret.push_back(x[m_var_register.local_to_external(j)].x); + ret.push_back(x[m_var_register.local_to_external(j)].x); } return ret; } @@ -178,43 +186,41 @@ public: bool overflow() const { return m_overflow; } - lia_move create_cut(lar_term& t, mpq& k, explanation& ex, bool & upper - #ifdef Z3DEBUG - , - const vector & x0 - #endif - ) { + lia_move create_cut(lar_term& t, mpq& k, explanation& ex, bool & upper, const vector & x0) { // we suppose that x0 has at least one non integer element + (void)x0; + init_matrix_A(); svector basis_rows; mpq big_number = m_abs_max.expt(3); mpq d = hnf_calc::determinant_of_rectangular_matrix(m_A, basis_rows, big_number); - // std::cout << "max = " << m_abs_max << ", d = " << d << ", d/max = " << ceil (d /m_abs_max) << std::endl; - //std::cout << "max cube " << m_abs_max * m_abs_max * m_abs_max << std::endl; + // std::cout << "max = " << m_abs_max << ", d = " << d << ", d/max = " << ceil (d /m_abs_max) << std::endl; + // std::cout << "max cube " << m_abs_max * m_abs_max * m_abs_max << std::endl; if (d >= big_number) { return lia_move::undef; } - if (m_settings.get_cancel_flag()) + if (m_settings.get_cancel_flag()) { return lia_move::undef; + } + if (basis_rows.size() < m_A.row_count()) { m_A.shrink_to_rank(basis_rows); shrink_explanation(basis_rows); } - hnf h(m_A, d); - // general_matrix A_orig = m_A; - + hnf h(m_A, d); vector b = create_b(basis_rows); lp_assert(m_A * x0 == b); - // vector bcopy = b; find_h_minus_1_b(h.W(), b); - // lp_assert(bcopy == h.W().take_first_n_columns(b.size()) * b); int cut_row = find_cut_row_index(b); - if (cut_row == -1) + + if (cut_row == -1) { return lia_move::undef; + } + // the matrix is not square - we can get // all integers in b's projection diff --git a/src/util/lp/indexed_vector.cpp b/src/util/lp/indexed_vector.cpp index 180291705..11378f151 100644 --- a/src/util/lp/indexed_vector.cpp +++ b/src/util/lp/indexed_vector.cpp @@ -37,10 +37,10 @@ template bool indexed_vector::is_OK() const; template bool indexed_vector::is_OK() const; template bool indexed_vector::is_OK() const; template bool indexed_vector >::is_OK() const; +#endif template void lp::indexed_vector< lp::mpq>::print(std::basic_ostream > &); template void lp::indexed_vector::print(std::basic_ostream > &); template void lp::indexed_vector >::print(std::ostream&); -#endif } // template void lp::print_vector(vector const&, std::ostream&); // template void lp::print_vector(vector const&, std::ostream&); diff --git a/src/util/lp/indexed_vector.h b/src/util/lp/indexed_vector.h index d6ff4e76a..24078ce84 100644 --- a/src/util/lp/indexed_vector.h +++ b/src/util/lp/indexed_vector.h @@ -172,6 +172,7 @@ public: } unsigned var() const { return m_var;} const T & coeff() const { return m_coeff; } + bool dead() const { return false; } }; struct const_iterator { @@ -216,7 +217,7 @@ public: #ifdef Z3DEBUG bool is_OK() const; - void print(std::ostream & out); #endif + void print(std::ostream & out); }; } diff --git a/src/util/lp/indexed_vector_def.h b/src/util/lp/indexed_vector_def.h index 2f7706089..a133eb379 100644 --- a/src/util/lp/indexed_vector_def.h +++ b/src/util/lp/indexed_vector_def.h @@ -96,6 +96,7 @@ bool indexed_vector::is_OK() const { return true; } +#endif template void indexed_vector::print(std::ostream & out) { out << "m_index " << std::endl; @@ -105,6 +106,5 @@ void indexed_vector::print(std::ostream & out) { out << std::endl; print_vector(m_data, out); } -#endif } diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 0691b5887..a77c202a0 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -324,7 +324,7 @@ lia_move int_solver::mk_gomory_cut( unsigned inf_col, const row_strip & row bool some_int_columns = false; mpq f_0 = int_solver::fractional_part(get_value(inf_col)); mpq one_min_f_0 = 1 - f_0; - for (auto & p : row) { + for (const auto & p : row) { x_j = p.var(); if (x_j == inf_col) continue; @@ -537,8 +537,9 @@ void int_solver::try_add_term_to_A_for_hnf(unsigned i) { mpq rs; const lar_term* t = m_lar_solver->terms()[i]; constraint_index ci; - if (!hnf_cutter_is_full() && m_lar_solver->get_equality_and_right_side_for_term_on_current_x(i, rs, ci)) { - m_hnf_cutter.add_term(t, rs, ci); + bool upper_bound; + if (!hnf_cutter_is_full() && m_lar_solver->get_equality_and_right_side_for_term_on_current_x(i, rs, ci, upper_bound)) { + m_hnf_cutter.add_term(t, rs, ci, upper_bound); } } @@ -577,17 +578,27 @@ lia_move int_solver::make_hnf_cut() { return lia_move::undef; } settings().st().m_hnf_cutter_calls++; - TRACE("hnf_cut", tout << "settings().st().m_hnf_cutter_calls = " << settings().st().m_hnf_cutter_calls;); + TRACE("hnf_cut", tout << "settings().st().m_hnf_cutter_calls = " << settings().st().m_hnf_cutter_calls << "\n"; + for (unsigned i : m_hnf_cutter.constraints_for_explanation()) { + m_lar_solver->print_constraint(i, tout); + } + m_lar_solver->print_constraints(tout); + ); #ifdef Z3DEBUG vector x0 = m_hnf_cutter.transform_to_local_columns(m_lar_solver->m_mpq_lar_core_solver.m_r_x); +#else + vector x0; #endif - lia_move r = m_hnf_cutter.create_cut(*m_t, *m_k, *m_ex, *m_upper -#ifdef Z3DEBUG - , x0 -#endif - ); - CTRACE("hnf_cut", r == lia_move::cut, tout<< "cut:"; m_lar_solver->print_term(*m_t, tout); tout << " <= " << *m_k << std::endl;); - if (r == lia_move::cut) { + lia_move r = m_hnf_cutter.create_cut(*m_t, *m_k, *m_ex, *m_upper, x0); + + if (r == lia_move::cut) { + TRACE("hnf_cut", + m_lar_solver->print_term(*m_t, tout << "cut:"); + tout << " <= " << *m_k << std::endl; + for (unsigned i : m_hnf_cutter.constraints_for_explanation()) { + m_lar_solver->print_constraint(i, tout); + } + ); lp_assert(current_solution_is_inf_on_cut()); settings().st().m_hnf_cuts++; m_ex->clear(); @@ -599,7 +610,10 @@ lia_move int_solver::make_hnf_cut() { } lia_move int_solver::hnf_cut() { - if ((m_number_of_calls) % settings().m_hnf_cut_period == 0) { + if (!settings().m_enable_hnf) { + return lia_move::undef; + } + if ((m_number_of_calls) % settings().hnf_cut_period() == 0) { return make_hnf_cut(); } return lia_move::undef; @@ -1138,13 +1152,13 @@ bool int_solver::at_upper(unsigned j) const { void int_solver::display_row_info(std::ostream & out, unsigned row_index) const { auto & rslv = m_lar_solver->m_mpq_lar_core_solver.m_r_solver; - for (auto &c: rslv.m_A.m_rows[row_index]) { + for (const auto &c: rslv.m_A.m_rows[row_index]) { if (numeric_traits::is_pos(c.coeff())) out << "+"; out << c.coeff() << rslv.column_name(c.var()) << " "; } - for (auto& c: rslv.m_A.m_rows[row_index]) { + for (const auto& c: rslv.m_A.m_rows[row_index]) { rslv.print_column_bound_info(c.var(), out); } rslv.print_column_bound_info(rslv.m_basis[row_index], out); diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 65c818d1e..ec708918d 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -50,7 +50,6 @@ public: // main function to check that the solution provided by lar_solver is valid for integral values, // or provide a way of how it can be adjusted. lia_move check(lar_term& t, mpq& k, explanation& ex, bool & upper); - lia_move check_(lar_term& t, mpq& k, explanation& ex, bool & upper); bool move_non_basic_column_to_bounds(unsigned j); lia_move check_wrapper(lar_term& t, mpq& k, explanation& ex); bool is_base(unsigned j) const; diff --git a/src/util/lp/lar_core_solver.h b/src/util/lp/lar_core_solver.h index 5f5518528..904550339 100644 --- a/src/util/lp/lar_core_solver.h +++ b/src/util/lp/lar_core_solver.h @@ -339,7 +339,7 @@ public: if (!update_xj_and_get_delta(j, pos_type, delta)) continue; for (const auto & cc : m_r_solver.m_A.m_columns[j]){ - unsigned i = cc.m_i; + unsigned i = cc.var(); unsigned jb = m_r_solver.m_basis[i]; m_r_solver.update_x_with_delta_and_track_feasibility(jb, - delta * m_r_solver.m_A.get_val(cc)); } @@ -584,7 +584,6 @@ public: return true; for (unsigned j : m_r_solver.m_basis) { lp_assert(m_r_solver.m_A.m_columns[j].size() == 1); - lp_assert(m_r_solver.m_A.get_val(m_r_solver.m_A.m_columns[j][0]) == one_of_type()); } for (unsigned j =0; j < m_r_solver.m_basis_heading.size(); j++) { if (m_r_solver.m_basis_heading[j] >= 0) continue; @@ -634,7 +633,7 @@ public: for (unsigned i = 0; i < m_r_A.row_count(); i++) { auto & row = m_r_A.m_rows[i]; for (row_cell & c : row) { - A.set(i, c.m_j, c.get_val().get_double()); + A.add_new_element(i, c.var(), c.get_val().get_double()); } } } diff --git a/src/util/lp/lar_core_solver_def.h b/src/util/lp/lar_core_solver_def.h index f9937e77a..b945b0e51 100644 --- a/src/util/lp/lar_core_solver_def.h +++ b/src/util/lp/lar_core_solver_def.h @@ -227,7 +227,7 @@ void lar_core_solver::fill_not_improvable_zero_sum_from_inf_row() { m_infeasible_sum_sign = m_r_solver.inf_sign_of_column(bj); m_infeasible_linear_combination.clear(); for (auto & rc : m_r_solver.m_A.m_rows[m_r_solver.m_inf_row_index_for_tableau]) { - m_infeasible_linear_combination.push_back(std::make_pair( rc.get_val(), rc.m_j)); + m_infeasible_linear_combination.push_back(std::make_pair( rc.get_val(), rc.var())); } } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 8b5d8814a..654eb7017 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -164,7 +164,6 @@ void lar_solver::analyze_new_bounds_on_row_tableau( if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation) return; - lp_assert(use_tableau()); bound_analyzer_on_row>::analyze_row(A_r().m_rows[row_index], static_cast(-1), @@ -216,7 +215,7 @@ void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp bound_j = m_var_register.external_to_local(bound_j); } for (auto const& r : A_r().m_rows[i]) { - unsigned j = r.m_j; + unsigned j = r.var(); if (j == bound_j) continue; mpq const& a = r.get_val(); int a_sign = is_pos(a)? 1: -1; @@ -428,8 +427,8 @@ void lar_solver::set_costs_to_zero(const lar_term& term) { if (i < 0) jset.insert(j); else { - for (auto & rc : A_r().m_rows[i]) - jset.insert(rc.m_j); + for (const auto & rc : A_r().m_rows[i]) + jset.insert(rc.var()); } } @@ -538,12 +537,18 @@ lp_status lar_solver::maximize_term(unsigned ext_j, if (column_value_is_integer(j)) continue; if (m_int_solver->is_base(j)) { - if (!remove_from_basis(j)) // consider a special version of remove_from_basis that would not remove inf_int columns + if (!remove_from_basis(j)) { // consider a special version of remove_from_basis that would not remove inf_int columns + m_mpq_lar_core_solver.m_r_x = backup; + term_max = prev_value; return lp_status::FEASIBLE; // it should not happen + } } m_int_solver->patch_nbasic_column(j, false); - if (!column_value_is_integer(j)) + if (!column_value_is_integer(j)) { + term_max = prev_value; + m_mpq_lar_core_solver.m_r_x = backup; return lp_status::FEASIBLE; + } change = true; } if (change) { @@ -633,7 +638,7 @@ void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j) { for (auto & rc : m_mpq_lar_core_solver.m_r_A.m_columns[j]) - m_rows_with_changed_bounds.insert(rc.m_i); + m_rows_with_changed_bounds.insert(rc.var()); } bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } @@ -661,8 +666,9 @@ void lar_solver::adjust_x_of_column(unsigned j) { bool lar_solver::row_is_correct(unsigned i) const { numeric_pair r = zero_of_type>(); - for (const auto & c : A_r().m_rows[i]) - r += c.m_value * m_mpq_lar_core_solver.m_r_x[c.m_j]; + for (const auto & c : A_r().m_rows[i]) { + r += c.coeff() * m_mpq_lar_core_solver.m_r_x[c.var()]; + } return is_zero(r); } @@ -685,7 +691,7 @@ bool lar_solver::costs_are_used() const { void lar_solver::change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair & delta) { if (use_tableau()) { for (const auto & c : A_r().m_columns[j]) { - unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.m_i]; + unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()]; if (tableau_with_costs()) { m_basic_columns_with_changed_cost.insert(bj); } @@ -784,10 +790,10 @@ numeric_pair lar_solver::get_basic_var_value_from_row_directly(unsigned i) unsigned bj = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; for (const auto & c: A_r().m_rows[i]) { - if (c.m_j == bj) continue; - const auto & x = m_mpq_lar_core_solver.m_r_x[c.m_j]; + if (c.var() == bj) continue; + const auto & x = m_mpq_lar_core_solver.m_r_x[c.var()]; if (!is_zero(x)) - r -= c.m_value * x; + r -= c.coeff() * x; } return r; } @@ -889,7 +895,7 @@ void lar_solver::copy_from_mpq_matrix(static_matrix & matr) { matr.m_columns.resize(A_r().column_count()); for (unsigned i = 0; i < matr.row_count(); i++) { for (auto & it : A_r().m_rows[i]) { - matr.set(i, it.m_j, convert_struct::convert(it.get_val())); + matr.set(i, it.var(), convert_struct::convert(it.get_val())); } } } @@ -1323,14 +1329,14 @@ void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsign int non_zero_column_cell_index = -1; for (unsigned k = last_column.size(); k-- > 0;){ auto & cc = last_column[k]; - if (cc.m_i == i) + if (cc.var() == i) return; non_zero_column_cell_index = k; } lp_assert(non_zero_column_cell_index != -1); lp_assert(static_cast(non_zero_column_cell_index) != i); - m_mpq_lar_core_solver.m_r_solver.transpose_rows_tableau(last_column[non_zero_column_cell_index].m_i, i); + m_mpq_lar_core_solver.m_r_solver.transpose_rows_tableau(last_column[non_zero_column_cell_index].var(), i); } void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { @@ -1348,15 +1354,15 @@ void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { for (unsigned k = last_row.size(); k-- > 0;) { auto &rc = last_row[k]; if (cost_is_nz) { - m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); + m_mpq_lar_core_solver.m_r_solver.m_d[rc.var()] += cost_j*rc.get_val(); } - A_r().remove_element(last_row, rc); } lp_assert(last_row.size() == 0); lp_assert(A_r().m_columns[j].size() == 0); A_r().m_rows.pop_back(); A_r().m_columns.pop_back(); + CASSERT("check_static_matrix", A_r().is_correct()); slv.m_b.pop_back(); } @@ -1507,11 +1513,6 @@ bool lar_solver::column_is_fixed(unsigned j) const { return m_mpq_lar_core_solver.column_is_fixed(j); } - -bool lar_solver::ext_var_is_int(var_index ext_var) const { - return m_var_register.external_is_int(ext_var); -} - // below is the initialization functionality of lar_solver bool lar_solver::strategy_is_undecided() const { @@ -1844,6 +1845,7 @@ void lar_solver::fill_last_row_of_A_d(static_matrix & A, const l unsigned basis_j = A.column_count() - 1; A.set(last_row, basis_j, -1); + lp_assert(A.is_correct()); } void lar_solver::update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) { @@ -2177,44 +2179,10 @@ bool lar_solver::tighten_term_bounds_by_delta(unsigned term_index, const impq& d return true; } -void lar_solver::update_delta_for_terms(const impq & delta, unsigned j, const vector& terms_of_var) { - for (unsigned i : terms_of_var) { - lar_term & t = *m_terms[i]; - auto it = t.m_coeffs.find(j); - unsigned tj = to_column(i + m_terms_start_index); - TRACE("cube", - tout << "t.apply = " << t.apply(m_mpq_lar_core_solver.m_r_x) << ", m_mpq_lar_core_solver.m_r_x[tj]= " << m_mpq_lar_core_solver.m_r_x[tj];); - TRACE("cube", print_term_as_indices(t, tout); - tout << ", it->second = " << it->second; - tout << ", tj = " << tj << ", "; - m_int_solver->display_column(tout, tj); - ); - - m_mpq_lar_core_solver.m_r_x[tj] += it->second * delta; - lp_assert(t.apply(m_mpq_lar_core_solver.m_r_x) == m_mpq_lar_core_solver.m_r_x[tj]); - TRACE("cube", m_int_solver->display_column(tout, tj); ); - } -} - - -void lar_solver::fill_vars_to_terms(vector> & vars_to_terms) { - for (unsigned j = 0; j < m_terms.size(); j++) { - if (!term_is_used_as_row(j + m_terms_start_index)) - continue; - for (const auto & p : *m_terms[j]) { - if (p.var() >= vars_to_terms.size()) - vars_to_terms.resize(p.var() + 1); - vars_to_terms[p.var()].push_back(j); - } - } -} void lar_solver::round_to_integer_solution() { - vector> vars_to_terms; - fill_vars_to_terms(vars_to_terms); - for (unsigned j = 0; j < column_count(); j++) { - if (column_is_int(j)) continue; + if (!column_is_int(j)) continue; if (column_corresponds_to_term(j)) continue; TRACE("cube", m_int_solver->display_column(tout, j);); impq& v = m_mpq_lar_core_solver.m_r_x[j]; @@ -2228,39 +2196,51 @@ void lar_solver::round_to_integer_solution() { } else { v = flv; } - TRACE("cube", m_int_solver->display_column(tout, j); tout << "v = " << v << " ,del = " << del;); - update_delta_for_terms(del, j, vars_to_terms[j]); } } +// return true if all y coords are zeroes +bool lar_solver::sum_first_coords(const lar_term& t, mpq & val) const { + val = zero_of_type(); + for (const auto & c : t) { + const auto & x = m_mpq_lar_core_solver.m_r_x[c.var()]; + if (!is_zero(x.y)) + return false; + val += x.x * c.coeff(); + } + return true; +} -bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term_index, mpq & rs, constraint_index& ci) const { +bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term_index, mpq & rs, constraint_index& ci, bool &upper_bound) const { unsigned tj = term_index + m_terms_start_index; unsigned j; bool is_int; if (m_var_register.external_is_used(tj, j, is_int) == false) - return false; // the term does not have bound because it does not correspond to a column + return false; // the term does not have a bound because it does not correspond to a column if (!is_int) // todo - allow for the next version of hnf return false; - impq term_val; - bool term_val_ready = false; + bool rs_is_calculated = false; mpq b; bool is_strict; + const lar_term& t = *terms()[term_index]; if (has_upper_bound(j, ci, b, is_strict) && !is_strict) { lp_assert(b.is_int()); - term_val = terms()[term_index]->apply(m_mpq_lar_core_solver.m_r_x); - term_val_ready = true; - if (term_val.x == b) { - rs = b; + if (!sum_first_coords(t, rs)) + return false; + rs_is_calculated = true; + if (rs == b) { + upper_bound = true; return true; } } if (has_lower_bound(j, ci, b, is_strict) && !is_strict) { - if (!term_val_ready) - term_val = terms()[term_index]->apply(m_mpq_lar_core_solver.m_r_x); + if (!rs_is_calculated){ + if (!sum_first_coords(t, rs)) + return false; + } lp_assert(b.is_int()); - if (term_val.x == b) { - rs = b; + if (rs == b) { + upper_bound = false; return true; } } @@ -2268,16 +2248,16 @@ bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term } void lar_solver::set_cut_strategy(unsigned cut_frequency) { - if (cut_frequency < 4) { // enable only gomory cut - settings().m_int_gomory_cut_period = 2; - settings().m_hnf_cut_period = 100000000; + if (cut_frequency < 4) { + settings().m_int_gomory_cut_period = 2; // do it often + settings().set_hnf_cut_period(4); // also create hnf cuts } else if (cut_frequency == 4) { // enable all cuts and cube equally settings().m_int_gomory_cut_period = 4; - settings().m_hnf_cut_period = 4; + settings().set_hnf_cut_period(4); } else { - // disable all heuristics + // disable all heuristics except cube settings().m_int_gomory_cut_period = 10000000; - settings().m_hnf_cut_period = 100000000; + settings().set_hnf_cut_period(100000000); } } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 9f79ff835..283c13c38 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -112,7 +112,7 @@ private: public : unsigned terms_start_index() const { return m_terms_start_index; } - const vector terms() const { return m_terms; } + const vector & terms() const { return m_terms; } const vector& constraints() const { return m_constraints; } @@ -155,8 +155,6 @@ public: bool var_is_int(var_index v) const; - bool ext_var_is_int(var_index ext_var) const; - void add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int); void add_new_var_to_core_fields_for_doubles(bool register_in_basis); @@ -249,6 +247,8 @@ public: void calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp); unsigned adjust_column_index_to_term_index(unsigned j) const; + + var_index local2external(var_index idx) const { return m_var_register.local_to_external(idx); } void propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset); @@ -575,9 +575,10 @@ public: unsigned column_count() const { return A_r().column_count(); } const vector & r_basis() const { return m_mpq_lar_core_solver.r_basis(); } const vector & r_nbasis() const { return m_mpq_lar_core_solver.r_nbasis(); } - bool get_equality_and_right_side_for_term_on_current_x(unsigned i, mpq &rs, constraint_index& ci) const; + bool get_equality_and_right_side_for_term_on_current_x(unsigned i, mpq &rs, constraint_index& ci, bool &upper_bound) const; bool remove_from_basis(unsigned); lar_term get_term_to_maximize(unsigned ext_j) const; void set_cut_strategy(unsigned cut_frequency); + bool sum_first_coords(const lar_term& t, mpq & val) const; }; } diff --git a/src/util/lp/lia_move.h b/src/util/lp/lia_move.h index ec4643e20..65da5826e 100644 --- a/src/util/lp/lia_move.h +++ b/src/util/lp/lia_move.h @@ -28,4 +28,25 @@ enum class lia_move { undef, unsat }; +inline std::string lia_move_to_string(lia_move m) { + switch (m) { + case lia_move::sat: + return "sat"; + case lia_move::branch: + return "branch"; + case lia_move::cut: + return "cut"; + case lia_move::conflict: + return "conflict"; + case lia_move::continue_with_check: + return "continue_with_check"; + case lia_move::undef: + return "undef"; + case lia_move::unsat: + return "unsat"; + default: + lp_assert(false); + }; + return "strange"; +} } diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index b8b7b7c0d..41b6fe31d 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -209,12 +209,18 @@ public: bool need_to_pivot_to_basis_tableau() const { - lp_assert(m_A.is_correct()); unsigned m = m_A.row_count(); for (unsigned i = 0; i < m; i++) { unsigned bj = m_basis[i]; lp_assert(m_A.m_columns[bj].size() > 0); - if (m_A.m_columns[bj].size() > 1 || m_A.get_val(m_A.m_columns[bj][0]) != one_of_type()) return true; + if (m_A.m_columns[bj].size() > 1) + return true; + for (const auto & c : m_A.m_columns[bj]) { + if (m_A.get_val(c) != one_of_type()) + return true; + else + break; + } } return false; } @@ -222,7 +228,7 @@ public: bool reduced_costs_are_correct_tableau() const { if (m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) return true; - lp_assert(m_A.is_correct()); + CASSERT("check_static_matrix", m_A.is_correct()); if (m_using_infeas_costs) { if (infeasibility_costs_are_correct() == false) { return false; @@ -237,8 +243,8 @@ public: } } else { auto d = m_costs[j]; - for (auto & cc : this->m_A.m_columns[j]) { - d -= this->m_costs[this->m_basis[cc.m_i]] * this->m_A.get_val(cc); + for (const auto & cc : this->m_A.m_columns[j]) { + d -= this->m_costs[this->m_basis[cc.var()]] * this->m_A.get_val(cc); } if (m_d[j] != d) { return false; @@ -638,14 +644,6 @@ public: return true; } - int find_pivot_index_in_row(unsigned i, const vector & col) const { - for (const auto & c: col) { - if (c.m_i == i) - return c.m_offset; - } - return -1; - } - void transpose_rows_tableau(unsigned i, unsigned ii); void pivot_to_reduced_costs_tableau(unsigned i, unsigned j); diff --git a/src/util/lp/lp_core_solver_base_def.h b/src/util/lp/lp_core_solver_base_def.h index f20eaf042..c3a0a0a00 100644 --- a/src/util/lp/lp_core_solver_base_def.h +++ b/src/util/lp/lp_core_solver_base_def.h @@ -103,10 +103,10 @@ pivot_to_reduced_costs_tableau(unsigned i, unsigned j) { T &a = m_d[j]; if (is_zero(a)) return; - for (const row_cell & r: m_A.m_rows[i]) - if (r.m_j != j) - m_d[r.m_j] -= a * r.get_val(); - + for (const row_cell & r: m_A.m_rows[i]){ + if (r.var() != j) + m_d[r.var()] -= a * r.get_val(); + } a = zero_of_type(); // zero the pivot column's m_d finally } @@ -309,7 +309,7 @@ calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned pivot_row) { continue; } for (auto & c : m_A.m_rows[i]) { - unsigned j = c.m_j; + unsigned j = c.var(); if (m_basis_heading[j] < 0) { m_pivot_row.add_value_at_index_with_drop_tolerance(j, c.get_val() * pi_1); } @@ -331,7 +331,7 @@ update_x(unsigned entering, const X& delta) { } else for (const auto & c : m_A.m_columns[entering]) { - unsigned i = c.m_i; + unsigned i = c.var(); m_x[m_basis[i]] -= delta * m_A.get_val(c); } } @@ -449,7 +449,7 @@ rs_minus_Anx(vector & rs) { while (row--) { auto &rsv = rs[row] = m_b[row]; for (auto & it : m_A.m_rows[row]) { - unsigned j = it.m_j; + unsigned j = it.var(); if (m_basis_heading[j] < 0) { rsv -= m_x[j] * it.get_val(); } @@ -591,7 +591,8 @@ divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { auto & row = m_A.m_rows[pivot_row]; unsigned size = row.size(); for (unsigned j = 0; j < size; j++) { - if (row[j].m_j == pivot_col) { + auto & c = row[j]; + if (c.var() == pivot_col) { pivot_index = static_cast(j); break; } @@ -599,16 +600,19 @@ divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { if (pivot_index == -1) return false; auto & pivot_cell = row[pivot_index]; - if (is_zero(pivot_cell.m_value)) + T & coeff = pivot_cell.coeff(); + if (is_zero(coeff)) return false; - this->m_b[pivot_row] /= pivot_cell.m_value; + this->m_b[pivot_row] /= coeff; for (unsigned j = 0; j < size; j++) { - if (row[j].m_j != pivot_col) { - row[j].m_value /= pivot_cell.m_value; + auto & c = row[j]; + if (c.var() != pivot_col) { + c.coeff() /= coeff; } } - pivot_cell.m_value = one_of_type(); + coeff = one_of_type(); + CASSERT("check_static_matrix", m_A.is_correct()); return true; } template bool lp_core_solver_base:: @@ -618,7 +622,7 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { auto &column = m_A.m_columns[j]; int pivot_col_cell_index = -1; for (unsigned k = 0; k < column.size(); k++) { - if (column[k].m_i == piv_row_index) { + if (column[k].var() == piv_row_index) { pivot_col_cell_index = k; break; } @@ -634,16 +638,16 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { column[pivot_col_cell_index] = c; m_A.m_rows[piv_row_index][column[0].m_offset].m_offset = 0; - m_A.m_rows[c.m_i][c.m_offset].m_offset = pivot_col_cell_index; + m_A.m_rows[c.var()][c.m_offset].m_offset = pivot_col_cell_index; } while (column.size() > 1) { auto & c = column.back(); - lp_assert(c.m_i != piv_row_index); + lp_assert(c.var() != piv_row_index); if(! m_A.pivot_row_to_row_given_cell(piv_row_index, c, j)) { return false; } if (m_pivoted_rows!= nullptr) - m_pivoted_rows->insert(c.m_i); + m_pivoted_rows->insert(c.var()); } if (m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs) @@ -758,10 +762,10 @@ fill_reduced_costs_from_m_y_by_rows() { while (i--) { const T & y = m_y[i]; if (is_zero(y)) continue; - for (row_cell & it : m_A.m_rows[i]) { - j = it.m_j; + for (row_cell & c : m_A.m_rows[i]) { + j = c.var(); if (m_basis_heading[j] < 0) { - m_d[j] -= y * it.get_val(); + m_d[j] -= y * c.get_val(); } } } @@ -802,7 +806,7 @@ find_error_in_BxB(vector& rs){ while (row--) { auto &rsv = rs[row]; for (auto & it : m_A.m_rows[row]) { - unsigned j = it.m_j; + unsigned j = it.var(); if (m_basis_heading[j] >= 0) { rsv -= m_x[j] * it.get_val(); } @@ -1043,8 +1047,8 @@ void lp_core_solver_base::calculate_pivot_row(unsigned i) { if (m_settings.use_tableau()) { unsigned basic_j = m_basis[i]; for (auto & c : m_A.m_rows[i]) { - if (c.m_j != basic_j) - m_pivot_row.set_value(c.get_val(), c.m_j); + if (c.var() != basic_j) + m_pivot_row.set_value(c.get_val(), c.var()); } return; } diff --git a/src/util/lp/lp_params.pyg b/src/util/lp/lp_params.pyg index 7731536f0..1ef788241 100644 --- a/src/util/lp/lp_params.pyg +++ b/src/util/lp/lp_params.pyg @@ -5,6 +5,7 @@ def_module_params('lp', ('min', BOOL, False, 'minimize cost'), ('print_stats', BOOL, False, 'print statistic'), ('simplex_strategy', UINT, 0, 'simplex strategy for the solver'), + ('enable_hnf', BOOL, True, 'enable hnf cuts'), ('bprop_on_pivoted_rows', BOOL, True, 'propagate bounds on rows changed by the pivot operation') )) diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index 26fc550b3..db92edb05 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -172,7 +172,7 @@ public: bool monoid_can_decrease(const row_cell & rc) const { - unsigned j = rc.m_j; + unsigned j = rc.var(); lp_assert(this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::free_column: @@ -205,7 +205,7 @@ public: } bool monoid_can_increase(const row_cell & rc) const { - unsigned j = rc.m_j; + unsigned j = rc.var(); lp_assert(this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::free_column: @@ -239,8 +239,8 @@ public: unsigned get_number_of_basic_vars_that_might_become_inf(unsigned j) const { // consider looking at the signs here: todo unsigned r = 0; - for (auto & cc : this->m_A.m_columns[j]) { - unsigned k = this->m_basis[cc.m_i]; + for (const auto & cc : this->m_A.m_columns[j]) { + unsigned k = this->m_basis[cc.var()]; if (this->m_column_types[k] != column_type::free_column) r++; } @@ -253,7 +253,7 @@ public: unsigned bj = this->m_basis[i]; bool bj_needs_to_grow = needs_to_grow(bj); for (const row_cell& rc : this->m_A.m_rows[i]) { - if (rc.m_j == bj) + if (rc.var() == bj) continue; if (bj_needs_to_grow) { if (!monoid_can_decrease(rc)) @@ -262,9 +262,9 @@ public: if (!monoid_can_increase(rc)) continue; } - if (rc.m_j < static_cast(j) ) { - j = rc.m_j; - a_ent = rc.m_value; + if (rc.var() < static_cast(j) ) { + j = rc.var(); + a_ent = rc.coeff(); } } if (j == -1) { @@ -278,13 +278,15 @@ public: if (m_bland_mode_tableau) return find_beneficial_column_in_row_tableau_rows_bland_mode(i, a_ent); // a short row produces short infeasibility explanation and benefits at least one pivot operation - vector*> choices; + int choice = -1; + int nchoices = 0; unsigned num_of_non_free_basics = 1000000; unsigned len = 100000000; unsigned bj = this->m_basis[i]; bool bj_needs_to_grow = needs_to_grow(bj); - for (const row_cell& rc : this->m_A.m_rows[i]) { - unsigned j = rc.m_j; + for (unsigned k = 0; k < this->m_A.m_rows[i].size(); k++) { + const row_cell& rc = this->m_A.m_rows[i][k]; + unsigned j = rc.var(); if (j == bj) continue; if (bj_needs_to_grow) { @@ -298,25 +300,23 @@ public: if (damage < num_of_non_free_basics) { num_of_non_free_basics = damage; len = this->m_A.m_columns[j].size(); - choices.clear(); - choices.push_back(&rc); + choice = k; + nchoices = 1; } else if (damage == num_of_non_free_basics && - this->m_A.m_columns[j].size() <= len && (this->m_settings.random_next() % 2)) { - choices.push_back(&rc); + this->m_A.m_columns[j].size() <= len && (this->m_settings.random_next() % (++nchoices))) { + choice = k; len = this->m_A.m_columns[j].size(); } } - if (choices.size() == 0) { + if (choice == -1) { m_inf_row_index_for_tableau = i; return -1; } - const row_cell* rc = choices.size() == 1? choices[0] : - choices[this->m_settings.random_next() % choices.size()]; - - a_ent = rc->m_value; - return rc->m_j; + const row_cell& rc = this->m_A.m_rows[i][choice]; + a_ent = rc.coeff(); + return rc.var(); } static X positive_infinity() { return convert_struct::convert(std::numeric_limits::max()); @@ -881,7 +881,7 @@ public: lp_assert(this->m_basis_heading[j] >= 0); unsigned i = static_cast(this->m_basis_heading[j]); for (const row_cell & rc : this->m_A.m_rows[i]) { - unsigned k = rc.m_j; + unsigned k = rc.var(); if (k == j) continue; this->m_d[k] += delta * rc.get_val(); diff --git a/src/util/lp/lp_primal_core_solver_tableau_def.h b/src/util/lp/lp_primal_core_solver_tableau_def.h index f85c131a3..8f9cf7ff1 100644 --- a/src/util/lp/lp_primal_core_solver_tableau_def.h +++ b/src/util/lp/lp_primal_core_solver_tableau_def.h @@ -269,7 +269,7 @@ template int lp_primal_core_solver::find_leaving_ unsigned col_size = col.size(); for (;k < col_size && unlimited; k++) { const column_cell & c = col[k]; - unsigned i = c.m_i; + unsigned i = c.var(); const T & ed = this->m_A.get_val(c); lp_assert(!numeric_traits::is_zero(ed)); unsigned j = this->m_basis[i]; @@ -288,7 +288,7 @@ template int lp_primal_core_solver::find_leaving_ X ratio; for (;k < col_size; k++) { const column_cell & c = col[k]; - unsigned i = c.m_i; + unsigned i = c.var(); const T & ed = this->m_A.get_val(c); lp_assert(!numeric_traits::is_zero(ed)); unsigned j = this->m_basis[i]; @@ -348,6 +348,7 @@ template void lp_primal_core_solver::init_run_tab template bool lp_primal_core_solver:: update_basis_and_x_tableau(int entering, int leaving, X const & tt) { lp_assert(this->use_tableau()); + lp_assert(entering != leaving); update_x_tableau(entering, tt); this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); this->change_basis(entering, leaving); @@ -358,7 +359,7 @@ update_x_tableau(unsigned entering, const X& delta) { this->add_delta_to_x_and_call_tracker(entering, delta); if (!this->m_using_infeas_costs) { for (const auto & c : this->m_A.m_columns[entering]) { - unsigned i = c.m_i; + unsigned i = c.var(); this->update_x_with_delta_and_track_feasibility(this->m_basis[i], - delta * this->m_A.get_val(c)); } } else { // m_using_infeas_costs == true @@ -366,7 +367,7 @@ update_x_tableau(unsigned entering, const X& delta) { lp_assert(this->m_costs[entering] == zero_of_type()); // m_d[entering] can change because of the cost change for basic columns. for (const auto & c : this->m_A.m_columns[entering]) { - unsigned i = c.m_i; + unsigned i = c.var(); unsigned j = this->m_basis[i]; this->add_delta_to_x_and_call_tracker(j, -delta * this->m_A.get_val(c)); update_inf_cost_for_column_tableau(j); @@ -407,7 +408,7 @@ template void lp_primal_core_solver::init_reduced else { T& d = this->m_d[j] = this->m_costs[j]; for (auto & cc : this->m_A.m_columns[j]) { - d -= this->m_costs[this->m_basis[cc.m_i]] * this->m_A.get_val(cc); + d -= this->m_costs[this->m_basis[cc.var()]] * this->m_A.get_val(cc); } } } diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index b2e785064..dd19df23a 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -189,13 +189,19 @@ public: unsigned column_number_threshold_for_using_lu_in_lar_solver; unsigned m_int_gomory_cut_period; unsigned m_int_find_cube_period; +private: unsigned m_hnf_cut_period; +public: bool m_int_run_gcd_test; bool m_int_pivot_fixed_vars_from_basis; bool m_int_patch_only_integer_values; unsigned limit_on_rows_for_hnf_cutter; unsigned limit_on_columns_for_hnf_cutter; + bool m_enable_hnf; + + unsigned hnf_cut_period() const { return m_hnf_cut_period; } + void set_hnf_cut_period(unsigned period) { m_hnf_cut_period = period; } unsigned random_next() { return m_rand(); } void set_random_seed(unsigned s) { m_rand.set_seed(s); } @@ -258,7 +264,8 @@ public: m_int_pivot_fixed_vars_from_basis(false), m_int_patch_only_integer_values(true), limit_on_rows_for_hnf_cutter(75), - limit_on_columns_for_hnf_cutter(150) + limit_on_columns_for_hnf_cutter(150), + m_enable_hnf(true) {} void set_resource_limit(lp_resource_limit& lim) { m_resource_limit = &lim; } diff --git a/src/util/lp/lu.cpp b/src/util/lp/lu.cpp index e6df10908..ac29dd71a 100644 --- a/src/util/lp/lu.cpp +++ b/src/util/lp/lu.cpp @@ -42,11 +42,11 @@ template void init_factorization> template void init_factorization> (lu>*&, static_matrix&, vector&, lp_settings&); template void init_factorization>(lu >*&, static_matrix&, vector&, lp_settings&); -#ifdef Z3DEBUG template void print_matrix>(square_sparse_matrix&, std::ostream & out); template void print_matrix>(static_matrix&, std::ostream&); template void print_matrix >(static_matrix&, std::ostream&); template void print_matrix>(static_matrix&, std::ostream & out); +#ifdef Z3DEBUG template bool lu>::is_correct(const vector& basis); template bool lu>::is_correct( vector const &); template dense_matrix get_B>(lu>&, const vector& basis); diff --git a/src/util/lp/lu.h b/src/util/lp/lu.h index 820786d87..95c00414e 100644 --- a/src/util/lp/lu.h +++ b/src/util/lp/lu.h @@ -39,15 +39,12 @@ Revision History: #include "util/lp/square_dense_submatrix.h" #include "util/lp/dense_matrix.h" namespace lp { -#ifdef Z3DEBUG template // print the nr x nc submatrix at the top left corner void print_submatrix(square_sparse_matrix & m, unsigned mr, unsigned nc); template void print_matrix(M &m, std::ostream & out); -#endif - template X dot_product(const vector & a, const vector & b) { lp_assert(a.size() == b.size()); @@ -333,11 +330,11 @@ public: for (unsigned i = m_prev; i < m; i++) { for (const row_cell & c : m_A.m_rows[i]) { - int h = heading[c.m_j]; + int h = heading[c.var()]; if (h < 0) { continue; } - columns_to_replace.insert(c.m_j); + columns_to_replace.insert(c.var()); } } return columns_to_replace; diff --git a/src/util/lp/lu_def.h b/src/util/lp/lu_def.h index be4cd724d..00d0466b7 100644 --- a/src/util/lp/lu_def.h +++ b/src/util/lp/lu_def.h @@ -25,7 +25,6 @@ Revision History: #include "util/debug.h" #include "util/lp/lu.h" namespace lp { -#ifdef Z3DEBUG template // print the nr x nc submatrix at the top left corner void print_submatrix(square_sparse_matrix & m, unsigned mr, unsigned nc, std::ostream & out) { vector> A; @@ -62,9 +61,6 @@ void print_matrix(M &m, std::ostream & out) { print_matrix_with_widths(A, widths, out); } -#endif - - template one_elem_on_diag::one_elem_on_diag(const one_elem_on_diag & o) { m_i = o.m_i; @@ -390,7 +386,7 @@ void lu< M>::find_error_of_yB_indexed(const indexed_vector& y, const vector -template void lp::print_matrix(lp::matrix const*, std::ostream & out); +#ifdef Z3DEBUG template bool lp::matrix::is_equal(lp::matrix const&); -template void lp::print_matrix >(lp::matrix > const *, std::basic_ostream > &); -template void lp::print_matrix(lp::matrix const*, std::ostream&); template bool lp::matrix >::is_equal(lp::matrix > const&); template bool lp::matrix::is_equal(lp::matrix const&); #endif +template void lp::print_matrix(lp::matrix const*, std::ostream & out); +template void lp::print_matrix >(lp::matrix > const *, std::basic_ostream > &); +template void lp::print_matrix(lp::matrix const*, std::ostream&); diff --git a/src/util/lp/matrix.h b/src/util/lp/matrix.h index 063513287..8b2fc4220 100644 --- a/src/util/lp/matrix.h +++ b/src/util/lp/matrix.h @@ -17,7 +17,6 @@ Revision History: --*/ -#ifdef Z3DEBUG #pragma once #include "util/lp/numeric_pair.h" #include "util/vector.h" @@ -70,4 +69,3 @@ void print_matrix(const vector> & A, std::ostream & out, unsigned blan } -#endif diff --git a/src/util/lp/matrix_def.h b/src/util/lp/matrix_def.h index ae5f05ad1..361540cae 100644 --- a/src/util/lp/matrix_def.h +++ b/src/util/lp/matrix_def.h @@ -18,11 +18,11 @@ Revision History: --*/ -#ifdef Z3DEBUG #include #include #include "util/lp/matrix.h" namespace lp { +#ifdef Z3DEBUG template bool matrix::is_equal(const matrix& other) { if (other.row_count() != row_count() || other.column_count() != column_count()) @@ -67,7 +67,7 @@ void apply_to_vector(matrix & m, T * w) { delete [] wc; } - +#endif unsigned get_width_of_column(unsigned j, vector> & A) { unsigned r = 0; @@ -132,4 +132,3 @@ void print_matrix(matrix const * m, std::ostream & out) { } } -#endif diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index b1ca67274..0d28058e8 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -24,11 +24,12 @@ namespace nra { lp::lar_solver& s; reslimit& m_limit; params_ref m_params; - u_map m_lp2nl; // map from lar_solver variables to nlsat::solver variables + u_map m_lp2nl; // map from lar_solver variables to nlsat::solver variables scoped_ptr m_nlsat; + scoped_ptr m_zero; vector m_monomials; unsigned_vector m_monomials_lim; - mutable std::unordered_map m_variable_values; // current model + mutable std::unordered_map m_variable_values; // current model imp(lp::lar_solver& s, reslimit& lim, params_ref const& p): s(s), @@ -90,6 +91,7 @@ namespace nra { lbool check(lp::explanation_t& ex) { SASSERT(need_check()); m_nlsat = alloc(nlsat::solver, m_limit, m_params, false); + m_zero = alloc(scoped_anum, am()); m_lp2nl.reset(); vector core; @@ -104,7 +106,18 @@ namespace nra { } // TBD: add variable bounds? - lbool r = m_nlsat->check(); + lbool r = l_undef; + try { + r = m_nlsat->check(); + } + catch (z3_exception&) { + if (m_limit.get_cancel_flag()) { + r = l_undef; + } + else { + throw; + } + } TRACE("arith", display(tout); m_nlsat->display(tout << r << "\n");); switch (r) { case l_true: @@ -197,12 +210,17 @@ namespace nra { if (!m_lp2nl.find(v, r)) { r = m_nlsat->mk_var(is_int(v)); m_lp2nl.insert(v, r); + TRACE("arith", tout << "v" << v << " := x" << r << "\n";); } return r; } nlsat::anum const& value(lp::var_index v) const { - return m_nlsat->value(m_lp2nl.find(v)); + polynomial::var pv; + if (m_lp2nl.find(v, pv)) + return m_nlsat->value(pv); + else + return *m_zero; } nlsat::anum_manager& am() { diff --git a/src/util/lp/random_updater_def.h b/src/util/lp/random_updater_def.h index 419335aa3..c972cc175 100644 --- a/src/util/lp/random_updater_def.h +++ b/src/util/lp/random_updater_def.h @@ -84,7 +84,7 @@ void random_updater::add_column_to_sets(unsigned j) { } else { unsigned row = m_lar_solver.get_core_solver().m_r_heading[j]; for (auto & row_c : m_lar_solver.get_core_solver().m_r_A.m_rows[row]) { - unsigned cj = row_c.m_j; + unsigned cj = row_c.var(); if (m_lar_solver.get_core_solver().m_r_heading[cj] < 0) { m_var_set.insert(cj); add_value(m_lar_solver.get_core_solver().m_r_x[cj]); diff --git a/src/util/lp/square_sparse_matrix.h b/src/util/lp/square_sparse_matrix.h index d84a8a289..cb5193b2d 100644 --- a/src/util/lp/square_sparse_matrix.h +++ b/src/util/lp/square_sparse_matrix.h @@ -40,9 +40,7 @@ namespace lp { // it is a square matrix template class square_sparse_matrix -#ifdef Z3DEBUG : public matrix -#endif { struct col_header { unsigned m_shortened_markovitz; @@ -173,10 +171,8 @@ public: unsigned dimension() const {return static_cast(m_row_permutation.size());} -#ifdef Z3DEBUG unsigned row_count() const override {return dimension();} unsigned column_count() const override {return dimension();} -#endif void init_row_headers(); @@ -309,13 +305,11 @@ public: template void solve_U_y_indexed_only(indexed_vector & y, const lp_settings&, vector & sorted_active_rows ); -#ifdef Z3DEBUG T get_elem(unsigned i, unsigned j) const override { return get(i, j); } unsigned get_number_of_rows() const { return dimension(); } unsigned get_number_of_columns() const { return dimension(); } void set_number_of_rows(unsigned /*m*/) override { } void set_number_of_columns(unsigned /*n*/) override { } -#endif template L dot_product_with_row (unsigned row, const vector & y) const; diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h index e4bf257f4..bb6cdefc8 100644 --- a/src/util/lp/static_matrix.h +++ b/src/util/lp/static_matrix.h @@ -29,14 +29,6 @@ Revision History: #include namespace lp { -struct column_cell { - unsigned m_i; // points to the row - unsigned m_offset; // the offset of the element in the matrix row - column_cell(unsigned i, unsigned offset) : m_i(i), m_offset(offset) { - } - -}; - template struct row_cell { unsigned m_j; // points to the column @@ -44,13 +36,22 @@ struct row_cell { T m_value; row_cell(unsigned j, unsigned offset, T const & val) : m_j(j), m_offset(offset), m_value(val) { } + row_cell(unsigned j, unsigned offset) : m_j(j), m_offset(offset) { + } const T & get_val() const { return m_value;} T & get_val() { return m_value;} - void set_val(const T& v) { m_value = v; } - unsigned var() const { return m_j;} const T & coeff() const { return m_value;} + T & coeff() { return m_value;} + unsigned var() const { return m_j;} + unsigned & var() { return m_j;} + unsigned offset() const { return m_offset;} + unsigned & offset() { return m_offset;} + }; +struct empty_struct {}; +typedef row_cell column_cell; + template using row_strip = vector>; @@ -98,7 +99,7 @@ public: public: const T & get_val(const column_cell & c) const { - return m_rows[c.m_i][c.m_offset].get_val(); + return m_rows[c.var()][c.m_offset].get_val(); } column_cell & get_column_cell(const row_cell &rc) { @@ -146,8 +147,8 @@ public: void multiply_column(unsigned column, T const & alpha) { for (auto & t : m_columns[column]) { - auto & r = m_rows[t.m_i][t.m_offset]; - r.m_value *= alpha; + auto & r = m_rows[t.var()][t.offset()]; + r.coeff() *= alpha; } } @@ -176,7 +177,7 @@ public: T get_max_abs_in_row(unsigned row) const; void add_column_to_vector (const T & a, unsigned j, T * v) const { for (const auto & it : m_columns[j]) { - v[it.m_i] += a * get_val(it); + v[it.var()] += a * get_val(it); } } @@ -241,7 +242,7 @@ public: for (auto & c : row) { unsigned j = c.m_j; auto & col = m_columns[j]; - lp_assert(col[col.size() - 1].m_i == m_rows.size() -1 ); // todo : start here!!!! + lp_assert(col[col.size() - 1].var() == m_rows.size() -1 ); // todo : start here!!!! col.pop_back(); } } @@ -287,7 +288,7 @@ public: lp_assert(j < column_count()); T ret = numeric_traits::zero(); for (auto & it : m_columns[j]) { - ret += y[it.m_i] * get_val(it); // get_value_of_column_cell(it); + ret += y[it.var()] * get_val(it); // get_value_of_column_cell(it); } return ret; } @@ -303,13 +304,13 @@ public: // now fix the columns for (auto & rc : m_rows[i]) { column_cell & cc = m_columns[rc.m_j][rc.m_offset]; - lp_assert(cc.m_i == ii); - cc.m_i = i; + lp_assert(cc.var() == ii); + cc.var() = i; } for (auto & rc : m_rows[ii]) { column_cell & cc = m_columns[rc.m_j][rc.m_offset]; - lp_assert(cc.m_i == i); - cc.m_i = ii; + lp_assert(cc.var() == i); + cc.var() = ii; } } @@ -377,7 +378,7 @@ public: for (auto & it : m_columns[j]) { const T& val = get_val(it); if (!is_zero(val)) - v[it.m_i] = val; + v[it.var()] = val; } } @@ -397,7 +398,7 @@ public: // constructor column_cell_plus(const column_cell & c, const static_matrix& A) : m_c(c), m_A(A) {} - unsigned var() const { return m_c.m_i; } + unsigned var() const { return m_c.var(); } const T & coeff() const { return m_A.m_rows[var()][m_c.m_offset].get_val(); } }; diff --git a/src/util/lp/static_matrix_def.h b/src/util/lp/static_matrix_def.h index 42249b4d8..7949573de 100644 --- a/src/util/lp/static_matrix_def.h +++ b/src/util/lp/static_matrix_def.h @@ -37,12 +37,12 @@ void static_matrix::init_row_columns(unsigned m, unsigned n) { template void static_matrix::scan_row_ii_to_offset_vector(const row_strip & rvals) { for (unsigned j = 0; j < rvals.size(); j++) - m_vector_of_row_offsets[rvals[j].m_j] = j; + m_vector_of_row_offsets[rvals[j].var()] = j; } template bool static_matrix::pivot_row_to_row_given_cell(unsigned i, column_cell & c, unsigned pivot_col) { - unsigned ii = c.m_i; + unsigned ii = c.var(); lp_assert(i < row_count() && ii < column_count() && i != ii); T alpha = -get_val(c); lp_assert(!is_zero(alpha)); @@ -52,7 +52,7 @@ template bool static_matrix::pivot_row_to_row_giv unsigned prev_size_ii = rowii.size(); // run over the pivot row and update row ii for (const auto & iv : m_rows[i]) { - unsigned j = iv.m_j; + unsigned j = iv.var(); if (j == pivot_col) continue; T alv = alpha * iv.m_value; lp_assert(!is_zero(iv.m_value)); @@ -66,7 +66,7 @@ template bool static_matrix::pivot_row_to_row_giv } // clean the work vector for (unsigned k = 0; k < prev_size_ii; k++) { - m_vector_of_row_offsets[rowii[k].m_j] = -1; + m_vector_of_row_offsets[rowii[k].var()] = -1; } // remove zeroes @@ -86,7 +86,7 @@ static_matrix::static_matrix(static_matrix const &A, unsigned * /* basis * init_row_columns(m, m); while (m--) { for (auto & col : A.m_columns[m]){ - set(col.m_i, m, A.get_value_of_column_cell(col)); + set(col.var(), m, A.get_value_of_column_cell(col)); } } } @@ -113,8 +113,8 @@ template unsigned static_matrix::lowest_row_in lp_assert(colstrip.size() > 0); unsigned ret = 0; for (auto & t : colstrip) { - if (t.m_i > ret) { - ret = t.m_i; + if (t.var() > ret) { + ret = t.var(); } } return ret; @@ -136,10 +136,10 @@ template void static_matrix::forget_last_colum template void static_matrix::remove_last_column(unsigned j) { column_strip & col = m_columns.back(); for (auto & it : col) { - auto & row = m_rows[it.m_i]; + auto & row = m_rows[it.var()]; unsigned offset = row.size() - 1; for (auto row_it = row.rbegin(); row_it != row.rend(); row_it ++) { - if (row_it->m_j == j) { + if (row_it.var() == j) { row.erase(row.begin() + offset); break; } @@ -167,7 +167,7 @@ std::set> static_matrix::get_domain() { std::set> ret; for (unsigned i = 0; i < m_rows.size(); i++) { for (auto &it : m_rows[i]) { - ret.insert(std::make_pair(i, it.m_j)); + ret.insert(std::make_pair(i, it.var())); } } return ret; @@ -179,7 +179,7 @@ template void static_matrix::copy_column_to_in for (auto & it : m_columns[j]) { const T& val = get_val(it); if (!is_zero(val)) - v.set_value(val, it.m_i); + v.set_value(val, it.var()); } } @@ -243,7 +243,7 @@ template void static_matrix::check_consistency std::unordered_map, T> by_rows; for (int i = 0; i < m_rows.size(); i++){ for (auto & t : m_rows[i]) { - std::pair p(i, t.m_j); + std::pair p(i, t.var()); lp_assert(by_rows.find(p) == by_rows.end()); by_rows[p] = t.get_val(); } @@ -251,7 +251,7 @@ template void static_matrix::check_consistency std::unordered_map, T> by_cols; for (int i = 0; i < m_columns.size(); i++){ for (auto & t : m_columns[i]) { - std::pair p(t.m_i, i); + std::pair p(t.var(), i); lp_assert(by_cols.find(p) == by_cols.end()); by_cols[p] = get_val(t); } @@ -285,8 +285,8 @@ template void static_matrix::fix_row_indices_i for (unsigned j = 0; j < m_columns.size(); j++) { auto & col = m_columns[j]; for (int i = 0; i < col.size(); i++) { - if (col[i].m_i > k) { - col[i].m_i--; + if (col[i].var() > k) { + col[i].var()--; } } } @@ -294,14 +294,14 @@ template void static_matrix::fix_row_indices_i template void static_matrix::cross_out_row_from_columns(unsigned k, row_strip & row) { for (auto & t : row) { - cross_out_row_from_column(t.m_j, k); + cross_out_row_from_column(t.var(), k); } } template void static_matrix::cross_out_row_from_column(unsigned col, unsigned k) { auto & s = m_columns[col]; for (unsigned i = 0; i < s.size(); i++) { - if (s[i].m_i == k) { + if (s[i].var() == k) { s.erase(s.begin() + i); break; } @@ -310,7 +310,7 @@ template void static_matrix::cross_out_row_fro template T static_matrix::get_elem(unsigned i, unsigned j) const { // should not be used in efficient code !!!! for (auto & t : m_rows[i]) { - if (t.m_j == j) { + if (t.var() == j) { return t.get_val(); } } @@ -342,15 +342,15 @@ template bool static_matrix::is_correct() const { auto &r = m_rows[i]; std::unordered_set s; for (auto & rc : r) { - if (s.find(rc.m_j) != s.end()) { + if (s.find(rc.var()) != s.end()) { return false; } - s.insert(rc.m_j); - if (rc.m_j >= m_columns.size()) + s.insert(rc.var()); + if (rc.var() >= m_columns.size()) return false; - if (rc.m_offset >= m_columns[rc.m_j].size()) + if (rc.m_offset >= m_columns[rc.var()].size()) return false; - if (rc.get_val() != get_val(m_columns[rc.m_j][rc.m_offset])) + if (rc.get_val() != get_val(m_columns[rc.var()][rc.m_offset])) return false; if (is_zero(rc.get_val())) { return false; @@ -363,15 +363,15 @@ template bool static_matrix::is_correct() const { auto & c = m_columns[j]; std::unordered_set s; for (auto & cc : c) { - if (s.find(cc.m_i) != s.end()) { + if (s.find(cc.var()) != s.end()) { return false; } - s.insert(cc.m_i); - if (cc.m_i >= m_rows.size()) + s.insert(cc.var()); + if (cc.var() >= m_rows.size()) return false; - if (cc.m_offset >= m_rows[cc.m_i].size()) + if (cc.m_offset >= m_rows[cc.var()].size()) return false; - if (get_val(cc) != m_rows[cc.m_i][cc.m_offset].get_val()) + if (get_val(cc) != m_rows[cc.var()][cc.m_offset].get_val()) return false; } } @@ -384,17 +384,17 @@ template bool static_matrix::is_correct() const { template void static_matrix::remove_element(vector> & row_vals, row_cell & row_el_iv) { unsigned column_offset = row_el_iv.m_offset; - auto & column_vals = m_columns[row_el_iv.m_j]; - column_cell& cs = m_columns[row_el_iv.m_j][column_offset]; + auto & column_vals = m_columns[row_el_iv.var()]; + column_cell& cs = m_columns[row_el_iv.var()][column_offset]; unsigned row_offset = cs.m_offset; if (column_offset != column_vals.size() - 1) { auto & cc = column_vals[column_offset] = column_vals.back(); // copy from the tail - m_rows[cc.m_i][cc.m_offset].m_offset = column_offset; + m_rows[cc.var()][cc.offset()].offset() = column_offset; } if (row_offset != row_vals.size() - 1) { auto & rc = row_vals[row_offset] = row_vals.back(); // copy from the tail - m_columns[rc.m_j][rc.m_offset].m_offset = row_offset; + m_columns[rc.var()][rc.offset()].offset() = row_offset; } column_vals.pop_back(); diff --git a/src/util/lp/var_register.h b/src/util/lp/var_register.h index 86c238e12..93404bf91 100644 --- a/src/util/lp/var_register.h +++ b/src/util/lp/var_register.h @@ -19,19 +19,19 @@ Revision History: #pragma once namespace lp { class ext_var_info { - unsigned m_internal_j; // the internal index + unsigned m_external_j; // the internal index bool m_is_integer; public: ext_var_info() {} ext_var_info(unsigned j): ext_var_info(j, true) {} - ext_var_info(unsigned j , bool is_int) : m_internal_j(j), m_is_integer(is_int) {} - unsigned internal_j() const { return m_internal_j;} + ext_var_info(unsigned j , bool is_int) : m_external_j(j), m_is_integer(is_int) {} + unsigned external_j() const { return m_external_j;} bool is_integer() const {return m_is_integer;} }; class var_register { - svector m_local_to_external; - std::unordered_map m_external_to_local; + svector m_local_to_external; + std::unordered_map m_external_to_local; public: unsigned add_var(unsigned user_var) { return add_var(user_var, true); @@ -39,19 +39,23 @@ public: unsigned add_var(unsigned user_var, bool is_int) { auto t = m_external_to_local.find(user_var); if (t != m_external_to_local.end()) { - return t->second.internal_j(); + return t->second; } - unsigned j = size(); - m_external_to_local[user_var] = ext_var_info(j, is_int); - m_local_to_external.push_back(user_var); - return j; + m_local_to_external.push_back(ext_var_info(user_var, is_int)); + return m_external_to_local[user_var] = size() - 1; } - const svector & vars() const { return m_local_to_external; } + svector vars() const { + svector ret; + for (const auto& p : m_local_to_external) { + ret.push_back(p.external_j()); + } + return ret; + } unsigned local_to_external(unsigned local_var) const { - return m_local_to_external[local_var]; + return m_local_to_external[local_var].external_j(); } unsigned size() const { return m_local_to_external.size(); @@ -64,13 +68,7 @@ public: unsigned external_to_local(unsigned j) const { auto it = m_external_to_local.find(j); lp_assert(it != m_external_to_local.end()); - return it->second.internal_j(); - } - - bool external_is_int(unsigned j) const { - auto it = m_external_to_local.find(j); - lp_assert(it != m_external_to_local.end()); - return it->second.is_integer(); + return it->second; } bool external_is_used(unsigned ext_j) const { @@ -82,7 +80,7 @@ public: auto it = m_external_to_local.find(ext_j); if ( it == m_external_to_local.end()) return false; - local_j = it->second.internal_j(); + local_j = it->second; return true; } @@ -90,19 +88,19 @@ public: auto it = m_external_to_local.find(ext_j); if ( it == m_external_to_local.end()) return false; - local_j = it->second.internal_j(); - is_int = it->second.is_integer(); + local_j = it->second; + is_int = m_local_to_external[local_j].is_integer(); return true; } bool local_is_int(unsigned j) const { - return external_is_int(m_local_to_external[j]); + return m_local_to_external[j].is_integer(); } void shrink(unsigned shrunk_size) { for (unsigned j = size(); j-- > shrunk_size;) { - m_external_to_local.erase(m_local_to_external[j]); + m_external_to_local.erase(m_local_to_external[j].external_j()); } m_local_to_external.resize(shrunk_size); } diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 59a6cb009..0a1d360c8 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -6,7 +6,7 @@ Copyright (c) 2015 Microsoft Corporation #include #include -#include +#include #include "util/trace.h" #include "util/memory_manager.h" #include "util/error_codes.h" diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index e00a25b1b..8ca2e983f 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -376,9 +376,11 @@ void mpff_manager::set(mpff & n, unsynch_mpz_manager & m, mpz const & v) { set_core(n, m, v); } +#ifndef _NO_OMP_ void mpff_manager::set(mpff & n, synch_mpz_manager & m, mpz const & v) { set_core(n, m, v); } +#endif template void mpff_manager::set_core(mpff & n, mpq_manager & m, mpq const & v) { @@ -397,9 +399,11 @@ void mpff_manager::set(mpff & n, unsynch_mpq_manager & m, mpq const & v) { set_core(n, m, v); } +#ifndef _NO_OMP_ void mpff_manager::set(mpff & n, synch_mpq_manager & m, mpq const & v) { set_core(n, m, v); } +#endif bool mpff_manager::eq(mpff const & a, mpff const & b) const { if (is_zero(a) && is_zero(b)) @@ -1077,9 +1081,11 @@ void mpff_manager::significand(mpff const & n, unsynch_mpz_manager & m, mpz & t) significand_core(n, m, t); } +#ifndef _NO_OMP_ void mpff_manager::significand(mpff const & n, synch_mpz_manager & m, mpz & t) { significand_core(n, m, t); } +#endif template void mpff_manager::to_mpz_core(mpff const & n, mpz_manager & m, mpz & t) { @@ -1109,9 +1115,11 @@ void mpff_manager::to_mpz(mpff const & n, unsynch_mpz_manager & m, mpz & t) { to_mpz_core(n, m, t); } +#ifndef _NO_OMP_ void mpff_manager::to_mpz(mpff const & n, synch_mpz_manager & m, mpz & t) { to_mpz_core(n, m, t); } +#endif template void mpff_manager::to_mpq_core(mpff const & n, mpq_manager & m, mpq & t) { @@ -1154,9 +1162,11 @@ void mpff_manager::to_mpq(mpff const & n, unsynch_mpq_manager & m, mpq & t) { to_mpq_core(n, m, t); } +#ifndef _NO_OMP_ void mpff_manager::to_mpq(mpff const & n, synch_mpq_manager & m, mpq & t) { to_mpq_core(n, m, t); } +#endif void mpff_manager::display_raw(std::ostream & out, mpff const & n) const { if (is_neg(n)) diff --git a/src/util/mpff.h b/src/util/mpff.h index 8023053d2..6f1e9d23c 100644 --- a/src/util/mpff.h +++ b/src/util/mpff.h @@ -58,9 +58,14 @@ class mpz; class mpq; template class mpz_manager; template class mpq_manager; +#ifndef _NO_OMP_ typedef mpz_manager synch_mpz_manager; -typedef mpz_manager unsynch_mpz_manager; typedef mpq_manager synch_mpq_manager; +#else +typedef mpz_manager synch_mpz_manager; +typedef mpq_manager synch_mpq_manager; +#endif +typedef mpz_manager unsynch_mpz_manager; typedef mpq_manager unsynch_mpq_manager; class mpff_manager { @@ -213,7 +218,9 @@ public: \brief Return the significand as a mpz numeral. */ void significand(mpff const & n, unsynch_mpz_manager & m, mpz & r); +#ifndef _NO_OMP_ void significand(mpff const & n, synch_mpz_manager & m, mpz & r); +#endif /** \brief Return true if n is negative @@ -378,9 +385,11 @@ public: void set(mpff & n, int64_t num, uint64_t den); void set(mpff & n, mpff const & v); void set(mpff & n, unsynch_mpz_manager & m, mpz const & v); - void set(mpff & n, synch_mpz_manager & m, mpz const & v); void set(mpff & n, unsynch_mpq_manager & m, mpq const & v); +#ifndef _NO_OMP_ void set(mpff & n, synch_mpq_manager & m, mpq const & v); + void set(mpff & n, synch_mpz_manager & m, mpz const & v); +#endif void set_plus_epsilon(mpff & n); void set_minus_epsilon(mpff & n); void set_max(mpff & n); @@ -420,6 +429,7 @@ public: */ void to_mpz(mpff const & n, unsynch_mpz_manager & m, mpz & t); +#ifndef _NO_OMP_ /** \brief Convert n into a mpz numeral. @@ -428,6 +438,7 @@ public: \remark if exponent(n) is too big, we may run out of memory. */ void to_mpz(mpff const & n, synch_mpz_manager & m, mpz & t); +#endif /** \brief Convert n into a mpq numeral. @@ -436,13 +447,15 @@ public: */ void to_mpq(mpff const & n, unsynch_mpq_manager & m, mpq & t); +#ifndef _NO_OMP_ /** \brief Convert n into a mpq numeral. \remark if exponent(n) is too big, we may run out of memory. */ void to_mpq(mpff const & n, synch_mpq_manager & m, mpq & t); - +#endif + /** \brief Return n as an int64. diff --git a/src/util/mpfx.cpp b/src/util/mpfx.cpp index 2ebc54840..8ed16ec68 100644 --- a/src/util/mpfx.cpp +++ b/src/util/mpfx.cpp @@ -272,9 +272,11 @@ void mpfx_manager::set(mpfx & n, unsynch_mpz_manager & m, mpz const & v) { set_core(n, m, v); } +#ifndef _NO_OMP_ void mpfx_manager::set(mpfx & n, synch_mpz_manager & m, mpz const & v) { set_core(n, m, v); } +#endif template void mpfx_manager::set_core(mpfx & n, mpq_manager & m, mpq const & v) { @@ -309,9 +311,11 @@ void mpfx_manager::set(mpfx & n, unsynch_mpq_manager & m, mpq const & v) { set_core(n, m, v); } +#ifndef _NO_OMP_ void mpfx_manager::set(mpfx & n, synch_mpq_manager & m, mpq const & v) { set_core(n, m, v); } +#endif bool mpfx_manager::eq(mpfx const & a, mpfx const & b) const { if (is_zero(a) && is_zero(b)) @@ -714,9 +718,11 @@ void mpfx_manager::to_mpz(mpfx const & n, unsynch_mpz_manager & m, mpz & t) { to_mpz_core(n, m, t); } +#ifndef _NO_OMP_ void mpfx_manager::to_mpz(mpfx const & n, synch_mpz_manager & m, mpz & t) { to_mpz_core(n, m, t); } +#endif template void mpfx_manager::to_mpq_core(mpfx const & n, mpq_manager & m, mpq & t) { @@ -738,9 +744,11 @@ void mpfx_manager::to_mpq(mpfx const & n, unsynch_mpq_manager & m, mpq & t) { to_mpq_core(n, m, t); } +#ifndef _NO_OMP_ void mpfx_manager::to_mpq(mpfx const & n, synch_mpq_manager & m, mpq & t) { to_mpq_core(n, m, t); } +#endif void mpfx_manager::display_raw(std::ostream & out, mpfx const & n) const { if (is_neg(n)) diff --git a/src/util/mpfx.h b/src/util/mpfx.h index a8e93f0b0..6de3f251b 100644 --- a/src/util/mpfx.h +++ b/src/util/mpfx.h @@ -51,9 +51,14 @@ class mpz; class mpq; template class mpz_manager; template class mpq_manager; +#ifndef _NO_OMP_ typedef mpz_manager synch_mpz_manager; -typedef mpz_manager unsynch_mpz_manager; typedef mpq_manager synch_mpq_manager; +#else +typedef mpz_manager synch_mpz_manager; +typedef mpq_manager synch_mpq_manager; +#endif +typedef mpz_manager unsynch_mpz_manager; typedef mpq_manager unsynch_mpq_manager; class mpfx_manager { @@ -312,9 +317,11 @@ public: void set(mpfx & n, int64_t num, uint64_t den); void set(mpfx & n, mpfx const & v); void set(mpfx & n, unsynch_mpz_manager & m, mpz const & v); - void set(mpfx & n, synch_mpz_manager & m, mpz const & v); void set(mpfx & n, unsynch_mpq_manager & m, mpq const & v); +#ifndef _NO_OMP_ + void set(mpfx & n, synch_mpz_manager & m, mpz const & v); void set(mpfx & n, synch_mpq_manager & m, mpq const & v); +#endif /** \brief Set n to the smallest representable numeral greater than zero. @@ -359,22 +366,26 @@ public: */ void to_mpz(mpfx const & n, unsynch_mpz_manager & m, mpz & t); +#ifndef _NO_OMP_ /** \brief Convert n into a mpz numeral. \pre is_int(n) */ void to_mpz(mpfx const & n, synch_mpz_manager & m, mpz & t); +#endif /** \brief Convert n into a mpq numeral. */ void to_mpq(mpfx const & n, unsynch_mpq_manager & m, mpq & t); +#ifndef _NO_OMP_ /** \brief Convert n into a mpq numeral. */ void to_mpq(mpfx const & n, synch_mpq_manager & m, mpq & t); +#endif /** \brief Return the biggest k s.t. 2^k <= a. diff --git a/src/util/mpq.cpp b/src/util/mpq.cpp index 4c636f1af..b126f4c5d 100644 --- a/src/util/mpq.cpp +++ b/src/util/mpq.cpp @@ -26,12 +26,12 @@ mpq_manager::mpq_manager() { template mpq_manager::~mpq_manager() { - del(m_n_tmp); - del(m_add_tmp1); - del(m_add_tmp2); - del(m_lt_tmp1); - del(m_lt_tmp2); - del(m_addmul_tmp); + del(m_tmp1); + del(m_tmp2); + del(m_tmp3); + del(m_tmp4); + del(m_q_tmp1); + del(m_q_tmp2); } @@ -68,9 +68,9 @@ bool mpq_manager::rat_lt(mpq const & a, mpq const & b) { return r; } else { - mul(na, db, m_lt_tmp1); - mul(nb, da, m_lt_tmp2); - return lt(m_lt_tmp1, m_lt_tmp2); + mul(na, db, m_q_tmp1); + mul(nb, da, m_q_tmp2); + return lt(m_q_tmp1, m_q_tmp2); } } @@ -230,6 +230,10 @@ void mpq_manager::set(mpq & a, char const * val) { exp_sign = true; ++str; } + else if (str[0] == '+') { + exp_sign = false; + ++str; + } while (str[0]) { if ('0' <= str[0] && str[0] <= '9') { SASSERT(str[0] - '0' <= 9); @@ -346,6 +350,7 @@ void mpq_manager::lin_arith_op(mpq const& a, mpq const& b, mpq& c, mpz& g template void mpq_manager::rat_mul(mpq const & a, mpq const & b, mpq & c, mpz& g1, mpz& g2, mpz& tmp1, mpz& tmp2) { +#if 1 gcd(a.m_den, b.m_num, g1); gcd(a.m_num, b.m_den, g2); div(a.m_num, g2, tmp1); @@ -354,6 +359,11 @@ void mpq_manager::rat_mul(mpq const & a, mpq const & b, mpq & c, mpz& g1, div(b.m_den, g2, tmp1); div(a.m_den, g1, tmp2); mul(tmp1, tmp2, c.m_den); +#else + mul(a.m_num, b.m_num, c.m_num); + mul(a.m_den, b.m_den, c.m_den); + normalize(c); +#endif } template @@ -378,8 +388,7 @@ void mpq_manager::rat_mul(mpq const & a, mpq const & b, mpq & c) { del(tmp2); } else { - mpz& g1 = m_n_tmp, &g2 = m_addmul_tmp.m_num, &tmp1 = m_add_tmp1, &tmp2 = m_add_tmp2; - rat_mul(a, b, c, g1, g2, tmp1, tmp2); + rat_mul(a, b, c, m_tmp1, m_tmp2, m_tmp3, m_tmp4); } STRACE("rat_mpq", tout << to_string(c) << "\n";); } @@ -396,8 +405,7 @@ void mpq_manager::rat_add(mpq const & a, mpq const & b, mpq & c) { del(g); } else { - mpz& g = m_n_tmp, &tmp1 = m_add_tmp1, &tmp2 = m_add_tmp2, &tmp3 = m_addmul_tmp.m_num; - lin_arith_op(a, b, c, g, tmp1, tmp2, tmp3); + lin_arith_op(a, b, c, m_tmp1, m_tmp2, m_tmp3, m_tmp4); } STRACE("rat_mpq", tout << to_string(c) << "\n";); } @@ -414,13 +422,13 @@ void mpq_manager::rat_sub(mpq const & a, mpq const & b, mpq & c) { del(g); } else { - mpz& g = m_n_tmp, &tmp1 = m_add_tmp1, &tmp2 = m_add_tmp2, &tmp3 = m_addmul_tmp.m_num; - lin_arith_op(a, b, c, g, tmp1, tmp2, tmp3); + lin_arith_op(a, b, c, m_tmp1, m_tmp2, m_tmp3, m_tmp4); } STRACE("rat_mpq", tout << to_string(c) << "\n";); } +#ifndef _NO_OMP_ template class mpq_manager; +#endif template class mpq_manager; - diff --git a/src/util/mpq.h b/src/util/mpq.h index 1bccabc74..20802f786 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -41,12 +41,12 @@ inline void swap(mpq & m1, mpq & m2) { m1.swap(m2); } template class mpq_manager : public mpz_manager { - mpz m_n_tmp; - mpz m_add_tmp1; - mpz m_add_tmp2; - mpq m_addmul_tmp; - mpq m_lt_tmp1; - mpq m_lt_tmp2; + mpz m_tmp1; + mpz m_tmp2; + mpz m_tmp3; + mpz m_tmp4; + mpq m_q_tmp1; + mpq m_q_tmp2; void reset_denominator(mpq & a) { del(a.m_den); @@ -66,11 +66,11 @@ class mpq_manager : public mpz_manager { del(tmp); } else { - gcd(a.m_num, a.m_den, m_n_tmp); - if (is_one(m_n_tmp)) + gcd(a.m_num, a.m_den, m_tmp1); + if (is_one(m_tmp1)) return; - div(a.m_num, m_n_tmp, a.m_num); - div(a.m_den, m_n_tmp, a.m_den); + div(a.m_num, m_tmp1, a.m_num); + div(a.m_den, m_tmp1, a.m_den); } } @@ -87,9 +87,9 @@ class mpq_manager : public mpz_manager { del(tmp1); } else { - mul(b, a.m_den, m_add_tmp1); + mul(b, a.m_den, m_tmp1); set(c.m_den, a.m_den); - add(a.m_num, m_add_tmp1, c.m_num); + add(a.m_num, m_tmp1, c.m_num); normalize(c); } STRACE("rat_mpq", tout << to_string(c) << "\n";); @@ -320,8 +320,8 @@ public: del(tmp); } else { - mul(b,c,m_addmul_tmp); - add(a, m_addmul_tmp, d); + mul(b, c, m_q_tmp1); + add(a, m_q_tmp1, d); } } } @@ -342,8 +342,8 @@ public: del(tmp); } else { - mul(b,c,m_addmul_tmp); - add(a, m_addmul_tmp, d); + mul(b,c, m_q_tmp1); + add(a, m_q_tmp1, d); } } } @@ -365,8 +365,8 @@ public: del(tmp); } else { - mul(b,c,m_addmul_tmp); - sub(a, m_addmul_tmp, d); + mul(b,c, m_q_tmp1); + sub(a, m_q_tmp1, d); } } } @@ -387,8 +387,8 @@ public: del(tmp); } else { - mul(b,c,m_addmul_tmp); - sub(a, m_addmul_tmp, d); + mul(b,c, m_q_tmp1); + sub(a, m_q_tmp1, d); } } } @@ -714,6 +714,12 @@ public: return temp; } + mpz dup(const mpz & source) { + mpz temp; + set(temp, source); + return temp; + } + void swap(mpz & a, mpz & b) { mpz_manager::swap(a, b); } void swap(mpq & a, mpq & b) { @@ -808,12 +814,13 @@ public: bool is_even(mpz const & a) { return mpz_manager::is_even(a); } public: bool is_even(mpq const & a) { return is_int(a) && is_even(a.m_num); } - - friend bool operator==(mpq const & a, mpq const & b) ; - friend bool operator>=(mpq const & a, mpq const & b); }; +#ifndef _NO_OMP_ typedef mpq_manager synch_mpq_manager; +#else +typedef mpq_manager synch_mpq_manager; +#endif typedef mpq_manager unsynch_mpq_manager; typedef _scoped_numeral scoped_mpq; diff --git a/src/util/mpq_inf.cpp b/src/util/mpq_inf.cpp index c6c160941..69de425cf 100644 --- a/src/util/mpq_inf.cpp +++ b/src/util/mpq_inf.cpp @@ -39,5 +39,7 @@ std::string mpq_inf_manager::to_string(mpq_inf const & a) { } +#ifndef _NO_OMP_ template class mpq_inf_manager; +#endif template class mpq_inf_manager; diff --git a/src/util/mpq_inf.h b/src/util/mpq_inf.h index 7b866994d..c7bd261e6 100644 --- a/src/util/mpq_inf.h +++ b/src/util/mpq_inf.h @@ -279,7 +279,11 @@ public: mpq_manager& get_mpq_manager() { return m; } }; +#ifndef _NO_OMP_ typedef mpq_inf_manager synch_mpq_inf_manager; +#else +typedef mpq_inf_manager synch_mpq_inf_manager; +#endif typedef mpq_inf_manager unsynch_mpq_inf_manager; #endif diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 7ad4797b7..32a074eb3 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -2369,5 +2369,7 @@ bool mpz_manager::divides(mpz const & a, mpz const & b) { return r; } +#ifndef _NO_OMP_ template class mpz_manager; +#endif template class mpz_manager; diff --git a/src/util/mpz.h b/src/util/mpz.h index f480b097e..65f89f078 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -19,7 +19,6 @@ Revision History: #ifndef MPZ_H_ #define MPZ_H_ -#include #include #include "util/util.h" #include "util/small_object_allocator.h" @@ -692,7 +691,11 @@ public: bool decompose(mpz const & n, svector & digits); }; +#ifndef _NO_OMP_ typedef mpz_manager synch_mpz_manager; +#else +typedef mpz_manager synch_mpz_manager; +#endif typedef mpz_manager unsynch_mpz_manager; typedef _scoped_numeral scoped_mpz; diff --git a/src/util/nat_set.h b/src/util/nat_set.h index 6e9ab1b6d..f2f2cb8e1 100644 --- a/src/util/nat_set.h +++ b/src/util/nat_set.h @@ -19,7 +19,7 @@ Revision History: #ifndef NAT_SET_H_ #define NAT_SET_H_ -#include +#include #include "util/vector.h" class nat_set { diff --git a/src/util/rlimit.h b/src/util/rlimit.h index 60d26be7f..cc022a963 100644 --- a/src/util/rlimit.h +++ b/src/util/rlimit.h @@ -65,12 +65,14 @@ public: class scoped_suspend_rlimit { reslimit & m_limit; + bool m_suspend; public: scoped_suspend_rlimit(reslimit& r): m_limit(r) { + m_suspend = r.m_suspend; r.m_suspend = true; } ~scoped_suspend_rlimit() { - m_limit.m_suspend = false; + m_limit.m_suspend = m_suspend; } }; diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index 56d40c47a..8078c46ee 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -50,7 +50,7 @@ Revision History: #undef max #endif #include "util/util.h" -#include +#include #include "util/z3_omp.h" struct scoped_timer::imp { diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index f2906b00c..b094a5b66 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -25,16 +25,22 @@ Notes: #define SORTING_NETWORK_H_ enum sorting_network_encoding { - grouped_at_most_1, - bimander_at_most_1, - ordered_at_most_1 + sorted_at_most, + grouped_at_most, + bimander_at_most, + ordered_at_most, + unate_at_most, + circuit_at_most }; inline std::ostream& operator<<(std::ostream& out, sorting_network_encoding enc) { switch (enc) { - case grouped_at_most_1: return out << "grouped"; - case bimander_at_most_1: return out << "bimander"; - case ordered_at_most_1: return out << "ordered"; + case grouped_at_most: return out << "grouped"; + case bimander_at_most: return out << "bimander"; + case ordered_at_most: return out << "ordered"; + case sorted_at_most: return out << "sorted"; + case unate_at_most: return out << "unate"; + case circuit_at_most: return out << "circuit"; } return out << "???"; } @@ -42,7 +48,7 @@ Notes: struct sorting_network_config { sorting_network_encoding m_encoding; sorting_network_config() { - m_encoding = grouped_at_most_1; + m_encoding = sorted_at_most; } }; @@ -158,12 +164,19 @@ Notes: vc operator+(vc const& other) const { return vc(v + other.v, c + other.c); } + vc operator-(vc const& other) const { + return vc(v - other.v, c - other.c); + } unsigned to_int() const { return lambda*v + c; } vc operator*(unsigned n) const { return vc(n*v, n*c); } + + std::ostream& pp(std::ostream& out) const { + return out << "v: " << v << " c: " << c; + } }; static vc mk_min(vc const& v1, vc const& v2) { @@ -176,13 +189,17 @@ Notes: cmp_t m_t; // for testing - static const bool m_disable_dcard = false; - static const bool m_disable_dsorting = false; + static const bool m_disable_dcard = false; + static const bool m_disable_dsorting = false; static const bool m_disable_dsmerge = false; static const bool m_force_dcard = false; static const bool m_force_dsorting = false; static const bool m_force_dsmerge = false; + bool is_power_of2(unsigned n) const { + return n != 0 && ((n-1) & n) == 0; + } + public: struct stats { unsigned m_num_compiled_vars; @@ -221,15 +238,31 @@ Notes: } SASSERT(0 < k && k <= n); literal_vector in, out; + if (k == 1) { + return mk_or(n, xs); + } if (dualize(k, n, xs, in)) { return le(full, k, in.size(), in.c_ptr()); } else { - SASSERT(2*k <= n); - m_t = full?GE_FULL:GE; - // scoped_stats _ss(m_stats, k, n); - psort_nw::card(k, n, xs, out); - return out[k-1]; + switch (m_cfg.m_encoding) { + case sorted_at_most: + case bimander_at_most: + case ordered_at_most: + case grouped_at_most: + SASSERT(2*k <= n); + m_t = full?GE_FULL:GE; + // scoped_stats _ss(m_stats, k, n); + psort_nw::card(k, n, xs, out); + return out[k-1]; + case unate_at_most: + return unate_ge(full, k, n, xs); + case circuit_at_most: + return circuit_ge(full, k, n, xs); + default: + UNREACHABLE(); + return xs[0]; + } } } @@ -246,23 +279,40 @@ Notes: literal_vector ors; // scoped_stats _ss(m_stats, k, n); switch (m_cfg.m_encoding) { - case grouped_at_most_1: + case grouped_at_most: + case sorted_at_most: + case unate_at_most: + case circuit_at_most: return mk_at_most_1(full, n, xs, ors, false); - case bimander_at_most_1: + case bimander_at_most: return mk_at_most_1_bimander(full, n, xs, ors); - case ordered_at_most_1: + case ordered_at_most: return mk_ordered_atmost_1(full, n, xs); + default: UNREACHABLE(); return xs[0]; } } else { - SASSERT(2*k <= n); - m_t = full?LE_FULL:LE; - // scoped_stats _ss(m_stats, k, n); - card(k + 1, n, xs, out); - return ctx.mk_not(out[k]); + switch (m_cfg.m_encoding) { + case sorted_at_most: + case bimander_at_most: + case ordered_at_most: + case grouped_at_most: + SASSERT(2*k <= n); + m_t = full?LE_FULL:LE; + // scoped_stats _ss(m_stats, k, n); + card(k + 1, n, xs, out); + return mk_not(out[k]); + case unate_at_most: + return unate_le(full, k, n, xs); + case circuit_at_most: + return circuit_le(full, k, n, xs); + default: + UNREACHABLE(); + return xs[0]; + } } } @@ -280,16 +330,29 @@ Notes: return mk_exactly_1(full, n, xs); } else { - // scoped_stats _ss(m_stats, k, n); - SASSERT(2*k <= n); - m_t = EQ; - card(k+1, n, xs, out); - SASSERT(out.size() >= k+1); - if (k == 0) { - return ctx.mk_not(out[k]); - } - else { - return ctx.mk_min(out[k-1], ctx.mk_not(out[k])); + switch (m_cfg.m_encoding) { + case sorted_at_most: + case bimander_at_most: + case grouped_at_most: + case ordered_at_most: + // scoped_stats _ss(m_stats, k, n); + SASSERT(2*k <= n); + m_t = EQ; + card(k+1, n, xs, out); + SASSERT(out.size() >= k+1); + if (k == 0) { + return mk_not(out[k]); + } + else { + return mk_min(out[k-1], mk_not(out[k])); + } + case unate_at_most: + return unate_eq(k, n, xs); + case circuit_at_most: + return circuit_eq(k, n, xs); + default: + UNREACHABLE(); + return xs[0]; } } } @@ -297,49 +360,191 @@ Notes: private: + // perform unate addition up to k. + literal unate_cmp(cmp_t cmp, unsigned k, unsigned n, literal const* xs) { + unsigned last = k; + if (cmp == LE || cmp == EQ || cmp == LE_FULL) { + last = k + 1; + } + literal_vector carry; + for (unsigned i = 0; i < last; ++i) { + carry.push_back(ctx.mk_false()); + } + for (unsigned i = 0; i < n; ++i) { + for (unsigned j = last; j-- > 0; ) { + // c'[j] <-> (xs[i] & c[j-1]) | c[j] + literal c0 = j > 0 ? carry[j-1] : ctx.mk_true(); + carry[j] = mk_or(mk_and(xs[i], c0), carry[j]); + } + } + switch (cmp) { + case LE: + case LE_FULL: + return mk_not(carry[k]); + case GE: + case GE_FULL: + return carry[k-1]; + case EQ: + return mk_and(mk_not(carry[k]), carry[k-1]); + default: + UNREACHABLE(); + return xs[0]; + } + } + + literal unate_ge(bool full, unsigned k, unsigned n, literal const* xs) { + return unate_cmp(full ? GE_FULL : GE, k, n, xs); + } + + literal unate_le(bool full, unsigned k, unsigned n, literal const* xs) { + return unate_cmp(full ? LE_FULL : LE, k, n, xs); + } + + literal unate_eq(unsigned k, unsigned n, literal const* xs) { + return unate_cmp(EQ, k, n, xs); + } + + // circuit encoding + void mk_unit_circuit(unsigned k, literal x, literal_vector& out) { + out.push_back(x); + for (unsigned i = 1; i < k; ++i) out.push_back(ctx.mk_false()); + } + + literal mk_add_circuit(literal_vector const& x, literal_vector const& y, literal_vector& out) { + literal c = ctx.mk_false(); + SASSERT(x.size() == y.size()); + for (unsigned i = 0; i < x.size(); ++i) { + // out[i] = c + x[i] + y[i] + // c' = c&x[i] | c&y[i] | x[i]&y[i]; + literal_vector ors; + ors.push_back(mk_and(c, mk_not(x[i]), mk_not(y[i]))); + ors.push_back(mk_and(x[i], mk_not(c), mk_not(y[i]))); + ors.push_back(mk_and(y[i], mk_not(c), mk_not(x[i]))); + ors.push_back(mk_and(c, x[i], y[i])); + literal o = mk_or(4, ors.c_ptr()); + out.push_back(o); + ors[0] = mk_and(c, x[i]); + ors[1] = mk_and(c, y[i]); + ors[2] = mk_and(x[i], y[i]); + c = mk_or(3, ors.c_ptr()); + } + return c; + } + + literal circuit_add(unsigned k, unsigned n, literal const* xs, literal_vector& out) { + switch (n) { + case 0: + for (unsigned i = 0; i < k; ++i) { + out.push_back(ctx.mk_false()); + } + return ctx.mk_false(); + case 1: + mk_unit_circuit(k, xs[0], out); + return ctx.mk_false(); + default: { + literal_vector o1, o2; + unsigned half = n / 2; + literal ovfl1 = circuit_add(k, half, xs, o1); + literal ovfl2 = circuit_add(k, n - half, xs + half, o2); + literal ovfl3 = mk_add_circuit(o1, o2, out); + return mk_or(ovfl1, ovfl2, ovfl3); + } + } + } + + literal circuit_cmp(cmp_t cmp, unsigned k, unsigned n, literal const* xs) { + literal_vector out, kvec; + unsigned num_bits = 0; + unsigned k1 = (cmp == LE || cmp == LE_FULL) ? k + 1 : k; + unsigned k0 = k1; + while (k0 > 0) { ++num_bits; k0 >>= 1; } + for (unsigned i = 0; i < num_bits; ++i) { + kvec.push_back((0 != (k1 & (1 << i))) ? ctx.mk_true() : ctx.mk_false()); + } + literal ovfl = circuit_add(num_bits, n, xs, out); + switch (cmp) { + case LE: + case LE_FULL: + return mk_not(mk_or(ovfl, mk_ge(out, kvec))); + case GE: + case GE_FULL: + return mk_or(ovfl, mk_ge(out, kvec)); + case EQ: { + literal_vector eqs; + SASSERT(kvec.size() == out.size()); + for (unsigned i = 0; i < num_bits; ++i) { + eqs.push_back(mk_or(mk_not(kvec[i]), out[i])); + eqs.push_back(mk_or(kvec[i], mk_not(out[i]))); + } + eqs.push_back(mk_not(ovfl)); + return mk_and(eqs); + } + default: + UNREACHABLE(); + return xs[0]; + } + } + + literal mk_ge(literal_vector const& x, literal_vector const& y) { + literal r = ctx.mk_true(); + literal g = ctx.mk_false(); + for (unsigned j = x.size(); j-- > 0; ) { + g = mk_or(g, mk_and(r, mk_and(x[j], mk_not(y[j])))); + r = mk_or(g, mk_and(r, mk_or( x[j], mk_not(y[j])))); + } + return r; + } + + literal circuit_ge(bool full, unsigned k, unsigned n, literal const* xs) { + return circuit_cmp(full ? GE_FULL : GE, k, n, xs); + } + + literal circuit_le(bool full, unsigned k, unsigned n, literal const* xs) { + return circuit_cmp(full ? LE_FULL : LE, k, n, xs); + } + + literal circuit_eq(unsigned k, unsigned n, literal const* xs) { + return circuit_cmp(EQ, k, n, xs); + } + void add_implies_or(literal l, unsigned n, literal const* xs) { literal_vector lits(n, xs); - lits.push_back(ctx.mk_not(l)); + lits.push_back(mk_not(l)); add_clause(lits); } - void add_or_implies(literal l, unsigned n, literal const* xs) { - for (unsigned j = 0; j < n; ++j) { - add_clause(ctx.mk_not(xs[j]), l); + literal mk_or(unsigned n, literal const* _ors) { + literal_vector ors(n, _ors); + unsigned j = 0; + for (literal lit : ors) { + if (is_true(lit)) return lit; + if (!is_false(lit)) ors[j++] = lit; } - } - - literal mk_or(unsigned n, literal const* ors) { - if (n == 1) { - return ors[0]; + ors.shrink(j); + switch (j) { + case 0: return ctx.mk_false(); + case 1: return ors[0]; + default: return ctx.mk_max(ors.size(), ors.c_ptr()); } - literal result = fresh("or"); - add_implies_or(result, n, ors); - add_or_implies(result, n, ors); - return result; } literal mk_or(literal l1, literal l2) { literal ors[2] = { l1, l2 }; return mk_or(2, ors); } + literal mk_or(literal l1, literal l2, literal l3) { + literal ors[3] = { l1, l2, l3 }; + return mk_or(3, ors); + } + literal mk_or(literal_vector const& ors) { return mk_or(ors.size(), ors.c_ptr()); } - void add_implies_and(literal l, literal_vector const& xs) { - for (literal const& x : xs) { - add_clause(ctx.mk_not(l), x); - } - } - - void add_and_implies(literal l, literal_vector const& xs) { - literal_vector lits; - for (literal const& x : xs) { - lits.push_back(ctx.mk_not(x)); - } - lits.push_back(l); - add_clause(lits); + literal mk_not(literal lit) { + if (is_true(lit)) return ctx.mk_false(); + if (is_false(lit)) return ctx.mk_true(); + return ctx.mk_not(lit); } literal mk_and(literal l1, literal l2) { @@ -348,14 +553,39 @@ Notes: return mk_and(xs); } - literal mk_and(literal_vector const& ands) { - if (ands.size() == 1) { - return ands[0]; + literal mk_and(literal l1, literal l2, literal l3) { + literal_vector xs; + xs.push_back(l1); xs.push_back(l2); xs.push_back(l3); + return mk_and(xs); + } + + bool is_true(literal l) { + return l == ctx.mk_true(); + } + + bool is_false(literal l) { + return l == ctx.mk_false(); + } + + literal mk_and(literal_vector const& _ands) { + literal_vector ands(_ands); + unsigned j = 0; + for (literal lit : ands) { + if (is_false(lit)) return lit; + if (!is_true(lit)) ands[j++] = lit; + } + ands.shrink(j); + switch (j) { + case 0: + return ctx.mk_true(); + case 1: + return ands[0]; + case 2: + return mk_min(ands[0], ands[1]); + default: { + return ctx.mk_min(ands.size(), ands.c_ptr()); + } } - literal result = fresh("and"); - add_implies_and(result, ands); - add_and_implies(result, ands); - return result; } literal mk_exactly_1(bool full, unsigned n, literal const* xs) { @@ -363,13 +593,16 @@ Notes: literal_vector ors; literal r1; switch (m_cfg.m_encoding) { - case grouped_at_most_1: + case grouped_at_most: + case sorted_at_most: + case unate_at_most: + case circuit_at_most: r1 = mk_at_most_1(full, n, xs, ors, true); break; - case bimander_at_most_1: + case bimander_at_most: r1 = mk_at_most_1_bimander(full, n, xs, ors); break; - case ordered_at_most_1: + case ordered_at_most: return mk_ordered_exactly_1(full, n, xs); default: UNREACHABLE(); @@ -426,7 +659,7 @@ Notes: // result => xs[0] + ... + xs[n-1] <= 1 for (unsigned i = 0; i < n; ++i) { for (unsigned j = i + 1; j < n; ++j) { - add_clause(ctx.mk_not(result), ctx.mk_not(xs[i]), ctx.mk_not(xs[j])); + add_clause(mk_not(result), mk_not(xs[i]), mk_not(xs[j])); } } @@ -441,7 +674,7 @@ Notes: } add_clause(lits); } - ands.push_back(ctx.mk_not(and_i)); + ands.push_back(mk_not(and_i)); } } @@ -457,7 +690,7 @@ Notes: literal_vector ands; for (unsigned i = 0; i < n; ++i) { for (unsigned j = i + 1; j < n; ++j) { - ands.push_back(mk_or(ctx.mk_not(xs[i]), ctx.mk_not(xs[j]))); + ands.push_back(mk_or(mk_not(xs[i]), mk_not(xs[j]))); } } return mk_and(ands); @@ -513,36 +746,36 @@ Notes: ys.push_back(fresh("y")); } for (unsigned i = 0; i + 2 < n; ++i) { - add_clause(ctx.mk_not(ys[i]), ys[i + 1]); + add_clause(mk_not(ys[i]), ys[i + 1]); } for (unsigned i = 0; i + 1 < n; ++i) { - add_clause(ctx.mk_not(xs[i]), ys[i]); - add_clause(ctx.mk_not(r), ctx.mk_not(ys[i]), ctx.mk_not(xs[i + 1])); + add_clause(mk_not(xs[i]), ys[i]); + add_clause(mk_not(r), mk_not(ys[i]), mk_not(xs[i + 1])); } if (is_eq) { - add_clause(ctx.mk_not(r), ys[n-2], xs[n-1]); + add_clause(mk_not(r), ys[n-2], xs[n-1]); } for (unsigned i = 1; i < n - 1; ++i) { - add_clause(ctx.mk_not(ys[i]), xs[i], ys[i-1]); + add_clause(mk_not(ys[i]), xs[i], ys[i-1]); } - add_clause(ctx.mk_not(ys[0]), xs[0]); + add_clause(mk_not(ys[0]), xs[0]); if (full) { literal_vector twos; for (unsigned i = 0; i < n - 1; ++i) { twos.push_back(fresh("two")); } - add_clause(ctx.mk_not(twos[0]), ys[0]); - add_clause(ctx.mk_not(twos[0]), xs[1]); + add_clause(mk_not(twos[0]), ys[0]); + add_clause(mk_not(twos[0]), xs[1]); for (unsigned i = 1; i < n - 1; ++i) { - add_clause(ctx.mk_not(twos[i]), ys[i], twos[i-1]); - add_clause(ctx.mk_not(twos[i]), xs[i + 1], twos[i-1]); + add_clause(mk_not(twos[i]), ys[i], twos[i-1]); + add_clause(mk_not(twos[i]), xs[i + 1], twos[i-1]); } if (is_eq) { literal zero = fresh("zero"); - add_clause(ctx.mk_not(zero), ctx.mk_not(xs[n-1])); - add_clause(ctx.mk_not(zero), ctx.mk_not(ys[n-2])); + add_clause(mk_not(zero), mk_not(xs[n-1])); + add_clause(mk_not(zero), mk_not(ys[n-2])); add_clause(r, zero, twos.back()); } else { @@ -579,7 +812,7 @@ Notes: for (unsigned i = 0; i < ors.size(); ++i) { for (unsigned k = 0; k < nbits; ++k) { bool bit_set = (i & (static_cast(1 << k))) != 0; - add_clause(ctx.mk_not(result), ctx.mk_not(ors[i]), bit_set ? bits[k] : ctx.mk_not(bits[k])); + add_clause(mk_not(result), mk_not(ors[i]), bit_set ? bits[k] : mk_not(bits[k])); } } return result; @@ -608,10 +841,10 @@ Notes: } k = N - k; for (unsigned i = 0; i < N; ++i) { - in.push_back(ctx.mk_not(xs[i])); + in.push_back(mk_not(xs[i])); } TRACE("pb_verbose", - pp(tout << N << ": ", in); + //pp(tout << N << ": ", in); tout << " ~ " << k << "\n";); return true; } @@ -627,13 +860,15 @@ Notes: literal mk_max(literal a, literal b) { if (a == b) return a; m_stats.m_num_compiled_vars++; - return ctx.mk_max(a, b); + literal lits[2] = { a, b}; + return ctx.mk_max(2, lits); } literal mk_min(literal a, literal b) { if (a == b) return a; m_stats.m_num_compiled_vars++; - return ctx.mk_min(a, b); + literal lits[2] = { a, b}; + return ctx.mk_min(2, lits); } literal fresh(char const* n) { @@ -652,6 +887,9 @@ Notes: add_clause(lits.size(), lits.c_ptr()); } void add_clause(unsigned n, literal const* ls) { + for (unsigned i = 0; i < n; ++i) { + if (is_true(ls[i])) return; + } m_stats.m_num_compiled_clauses++; m_stats.m_num_clause_vars += n; literal_vector tmp(n, ls); @@ -661,17 +899,17 @@ Notes: // y1 <= mk_max(x1,x2) // y2 <= mk_min(x1,x2) void cmp_ge(literal x1, literal x2, literal y1, literal y2) { - add_clause(ctx.mk_not(y2), x1); - add_clause(ctx.mk_not(y2), x2); - add_clause(ctx.mk_not(y1), x1, x2); + add_clause(mk_not(y2), x1); + add_clause(mk_not(y2), x2); + add_clause(mk_not(y1), x1, x2); } // mk_max(x1,x2) <= y1 // mk_min(x1,x2) <= y2 void cmp_le(literal x1, literal x2, literal y1, literal y2) { - add_clause(ctx.mk_not(x1), y1); - add_clause(ctx.mk_not(x2), y1); - add_clause(ctx.mk_not(x1), ctx.mk_not(x2), y2); + add_clause(mk_not(x1), y1); + add_clause(mk_not(x2), y1); + add_clause(mk_not(x1), mk_not(x2), y2); } void cmp_eq(literal x1, literal x2, literal y1, literal y2) { @@ -696,18 +934,21 @@ Notes: psort_nw::sorting(n, xs, out); } else if (use_dcard(k, n)) { + TRACE("pb_verbose", tout << "use dcard\n";); dsorting(k, n, xs, out); } else { + TRACE("pb_verbose", tout << "use merge\n";); literal_vector out1, out2; - unsigned l = n/2; // TBD - card(k, l, xs, out1); - card(k, n-l, xs + l, out2); + unsigned half = n/2; // TBD + card(k, half, xs, out1); + card(k, n-half, xs + half, out2); smerge(k, out1.size(), out1.c_ptr(), out2.size(), out2.c_ptr(), out); } TRACE("pb_verbose", tout << "card k: " << k << " n: " << n << "\n"; - pp(tout << "in:", n, xs) << "\n"; - pp(tout << "out:", out) << "\n";); + //pp(tout << "in:", n, xs) << "\n"; + //pp(tout << "out:", out) << "\n"; + ); } vc vc_card(unsigned k, unsigned n) { @@ -733,7 +974,8 @@ Notes: void merge(unsigned a, literal const* as, unsigned b, literal const* bs, literal_vector& out) { - TRACE("pb_verbose", tout << "merge a: " << a << " b: " << b << "\n";); + unsigned nc = m_stats.m_num_compiled_clauses; + (void)nc; if (a == 1 && b == 1) { literal y1 = mk_max(as[0], bs[0]); literal y2 = mk_min(as[0], bs[0]); @@ -768,10 +1010,14 @@ Notes: odd_b.size(), odd_b.c_ptr(), out2); interleave(out1, out2, out); } - TRACE("pb_verbose", tout << "merge a: " << a << " b: " << b << "\n"; - pp(tout << "a:", a, as) << "\n"; - pp(tout << "b:", b, bs) << "\n"; - pp(tout << "out:", out) << "\n";); + TRACE("pb_verbose", tout << "merge a: " << a << " b: " << b << " "; + tout << "num clauses " << m_stats.m_num_compiled_clauses - nc << "\n"; + vc_dsmerge(a, b, a + b).pp(tout << "vc_dsmerge ") << "\n"; + vc_smerge_rec(a, b, a + b).pp(tout << "vc_smerge_rec ") << "\n"; + //pp(tout << "a:", a, as) << "\n"; + //pp(tout << "b:", b, bs) << "\n"; + //pp(tout << "out:", out) << "\n"; + ); } vc vc_merge(unsigned a, unsigned b) { if (a == 1 && b == 1) { @@ -791,7 +1037,8 @@ Notes: return vc_merge(ceil2(a), ceil2(b)) + vc_merge(floor2(a), floor2(b)) + - vc_interleave(ceil2(a) + ceil2(b), floor2(a) + floor2(b)); + vc_interleave(ceil2(a) + ceil2(b), floor2(a) + floor2(b)) - + vc(0, 2); } void split(unsigned n, literal const* ls, literal_vector& even, literal_vector& odd) { for (unsigned i = 0; i < n; i += 2) { @@ -805,7 +1052,8 @@ Notes: void interleave(literal_vector const& as, literal_vector const& bs, literal_vector& out) { - TRACE("pb_verbose", tout << "interleave: " << as.size() << " " << bs.size() << "\n";); + unsigned nc = m_stats.m_num_compiled_clauses; + (void)nc; SASSERT(as.size() >= bs.size()); SASSERT(as.size() <= bs.size() + 2); SASSERT(!as.empty()); @@ -825,10 +1073,12 @@ Notes: out.push_back(as[sz+1]); } SASSERT(out.size() == as.size() + bs.size()); - TRACE("pb_verbose", tout << "interleave: " << as.size() << " " << bs.size() << "\n"; - pp(tout << "a: ", as) << "\n"; - pp(tout << "b: ", bs) << "\n"; - pp(tout << "out: ", out) << "\n";); + TRACE("pb_verbose", tout << "interleave: " << as.size() << " " << bs.size() << " "; + tout << "num clauses " << m_stats.m_num_compiled_clauses - nc << "\n"; + //pp(tout << "a: ", as) << "\n"; + //pp(tout << "b: ", bs) << "\n"; + //pp(tout << "out: ", out) << "\n"; + ); } vc vc_interleave(unsigned a, unsigned b) { @@ -849,13 +1099,15 @@ Notes: break; default: if (use_dsorting(n)) { + TRACE("pb_verbose", tout << "use dsorting: " << n << "\n";); dsorting(n, n, xs, out); } else { + TRACE("pb_verbose", tout << "use merge: " << n << "\n";); literal_vector out1, out2; - unsigned l = n/2; // TBD - sorting(l, xs, out1); - sorting(n-l, xs+l, out2); + unsigned half = n/2; // TBD + sorting(half, xs, out1); + sorting(n-half, xs+half, out2); merge(out1.size(), out1.c_ptr(), out2.size(), out2.c_ptr(), out); @@ -863,8 +1115,9 @@ Notes: break; } TRACE("pb_verbose", tout << "sorting: " << n << "\n"; - pp(tout << "in:", n, xs) << "\n"; - pp(tout << "out:", out) << "\n";); + //pp(tout << "in:", n, xs) << "\n"; + //pp(tout << "out:", out) << "\n"; + ); } private: @@ -898,18 +1151,19 @@ Notes: unsigned a, literal const* as, unsigned b, literal const* bs, literal_vector& out) { - TRACE("pb_verbose", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n";); + unsigned nc = m_stats.m_num_compiled_clauses; + (void)nc; if (a == 1 && b == 1 && c == 1) { literal y = mk_max(as[0], bs[0]); if (m_t != GE) { // x1 <= mk_max(x1,x2) // x2 <= mk_max(x1,x2) - add_clause(ctx.mk_not(as[0]), y); - add_clause(ctx.mk_not(bs[0]), y); + add_clause(mk_not(as[0]), y); + add_clause(mk_not(bs[0]), y); } if (m_t != LE) { // mk_max(x1,x2) <= x1, x2 - add_clause(ctx.mk_not(y), as[0], bs[0]); + add_clause(mk_not(y), as[0], bs[0]); } out.push_back(y); } @@ -960,11 +1214,11 @@ Notes: out2.pop_back(); y = mk_max(z1, z2); if (m_t != GE) { - add_clause(ctx.mk_not(z1), y); - add_clause(ctx.mk_not(z2), y); + add_clause(mk_not(z1), y); + add_clause(mk_not(z2), y); } if (m_t != LE) { - add_clause(ctx.mk_not(y), z1, z2); + add_clause(mk_not(y), z1, z2); } } interleave(out1, out2, out); @@ -972,10 +1226,11 @@ Notes: out.push_back(y); } } - TRACE("pb_verbose", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n"; - pp(tout << "a:", a, as) << "\n"; - pp(tout << "b:", b, bs) << "\n"; - pp(tout << "out:", out) << "\n"; + TRACE("pb_verbose", tout << "smerge: c:" << c << " a:" << a << " b:" << b << " "; + tout << "num clauses " << m_stats.m_num_compiled_clauses - nc << "\n"; + //pp(tout << "a:", a, as) << "\n"; + //pp(tout << "b:", b, bs) << "\n"; + //pp(tout << "out:", out) << "\n"; ); SASSERT(out.size() == std::min(a + b, c)); } @@ -1007,7 +1262,7 @@ Notes: return m_force_dsmerge || (!m_disable_dsmerge && - a < (1 << 15) && b < (1 << 15) && + a < 10 && b < 10 && vc_dsmerge(a, b, a + b) < vc_smerge_rec(a, b, c)); } @@ -1016,7 +1271,8 @@ Notes: unsigned a, literal const* as, unsigned b, literal const* bs, literal_vector& out) { - TRACE("pb_verbose", tout << "dsmerge: c:" << c << " a:" << a << " b:" << b << "\n";); + unsigned nc = m_stats.m_num_compiled_clauses; + (void)nc; SASSERT(a <= c); SASSERT(b <= c); SASSERT(a + b >= c); @@ -1025,14 +1281,14 @@ Notes: } if (m_t != GE) { for (unsigned i = 0; i < a; ++i) { - add_clause(ctx.mk_not(as[i]), out[i]); + add_clause(mk_not(as[i]), out[i]); } for (unsigned i = 0; i < b; ++i) { - add_clause(ctx.mk_not(bs[i]), out[i]); + add_clause(mk_not(bs[i]), out[i]); } for (unsigned i = 1; i <= a; ++i) { for (unsigned j = 1; j <= b && i + j <= c; ++j) { - add_clause(ctx.mk_not(as[i-1]),ctx.mk_not(bs[j-1]),out[i+j-1]); + add_clause(mk_not(as[i-1]),mk_not(bs[j-1]),out[i+j-1]); } } } @@ -1040,12 +1296,12 @@ Notes: literal_vector ls; for (unsigned k = 0; k < c; ++k) { ls.reset(); - ls.push_back(ctx.mk_not(out[k])); + ls.push_back(mk_not(out[k])); if (a <= k) { - add_clause(ctx.mk_not(out[k]), bs[k-a]); + add_clause(mk_not(out[k]), bs[k-a]); } if (b <= k) { - add_clause(ctx.mk_not(out[k]), as[k-b]); + add_clause(mk_not(out[k]), as[k-b]); } for (unsigned i = 0; i < std::min(a,k + 1); ++i) { unsigned j = k - i; @@ -1060,7 +1316,13 @@ Notes: } } } + TRACE("pb_verbose", tout << "dsmerge: c:" << c << " a:" << a << " b:" << b << " "; + tout << "num clauses: " << m_stats.m_num_compiled_clauses - nc << "\n"; + vc_dsmerge(a, b, c).pp(tout << "vc_dsmerge ") << "\n"; + vc_smerge_rec(a, b, c).pp(tout << "vc_smerge_rec ") << "\n"; + ); } + vc vc_dsmerge(unsigned a, unsigned b, unsigned c) { vc v(c, 0); if (m_t != GE) { @@ -1075,9 +1337,10 @@ Notes: void dsorting(unsigned m, unsigned n, literal const* xs, literal_vector& out) { - TRACE("pb_verbose", tout << "dsorting m: " << m << " n: " << n << "\n";); SASSERT(m <= n); literal_vector lits; + unsigned nc = m_stats.m_num_compiled_clauses; + (void)nc; for (unsigned i = 0; i < m; ++i) { out.push_back(fresh("dsort")); } @@ -1090,12 +1353,16 @@ Notes: } if (m_t != LE) { for (unsigned k = 1; k <= m; ++k) { - lits.push_back(ctx.mk_not(out[k-1])); + lits.push_back(mk_not(out[k-1])); add_subset(false, n-k+1, 0, lits, n, xs); lits.pop_back(); } } + TRACE("pb_verbose", + tout << "dsorting m: " << m << " n: " << n << " "; + tout << "num clauses: " << m_stats.m_num_compiled_clauses - nc << "\n";); } + vc vc_dsorting(unsigned m, unsigned n) { SASSERT(m <= n && n < 10); vc v(m, 0); @@ -1111,14 +1378,15 @@ Notes: void add_subset(bool polarity, unsigned k, unsigned offset, literal_vector& lits, unsigned n, literal const* xs) { TRACE("pb_verbose", tout << "k:" << k << " offset: " << offset << " n: " << n << " "; - pp(tout, lits) << "\n";); + //pp(tout, lits) << "\n"; + ); SASSERT(k + offset <= n); if (k == 0) { add_clause(lits); return; } for (unsigned i = offset; i < n - k + 1; ++i) { - lits.push_back(polarity?ctx.mk_not(xs[i]):xs[i]); + lits.push_back(polarity?mk_not(xs[i]):xs[i]); add_subset(polarity, k-1, i+1, lits, n, xs); lits.pop_back(); } diff --git a/src/util/symbol.h b/src/util/symbol.h index 88e825551..40844cf3b 100644 --- a/src/util/symbol.h +++ b/src/util/symbol.h @@ -19,7 +19,7 @@ Revision History: #ifndef SYMBOL_H_ #define SYMBOL_H_ #include -#include +#include #include "util/util.h" #include "util/tptr.h" diff --git a/src/util/trace.cpp b/src/util/trace.cpp index 9571e99e6..68437ab92 100644 --- a/src/util/trace.cpp +++ b/src/util/trace.cpp @@ -21,7 +21,6 @@ Revision History: #ifdef _TRACE std::ofstream tout(".z3-trace"); -#endif static bool g_enable_all_trace_tags = false; static str_hashtable* g_enabled_trace_tags = nullptr; @@ -56,13 +55,11 @@ bool is_trace_enabled(const char * tag) { } void close_trace() { -#ifdef _TRACE tout.close(); -#endif } void open_trace() { -#ifdef _TRACE tout.open(".z3-trace"); -#endif } + +#endif diff --git a/src/util/trace.h b/src/util/trace.h index 789beafc1..1a245036f 100644 --- a/src/util/trace.h +++ b/src/util/trace.h @@ -33,9 +33,6 @@ Revision History: #ifdef _TRACE extern std::ofstream tout; #define TRACE_CODE(CODE) { CODE } ((void) 0 ) -#else -#define TRACE_CODE(CODE) ((void) 0) -#endif void enable_trace(const char * tag); void enable_all_trace(bool flag); @@ -48,6 +45,18 @@ void finalize_trace(); ADD_FINALIZER('finalize_trace();') */ +#else +#define TRACE_CODE(CODE) ((void) 0) + +static inline void enable_trace(const char * tag) {} +static inline void enable_all_trace(bool flag) {} +static inline void disable_trace(const char * tag) {} +static inline bool is_trace_enabled(const char * tag) { return false; } +static inline void close_trace() {} +static inline void open_trace() {} +static inline void finalize_trace() {} +#endif + #define TRACE(TAG, CODE) TRACE_CODE(if (is_trace_enabled(TAG)) { tout << "-------- [" << TAG << "] " << __FUNCTION__ << " " << __FILE__ << ":" << __LINE__ << " ---------\n"; CODE tout << "------------------------------------------------\n"; tout.flush(); }) #define STRACE(TAG, CODE) TRACE_CODE(if (is_trace_enabled(TAG)) { CODE tout.flush(); }) @@ -55,4 +64,3 @@ void finalize_trace(); #define CTRACE(TAG, COND, CODE) TRACE_CODE(if (is_trace_enabled(TAG) && (COND)) { tout << "-------- [" << TAG << "] " << __FUNCTION__ << " " << __FILE__ << ":" << __LINE__ << " ---------\n"; CODE tout << "------------------------------------------------\n"; tout.flush(); }) #endif /* TRACE_H_ */ -