diff --git a/README.md b/README.md index 502b32147..e0821ac79 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ Z3 can be built using [Visual Studio][1], a [Makefile][2] or using [CMake][3]. I See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z3. +## Build status + +| Windows x86 | Windows x64 | Ubuntu x64 | Ubuntu x86 | Debian x64 | OSX | +| ----------- | ----------- | ---------- | ---------- | ---------- | --- | +![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge) | ![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge) | ![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge) | ![ubuntu-x86-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/6/badge) | ![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge) | ![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge) + [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang [3]: #building-z3-using-cmake diff --git a/contrib/cmake/src/math/polynomial/CMakeLists.txt b/contrib/cmake/src/math/polynomial/CMakeLists.txt index 1792f50aa..1d320d751 100644 --- a/contrib/cmake/src/math/polynomial/CMakeLists.txt +++ b/contrib/cmake/src/math/polynomial/CMakeLists.txt @@ -3,7 +3,6 @@ z3_add_component(polynomial algebraic_numbers.cpp polynomial_cache.cpp polynomial.cpp - polynomial_factorization.cpp rpolynomial.cpp sexpr2upolynomial.cpp upolynomial.cpp diff --git a/contrib/cmake/src/sat/CMakeLists.txt b/contrib/cmake/src/sat/CMakeLists.txt index cfc3835c1..3eec21ec3 100644 --- a/contrib/cmake/src/sat/CMakeLists.txt +++ b/contrib/cmake/src/sat/CMakeLists.txt @@ -2,7 +2,6 @@ z3_add_component(sat SOURCES dimacs.cpp sat_asymm_branch.cpp - sat_bceq.cpp sat_clause.cpp sat_clause_set.cpp sat_clause_use_list.cpp @@ -16,7 +15,6 @@ z3_add_component(sat sat_probing.cpp sat_scc.cpp sat_simplifier.cpp - sat_sls.cpp sat_solver.cpp sat_watched.cpp COMPONENT_DEPENDENCIES diff --git a/contrib/cmake/src/smt/CMakeLists.txt b/contrib/cmake/src/smt/CMakeLists.txt index 035ac07c9..bd8ad3f31 100644 --- a/contrib/cmake/src/smt/CMakeLists.txt +++ b/contrib/cmake/src/smt/CMakeLists.txt @@ -43,6 +43,7 @@ z3_add_component(smt smt_statistics.cpp smt_theory.cpp smt_value_sort.cpp + smt2_extra_cmds.cpp theory_arith.cpp theory_array_base.cpp theory_array.cpp diff --git a/contrib/cmake/src/test/CMakeLists.txt b/contrib/cmake/src/test/CMakeLists.txt index 6f6615e0c..6ea07e84c 100644 --- a/contrib/cmake/src/test/CMakeLists.txt +++ b/contrib/cmake/src/test/CMakeLists.txt @@ -82,7 +82,6 @@ add_executable(test-z3 pdr.cpp permutation.cpp polynomial.cpp - polynomial_factorization.cpp polynorm.cpp prime_generator.cpp proof_checker.cpp diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 5b10dadd0..20bb012b1 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -818,6 +818,7 @@ namespace test_mapi BigIntCheck(ctx, ctx.MkReal("234234333/2")); +#if !FRAMEWORK_LT_4 string bn = "1234567890987654321"; if (ctx.MkInt(bn).BigInteger.ToString() != bn) @@ -828,6 +829,7 @@ namespace test_mapi if (ctx.MkBV(bn, 32).BigInteger.ToString() == bn) throw new TestFailedException(); +#endif // Error handling test. try @@ -1094,8 +1096,10 @@ namespace test_mapi static void BigIntCheck(Context ctx, RatNum r) { +#if !FRAMEWORK_LT_4 Console.WriteLine("Num: " + r.BigIntNumerator); Console.WriteLine("Den: " + r.BigIntDenominator); +#endif } /// diff --git a/scripts/mk_consts_files.py b/scripts/mk_consts_files.py index e582d8468..d0502c19d 100755 --- a/scripts/mk_consts_files.py +++ b/scripts/mk_consts_files.py @@ -22,6 +22,7 @@ def main(args): dest="java_package_name", default=None, help="Name to give the Java package (e.g. ``com.microsoft.z3``).") + parser.add_argument("--ml-output-dir", dest="ml_output_dir", default=None) pargs = parser.parse_args(args) if not mk_genfile_common.check_files_exist(pargs.api_files): @@ -60,6 +61,15 @@ def main(args): logging.info('Generated "{}"'.format(generated_file)) count += 1 + if pargs.ml_output_dir: + if not mk_genfile_common.check_dir_exists(pargs.ml_output_dir): + return 1 + output = mk_genfile_common.mk_z3consts_ml_internal( + pargs.api_files, + pargs.ml_output_dir) + logging.info('Generated "{}"'.format(output)) + count += 1 + if count == 0: logging.info('No files generated. You need to specific an output directory' ' for the relevant langauge bindings') diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index 7e7cb5584..98346f99f 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -376,6 +376,180 @@ def mk_z3consts_java_internal(api_files, package_name, output_dir): api.close() return generated_enumeration_files +# Extract enumeration types from z3_api.h, and add ML definitions +def mk_z3consts_ml_internal(api_files, output_dir): + """ + Generate ``z3enums.ml`` from the list of API header files + in ``api_files`` and write the output file into + the ``output_dir`` directory + + Returns the path to the generated file. + """ + assert os.path.isdir(output_dir) + assert isinstance(api_files, list) + blank_pat = re.compile("^ *$") + comment_pat = re.compile("^ *//.*$") + typedef_pat = re.compile("typedef enum *") + typedef2_pat = re.compile("typedef enum { *") + openbrace_pat = re.compile("{ *") + closebrace_pat = re.compile("}.*;") + + + DeprecatedEnums = [ 'Z3_search_failure' ] + if not os.path.exists(output_dir): + os.mkdir(output_dir) + + efile = open('%s.ml' % os.path.join(output_dir, "z3enums"), 'w') + z3consts_output_path = efile.name + efile.write('(* Automatically generated file *)\n\n') + efile.write('(** The enumeration types of Z3. *)\n\n') + for api_file in api_files: + api = open(api_file, 'r') + + SEARCHING = 0 + FOUND_ENUM = 1 + IN_ENUM = 2 + + mode = SEARCHING + decls = {} + idx = 0 + + linenum = 1 + for line in api: + m1 = blank_pat.match(line) + m2 = comment_pat.match(line) + if m1 or m2: + # skip blank lines and comments + linenum = linenum + 1 + elif mode == SEARCHING: + m = typedef_pat.match(line) + if m: + mode = FOUND_ENUM + m = typedef2_pat.match(line) + if m: + mode = IN_ENUM + decls = {} + idx = 0 + elif mode == FOUND_ENUM: + m = openbrace_pat.match(line) + if m: + mode = IN_ENUM + decls = {} + idx = 0 + else: + assert False, "Invalid %s, line: %s" % (api_file, linenum) + else: + assert mode == IN_ENUM + words = re.split('[^\-a-zA-Z0-9_]+', line) + m = closebrace_pat.match(line) + if m: + name = words[1] + if name not in DeprecatedEnums: + sorted_decls = sorted(decls.items(), key=lambda pair: pair[1]) + efile.write('(** %s *)\n' % name[3:]) + efile.write('type %s =\n' % name[3:]) # strip Z3_ + for k, i in sorted_decls: + efile.write(' | %s \n' % k[3:]) # strip Z3_ + efile.write('\n') + efile.write('(** Convert %s to int*)\n' % name[3:]) + efile.write('let int_of_%s x : int =\n' % (name[3:])) # strip Z3_ + efile.write(' match x with\n') + for k, i in sorted_decls: + efile.write(' | %s -> %d\n' % (k[3:], i)) + efile.write('\n') + efile.write('(** Convert int to %s*)\n' % name[3:]) + efile.write('let %s_of_int x : %s =\n' % (name[3:],name[3:])) # strip Z3_ + efile.write(' match x with\n') + for k, i in sorted_decls: + efile.write(' | %d -> %s\n' % (i, k[3:])) + # use Z3.Exception? + efile.write(' | _ -> raise (Failure "undefined enum value")\n\n') + mode = SEARCHING + else: + if words[2] != '': + if len(words[2]) > 1 and words[2][1] == 'x': + idx = int(words[2], 16) + else: + idx = int(words[2]) + decls[words[1]] = idx + idx = idx + 1 + linenum = linenum + 1 + api.close() + efile.close() + return z3consts_output_path + # efile = open('%s.mli' % os.path.join(gendir, "z3enums"), 'w') + # efile.write('(* Automatically generated file *)\n\n') + # efile.write('(** The enumeration types of Z3. *)\n\n') + # for api_file in api_files: + # api_file_c = ml.find_file(api_file, ml.name) + # api_file = os.path.join(api_file_c.src_dir, api_file) + + # api = open(api_file, 'r') + + # SEARCHING = 0 + # FOUND_ENUM = 1 + # IN_ENUM = 2 + + # mode = SEARCHING + # decls = {} + # idx = 0 + + # linenum = 1 + # for line in api: + # m1 = blank_pat.match(line) + # m2 = comment_pat.match(line) + # if m1 or m2: + # # skip blank lines and comments + # linenum = linenum + 1 + # elif mode == SEARCHING: + # m = typedef_pat.match(line) + # if m: + # mode = FOUND_ENUM + # m = typedef2_pat.match(line) + # if m: + # mode = IN_ENUM + # decls = {} + # idx = 0 + # elif mode == FOUND_ENUM: + # m = openbrace_pat.match(line) + # if m: + # mode = IN_ENUM + # decls = {} + # idx = 0 + # else: + # assert False, "Invalid %s, line: %s" % (api_file, linenum) + # else: + # assert mode == IN_ENUM + # words = re.split('[^\-a-zA-Z0-9_]+', line) + # m = closebrace_pat.match(line) + # if m: + # name = words[1] + # if name not in DeprecatedEnums: + # efile.write('(** %s *)\n' % name[3:]) + # efile.write('type %s =\n' % name[3:]) # strip Z3_ + # for k, i in sorted(decls.items(), key=lambda pair: pair[1]): + # efile.write(' | %s \n' % k[3:]) # strip Z3_ + # efile.write('\n') + # efile.write('(** Convert %s to int*)\n' % name[3:]) + # efile.write('val int_of_%s : %s -> int\n' % (name[3:], name[3:])) # strip Z3_ + # efile.write('(** Convert int to %s*)\n' % name[3:]) + # efile.write('val %s_of_int : int -> %s\n' % (name[3:],name[3:])) # strip Z3_ + # efile.write('\n') + # mode = SEARCHING + # else: + # if words[2] != '': + # if len(words[2]) > 1 and words[2][1] == 'x': + # idx = int(words[2], 16) + # else: + # idx = int(words[2]) + # decls[words[1]] = idx + # idx = idx + 1 + # linenum = linenum + 1 + # api.close() + # efile.close() + # if VERBOSE: + # print ('Generated "%s/z3enums.mli"' % ('%s' % gendir)) + ############################################################################### # Functions for generating a "module definition file" for MSVC diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 527797e66..488bc4364 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -27,6 +27,7 @@ DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False PYTHON_ENABLED=True +MAKEJOBS=getenv("MAKEJOBS", '8') def set_verbose(flag): global VERBOSE @@ -139,7 +140,7 @@ class cd: def mk_z3(): with cd(BUILD_DIR): try: - return subprocess.call(['make', '-j', '8']) + return subprocess.call(['make', '-j', MAKEJOBS]) except: return 1 diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 235453845..807a131c1 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2442,7 +2442,7 @@ def mk_config(): CXXFLAGS = '%s -O3 -D _EXTERNAL_RELEASE -fomit-frame-pointer' % CXXFLAGS if is_CXX_clangpp(): CXXFLAGS = '%s -Wno-unknown-pragmas -Wno-overloaded-virtual -Wno-unused-value' % CXXFLAGS - sysname = os.uname()[0] + sysname, _, _, _, machine = os.uname() if sysname == 'Darwin': SO_EXT = '.dylib' SLIBFLAGS = '-dynamiclib' @@ -2493,7 +2493,9 @@ def mk_config(): # and to make it create an import library. SLIBEXTRAFLAGS = '%s -static-libgcc -static-libstdc++ -Wl,--out-implib,libz3.dll.a' % SLIBEXTRAFLAGS LDFLAGS = '%s -static-libgcc -static-libstdc++' % LDFLAGS - + if sysname == 'Linux' and machine.startswith('armv7') or machine.startswith('armv8'): + CXXFLAGS = '%s -fpic' % CXXFLAGS + config.write('PREFIX=%s\n' % PREFIX) config.write('CC=%s\n' % CC) config.write('CXX=%s\n' % CXX) @@ -2870,7 +2872,8 @@ def mk_bindings(api_files): dotnet_output_dir=dotnet_output_dir, java_output_dir=java_output_dir, java_package_name=java_package_name, - ml_output_dir=ml_output_dir + ml_output_dir=ml_output_dir, + ml_src_dir=ml_output_dir ) cp_z3py_to_build() if is_ml_enabled(): @@ -2924,172 +2927,17 @@ def mk_z3consts_java(api_files): # Extract enumeration types from z3_api.h, and add ML definitions def mk_z3consts_ml(api_files): - blank_pat = re.compile("^ *$") - comment_pat = re.compile("^ *//.*$") - typedef_pat = re.compile("typedef enum *") - typedef2_pat = re.compile("typedef enum { *") - openbrace_pat = re.compile("{ *") - closebrace_pat = re.compile("}.*;") - ml = get_component(ML_COMPONENT) - - DeprecatedEnums = [ 'Z3_search_failure' ] - gendir = ml.src_dir - if not os.path.exists(gendir): - os.mkdir(gendir) - - efile = open('%s.ml' % os.path.join(gendir, "z3enums"), 'w') - efile.write('(* Automatically generated file *)\n\n') - efile.write('(** The enumeration types of Z3. *)\n\n') + full_path_api_files = [] for api_file in api_files: api_file_c = ml.find_file(api_file, ml.name) api_file = os.path.join(api_file_c.src_dir, api_file) - - api = open(api_file, 'r') - - SEARCHING = 0 - FOUND_ENUM = 1 - IN_ENUM = 2 - - mode = SEARCHING - decls = {} - idx = 0 - - linenum = 1 - for line in api: - m1 = blank_pat.match(line) - m2 = comment_pat.match(line) - if m1 or m2: - # skip blank lines and comments - linenum = linenum + 1 - elif mode == SEARCHING: - m = typedef_pat.match(line) - if m: - mode = FOUND_ENUM - m = typedef2_pat.match(line) - if m: - mode = IN_ENUM - decls = {} - idx = 0 - elif mode == FOUND_ENUM: - m = openbrace_pat.match(line) - if m: - mode = IN_ENUM - decls = {} - idx = 0 - else: - assert False, "Invalid %s, line: %s" % (api_file, linenum) - else: - assert mode == IN_ENUM - words = re.split('[^\-a-zA-Z0-9_]+', line) - m = closebrace_pat.match(line) - if m: - name = words[1] - if name not in DeprecatedEnums: - efile.write('(** %s *)\n' % name[3:]) - efile.write('type %s =\n' % name[3:]) # strip Z3_ - for k, i in decls.items(): - efile.write(' | %s \n' % k[3:]) # strip Z3_ - efile.write('\n') - efile.write('(** Convert %s to int*)\n' % name[3:]) - efile.write('let int_of_%s x : int =\n' % (name[3:])) # strip Z3_ - efile.write(' match x with\n') - for k, i in decls.items(): - efile.write(' | %s -> %d\n' % (k[3:], i)) - efile.write('\n') - efile.write('(** Convert int to %s*)\n' % name[3:]) - efile.write('let %s_of_int x : %s =\n' % (name[3:],name[3:])) # strip Z3_ - efile.write(' match x with\n') - for k, i in decls.items(): - efile.write(' | %d -> %s\n' % (i, k[3:])) - # use Z3.Exception? - efile.write(' | _ -> raise (Failure "undefined enum value")\n\n') - mode = SEARCHING - else: - if words[2] != '': - if len(words[2]) > 1 and words[2][1] == 'x': - idx = int(words[2], 16) - else: - idx = int(words[2]) - decls[words[1]] = idx - idx = idx + 1 - linenum = linenum + 1 - api.close() - efile.close() + full_path_api_files.append(api_file) + generated_file = mk_genfile_common.mk_z3consts_ml_internal( + full_path_api_files, + ml.src_dir) if VERBOSE: - print ('Generated "%s/z3enums.ml"' % ('%s' % gendir)) - # efile = open('%s.mli' % os.path.join(gendir, "z3enums"), 'w') - # efile.write('(* Automatically generated file *)\n\n') - # efile.write('(** The enumeration types of Z3. *)\n\n') - # for api_file in api_files: - # api_file_c = ml.find_file(api_file, ml.name) - # api_file = os.path.join(api_file_c.src_dir, api_file) - - # api = open(api_file, 'r') - - # SEARCHING = 0 - # FOUND_ENUM = 1 - # IN_ENUM = 2 - - # mode = SEARCHING - # decls = {} - # idx = 0 - - # linenum = 1 - # for line in api: - # m1 = blank_pat.match(line) - # m2 = comment_pat.match(line) - # if m1 or m2: - # # skip blank lines and comments - # linenum = linenum + 1 - # elif mode == SEARCHING: - # m = typedef_pat.match(line) - # if m: - # mode = FOUND_ENUM - # m = typedef2_pat.match(line) - # if m: - # mode = IN_ENUM - # decls = {} - # idx = 0 - # elif mode == FOUND_ENUM: - # m = openbrace_pat.match(line) - # if m: - # mode = IN_ENUM - # decls = {} - # idx = 0 - # else: - # assert False, "Invalid %s, line: %s" % (api_file, linenum) - # else: - # assert mode == IN_ENUM - # words = re.split('[^\-a-zA-Z0-9_]+', line) - # m = closebrace_pat.match(line) - # if m: - # name = words[1] - # if name not in DeprecatedEnums: - # efile.write('(** %s *)\n' % name[3:]) - # efile.write('type %s =\n' % name[3:]) # strip Z3_ - # for k, i in decls.items(): - # efile.write(' | %s \n' % k[3:]) # strip Z3_ - # efile.write('\n') - # efile.write('(** Convert %s to int*)\n' % name[3:]) - # efile.write('val int_of_%s : %s -> int\n' % (name[3:], name[3:])) # strip Z3_ - # efile.write('(** Convert int to %s*)\n' % name[3:]) - # efile.write('val %s_of_int : int -> %s\n' % (name[3:],name[3:])) # strip Z3_ - # efile.write('\n') - # mode = SEARCHING - # else: - # if words[2] != '': - # if len(words[2]) > 1 and words[2][1] == 'x': - # idx = int(words[2], 16) - # else: - # idx = int(words[2]) - # decls[words[1]] = idx - # idx = idx + 1 - # linenum = linenum + 1 - # api.close() - # efile.close() - # if VERBOSE: - # print ('Generated "%s/z3enums.mli"' % ('%s' % gendir)) + print ('Generated "%s"' % generated_file) def mk_gui_str(id): return '4D2F40D8-E5F9-473B-B548-%012d' % id diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 92d89480f..66f44426f 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -29,6 +29,9 @@ DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False PYTHON_ENABLED=True +X86ONLY=False +X64ONLY=False +MAKEJOBS=getenv("MAKEJOBS", "24") def set_verbose(flag): global VERBOSE @@ -63,11 +66,13 @@ def display_help(): print(" --nojava do not include Java bindings in the binary distribution files.") print(" --nopython do not include Python bindings in the binary distribution files.") print(" --githash include git hash in the Zip file.") + print(" --x86-only x86 dist only.") + print(" --x64-only x64 dist only.") exit(0) # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED, X86ONLY, X64ONLY path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -77,7 +82,9 @@ def parse_options(): 'nodotnet', 'dotnet-key=', 'githash', - 'nopython' + 'nopython', + 'x86-only', + 'x64-only' ]) for opt, arg in options: if opt in ('-b', '--build'): @@ -100,6 +107,10 @@ def parse_options(): JAVA_ENABLED = False elif opt == '--githash': GIT_HASH = True + elif opt == '--x86-only' and not X64ONLY: + X86ONLY = True + elif opt == '--x64-only' and not X86ONLY: + X64ONLY = True else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) @@ -111,7 +122,8 @@ def check_build_dir(path): # Create a build directory using mk_make.py def mk_build_dir(path, x64): if not check_build_dir(path) or FORCE_MK: - opts = ["python", os.path.join('scripts', 'mk_make.py'), "--parallel=24", "-b", path] + parallel = '--parallel=' + MAKEJOBS + opts = ["python", os.path.join('scripts', 'mk_make.py'), parallel, "-b", path] if DOTNET_ENABLED: opts.append('--dotnet') if not DOTNET_KEY_FILE is None: @@ -160,7 +172,7 @@ def exec_cmds(cmds): return res # Compile Z3 (if x64 == True, then it builds it in x64 mode). -def mk_z3_core(x64): +def mk_z3(x64): cmds = [] if x64: cmds.append('call "%VCINSTALLDIR%vcvarsall.bat" amd64') @@ -172,9 +184,9 @@ def mk_z3_core(x64): if exec_cmds(cmds) != 0: raise MKException("Failed to make z3, x64: %s" % x64) -def mk_z3(): - mk_z3_core(False) - mk_z3_core(True) +def mk_z3s(): + mk_z3(False) + mk_z3(True) def get_z3_name(x64): major, minor, build, revision = get_version() @@ -187,7 +199,7 @@ def get_z3_name(x64): else: return 'z3-%s.%s.%s-%s-win' % (major, minor, build, platform) -def mk_dist_dir_core(x64): +def mk_dist_dir(x64): if x64: platform = "x64" build_path = BUILD_X64_DIR @@ -204,14 +216,14 @@ def mk_dist_dir_core(x64): if is_verbose(): print("Generated %s distribution folder at '%s'" % (platform, dist_path)) -def mk_dist_dir(): - mk_dist_dir_core(False) - mk_dist_dir_core(True) +def mk_dist_dirs(): + mk_dist_dir(False) + mk_dist_dir(True) def get_dist_path(x64): return get_z3_name(x64) -def mk_zip_core(x64): +def mk_zip(x64): dist_path = get_dist_path(x64) old = os.getcwd() try: @@ -228,9 +240,9 @@ def mk_zip_core(x64): os.chdir(old) # Create a zip file for each platform -def mk_zip(): - mk_zip_core(False) - mk_zip_core(True) +def mk_zips(): + mk_zip(False) + mk_zip(True) VS_RUNTIME_PATS = [re.compile('vcomp.*\.dll'), @@ -238,7 +250,7 @@ VS_RUNTIME_PATS = [re.compile('vcomp.*\.dll'), re.compile('msvcr.*\.dll')] # Copy Visual Studio Runtime libraries -def cp_vs_runtime_core(x64): +def cp_vs_runtime(x64): if x64: platform = "x64" @@ -262,27 +274,49 @@ def cp_vs_runtime_core(x64): if is_verbose(): print("Copied '%s' to '%s'" % (f, bin_dist_path)) -def cp_vs_runtime(): - cp_vs_runtime_core(True) - cp_vs_runtime_core(False) +def cp_vs_runtimes(): + cp_vs_runtime(True) + cp_vs_runtime(False) -def cp_license(): - shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_dist_path(True))) - shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_dist_path(False))) +def cp_license(x64): + shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_dist_path(x64))) + +def cp_licenses(): + cp_license(True) + cp_license(False) # Entry point def main(): if os.name != 'nt': raise MKException("This script is for Windows only") + parse_options() check_vc_cmd_prompt() - mk_build_dirs() - mk_z3() - init_project_def() - mk_dist_dir() - cp_license() - cp_vs_runtime() - mk_zip() + + if X86ONLY: + mk_build_dir(BUILD_X86_DIR, False) + mk_z3(False) + init_project_def() + mk_dist_dir(False) + cp_license(False) + cp_vs_runtime(False) + mk_zip(False) + elif X64ONLY: + mk_build_dir(BUILD_X64_DIR, True) + mk_z3(True) + init_project_def() + mk_dist_dir(True) + cp_license(True) + cp_vs_runtime(True) + mk_zip(True) + else: + mk_build_dirs() + mk_z3s() + init_project_def() + mk_dist_dirs() + cp_licenses() + cp_vs_runtimes() + mk_zips() main() diff --git a/scripts/update_api.py b/scripts/update_api.py index 3a3b2c40a..031b39c75 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -365,7 +365,7 @@ def mk_dotnet(dotnet): dotnet.write(' public delegate void Z3_error_handler(Z3_context c, Z3_error_code e);\n\n') dotnet.write(' public class LIB\n') dotnet.write(' {\n') - dotnet.write(' const string Z3_DLL_NAME = \"libz3.dll\";\n' + dotnet.write(' const string Z3_DLL_NAME = \"libz3\";\n' ' \n') dotnet.write(' [DllImport(Z3_DLL_NAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]\n') dotnet.write(' public extern static void Z3_set_error_handler(Z3_context a0, Z3_error_handler a1);\n\n') @@ -1195,13 +1195,13 @@ def ml_alloc_and_store(t, lhs, rhs): alloc_str = '%s = caml_alloc_custom(&%s, sizeof(%s), 0, 1); ' % (lhs, pops, pts) return alloc_str + ml_set_wrap(t, lhs, rhs) -def mk_ml(ml_dir): +def mk_ml(ml_src_dir, ml_output_dir): global Type2Str - ml_nativef = os.path.join(ml_dir, 'z3native.ml') + ml_nativef = os.path.join(ml_output_dir, 'z3native.ml') ml_native = open(ml_nativef, 'w') ml_native.write('(* Automatically generated file *)\n\n') - ml_pref = open(os.path.join(ml_dir, 'z3native.ml.pre'), 'r') + ml_pref = open(os.path.join(ml_src_dir, 'z3native.ml.pre'), 'r') for s in ml_pref: ml_native.write(s); ml_pref.close() @@ -1250,14 +1250,14 @@ def mk_ml(ml_dir): if mk_util.is_verbose(): print ('Generated "%s"' % ml_nativef) - mk_z3native_stubs_c(ml_dir) + mk_z3native_stubs_c(ml_src_dir, ml_output_dir) -def mk_z3native_stubs_c(ml_dir): # C interface - ml_wrapperf = os.path.join(ml_dir, 'z3native_stubs.c') +def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface + ml_wrapperf = os.path.join(ml_output_dir, 'z3native_stubs.c') ml_wrapper = open(ml_wrapperf, 'w') ml_wrapper.write('// Automatically generated file\n\n') - ml_pref = open(os.path.join(ml_dir, 'z3native_stubs.c.pre'), 'r') + ml_pref = open(os.path.join(ml_src_dir, 'z3native_stubs.c.pre'), 'r') for s in ml_pref: ml_wrapper.write(s); ml_pref.close() @@ -1574,6 +1574,7 @@ def write_log_h_preamble(log_h): log_h.write('#define _Z3_UNUSED\n') log_h.write('#endif\n') # + log_h.write('#include\n') log_h.write('extern std::ostream * g_z3_log;\n') log_h.write('extern bool g_z3_log_enabled;\n') log_h.write('class z3_log_ctx { bool m_prev; public: z3_log_ctx():m_prev(g_z3_log_enabled) { g_z3_log_enabled = false; } ~z3_log_ctx() { g_z3_log_enabled = m_prev; } bool enabled() const { return m_prev; } };\n') @@ -1666,7 +1667,8 @@ def generate_files(api_files, dotnet_output_dir=None, java_output_dir=None, java_package_name=None, - ml_output_dir=None): + ml_output_dir=None, + ml_src_dir=None): """ Scan the api files in ``api_files`` and emit the relevant API files into the output directories specified. If an output directory is set to ``None`` @@ -1741,7 +1743,8 @@ def generate_files(api_files, mk_java(java_output_dir, java_package_name) if ml_output_dir: - mk_ml(ml_output_dir) + assert not ml_src_dir is None + mk_ml(ml_src_dir, ml_output_dir) def main(args): logging.basicConfig(level=logging.INFO) @@ -1768,6 +1771,10 @@ def main(args): dest="java_package_name", default=None, help="Name to give the Java package (e.g. ``com.microsoft.z3``).") + parser.add_argument("--ml-src-dir", + dest="ml_src_dir", + default=None, + help="Directory containing OCaml source files. If not specified no files are emitted") parser.add_argument("--ml-output-dir", dest="ml_output_dir", default=None, @@ -1779,6 +1786,11 @@ def main(args): logging.error('--java-package-name must be specified') return 1 + if pargs.ml_output_dir: + if pargs.ml_src_dir is None: + logging.error('--ml-src-dir must be specified') + return 1 + for api_file in pargs.api_files: if not os.path.exists(api_file): logging.error('"{}" does not exist'.format(api_file)) @@ -1790,7 +1802,8 @@ def main(args): dotnet_output_dir=pargs.dotnet_output_dir, java_output_dir=pargs.java_output_dir, java_package_name=pargs.java_package_name, - ml_output_dir=pargs.ml_output_dir) + ml_output_dir=pargs.ml_output_dir, + ml_src_dir=pargs.ml_src_dir) return 0 if __name__ == '__main__': diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index 2e14a1bd8..c4e4dac5d 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Additional APIs for handling Z3 algebraic numbers encoded as + Additional APIs for handling Z3 algebraic numbers encoded as Z3_ASTs Author: @@ -15,9 +15,8 @@ Author: Leonardo de Moura (leonardo) 2012-12-07 Notes: - + --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -74,9 +73,9 @@ extern "C" { bool Z3_algebraic_is_value_core(Z3_context c, Z3_ast a) { api::context * _c = mk_c(c); - return - is_expr(a) && - (_c->autil().is_numeral(to_expr(a)) || + return + is_expr(a) && + (_c->autil().is_numeral(to_expr(a)) || _c->autil().is_irrational_algebraic_numeral(to_expr(a))); } @@ -162,9 +161,9 @@ extern "C" { Z3_ast Z3_API Z3_algebraic_add(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_add(c, a, b); - RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); - CHECK_IS_ALGEBRAIC_X(b, 0); + RESET_ERROR_CODE(); + CHECK_IS_ALGEBRAIC_X(a, 0); + CHECK_IS_ALGEBRAIC_X(b, 0); BIN_OP(+,add); Z3_CATCH_RETURN(0); } @@ -172,9 +171,9 @@ extern "C" { Z3_ast Z3_API Z3_algebraic_sub(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_sub(c, a, b); - RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); - CHECK_IS_ALGEBRAIC_X(b, 0); + RESET_ERROR_CODE(); + CHECK_IS_ALGEBRAIC_X(a, 0); + CHECK_IS_ALGEBRAIC_X(b, 0); BIN_OP(-,sub); Z3_CATCH_RETURN(0); } @@ -182,9 +181,9 @@ extern "C" { Z3_ast Z3_API Z3_algebraic_mul(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_mul(c, a, b); - RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); - CHECK_IS_ALGEBRAIC_X(b, 0); + RESET_ERROR_CODE(); + CHECK_IS_ALGEBRAIC_X(a, 0); + CHECK_IS_ALGEBRAIC_X(b, 0); BIN_OP(*,mul); Z3_CATCH_RETURN(0); } @@ -219,8 +218,8 @@ extern "C" { algebraic_numbers::manager & _am = am(c); scoped_anum _r(_am); if (is_rational(c, a)) { - scoped_anum av(_am); - _am.set(av, get_rational(c, a).to_mpq()); + scoped_anum av(_am); + _am.set(av, get_rational(c, a).to_mpq()); _am.root(av, k, _r); } else { @@ -241,8 +240,8 @@ extern "C" { algebraic_numbers::manager & _am = am(c); scoped_anum _r(_am); if (is_rational(c, a)) { - scoped_anum av(_am); - _am.set(av, get_rational(c, a).to_mpq()); + scoped_anum av(_am); + _am.set(av, get_rational(c, a).to_mpq()); _am.power(av, k, _r); } else { @@ -328,7 +327,7 @@ extern "C" { scoped_anum tmp(_am); for (unsigned i = 0; i < n; i++) { if (is_rational(c, a[i])) { - _am.set(tmp, get_rational(c, a[i]).to_mpq()); + _am.set(tmp, get_rational(c, a[i]).to_mpq()); as.push_back(tmp); } else if (is_irrational(c, a[i])) { diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index dcd250c98..51aea9676 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -37,7 +36,7 @@ extern "C" { RETURN_Z3(r); Z3_CATCH_RETURN(0); } - + Z3_sort Z3_API Z3_mk_real_sort(Z3_context c) { Z3_TRY; LOG_Z3_mk_real_sort(c); @@ -50,7 +49,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_real(Z3_context c, int num, int den) { Z3_TRY; LOG_Z3_mk_real(c, num, den); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); if (den == 0) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); @@ -60,7 +59,7 @@ extern "C" { RETURN_Z3(of_ast(a)); Z3_CATCH_RETURN(0); } - + MK_ARITH_OP(Z3_mk_add, OP_ADD); MK_ARITH_OP(Z3_mk_mul, OP_MUL); MK_BINARY_ARITH_OP(Z3_mk_power, OP_POWER); @@ -70,17 +69,17 @@ extern "C" { Z3_ast Z3_API Z3_mk_div(Z3_context c, Z3_ast n1, Z3_ast n2) { Z3_TRY; LOG_Z3_mk_div(c, n1, n2); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); decl_kind k = OP_IDIV; sort* ty = mk_c(c)->m().get_sort(to_expr(n1)); sort* real_ty = mk_c(c)->m().mk_sort(mk_c(c)->get_arith_fid(), REAL_SORT); if (ty == real_ty) { k = OP_DIV; } - expr * args[2] = { to_expr(n1), to_expr(n2) }; - ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_arith_fid(), k, 0, 0, 2, args); - mk_c(c)->save_ast_trail(a); - check_sorts(c, a); + expr * args[2] = { to_expr(n1), to_expr(n2) }; + ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_arith_fid(), k, 0, 0, 2, args); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); RETURN_Z3(of_ast(a)); Z3_CATCH_RETURN(0); } @@ -142,7 +141,7 @@ extern "C" { rational l; mk_c(c)->autil().am().get_lower(val, l, precision); expr * r = mk_c(c)->autil().mk_numeral(l, false); - mk_c(c)->save_ast_trail(r); + mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); Z3_CATCH_RETURN(0); } @@ -160,7 +159,7 @@ extern "C" { rational l; mk_c(c)->autil().am().get_upper(val, l, precision); expr * r = mk_c(c)->autil().mk_numeral(l, false); - mk_c(c)->save_ast_trail(r); + mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); Z3_CATCH_RETURN(0); } @@ -176,7 +175,7 @@ extern "C" { RETURN_Z3(0); } expr * r = mk_c(c)->autil().mk_numeral(numerator(val), true); - mk_c(c)->save_ast_trail(r); + mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); Z3_CATCH_RETURN(0); } @@ -192,7 +191,7 @@ extern "C" { RETURN_Z3(0); } expr * r = mk_c(c)->autil().mk_numeral(denominator(val), true); - mk_c(c)->save_ast_trail(r); + mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); Z3_CATCH_RETURN(0); } diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index d3dda5d9d..ed431882e 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -27,7 +26,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_array_sort(Z3_context c, Z3_sort domain, Z3_sort range) { Z3_TRY; LOG_Z3_mk_array_sort(c, domain, range); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); parameter params[2] = { parameter(to_sort(domain)), parameter(to_sort(range)) }; sort * ty = mk_c(c)->m().mk_sort(mk_c(c)->get_array_fid(), ARRAY_SORT, 2, params); mk_c(c)->save_ast_trail(ty); @@ -57,7 +56,7 @@ extern "C" { RETURN_Z3(of_ast(r)); Z3_CATCH_RETURN(0); } - + Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v) { Z3_TRY; LOG_Z3_mk_store(c, a, i, v); @@ -82,7 +81,7 @@ extern "C" { RETURN_Z3(of_ast(r)); Z3_CATCH_RETURN(0); } - + Z3_ast Z3_API Z3_mk_map(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast const* args) { Z3_TRY; LOG_Z3_mk_map(c, f, n, args); @@ -94,7 +93,7 @@ extern "C" { ast_manager & m = mk_c(c)->m(); func_decl* _f = to_func_decl(f); expr* const* _args = to_exprs(args); - + ptr_vector domain; for (unsigned i = 0; i < n; ++i) { domain.push_back(m.get_sort(_args[i])); @@ -111,7 +110,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_const_array(Z3_context c, Z3_sort domain, Z3_ast v) { Z3_TRY; LOG_Z3_mk_const_array(c, domain, v); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); expr * _v = to_expr(v); sort * _range = m.get_sort(_v); @@ -123,14 +122,14 @@ extern "C" { app * r = m.mk_app(cd, 1, &_v); mk_c(c)->save_ast_trail(r); check_sorts(c, r); - RETURN_Z3(of_ast(r)); + RETURN_Z3(of_ast(r)); Z3_CATCH_RETURN(0); } Z3_ast Z3_API Z3_mk_array_default(Z3_context c, Z3_ast array) { Z3_TRY; LOG_Z3_mk_array_default(c, array); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); expr * _a = to_expr(array); @@ -138,12 +137,12 @@ extern "C" { app * r = m.mk_app(f, 1, &_a); mk_c(c)->save_ast_trail(r); check_sorts(c, r); - RETURN_Z3(of_ast(r)); + RETURN_Z3(of_ast(r)); Z3_CATCH_RETURN(0); } Z3_ast mk_app_array_core(Z3_context c, Z3_sort domain, Z3_ast v) { - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); expr * _v = to_expr(v); sort * _range = m.get_sort(_v); @@ -178,7 +177,7 @@ extern "C" { LOG_Z3_mk_full_set(c, domain); RESET_ERROR_CODE(); Z3_ast r = mk_app_array_core(c, domain, Z3_mk_true(c)); - RETURN_Z3(r); + RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -205,8 +204,8 @@ extern "C" { Z3_TRY; LOG_Z3_get_array_sort_domain(c, t); RESET_ERROR_CODE(); - CHECK_VALID_AST(t, 0); - if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && + CHECK_VALID_AST(t, 0); + if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && to_sort(t)->get_decl_kind() == ARRAY_SORT) { Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(0).get_ast()); RETURN_Z3(r); @@ -215,13 +214,13 @@ extern "C" { RETURN_Z3(0); Z3_CATCH_RETURN(0); } - + Z3_sort Z3_API Z3_get_array_sort_range(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_array_sort_range(c, t); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); CHECK_VALID_AST(t, 0); - if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && + if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && to_sort(t)->get_decl_kind() == ARRAY_SORT) { Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(1).get_ast()); RETURN_Z3(r); diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index efa3ec098..fd2776079 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1063,9 +1063,10 @@ extern "C" { case OP_BV2INT: return Z3_OP_BV2INT; case OP_CARRY: return Z3_OP_CARRY; case OP_XOR3: return Z3_OP_XOR3; + case OP_BIT2BOOL: return Z3_OP_BIT2BOOL; case OP_BSMUL_NO_OVFL: return Z3_OP_BSMUL_NO_OVFL; case OP_BUMUL_NO_OVFL: return Z3_OP_BUMUL_NO_OVFL; - case OP_BSMUL_NO_UDFL: return Z3_OP_BSMUL_NO_UDFL; + case OP_BSMUL_NO_UDFL: return Z3_OP_BSMUL_NO_UDFL; case OP_BSDIV_I: return Z3_OP_BSDIV_I; case OP_BUDIV_I: return Z3_OP_BUDIV_I; case OP_BSREM_I: return Z3_OP_BSREM_I; @@ -1210,7 +1211,9 @@ extern "C" { switch(_d->get_decl_kind()) { case OP_PB_LE: return Z3_OP_PB_LE; case OP_PB_GE: return Z3_OP_PB_GE; + case OP_PB_EQ: return Z3_OP_PB_EQ; case OP_AT_MOST_K: return Z3_OP_PB_AT_MOST; + case OP_AT_LEAST_K: return Z3_OP_PB_AT_LEAST; default: return Z3_OP_INTERNAL; } } diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index 353cf913c..ff090ef54 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -27,7 +26,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_bv_sort(Z3_context c, unsigned sz) { Z3_TRY; LOG_Z3_mk_bv_sort(c, sz); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); if (sz == 0) { SET_ERROR_CODE(Z3_INVALID_ARG); } @@ -39,7 +38,7 @@ extern "C" { #define MK_BV_UNARY(NAME, OP) MK_UNARY(NAME, mk_c(c)->get_bv_fid(), OP, SKIP) #define MK_BV_BINARY(NAME, OP) MK_BINARY(NAME, mk_c(c)->get_bv_fid(), OP, SKIP) - + MK_BV_UNARY(Z3_mk_bvnot, OP_BNOT); MK_BV_UNARY(Z3_mk_bvredand, OP_BREDAND); MK_BV_UNARY(Z3_mk_bvredor, OP_BREDOR); @@ -75,11 +74,11 @@ extern "C" { expr * _n = to_expr(n); parameter params[2] = { parameter(high), parameter(low) }; expr * a = mk_c(c)->m().mk_app(mk_c(c)->get_bv_fid(), OP_EXTRACT, 2, params, 1, &_n); - mk_c(c)->save_ast_trail(a); + mk_c(c)->save_ast_trail(a); check_sorts(c, a); return of_ast(a); } - + Z3_ast Z3_API Z3_mk_extract(Z3_context c, unsigned high, unsigned low, Z3_ast n) { Z3_TRY; LOG_Z3_mk_extract(c, high, low, n); @@ -88,7 +87,7 @@ extern "C" { RETURN_Z3(r); Z3_CATCH_RETURN(0); } - + #define MK_BV_PUNARY(NAME, OP) \ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_TRY; \ @@ -113,7 +112,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_ast Z3_API Z3_mk_bv2int(Z3_context c, Z3_ast n, Z3_bool is_signed) { Z3_TRY; LOG_Z3_mk_bv2int(c, n, is_signed); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); Z3_sort int_s = Z3_mk_int_sort(c); if (is_signed) { Z3_ast r = Z3_mk_bv2int(c, n, false); @@ -125,7 +124,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_inc_ref(c, bound); Z3_ast zero = Z3_mk_int(c, 0, s); Z3_inc_ref(c, zero); - Z3_ast pred = Z3_mk_bvslt(c, n, zero); + Z3_ast pred = Z3_mk_bvslt(c, n, zero); Z3_inc_ref(c, pred); // if n <_sigend 0 then r - s^sz else r Z3_ast args[2] = { r, bound }; @@ -140,19 +139,19 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ RETURN_Z3(res); } else { - expr * _n = to_expr(n); - parameter p(to_sort(int_s)); - ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_bv_fid(), OP_BV2INT, 1, &p, 1, &_n); - mk_c(c)->save_ast_trail(a); - check_sorts(c, a); - RETURN_Z3(of_ast(a)); + expr * _n = to_expr(n); + parameter p(to_sort(int_s)); + ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_bv_fid(), OP_BV2INT, 1, &p, 1, &_n); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); + RETURN_Z3(of_ast(a)); } Z3_CATCH_RETURN(0); } /** \brief Create a bit-vector of sort \s with 1 in the most significant bit position. - + The sort \s must be a bit-vector sort. This function is a shorthand for shl(1, N-1) @@ -343,7 +342,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ return Z3_mk_not(c, eq); Z3_CATCH_RETURN(0); } - + // only for signed machine integers Z3_ast Z3_API Z3_mk_bvsdiv_no_overflow(Z3_context c, Z3_ast t1, Z3_ast t2) { Z3_TRY; @@ -369,7 +368,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ return result; Z3_CATCH_RETURN(0); } - + Z3_ast Z3_API Z3_mk_bvsub(Z3_context c, Z3_ast n1, Z3_ast n2) { Z3_TRY; LOG_Z3_mk_bvsub(c, n1, n2); @@ -389,7 +388,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ unsigned Z3_API Z3_get_bv_sort_size(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_bv_sort_size(c, t); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); CHECK_VALID_AST(t, 0); 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(); @@ -398,5 +397,5 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ return 0; Z3_CATCH_RETURN(0); } - + }; diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index cc512c08e..8843256c6 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -290,8 +290,8 @@ extern "C" { r = to_fixedpoint_ref(d)->ctx().query(to_expr(q)); } catch (z3_exception& ex) { - mk_c(c)->handle_exception(ex); r = l_undef; + mk_c(c)->handle_exception(ex); } to_fixedpoint_ref(d)->ctx().cleanup(); } diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 706ba9d89..5096c8e80 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -24,16 +23,16 @@ Revision History: extern "C" { - Z3_sort Z3_API Z3_mk_tuple_sort(Z3_context c, + Z3_sort Z3_API Z3_mk_tuple_sort(Z3_context c, Z3_symbol name, - unsigned num_fields, + unsigned num_fields, Z3_symbol const field_names[], Z3_sort const field_sorts[], Z3_func_decl * mk_tuple_decl, Z3_func_decl proj_decls[]) { Z3_TRY; LOG_Z3_mk_tuple_sort(c, name, num_fields, field_names, field_sorts, mk_tuple_decl, proj_decls); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); mk_c(c)->reset_last_result(); ast_manager& m = mk_c(c)->m(); datatype_util& dt_util = mk_c(c)->dtutil(); @@ -43,14 +42,14 @@ extern "C" { std::string recognizer_s("is_"); recognizer_s += to_symbol(name).str(); symbol recognizer(recognizer_s.c_str()); - + ptr_vector acc; for (unsigned i = 0; i < num_fields; ++i) { acc.push_back(mk_accessor_decl(to_symbol(field_names[i]), type_ref(to_sort(field_sorts[i])))); } constructor_decl* constrs[1] = { mk_constructor_decl(to_symbol(name), recognizer, acc.size(), acc.c_ptr()) }; - + { datatype_decl * dt = mk_datatype_decl(to_symbol(name), 1, constrs); bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, tuples); @@ -63,7 +62,7 @@ extern "C" { } // create tuple type - SASSERT(tuples.size() == 1); + SASSERT(tuples.size() == 1); tuple = tuples[0].get(); mk_c(c)->save_multiple_ast_trail(tuple); @@ -72,9 +71,9 @@ extern "C" { SASSERT(!dt_util.is_recursive(tuple)); ptr_vector const * decls = dt_util.get_datatype_constructors(tuple); func_decl* decl = (*decls)[0]; - mk_c(c)->save_multiple_ast_trail(decl); + mk_c(c)->save_multiple_ast_trail(decl); *mk_tuple_decl = of_func_decl(decl); - + // Create projections ptr_vector const * accs = dt_util.get_constructor_accessors(decl); if (!accs) { @@ -90,8 +89,8 @@ extern "C" { RETURN_Z3_mk_tuple_sort(of_sort(tuple)); Z3_CATCH_RETURN(0); } - - Z3_sort Z3_API Z3_mk_enumeration_sort(Z3_context c, + + Z3_sort Z3_API Z3_mk_enumeration_sort(Z3_context c, Z3_symbol name, unsigned n, Z3_symbol const enum_names[], @@ -106,7 +105,7 @@ extern "C" { sort_ref_vector sorts(m); sort* e; - + ptr_vector constrs; for (unsigned i = 0; i < n; ++i) { symbol e_name(to_symbol(enum_names[i])); @@ -128,9 +127,9 @@ extern "C" { RETURN_Z3(0); } } - + // create enum type. - SASSERT(sorts.size() == 1); + SASSERT(sorts.size() == 1); e = sorts[0].get(); mk_c(c)->save_multiple_ast_trail(e); @@ -141,10 +140,10 @@ extern "C" { SASSERT(decls && decls->size() == n); for (unsigned i = 0; i < n; ++i) { func_decl* decl = (*decls)[i]; - mk_c(c)->save_multiple_ast_trail(decl); + mk_c(c)->save_multiple_ast_trail(decl); enum_consts[i] = of_func_decl(decl); decl = dt_util.get_constructor_recognizer(decl); - mk_c(c)->save_multiple_ast_trail(decl); + mk_c(c)->save_multiple_ast_trail(decl); enum_testers[i] = of_func_decl(decl); } @@ -168,11 +167,11 @@ extern "C" { ast_manager& m = mk_c(c)->m(); mk_c(c)->reset_last_result(); datatype_util data_util(m); - accessor_decl* head_tail[2] = { + accessor_decl* head_tail[2] = { mk_accessor_decl(symbol("head"), type_ref(to_sort(elem_sort))), mk_accessor_decl(symbol("tail"), type_ref(0)) }; - constructor_decl* constrs[2] = { + constructor_decl* constrs[2] = { mk_constructor_decl(symbol("nil"), symbol("is_nil"), 0, 0), // Leo: SMT 2.0 document uses 'insert' instead of cons mk_constructor_decl(symbol("cons"), symbol("is_cons"), 2, head_tail) @@ -197,22 +196,22 @@ extern "C" { func_decl* f; if (nil_decl) { f = cnstrs[0]; - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *nil_decl = of_func_decl(f); } if (is_nil_decl) { f = data_util.get_constructor_recognizer(cnstrs[0]); - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *is_nil_decl = of_func_decl(f); } if (cons_decl) { f = cnstrs[1]; - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *cons_decl = of_func_decl(f); } if (is_cons_decl) { f = data_util.get_constructor_recognizer(cnstrs[1]); - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *is_cons_decl = of_func_decl(f); } if (head_decl) { @@ -220,7 +219,7 @@ extern "C" { SASSERT(acc); SASSERT(acc->size() == 2); f = (*acc)[0]; - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *head_decl = of_func_decl(f); } if (tail_decl) { @@ -228,7 +227,7 @@ extern "C" { SASSERT(acc); SASSERT(acc->size() == 2); f = (*acc)[1]; - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *tail_decl = of_func_decl(f); } RETURN_Z3_mk_list_sort(of_sort(s)); @@ -255,7 +254,7 @@ extern "C" { ) { Z3_TRY; LOG_Z3_mk_constructor(c, name, tester, num_fields, field_names, sorts, sort_refs); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); ast_manager& m = mk_c(c)->m(); constructor* cnstr = alloc(constructor, m); cnstr->m_name = to_symbol(name); @@ -291,7 +290,7 @@ extern "C" { if (!f) { SET_ERROR_CODE(Z3_INVALID_ARG); return; - } + } if (constructor_decl) { mk_c(c)->save_multiple_ast_trail(f); *constructor_decl = of_func_decl(f); @@ -301,15 +300,15 @@ extern "C" { mk_c(c)->save_multiple_ast_trail(f2); *tester = of_func_decl(f2); } - + ptr_vector const* accs = data_util.get_constructor_accessors(f); if (!accs && num_fields > 0) { SET_ERROR_CODE(Z3_INVALID_ARG); - return; + return; } for (unsigned i = 0; i < num_fields; ++i) { func_decl* f2 = (*accs)[i]; - mk_c(c)->save_multiple_ast_trail(f2); + mk_c(c)->save_multiple_ast_trail(f2); accessors[i] = of_func_decl(f2); } RETURN_Z3_query_constructor; @@ -324,7 +323,7 @@ extern "C" { Z3_CATCH; } - static datatype_decl* mk_datatype_decl(Z3_context c, + static datatype_decl* mk_datatype_decl(Z3_context c, Z3_symbol name, unsigned num_constructors, Z3_constructor constructors[]) { @@ -342,7 +341,7 @@ extern "C" { } constrs.push_back(mk_constructor_decl(cn->m_name, cn->m_tester, acc.size(), acc.c_ptr())); } - return mk_datatype_decl(to_symbol(name), num_constructors, constrs.c_ptr()); + return mk_datatype_decl(to_symbol(name), num_constructors, constrs.c_ptr()); } Z3_sort Z3_API Z3_mk_datatype(Z3_context c, @@ -352,9 +351,9 @@ extern "C" { Z3_TRY; LOG_Z3_mk_datatype(c, name, num_constructors, constructors); RESET_ERROR_CODE(); - ast_manager& m = mk_c(c)->m(); + ast_manager& m = mk_c(c)->m(); datatype_util data_util(m); - + sort_ref_vector sorts(m); { datatype_decl * data = mk_datatype_decl(c, name, num_constructors, constructors); @@ -370,7 +369,7 @@ extern "C" { mk_c(c)->save_ast_trail(s); ptr_vector const* cnstrs = data_util.get_datatype_constructors(s); - + for (unsigned i = 0; i < num_constructors; ++i) { constructor* cn = reinterpret_cast(constructors[i]); cn->m_constructor = (*cnstrs)[i]; @@ -411,7 +410,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_datatypes(c, num_sorts, sort_names, sorts, constructor_lists); RESET_ERROR_CODE(); - ast_manager& m = mk_c(c)->m(); + ast_manager& m = mk_c(c)->m(); mk_c(c)->reset_last_result(); datatype_util data_util(m); @@ -423,7 +422,7 @@ extern "C" { sort_ref_vector _sorts(m); bool ok = mk_c(c)->get_dt_plugin()->mk_datatypes(datas.size(), datas.c_ptr(), _sorts); del_datatype_decls(datas.size(), datas.c_ptr()); - + if (!ok) { SET_ERROR_CODE(Z3_INVALID_ARG); return; @@ -437,8 +436,8 @@ extern "C" { constructor_list* cl = reinterpret_cast(constructor_lists[i]); ptr_vector const* cnstrs = data_util.get_datatype_constructors(s); for (unsigned j = 0; j < cl->size(); ++j) { - constructor* cn = (*cl)[j]; - cn->m_constructor = (*cnstrs)[j]; + constructor* cn = (*cl)[j]; + cn->m_constructor = (*cnstrs)[j]; } } RETURN_Z3_mk_datatypes; @@ -452,15 +451,15 @@ extern "C" { CHECK_VALID_AST(t, 0); 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); - return 0; + return 0; } ptr_vector const * decls = dt_util.get_datatype_constructors(_t); if (!decls) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return 0; } return decls->size(); Z3_CATCH_RETURN(0); @@ -468,7 +467,7 @@ extern "C" { Z3_func_decl get_datatype_sort_constructor_core(Z3_context c, Z3_sort t, unsigned idx) { RESET_ERROR_CODE(); - CHECK_VALID_AST(t, 0); + CHECK_VALID_AST(t, 0); sort * _t = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(_t)) { @@ -497,10 +496,10 @@ extern "C" { Z3_func_decl Z3_API Z3_get_datatype_sort_recognizer(Z3_context c, Z3_sort t, unsigned idx) { Z3_TRY; LOG_Z3_get_datatype_sort_recognizer(c, t, idx); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); 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); RETURN_Z3(0); @@ -520,13 +519,13 @@ extern "C" { Z3_func_decl Z3_API Z3_get_datatype_sort_constructor_accessor(Z3_context c, Z3_sort t, unsigned idx_c, unsigned idx_a) { Z3_TRY; LOG_Z3_get_datatype_sort_constructor_accessor(c, t, idx_c, idx_a); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); 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); - RETURN_Z3(0); + RETURN_Z3(0); } ptr_vector const * decls = dt_util.get_datatype_constructors(_t); if (!decls || idx_c >= decls->size()) { @@ -536,24 +535,24 @@ extern "C" { func_decl* decl = (*decls)[idx_c]; if (decl->get_arity() <= idx_a) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(0); } ptr_vector const * accs = dt_util.get_constructor_accessors(decl); SASSERT(accs && accs->size() == decl->get_arity()); if (!accs || accs->size() <= idx_a) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(0); } decl = (*accs)[idx_a]; mk_c(c)->save_ast_trail(decl); - RETURN_Z3(of_func_decl(decl)); + RETURN_Z3(of_func_decl(decl)); Z3_CATCH_RETURN(0); } Z3_func_decl Z3_API Z3_get_tuple_sort_mk_decl(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_tuple_sort_mk_decl(c, t); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); 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) { @@ -564,34 +563,34 @@ extern "C" { RETURN_Z3(r); Z3_CATCH_RETURN(0); } - + unsigned Z3_API Z3_get_tuple_sort_num_fields(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_tuple_sort_num_fields(c, t); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); 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); - return 0; + return 0; } ptr_vector const * decls = dt_util.get_datatype_constructors(tuple); if (!decls || decls->size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return 0; } ptr_vector const * accs = dt_util.get_constructor_accessors((*decls)[0]); if (!accs) { - return 0; + return 0; } return accs->size(); Z3_CATCH_RETURN(0); } - + Z3_func_decl Z3_API Z3_get_tuple_sort_field_decl(Z3_context c, Z3_sort t, unsigned i) { Z3_TRY; LOG_Z3_get_tuple_sort_field_decl(c, t, i); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); 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) { @@ -619,14 +618,14 @@ extern "C" { } Z3_ast Z3_datatype_update_field( - Z3_context c, Z3_func_decl f, Z3_ast t, Z3_ast v) { + Z3_context c, Z3_func_decl f, Z3_ast t, Z3_ast v) { Z3_TRY; LOG_Z3_datatype_update_field(c, f, t, v); RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); func_decl* _f = to_func_decl(f); expr* _t = to_expr(t); - expr* _v = to_expr(v); + expr* _v = to_expr(v); expr* args[2] = { _t, _v }; sort* domain[2] = { m.get_sort(_t), m.get_sort(_v) }; parameter param(_f); diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index b14f3db72..10aa06568 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -15,7 +15,6 @@ Revision History: --*/ -#include #include #include #include"z3.h" @@ -375,7 +374,7 @@ extern "C" { for(int i = 0; i < num_theory; i++) fmlas[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),fmlas[i]); std::copy(cnsts,cnsts+num,fmlas.begin()+num_theory); - Z3_string smt = Z3_benchmark_to_smtlib_string(ctx,"none","AUFLIA","unknown","",num_fmlas-1,&fmlas[0],fmlas[num_fmlas-1]); + Z3_string smt = Z3_benchmark_to_smtlib_string(ctx,"none","AUFLIA","unknown","",num_fmlas-1,&fmlas[0],fmlas[num_fmlas-1]); std::ofstream f(filename); if(num_theory) f << ";! THEORY=" << num_theory << "\n"; @@ -469,7 +468,7 @@ extern "C" { } f.close(); -#if 0 +#if 0 if(!parents){ diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index 43cb607c8..43ed98986 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include #include"z3.h" #include"api_log_macros.h" diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp index b7c28c34f..f19fd8661 100644 --- a/src/api/api_pb.cpp +++ b/src/api/api_pb.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -23,8 +22,8 @@ Revision History: #include"pb_decl_plugin.h" extern "C" { - - Z3_ast Z3_API Z3_mk_atmost(Z3_context c, unsigned num_args, + + Z3_ast Z3_API Z3_mk_atmost(Z3_context c, unsigned num_args, Z3_ast const args[], unsigned k) { Z3_TRY; LOG_Z3_mk_atmost(c, num_args, args, k); @@ -38,8 +37,21 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_mk_atleast(Z3_context c, unsigned num_args, + Z3_ast const args[], unsigned k) { + Z3_TRY; + LOG_Z3_mk_atmost(c, num_args, args, k); + RESET_ERROR_CODE(); + parameter param(k); + pb_util util(mk_c(c)->m()); + ast* a = util.mk_at_least_k(num_args, to_exprs(args), k); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); + } - Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args, + Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args, Z3_ast const args[], int _coeffs[], int k) { Z3_TRY; @@ -57,7 +69,25 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args, + Z3_ast Z3_API Z3_mk_pbge(Z3_context c, unsigned num_args, + Z3_ast const args[], int _coeffs[], + int k) { + Z3_TRY; + LOG_Z3_mk_pble(c, num_args, args, _coeffs, k); + RESET_ERROR_CODE(); + pb_util util(mk_c(c)->m()); + vector coeffs; + for (unsigned i = 0; i < num_args; ++i) { + coeffs.push_back(rational(_coeffs[i])); + } + ast* a = util.mk_ge(num_args, coeffs.c_ptr(), to_exprs(args), rational(k)); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args, Z3_ast const args[], int _coeffs[], int k) { Z3_TRY; diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index 979d2ea50..eebe36717 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -14,9 +14,8 @@ Author: Leonardo de Moura (leonardo) 2012-12-08 Notes: - + --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -35,7 +34,7 @@ namespace api { pmanager::~pmanager() { } - + }; extern "C" { diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index ddcd90cca..bf64aa571 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -26,17 +25,17 @@ Revision History: extern "C" { Z3_ast Z3_API Z3_mk_quantifier( - Z3_context c, - Z3_bool is_forall, - unsigned weight, - unsigned num_patterns, Z3_pattern const patterns[], - unsigned num_decls, Z3_sort const sorts[], - Z3_symbol const decl_names[], - Z3_ast body) + Z3_context c, + Z3_bool is_forall, + unsigned weight, + unsigned num_patterns, Z3_pattern const patterns[], + unsigned num_decls, Z3_sort const sorts[], + Z3_symbol const decl_names[], + Z3_ast body) { return Z3_mk_quantifier_ex( - c, - is_forall, + c, + is_forall, weight, 0, 0, @@ -50,15 +49,15 @@ extern "C" { } Z3_ast mk_quantifier_ex_core( - Z3_context c, - Z3_bool is_forall, - unsigned weight, + Z3_context c, + Z3_bool is_forall, + unsigned weight, Z3_symbol quantifier_id, Z3_symbol skolem_id, - unsigned num_patterns, Z3_pattern const patterns[], - unsigned num_no_patterns, Z3_ast const no_patterns[], - unsigned num_decls, Z3_sort const sorts[], - Z3_symbol const decl_names[], + unsigned num_patterns, Z3_pattern const patterns[], + unsigned num_no_patterns, Z3_ast const no_patterns[], + unsigned num_decls, Z3_sort const sorts[], + Z3_symbol const decl_names[], Z3_ast body) { Z3_TRY; RESET_ERROR_CODE(); @@ -86,9 +85,9 @@ extern "C" { expr_ref result(mk_c(c)->m()); if (num_decls > 0) { result = mk_c(c)->m().mk_quantifier( - (0 != is_forall), - names.size(), ts, names.c_ptr(), to_expr(body), - weight, + (0 != is_forall), + names.size(), ts, names.c_ptr(), to_expr(body), + weight, to_symbol(quantifier_id), to_symbol(skolem_id), num_patterns, ps, @@ -104,44 +103,44 @@ extern "C" { } Z3_ast Z3_API Z3_mk_quantifier_ex( - Z3_context c, - Z3_bool is_forall, - unsigned weight, + Z3_context c, + Z3_bool is_forall, + unsigned weight, Z3_symbol quantifier_id, Z3_symbol skolem_id, - unsigned num_patterns, Z3_pattern const patterns[], - unsigned num_no_patterns, Z3_ast const no_patterns[], - unsigned num_decls, Z3_sort const sorts[], - Z3_symbol const decl_names[], + unsigned num_patterns, Z3_pattern const patterns[], + unsigned num_no_patterns, Z3_ast const no_patterns[], + unsigned num_decls, Z3_sort const sorts[], + Z3_symbol const decl_names[], Z3_ast body) { - LOG_Z3_mk_quantifier_ex(c, is_forall, weight, quantifier_id, skolem_id, num_patterns, patterns, + LOG_Z3_mk_quantifier_ex(c, is_forall, weight, quantifier_id, skolem_id, num_patterns, patterns, num_no_patterns, no_patterns, num_decls, sorts, decl_names, body); - Z3_ast r = mk_quantifier_ex_core(c, is_forall, weight, quantifier_id, skolem_id, num_patterns, patterns, + Z3_ast r = mk_quantifier_ex_core(c, is_forall, weight, quantifier_id, skolem_id, num_patterns, patterns, num_no_patterns, no_patterns, num_decls, sorts, decl_names, body); RETURN_Z3(r); } - - Z3_ast Z3_API Z3_mk_forall(Z3_context c, - unsigned weight, - unsigned num_patterns, Z3_pattern const patterns[], - unsigned num_decls, Z3_sort const types[], - Z3_symbol const decl_names[], + + Z3_ast Z3_API Z3_mk_forall(Z3_context c, + unsigned weight, + unsigned num_patterns, Z3_pattern const patterns[], + unsigned num_decls, Z3_sort const types[], + Z3_symbol const decl_names[], Z3_ast body) { return Z3_mk_quantifier(c, 1, weight, num_patterns, patterns, num_decls, types, decl_names, body); } - - Z3_ast Z3_API Z3_mk_exists(Z3_context c, - unsigned weight, - unsigned num_patterns, Z3_pattern const patterns[], - unsigned num_decls, Z3_sort const types[], - Z3_symbol const decl_names[], + + Z3_ast Z3_API Z3_mk_exists(Z3_context c, + unsigned weight, + unsigned num_patterns, Z3_pattern const patterns[], + unsigned num_decls, Z3_sort const types[], + Z3_symbol const decl_names[], Z3_ast body) { return Z3_mk_quantifier(c, 0, weight, num_patterns, patterns, num_decls, types, decl_names, body); } - Z3_ast Z3_API Z3_mk_quantifier_const_ex(Z3_context c, + Z3_ast Z3_API Z3_mk_quantifier_const_ex(Z3_context c, Z3_bool is_forall, unsigned weight, Z3_symbol quantifier_id, @@ -166,7 +165,7 @@ extern "C" { } if (num_bound == 0) { SET_ERROR_CODE(Z3_INVALID_USAGE); - RETURN_Z3(0); + RETURN_Z3(0); } for (unsigned i = 0; i < num_bound; ++i) { app* a = to_app(bound[i]); @@ -191,7 +190,7 @@ extern "C" { app* pat = to_pattern(patterns[i]); SASSERT(mk_c(c)->m().is_pattern(pat)); expr_abstract(mk_c(c)->m(), 0, num_bound, bound_asts.c_ptr(), pat, result); - SASSERT(result.get()->get_kind() == AST_APP); + SASSERT(result.get()->get_kind() == AST_APP); pinned.push_back(result.get()); SASSERT(mk_c(c)->m().is_pattern(result.get())); _patterns.push_back(of_pattern(result.get())); @@ -205,25 +204,25 @@ extern "C" { } app* pat = to_app(to_expr(no_patterns[i])); expr_abstract(mk_c(c)->m(), 0, num_bound, bound_asts.c_ptr(), pat, result); - SASSERT(result.get()->get_kind() == AST_APP); + SASSERT(result.get()->get_kind() == AST_APP); pinned.push_back(result.get()); _no_patterns.push_back(of_ast(result.get())); } expr_ref abs_body(mk_c(c)->m()); expr_abstract(mk_c(c)->m(), 0, num_bound, bound_asts.c_ptr(), to_expr(body), abs_body); - Z3_ast result = mk_quantifier_ex_core(c, is_forall, weight, + Z3_ast result = mk_quantifier_ex_core(c, is_forall, weight, quantifier_id, skolem_id, - num_patterns, _patterns.c_ptr(), + num_patterns, _patterns.c_ptr(), num_no_patterns, _no_patterns.c_ptr(), - names.size(), types.c_ptr(), names.c_ptr(), + names.size(), types.c_ptr(), names.c_ptr(), of_ast(abs_body.get())); RETURN_Z3(result); Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_quantifier_const(Z3_context c, + Z3_ast Z3_API Z3_mk_quantifier_const(Z3_context c, Z3_bool is_forall, unsigned weight, unsigned num_bound, @@ -231,14 +230,14 @@ extern "C" { unsigned num_patterns, Z3_pattern const patterns[], Z3_ast body) { - return Z3_mk_quantifier_const_ex(c, is_forall, weight, 0, 0, - num_bound, bound, + return Z3_mk_quantifier_const_ex(c, is_forall, weight, 0, 0, + num_bound, bound, num_patterns, patterns, 0, 0, body); } - Z3_ast Z3_API Z3_mk_forall_const(Z3_context c, + Z3_ast Z3_API Z3_mk_forall_const(Z3_context c, unsigned weight, unsigned num_bound, Z3_app const bound[], @@ -248,7 +247,7 @@ extern "C" { return Z3_mk_quantifier_const(c, true, weight, num_bound, bound, num_patterns, patterns, body); } - Z3_ast Z3_API Z3_mk_exists_const(Z3_context c, + Z3_ast Z3_API Z3_mk_exists_const(Z3_context c, unsigned weight, unsigned num_bound, Z3_app const bound[], @@ -257,7 +256,7 @@ extern "C" { Z3_ast body) { return Z3_mk_quantifier_const(c, false, weight, num_bound, bound, num_patterns, patterns, body); } - + Z3_pattern Z3_API Z3_mk_pattern(Z3_context c, unsigned num_patterns, Z3_ast const terms[]) { Z3_TRY; LOG_Z3_mk_pattern(c, num_patterns, terms); @@ -273,7 +272,7 @@ extern "C" { RETURN_Z3(of_pattern(a)); Z3_CATCH_RETURN(0); } - + Z3_ast Z3_API Z3_mk_bound(Z3_context c, unsigned index, Z3_sort ty) { Z3_TRY; LOG_Z3_mk_bound(c, index, ty); @@ -436,7 +435,7 @@ extern "C" { else { SET_ERROR_CODE(Z3_SORT_ERROR); return 0; - } + } Z3_CATCH_RETURN(0); } @@ -450,7 +449,7 @@ extern "C" { } else { SET_ERROR_CODE(Z3_SORT_ERROR); - return 0; + return 0; } Z3_CATCH_RETURN(0); } @@ -471,13 +470,13 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_pattern_to_ast(Z3_context c, Z3_pattern p) { + Z3_ast Z3_API Z3_pattern_to_ast(Z3_context c, Z3_pattern p) { RESET_ERROR_CODE(); - return (Z3_ast)(p); - } + return (Z3_ast)(p); + } Z3_API char const * Z3_pattern_to_string(Z3_context c, Z3_pattern p) { return Z3_ast_to_string(c, reinterpret_cast(p)); } - + }; diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 138ea6fb0..478ee6274 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -16,7 +16,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -28,7 +27,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_seq_sort(Z3_context c, Z3_sort domain) { Z3_TRY; LOG_Z3_mk_seq_sort(c, domain); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); sort * ty = mk_c(c)->sutil().str.mk_seq(to_sort(domain)); mk_c(c)->save_ast_trail(ty); RETURN_Z3(of_sort(ty)); @@ -38,7 +37,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_re_sort(Z3_context c, Z3_sort domain) { Z3_TRY; LOG_Z3_mk_re_sort(c, domain); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); sort * ty = mk_c(c)->sutil().re.mk_re(to_sort(domain)); mk_c(c)->save_ast_trail(ty); RETURN_Z3(of_sort(ty)); @@ -48,14 +47,14 @@ extern "C" { Z3_ast Z3_API Z3_mk_string(Z3_context c, Z3_string str) { Z3_TRY; LOG_Z3_mk_string(c, str); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); zstring s(str, zstring::ascii); app* a = mk_c(c)->sutil().str.mk_string(s); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_ast(a)); Z3_CATCH_RETURN(0); } - + Z3_sort Z3_API Z3_mk_string_sort(Z3_context c) { Z3_TRY; LOG_Z3_mk_string_sort(c); @@ -71,8 +70,8 @@ extern "C" { LOG_Z3_is_seq_sort(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().is_seq(to_sort(s)); - return result?Z3_TRUE:Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return result?Z3_TRUE:Z3_FALSE; + Z3_CATCH_RETURN(Z3_FALSE); } Z3_bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s) { @@ -80,8 +79,8 @@ extern "C" { LOG_Z3_is_re_sort(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().is_re(to_sort(s)); - return result?Z3_TRUE:Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return result?Z3_TRUE:Z3_FALSE; + Z3_CATCH_RETURN(Z3_FALSE); } Z3_bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s) { @@ -89,8 +88,8 @@ extern "C" { LOG_Z3_is_string_sort(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().is_string(to_sort(s)); - return result?Z3_TRUE:Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return result?Z3_TRUE:Z3_FALSE; + Z3_CATCH_RETURN(Z3_FALSE); } Z3_bool Z3_API Z3_is_string(Z3_context c, Z3_ast s) { @@ -98,7 +97,7 @@ extern "C" { LOG_Z3_is_string(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().str.is_string(to_expr(s)); - return result?Z3_TRUE:Z3_FALSE; + return result?Z3_TRUE:Z3_FALSE; Z3_CATCH_RETURN(Z3_FALSE); } @@ -125,7 +124,7 @@ extern "C" { mk_c(c)->save_ast_trail(a); \ RETURN_Z3(of_ast(a)); \ Z3_CATCH_RETURN(0); \ - } + } MK_SORTED(Z3_mk_seq_empty, mk_c(c)->sutil().str.mk_empty); @@ -143,13 +142,13 @@ extern "C" { MK_BINARY(Z3_mk_seq_in_re, mk_c(c)->get_seq_fid(), OP_SEQ_IN_RE, SKIP); Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi) { - Z3_TRY; - LOG_Z3_mk_re_loop(c, r, lo, hi); - RESET_ERROR_CODE(); + Z3_TRY; + LOG_Z3_mk_re_loop(c, r, lo, hi); + RESET_ERROR_CODE(); app* a = hi == 0 ? mk_c(c)->sutil().re.mk_loop(to_expr(r), lo) : mk_c(c)->sutil().re.mk_loop(to_expr(r), lo, hi); - mk_c(c)->save_ast_trail(a); - RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); } MK_UNARY(Z3_mk_re_plus, mk_c(c)->get_seq_fid(), OP_RE_PLUS, SKIP); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 86dc77ad5..1556064d6 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -132,16 +132,19 @@ namespace z3 { \brief A Context manages all other Z3 objects, global configuration options, etc. */ class context { + bool m_enable_exceptions; Z3_context m_ctx; static void error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } void init(config & c) { m_ctx = Z3_mk_context_rc(c); + m_enable_exceptions = true; Z3_set_error_handler(m_ctx, error_handler); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } void init_interp(config & c) { m_ctx = Z3_mk_interpolation_context(c); + m_enable_exceptions = true; Z3_set_error_handler(m_ctx, error_handler); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } @@ -159,12 +162,24 @@ namespace z3 { /** \brief Auxiliary method used to check for API usage errors. */ - void check_error() const { + Z3_error_code check_error() const { Z3_error_code e = Z3_get_error_code(m_ctx); - if (e != Z3_OK) + if (e != Z3_OK && enable_exceptions()) throw exception(Z3_get_error_msg(m_ctx, e)); + return e; } + /** + \brief The C++ API uses by defaults exceptions on errors. + For applications that don't work well with exceptions (there should be only few) + you have the ability to turn off exceptions. The tradeoffs are that applications + have to very careful about using check_error() after calls that may result in an errornous + state. + */ + void set_enable_exceptions(bool f) { m_enable_exceptions = f; } + + bool enable_exceptions() const { return m_enable_exceptions; } + /** \brief Update global parameter \c param with string \c value. */ @@ -330,7 +345,7 @@ namespace z3 { object(context & c):m_ctx(&c) {} object(object const & s):m_ctx(s.m_ctx) {} context & ctx() const { return *m_ctx; } - void check_error() const { m_ctx->check_error(); } + Z3_error_code check_error() const { return m_ctx->check_error(); } friend void check_context(object const & a, object const & b); }; inline void check_context(object const & a, object const & b) { assert(a.m_ctx == b.m_ctx); } @@ -672,12 +687,18 @@ namespace z3 { /** \brief Return int value of numeral, throw if result cannot fit in machine int + + It only makes sense to use this function if the caller can ensure that + the result is an integer or if exceptions are enabled. + If exceptions are disabled, then use the the is_numeral_i function. \pre is_numeral() */ int get_numeral_int() const { - int result; + int result = 0; if (!is_numeral_i(result)) { + assert(ctx().enable_exceptions()); + if (!ctx().enable_exceptions()) return 0; throw exception("numeral does not fit in machine int"); } return result; @@ -686,13 +707,18 @@ namespace z3 { /** \brief Return uint value of numeral, throw if result cannot fit in machine uint - + + It only makes sense to use this function if the caller can ensure that + the result is an integer or if exceptions are enabled. + If exceptions are disabled, then use the the is_numeral_u function. \pre is_numeral() */ unsigned get_numeral_uint() const { assert(is_numeral()); - unsigned result; + unsigned result = 0; if (!is_numeral_u(result)) { + assert(ctx().enable_exceptions()); + if (!ctx().enable_exceptions()) return 0; throw exception("numeral does not fit in machine uint"); } return result; @@ -706,8 +732,10 @@ namespace z3 { */ __int64 get_numeral_int64() const { assert(is_numeral()); - __int64 result; + __int64 result = 0; if (!is_numeral_i64(result)) { + assert(ctx().enable_exceptions()); + if (!ctx().enable_exceptions()) return 0; throw exception("numeral does not fit in machine __int64"); } return result; @@ -721,8 +749,10 @@ namespace z3 { */ __uint64 get_numeral_uint64() const { assert(is_numeral()); - __uint64 result; + __uint64 result = 0; if (!is_numeral_u64(result)) { + assert(ctx().enable_exceptions()); + if (!ctx().enable_exceptions()) return 0; throw exception("numeral does not fit in machine __uint64"); } return result; @@ -1615,7 +1645,7 @@ namespace z3 { Z3_ast r = 0; Z3_bool status = Z3_model_eval(ctx(), m_model, n, model_completion, &r); check_error(); - if (status == Z3_FALSE) + if (status == Z3_FALSE && ctx().enable_exceptions()) throw exception("failed to evaluate expression"); return expr(ctx(), r); } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index f12ad58ea..f5c4dc99d 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2692,6 +2692,18 @@ namespace Microsoft.Z3 AST.ArrayToNative(args), k)); } + /// + /// Create an at-least-k constraint. + /// + public BoolExpr MkAtLeast(BoolExpr[] args, uint k) + { + Contract.Requires(args != null); + Contract.Requires(Contract.Result() != null); + CheckContextMatch(args); + return new BoolExpr(this, Native.Z3_mk_atleast(nCtx, (uint) args.Length, + AST.ArrayToNative(args), k)); + } + /// /// Create a pseudo-Boolean less-or-equal constraint. /// @@ -2707,6 +2719,20 @@ namespace Microsoft.Z3 coeffs, k)); } + /// + /// Create a pseudo-Boolean greater-or-equal constraint. + /// + public BoolExpr MkPBGe(int[] coeffs, BoolExpr[] args, int k) + { + Contract.Requires(args != null); + Contract.Requires(coeffs != null); + Contract.Requires(args.Length == coeffs.Length); + Contract.Requires(Contract.Result() != null); + CheckContextMatch(args); + return new BoolExpr(this, Native.Z3_mk_pbge(nCtx, (uint) args.Length, + AST.ArrayToNative(args), + coeffs, k)); + } /// /// Create a pseudo-Boolean equal constraint. /// diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 8cb7670d7..dff2677df 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -18,6 +18,7 @@ Notes: --*/ using System; +using System.Linq; using System.Collections.Generic; using System.Diagnostics.Contracts; @@ -126,6 +127,14 @@ namespace Microsoft.Z3 Assert(constraints); } + /// + /// Alias for Assert. + /// + public void Add(IEnumerable constraints) + { + Assert(constraints.ToArray()); + } + /// /// Assert multiple constraints into the solver, and track them (in the unsat) core /// using the Boolean constants in ps. diff --git a/src/api/dotnet/core/DummyContracts.cs b/src/api/dotnet/core/DummyContracts.cs index e0002e5be..49b498b1a 100644 --- a/src/api/dotnet/core/DummyContracts.cs +++ b/src/api/dotnet/core/DummyContracts.cs @@ -44,15 +44,21 @@ namespace System.Diagnostics.Contracts public static class Contract { + [Conditional("false")] public static void Ensures(bool b) { } + [Conditional("false")] public static void Requires(bool b) { } + [Conditional("false")] public static void Assume(bool b, string msg) { } + [Conditional("false")] public static void Assert(bool b) { } public static bool ForAll(bool b) { return true; } public static bool ForAll(Object c, Func p) { return true; } public static bool ForAll(int from, int to, Predicate p) { return true; } + [Conditional("false")] public static void Invariant(bool b) { } public static T[] Result() { return new T[1]; } + [Conditional("false")] public static void EndContractBlock() { } public static T ValueAtReturn(out T v) { T[] t = new T[1]; v = t[0]; return v; } } diff --git a/src/api/dotnet/dotnet35/Example/App.config b/src/api/dotnet/dotnet35/Example/App.config new file mode 100644 index 000000000..88fa4027b --- /dev/null +++ b/src/api/dotnet/dotnet35/Example/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/api/dotnet/dotnet35/Example/Example.csproj b/src/api/dotnet/dotnet35/Example/Example.csproj new file mode 100644 index 000000000..2b096ed40 --- /dev/null +++ b/src/api/dotnet/dotnet35/Example/Example.csproj @@ -0,0 +1,78 @@ + + + + + Debug + AnyCPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812} + Exe + Properties + Example + Example + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + TRACE;DEBUG;FRAMEWORK_LT_4 + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE;FRAMEWORK_LT_4 + prompt + 4 + + + true + bin\x64\Debug\ + TRACE;DEBUG;FRAMEWORK_LT_4 + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\Release\ + TRACE;FRAMEWORK_LT_4 + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + + Program.cs + + + + + + + + + {ec3db697-b734-42f7-9468-5b62821eeb5a} + Microsoft.Z3.NET35 + + + + + \ No newline at end of file diff --git a/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs b/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ed0d8454f --- /dev/null +++ b/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Example")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Example")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2a8e577b-7b6d-4ca9-832a-ca2eec314812")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj new file mode 100644 index 000000000..d278b4f1d --- /dev/null +++ b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj @@ -0,0 +1,347 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {EC3DB697-B734-42F7-9468-5B62821EEB5A} + Library + Properties + Microsoft.Z3 + Microsoft.Z3 + v3.5 + 512 + + + 0 + + + true + full + false + Debug\ + TRACE;DEBUG;FRAMEWORK_LT_4 + prompt + 4 + true + Debug\Microsoft.Z3.XML + False + False + True + False + False + True + False + True + True + False + False + False + True + False + False + False + True + False + False + True + True + True + False + False + + + + + + + True + Full + %28none%29 + 2 + + + pdbonly + true + Release\ + FRAMEWORK_LT_4 + prompt + 4 + true + Release\Microsoft.Z3.xml + x86 + + + true + + + + + + + false + + + true + bin\x64\Debug\ + TRACE;DEBUG;FRAMEWORK_LT_4 + true + Debug\Microsoft.Z3.XML + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + FRAMEWORK_LT_4 + true + Release\Microsoft.Z3.xml + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + + + packages\Code.Contract.1.0.0\lib\net35\Microsoft.Contracts.dll + True + + + + + + + AlgebraicNum.cs + + + ApplyResult.cs + + + ArithExpr.cs + + + ArithSort.cs + + + ArrayExpr.cs + + + ArraySort.cs + + + AST.cs + + + ASTMap.cs + + + ASTVector.cs + + + BitVecExpr.cs + + + BitVecNum.cs + + + BitVecSort.cs + + + BoolExpr.cs + + + BoolSort.cs + + + Constructor.cs + + + ConstructorList.cs + + + Context.cs + + + DatatypeExpr.cs + + + DatatypeSort.cs + + + Deprecated.cs + + + Enumerations.cs + + + EnumSort.cs + + + Expr.cs + + + FiniteDomainExpr.cs + + + FiniteDomainNum.cs + + + FiniteDomainSort.cs + + + Fixedpoint.cs + + + FPExpr.cs + + + FPNum.cs + + + FPRMExpr.cs + + + FPRMNum.cs + + + FPRMSort.cs + + + FPSort.cs + + + FuncDecl.cs + + + FuncInterp.cs + + + Global.cs + + + Goal.cs + + + IDecRefQueue.cs + + + InterpolationContext.cs + + + IntExpr.cs + + + IntNum.cs + + + IntSort.cs + + + IntSymbol.cs + + + ListSort.cs + + + Log.cs + + + Model.cs + + + Native.cs + + + Optimize.cs + + + ParamDescrs.cs + + + Params.cs + + + Pattern.cs + + + Probe.cs + + + Quantifier.cs + + + RatNum.cs + + + RealExpr.cs + + + RealSort.cs + + + ReExpr.cs + + + RelationSort.cs + + + ReSort.cs + + + SeqExpr.cs + + + SeqSort.cs + + + SetSort.cs + + + Solver.cs + + + Sort.cs + + + Statistics.cs + + + Status.cs + + + StringSymbol.cs + + + Symbol.cs + + + Tactic.cs + + + TupleSort.cs + + + UninterpretedSort.cs + + + Version.cs + + + Z3Exception.cs + + + Z3Object.cs + + + + + + + + + + + \ No newline at end of file diff --git a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln new file mode 100644 index 000000000..b6e252684 --- /dev/null +++ b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Z3.NET35", "Microsoft.Z3.NET35.csproj", "{EC3DB697-B734-42F7-9468-5B62821EEB5A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{2A8E577B-7B6D-4CA9-832A-CA2EEC314812}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.Build.0 = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.ActiveCfg = Release|x64 + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.Build.0 = Release|x64 + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.ActiveCfg = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.Build.0 = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.Build.0 = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.ActiveCfg = Release|x64 + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.Build.0 = Release|x64 + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.ActiveCfg = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs b/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..fb4319002 --- /dev/null +++ b/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs @@ -0,0 +1,38 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Permissions; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Z3 .NET Interface")] +[assembly: AssemblyDescription(".NET Interface to the Z3 Theorem Prover")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft Corporation")] +[assembly: AssemblyProduct("Z3")] +[assembly: AssemblyCopyright("Copyright (C) 2006-2015 Microsoft Corporation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4853ed71-2078-40f4-8117-bc46646bce0e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyVersion("4.5.1.6031")] +[assembly: AssemblyFileVersion("4.5.1.6031")] diff --git a/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in b/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in new file mode 100644 index 000000000..e5a85f16f --- /dev/null +++ b/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in @@ -0,0 +1,38 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Permissions; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Z3 .NET Interface")] +[assembly: AssemblyDescription(".NET Interface to the Z3 Theorem Prover")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft Corporation")] +[assembly: AssemblyProduct("Z3")] +[assembly: AssemblyCopyright("Copyright (C) 2006-2015 Microsoft Corporation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4853ed71-2078-40f4-8117-bc46646bce0e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyVersion("@VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@")] +[assembly: AssemblyFileVersion("@VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@")] diff --git a/src/api/dotnet/Readme.NET35 b/src/api/dotnet/dotnet35/Readme.NET35 similarity index 87% rename from src/api/dotnet/Readme.NET35 rename to src/api/dotnet/dotnet35/Readme.NET35 index 73743fd15..f8c2958ee 100644 --- a/src/api/dotnet/Readme.NET35 +++ b/src/api/dotnet/dotnet35/Readme.NET35 @@ -6,4 +6,5 @@ In the project properties of Microsoft.Z3.csproj: - Under 'Application': Change Target framework to .NET Framework 3.5 - Under 'Build': Add FRAMEWORK_LT_4 to the condidional compilation symbols - Remove the reference to System.Numerics -- Install the NuGet Package "Microsoft Code Contracts for Net3.5" +- Install the NuGet Package "Microsoft Code Contracts for Net3.5": + In the Package Manager Console enter Install-Package Code.Contract diff --git a/src/api/dotnet/dotnet35/packages.config b/src/api/dotnet/dotnet35/packages.config new file mode 100644 index 000000000..daa06aed7 --- /dev/null +++ b/src/api/dotnet/dotnet35/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 3a62f4507..a6f91a0a2 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7648,11 +7648,6 @@ def AtLeast(*args): >>> a, b, c = Bools('a b c') >>> f = AtLeast(a, b, c, 2) """ - def mk_not(a): - if is_not(a): - return a.arg(0) - else: - return Not(a) args = _get_args(args) if __debug__: _z3_assert(len(args) > 1, "Non empty list of arguments expected") @@ -7660,10 +7655,25 @@ def AtLeast(*args): if __debug__: _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") args1 = _coerce_expr_list(args[:-1], ctx) - args1 = [ mk_not(a) for a in args1 ] - k = len(args1) - args[-1] + k = args[-1] _args, sz = _to_ast_array(args1) - return BoolRef(Z3_mk_atmost(ctx.ref(), sz, _args, k), ctx) + return BoolRef(Z3_mk_atleast(ctx.ref(), sz, _args, k), ctx) + + +def _pb_args_coeffs(args): + args = _get_args(args) + args, coeffs = zip(*args) + if __debug__: + _z3_assert(len(args) > 0, "Non empty list of arguments expected") + ctx = _ctx_from_ast_arg_list(args) + if __debug__: + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") + args = _coerce_expr_list(args, ctx) + _args, sz = _to_ast_array(args) + _coeffs = (ctypes.c_int * len(coeffs))() + for i in range(len(coeffs)): + _coeffs[i] = coeffs[i] + return ctx, sz, _args, _coeffs def PbLe(args, k): """Create a Pseudo-Boolean inequality k constraint. @@ -7671,38 +7681,25 @@ def PbLe(args, k): >>> a, b, c = Bools('a b c') >>> f = PbLe(((a,1),(b,3),(c,2)), 3) """ - args = _get_args(args) - args, coeffs = zip(*args) - if __debug__: - _z3_assert(len(args) > 0, "Non empty list of arguments expected") - ctx = _ctx_from_ast_arg_list(args) - if __debug__: - _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") - args = _coerce_expr_list(args, ctx) - _args, sz = _to_ast_array(args) - _coeffs = (ctypes.c_int * len(coeffs))() - for i in range(len(coeffs)): - _coeffs[i] = coeffs[i] + ctx, sz, _args, _coeffs = _pb_args_coeffs(args) return BoolRef(Z3_mk_pble(ctx.ref(), sz, _args, _coeffs, k), ctx) +def PbGe(args, k): + """Create a Pseudo-Boolean inequality k constraint. + + >>> a, b, c = Bools('a b c') + >>> f = PbGe(((a,1),(b,3),(c,2)), 3) + """ + ctx, sz, _args, _coeffs = _pb_args_coeffs(args) + return BoolRef(Z3_mk_pbge(ctx.ref(), sz, _args, _coeffs, k), ctx) + def PbEq(args, k): """Create a Pseudo-Boolean inequality k constraint. >>> a, b, c = Bools('a b c') >>> f = PbEq(((a,1),(b,3),(c,2)), 3) """ - args = _get_args(args) - args, coeffs = zip(*args) - if __debug__: - _z3_assert(len(args) > 0, "Non empty list of arguments expected") - ctx = _ctx_from_ast_arg_list(args) - if __debug__: - _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") - args = _coerce_expr_list(args, ctx) - _args, sz = _to_ast_array(args) - _coeffs = (ctypes.c_int * len(coeffs))() - for i in range(len(coeffs)): - _coeffs[i] = coeffs[i] + ctx, sz, _args, _coeffs = _pb_args_coeffs(args) return BoolRef(Z3_mk_pbeq(ctx.ref(), sz, _args, _coeffs, k), ctx) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 356f933d4..65c155d63 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -855,6 +855,9 @@ typedef enum - Z3_OP_PB_AT_MOST: Cardinality constraint. E.g., x + y + z <= 2 + - Z3_OP_PB_AT_LEAST: Cardinality constraint. + E.g., x + y + z >= 2 + - Z3_OP_PB_LE: Generalized Pseudo-Boolean cardinality constraint. Example 2*x + 3*y <= 4 @@ -1060,6 +1063,7 @@ typedef enum { Z3_OP_EXT_ROTATE_LEFT, Z3_OP_EXT_ROTATE_RIGHT, + Z3_OP_BIT2BOOL, Z3_OP_INT2BV, Z3_OP_BV2INT, Z3_OP_CARRY, @@ -1173,6 +1177,7 @@ typedef enum { // Pseudo Booleans Z3_OP_PB_AT_MOST=0x900, + Z3_OP_PB_AT_LEAST, Z3_OP_PB_LE, Z3_OP_PB_GE, Z3_OP_PB_EQ, @@ -1948,7 +1953,7 @@ extern "C" { The datatype may be recursive. Return the datatype sort. \param c logical context. - \param name name of datatype. + \param name name of datatype. \param num_constructors number of constructors passed in. \param constructors array of constructor containers. @@ -3083,7 +3088,7 @@ extern "C" { \param c logical context. \param numeral A string representing the numeral value in decimal notation. The string may be of the form \code{[num]*[.[num]*][E[+|-][num]+]}. - If the given sort is a real, then the numeral can be a rational, that is, a string of the form \ccode{[num]* / [num]*}. + If the given sort is a real, then the numeral can be a rational, that is, a string of the form \ccode{[num]* / [num]*}. \param ty The sort of the numeral. In the current implementation, the given sort can be an int, real, finite-domain, or bit-vectors of arbitrary size. \sa Z3_mk_int @@ -3388,7 +3393,7 @@ extern "C" { \c lo number of times, and with an unbounded upper bound. def_API('Z3_mk_re_loop', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in(UINT))) - */ + */ Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi); /** @@ -3425,7 +3430,7 @@ extern "C" { def_API('Z3_mk_re_full' ,AST ,(_in(CONTEXT), _in(SORT))) */ Z3_ast Z3_API Z3_mk_re_full(Z3_context c, Z3_sort re); - + /*@}*/ @@ -3961,10 +3966,19 @@ extern "C" { def_API('Z3_mk_atmost', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_atmost(Z3_context c, unsigned num_args, Z3_ast const args[], unsigned k); + /** + \brief Pseudo-Boolean relations. + + Encode p1 + p2 + ... + pn >= k + + def_API('Z3_mk_atleast', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in(UINT))) + */ + Z3_ast Z3_API Z3_mk_atleast(Z3_context c, unsigned num_args, + Z3_ast const args[], unsigned k); + /** \brief Pseudo-Boolean relations. @@ -3972,11 +3986,21 @@ extern "C" { def_API('Z3_mk_pble', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT))) */ - Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args, Z3_ast const args[], int coeffs[], int k); + /** + \brief Pseudo-Boolean relations. + + Encode k1*p1 + k2*p2 + ... + kn*pn >= k + + def_API('Z3_mk_pbge', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT))) + */ + Z3_ast Z3_API Z3_mk_pbge(Z3_context c, unsigned num_args, + Z3_ast const args[], int coeffs[], + int k); + /** \brief Pseudo-Boolean relations. @@ -3984,7 +4008,6 @@ extern "C" { def_API('Z3_mk_pbeq', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT))) */ - Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args, Z3_ast const args[], int coeffs[], int k); @@ -5199,7 +5222,7 @@ extern "C" { /*@}*/ /** - \brief Return a string describing the given error code. + \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); @@ -5972,11 +5995,11 @@ extern "C" { /** \brief retrieve consequences from solver that determine values of the supplied function symbols. - + def_API('Z3_solver_get_consequences', INT, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR), _in(AST_VECTOR), _in(AST_VECTOR))) */ - Z3_lbool Z3_API Z3_solver_get_consequences(Z3_context c, + Z3_lbool Z3_API Z3_solver_get_consequences(Z3_context c, Z3_solver s, Z3_ast_vector assumptions, Z3_ast_vector variables, diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index 75b4e55f4..b17e1ce28 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -106,7 +106,7 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) { if (!m_deps.insert(f, s)) { return false; } - + // add macro m_decl2macro.insert(f, m); m_decls.push_back(f); @@ -117,8 +117,8 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) { } TRACE("macro_insert", tout << "A macro was successfully created for: " << f->get_name() << "\n";); - - // Nothing's forbidden anymore; if something's bad, we detected it earlier. + + // Nothing's forbidden anymore; if something's bad, we detected it earlier. // mark_forbidden(m->get_expr()); return true; } @@ -144,7 +144,7 @@ namespace macro_manager_ns { \brief Mark all func_decls used in exprs as forbidden. */ void macro_manager::mark_forbidden(unsigned n, expr * const * exprs) { - expr_mark visited; + expr_mark visited; macro_manager_ns::proc p(m_forbidden_set, m_forbidden); for (unsigned i = 0; i < n; i++) for_each_expr(p, visited, exprs[i]); @@ -187,9 +187,9 @@ func_decl * macro_manager::get_macro_interpretation(unsigned i, expr_ref & inter app * head; expr * def; get_head_def(q, f, head, def); - TRACE("macro_bug", + TRACE("macro_bug", tout << f->get_name() << "\n" << mk_pp(head, m_manager) << "\n" << mk_pp(q, m_manager) << "\n";); - m_util.mk_macro_interpretation(head, def, interp); + m_util.mk_macro_interpretation(head, q->get_num_decls(), def, interp); return f; } @@ -237,7 +237,7 @@ void macro_manager::macro_expander::reduce1_quantifier(quantifier * q) { erase_patterns = true; } for (unsigned i = 0; !erase_patterns && i < q->get_num_no_patterns(); i++) { - if (q->get_no_pattern(i) != new_q->get_no_pattern(i)) + if (q->get_no_pattern(i) != new_q->get_no_pattern(i)) erase_patterns = true; } } @@ -254,7 +254,7 @@ bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref return false; app * n = to_app(_n); quantifier * q = 0; - func_decl * d = n->get_decl(); + func_decl * d = n->get_decl(); TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";); if (m_macro_manager.m_decl2macro.find(d, q)) { TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";); @@ -308,7 +308,7 @@ void macro_manager::expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref if (r.get() == old_n.get()) return; old_n = r; - old_pr = new_pr; + old_pr = new_pr; } } else { diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 027cce09d..99732871c 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -405,7 +405,7 @@ bool macro_util::is_quasi_macro_head(expr * n, unsigned num_decls) const { \brief Convert a quasi-macro head into a macro head, and store the conditions under which it is valid in cond. */ -void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, app_ref & head, expr_ref & cond) const { +void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned & num_decls, app_ref & head, expr_ref & cond) const { unsigned num_args = qhead->get_num_args(); sbuffer found_vars; found_vars.resize(num_decls, false); @@ -431,6 +431,7 @@ void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, } get_basic_simp()->mk_and(new_conds.size(), new_conds.c_ptr(), cond); head = m_manager.mk_app(qhead->get_decl(), new_args.size(), new_args.c_ptr()); + num_decls = next_var_idx; } /** @@ -440,10 +441,10 @@ void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, See normalize_expr */ -void macro_util::mk_macro_interpretation(app * head, expr * def, expr_ref & interp) const { +void macro_util::mk_macro_interpretation(app * head, unsigned num_decls, expr * def, expr_ref & interp) const { SASSERT(is_macro_head(head, head->get_num_args())); SASSERT(!occurs(head->get_decl(), def)); - normalize_expr(head, def, interp); + normalize_expr(head, num_decls, def, interp); } /** @@ -456,40 +457,31 @@ void macro_util::mk_macro_interpretation(app * head, expr * def, expr_ref & inte f(x_1, x_2) --> f(x_0, x_1) f(x_3, x_2) --> f(x_0, x_1) */ -void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { - expr_ref_buffer var_mapping(m_manager); +void macro_util::normalize_expr(app * head, unsigned num_decls, expr * t, expr_ref & norm_t) const { + expr_ref_buffer var_mapping(m_manager); + var_mapping.resize(num_decls); bool changed = false; unsigned num_args = head->get_num_args(); - unsigned max_var_idx = 0; - for (unsigned i = 0; i < num_args; i++) { - var const * v = to_var(head->get_arg(i)); - if (v->get_idx() > max_var_idx) - max_var_idx = v->get_idx(); - } - TRACE("normalize_expr_bug", + TRACE("macro_util", tout << "head: " << mk_pp(head, m_manager) << "\n"; tout << "applying substitution to:\n" << mk_bounded_pp(t, m_manager) << "\n";); for (unsigned i = 0; i < num_args; i++) { var * v = to_var(head->get_arg(i)); - if (v->get_idx() != i) { + unsigned vi = v->get_idx(); + SASSERT(vi < num_decls); + if (vi != i) { changed = true; var_ref new_var(m_manager.mk_var(i, v->get_sort()), m_manager); - var_mapping.setx(max_var_idx - v->get_idx(), new_var); + var_mapping.setx(num_decls - vi - 1, new_var); } else - var_mapping.setx(max_var_idx - i, v); + var_mapping.setx(num_decls - i - 1, v); } - for (unsigned i = num_args; i <= max_var_idx; i++) - // CMW: Won't be used, but dictates a larger binding size, - // so that the indexes between here and in the rewriter match. - // It's possible that we don't see the true max idx of all vars here. - var_mapping.setx(max_var_idx - i, 0); - if (changed) { // REMARK: t may have nested quantifiers... So, I must use the std order for variable substitution. var_subst subst(m_manager, true); - TRACE("macro_util_bug", + TRACE("macro_util", tout << "head: " << mk_pp(head, m_manager) << "\n"; tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitution:\n"; for (unsigned i = 0; i < var_mapping.size(); i++) { @@ -573,7 +565,7 @@ bool is_hint_atom(expr * lhs, expr * rhs) { return !occurs(to_app(lhs)->get_decl(), rhs) && vars_of_is_subset(rhs, vars); } -void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref & new_head) { +void hint_to_macro_head(ast_manager & m, app * head, unsigned & num_decls, app_ref & new_head) { unsigned num_args = head->get_num_args(); ptr_buffer new_args; sbuffer found_vars; @@ -595,6 +587,7 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref new_args.push_back(new_var); } new_head = m.mk_app(head->get_decl(), new_args.size(), new_args.c_ptr()); + num_decls = next_var_idx; } /** @@ -604,12 +597,12 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref is_hint_head(head, vars) must also return true */ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { - TRACE("macro_util_hint", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n"; + TRACE("macro_util", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n"; if (exception) tout << mk_pp(exception, m_manager); else tout << ""; tout << "\n";); ptr_buffer vars; if (!is_hint_head(head, vars)) { - TRACE("macro_util_hint", tout << "failed because head is not hint head\n";); + TRACE("macro_util", tout << "failed because head is not hint head\n";); return false; } func_decl * f = head->get_decl(); @@ -626,11 +619,11 @@ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; if (arg != exception && (occurs(f, arg) || !vars_of_is_subset(arg, vars))) { - TRACE("macro_util_hint", tout << "failed because of:\n" << mk_pp(arg, m_manager) << "\n";); + TRACE("macro_util", tout << "failed because of:\n" << mk_pp(arg, m_manager) << "\n";); return false; } } - TRACE("macro_util_hint", tout << "succeeded\n";); + TRACE("macro_util", tout << "succeeded\n";); return true; } @@ -671,12 +664,12 @@ void macro_util::macro_candidates::insert(func_decl * f, expr * def, expr * cond // // ----------------------------- -void macro_util::insert_macro(app * head, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r) { +void macro_util::insert_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r) { expr_ref norm_def(m_manager); expr_ref norm_cond(m_manager); - normalize_expr(head, def, norm_def); + normalize_expr(head, num_decls, def, norm_def); if (cond != 0) - normalize_expr(head, cond, norm_cond); + normalize_expr(head, num_decls, cond, norm_cond); else if (!hint) norm_cond = m_manager.mk_true(); SASSERT(!hint || norm_cond.get() == 0); @@ -698,11 +691,14 @@ void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, } else { hint_to_macro_head(m_manager, head, num_decls, new_head); + TRACE("macro_util", + tout << "hint macro head: " << mk_ismt2_pp(new_head, m_manager) << std::endl; + tout << "hint macro def: " << mk_ismt2_pp(def, m_manager) << std::endl; ); } - insert_macro(new_head, def, new_cond, ineq, satisfy_atom, hint, r); + insert_macro(new_head, num_decls, def, new_cond, ineq, satisfy_atom, hint, r); } else { - insert_macro(head, def, cond, ineq, satisfy_atom, hint, r); + insert_macro(head, num_decls, def, cond, ineq, satisfy_atom, hint, r); } } @@ -831,7 +827,7 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a } void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls, macro_candidates & r) { - TRACE("macro_util_hint", tout << "collect_arith_macro_candidates:\n" << mk_pp(atom, m_manager) << "\n";); + TRACE("macro_util", tout << "collect_arith_macro_candidates:\n" << mk_pp(atom, m_manager) << "\n";); if (!m_manager.is_eq(atom) && !is_le_ge(atom)) return; expr * lhs = to_app(atom)->get_arg(0); @@ -879,6 +875,9 @@ void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls, */ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, macro_candidates & r) { expr* lhs, *rhs; + + TRACE("macro_util", tout << "Candidate check for: " << mk_ismt2_pp(atom, m_manager) << std::endl;); + if (m_manager.is_eq(atom, lhs, rhs) || m_manager.is_iff(atom, lhs, rhs)) { if (is_quasi_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && diff --git a/src/ast/macros/macro_util.h b/src/ast/macros/macro_util.h index 18b00c1f7..033f6ecb4 100644 --- a/src/ast/macros/macro_util.h +++ b/src/ast/macros/macro_util.h @@ -74,9 +74,9 @@ private: void collect_arith_macros(expr * n, unsigned num_decls, unsigned max_macros, bool allow_cond_macros, macro_candidates & r); - void normalize_expr(app * head, expr * t, expr_ref & norm_t) const; - void insert_macro(app * head, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r); - void insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, + void normalize_expr(app * head, unsigned num_decls, expr * t, expr_ref & norm_t) const; + void insert_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r); + void insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r); expr * m_curr_clause; // auxiliary var used in collect_macro_candidates. @@ -105,7 +105,7 @@ public: bool is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const; bool is_right_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const; bool is_simple_macro(expr * n, unsigned num_decls, app_ref& head, expr_ref & def) const { - return is_left_simple_macro(n, num_decls, head, def) || is_right_simple_macro(n, num_decls, head, def); + return is_left_simple_macro(n, num_decls, head, def) || is_right_simple_macro(n, num_decls, head, def); } bool is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def, bool & inv) const; @@ -113,20 +113,20 @@ public: bool inv; return is_arith_macro(n, num_decls, head, def, inv); } - + bool is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t); bool is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def); bool is_quasi_macro_head(expr * n, unsigned num_decls) const; - void quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, app_ref & head, expr_ref & cond) const; + void quasi_macro_head_to_macro_head(app * qhead, unsigned & num_decls, app_ref & head, expr_ref & cond) const; - void mk_macro_interpretation(app * head, expr * def, expr_ref & interp) const; + void mk_macro_interpretation(app * head, unsigned num_decls, expr * def, expr_ref & interp) const; void collect_macro_candidates(expr * atom, unsigned num_decls, macro_candidates & r); void collect_macro_candidates(quantifier * q, macro_candidates & r); // - // Auxiliary goodness that allows us to manipulate BV and Arith polynomials. + // Auxiliary goodness that allows us to manipulate BV and Arith polynomials. // bool is_bv(expr * n) const; bool is_bv_sort(sort * s) const; diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 05f47ada7..f6597fbc5 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -59,9 +59,12 @@ br_status bool_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * co mk_implies(args[0], args[1], result); return BR_DONE; case OP_XOR: - SASSERT(num_args == 2); - mk_xor(args[0], args[1], result); - return BR_DONE; + switch (num_args) { + case 0: return BR_FAILED; + case 1: result = args[0]; return BR_DONE; + case 2: mk_xor(args[0], args[1], result); return BR_DONE; + default: UNREACHABLE(); return BR_FAILED; + } default: return BR_FAILED; } diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index 93858b6be..1a4aa8304 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -25,7 +25,6 @@ Notes: #include"scoped_ptr_vector.h" #include"cooperate.h" #include"upolynomial_factorization.h" -#include"polynomial_factorization.h" #include"polynomial_primes.h" #include"permutation.h" #include"algebraic_numbers.h" diff --git a/src/math/polynomial/polynomial_factorization.cpp b/src/math/polynomial/polynomial_factorization.cpp deleted file mode 100644 index 4bf227d44..000000000 --- a/src/math/polynomial/polynomial_factorization.cpp +++ /dev/null @@ -1,1143 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - polynomial_factorization.cpp - -Abstract: - - Implementation of polynomial factorization. - -Author: - - Dejan (t-dejanj) 2011-11-15 - -Notes: - - [1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal, - 46(8-10):1853-1859, 1967. - [2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third - edition, 1997. - [3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993. - ---*/ -#if 0 -// disabled for reorg - -#include"trace.h" -#include"util.h" -#include"polynomial_factorization.h" -#include"upolynomial_factorization_int.h" -#include"prime_generator.h" - -using namespace std; - -namespace polynomial { - -typedef upolynomial::manager::scoped_numeral scoped_numeral; - -/** - Generates a substitution of values for f -> f_univariate in order to reduce the factorization to the - univariate case. - - @param f multivariate polynomial (square-free, primitive, vars(f) > 1) - @param x the variable we want to keep as the univarate one - @param f_lc the leading coefficient of f in x - @param vars the vector of all variables from f witouth x - @param size the bound to use for selecting the values, i.e. |a_i| <= size - @param a the output values corresponding to vairables in (place place for x should be ignored) - @param f_univariate the output substitution -*/ -void generate_substitution_values( - polynomial_ref const & f, var x, polynomial_ref const & f_lc, var_vector const & vars, unsigned & size, - upolynomial::numeral_vector & a, upolynomial::manager upm, upolynomial::numeral_vector & f_u) { - - SASSERT(a.size() == vars.size()); - - TRACE("polynomial::factorization", tout << "polynomial::generate_substitution_values(f = " << f << ", f_lc = " << f_lc << ")";); - - // f = f_n x^n + ... + f_0, square-free and primitive - // this means - // f_lc = f_n - // since f is primitive, - // we are looking for numbers a_i such that - // (1) f_lc doesn't vanish - // (2) f_u = f(a_0, ..., a_n, x) is square-free - - manager & pm = f.m(); - numeral_manager & nm = pm.m(); - - // polynomial to use for subtituting into the lc(f) - polynomial_ref f_lc_subst(pm); - - // random generator - random_gen generator; - - // increase the size every once in a while (RETHINK THIS) - unsigned inc_size_c = 0; - unsigned inc_size_c_max = size; - - while (true) { - - // see if we should increase the size of the substitution - if ((++ inc_size_c) % inc_size_c_max == 0) { - size ++; - inc_size_c = 0; - inc_size_c_max *= 2; - } - - // the head coefficient we'll substitute in - f_lc_subst = f_lc; - - bool vanished = false; - for (unsigned i = 0; i < vars.size() && !vanished; ++ i) { - SASSERT(vars[i] != x); - - // the value for x_i - nm.set(a[i], (int)generator(2*size+1) - (int)size); - - // substitute - f_lc_subst = pm.substitute(f_lc_subst, x, a[i]); - - // did it vanish - vanished = pm.is_zero(f_lc_subst); - } - - if (vanished) { - // leading coefficient vanished, try again - continue; - } - - // substitute into f and get the univariate one - polynomial_ref f_subst(pm); - f_subst = pm.substitute(f, vars.size(), vars.c_ptr(), a.c_ptr()); - upm.to_numeral_vector(f_subst, f_u); - - // if the result is not square-free we try again - if (!upm.is_square_free(f_u)) - continue; - - // found it, break - break; - } -} - -/** - \brief Bound for the coefficients of the factorst of the multivariate polynomial f. R - Returns power of p -> p^e that covers the bound - - We use the gelfond bound here: - d_i: degree of x_i in f(x1, ..., x_n) - bound = |f| * 2^(\sum d_i - (n-1)/2)) -*/ -void multivariate_factor_coefficient_bound(polynomial_ref const & f, var x, numeral const & p, unsigned & e, numeral & p_e, var2degree & d) { - manager & pm = f.m(); - numeral_manager & nm = pm.m(); - - // compute g = lc(f)*f - polynomial_ref f_lc(pm), g(pm); - f_lc = pm.coeff(f, x, pm.degree(f, x)); - g = pm.mul(f, f_lc); - - // get the norm - scoped_numeral g_norm(nm); - pm.abs_norm(g, g_norm); - - // get the variable degrees - var_vector vars; - pm.vars(f, vars); - unsigned power = 0; - for (unsigned i = 0; i < vars.size(); ++ i) { - unsigned c_d = pm.degree(g, vars[i]); - d.set_degree(vars[i], c_d + 1); - power += c_d; - } - power = power - (vars.size()-1)/2; - - // compute the bound - scoped_numeral bound(nm); - nm.set(bound, 2); - nm.power(bound, power, bound); - nm.mul(g_norm, bound, bound); - - // return the first power of two that is bigger than the norm - e = 1; - nm.set(p_e, p); - while (nm.lt(p_e, bound)) { - nm.mul(p_e, p_e, p_e); - e *= 2; - } -} - -// check that A*S+B*T=C in zp mod ideal -bool check_solve(zp_manager & zp_pm, var2degree const & ideal, - zp_polynomial_ref const & A, zp_polynomial_ref const & B, zp_polynomial_ref const & C, - zp_polynomial_ref const & S, zp_polynomial_ref const & T) { - zp_polynomial_ref AS(zp_pm), BT(zp_pm), sum(zp_pm); - AS = zp_pm.mul(A, S); AS = zp_pm.mod_d(AS, ideal); - BT = zp_pm.mul(B, T); BT = zp_pm.mod_d(BT, ideal); - sum = zp_pm.add(AS, BT); - - TRACE("polynomial::factorization::multivariate", - tout << "zp_pm = Z_" << zp_pm.m().m().to_string(zp_pm.m().p()) << endl; - tout << "ideal = " << ideal << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - tout << "S = " << S << endl; - tout << "T = " << T << endl; - tout << "C = " << C << endl; - tout << "sum = " << sum << endl; - ); - - bool result = zp_pm.eq(sum, C); - return result; -} - -/** - Solve the equation A*S + B*T = C, given, AU + BV = 1, with deg(T) < deg(A) - S = U*C + tB - T = V*C - tA - we divide VC with A to get (T, t) -*/ -template -void solve(zp_manager & zp_pm, var x, var2degree const & ideal, - zp_polynomial_ref const & A, zp_polynomial_ref const & U, - zp_polynomial_ref const & B, zp_polynomial_ref const & V, - zp_polynomial_ref const & C, - output_manager & out_pm, - typename output_manager::polynomial_ref & S_out, - typename output_manager::polynomial_ref & T_out) { - TRACE("polynomial::factorization::multivariate", - tout << "polynomial::solve(" << endl; - tout << "zp_pm = Z_" << zp_pm.m().m().to_string(zp_pm.m().p()) << endl; - tout << "ideal = " << ideal << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - tout << "U = " << U << endl; - tout << "V = " << V << endl; - tout << "C = " << C << endl; - ); - - // solution is S = C*U + tB, T = C*V - tA - zp_polynomial_ref CV(zp_pm); - CV = zp_pm.mul(C, V); CV = zp_pm.mod_d(CV, ideal); - zp_polynomial_ref CU(zp_pm); - CU = zp_pm.mul(C, U); CU = zp_pm.mod_d(CU, ideal); - zp_polynomial_ref t(zp_pm), T(zp_pm); - zp_pm.exact_pseudo_division_mod_d(CV, A, x, ideal, t, T); - - zp_polynomial_ref tB(zp_pm); - tB = zp_pm.mul(t, B); tB = zp_pm.mod_d(tB, ideal); - zp_polynomial_ref S(zp_pm); - S = zp_pm.add(CU, tB); - - SASSERT(check_solve(zp_pm, ideal, A, B, C, S, T)); - - // convert to the other manager - S_out = convert(zp_pm, S, out_pm); - T_out = convert(zp_pm, T, out_pm); - - TRACE("polynomial::factorization::multivariate", - tout << "CU = " << CU << endl; - tout << "CV = " << CV << endl; - tout << "t = " << t << endl; - tout << "--- solution ---" << endl; - tout << "S = " << S_out << endl; - tout << "T = " << T_out << endl; - ); -} - -/** - A, B, U, V: multivariate polynomials in Z_p[x, ...], mod ..., also the output polynomials, y is not there - C: C = A*B in Z_p[x, ...] mod p, ... - - ideal: all the vars we care about in the ideal - - y, the variable we are lifting is not in ideal_vars, we will add it - - A monic, A*U+B*V = 1 - - p is not necessary prime, it's a power of a prime - - we're doing quadratic lifting here - - output: added y, i.e. - * all polynomials in Z_p[x, ..., y] mod (..., y^d) -*/ -void multivariate_hansel_lift_ideal( - zp_manager & zp_pm, var x, - zp_polynomial_ref const & C, - zp_polynomial_ref & A, zp_polynomial_ref & U, zp_polynomial_ref & B, zp_polynomial_ref & V, - var2degree & ideal, var y, unsigned d) { - numeral_manager & nm = zp_pm.m().m(); - - TRACE("polynomial::factorization::multivariate", - tout << "polynomial::multiratiate_hensel_lift_ideal" << endl; - tout << "zp_pm is Z_" << zp_pm.m().m().to_string(zp_pm.m().p()) << endl; - tout << "x = x" << x << endl; - tout << "y = x" << y << endl; - tout << "C = " << C << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - tout << "U = " << U << endl; - tout << "V = " << V << endl; - tout << "ideal = " << ideal << endl; - ); - - // constant 1 - scoped_numeral one(nm); - nm.set(one, 1); - zp_polynomial_ref one_p(zp_pm); - one_p = zp_pm.mk_const(one); - - SASSERT(zp_pm.degree(A, y) == 0 && zp_pm.degree(B, y) == 0 && zp_pm.degree(U, y) == 0 && zp_pm.degree(V, y) == 0); - - // update the ideal, and start with y - ideal.set_degree(y, 1); - unsigned current_d = 1; - zp_polynomial_ref current_power(zp_pm); - current_power = zp_pm.mk_polynomial(y); - - // lift quadratic until we are over the asked for - while (current_d < d) { - - TRACE("polynomial::factorization::multivariate", - tout << "zp_pm = Z_" << nm.to_string(zp_pm.m().p()) << endl; - tout << "ideal = " << ideal << endl; - tout << "C = " << C << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - ); - - // again, classic hensel: - // since C = A*B mod (p, ideal, y^k) we know that (C - A*B) = 0 mod (p, ideal, y^k) - // f = (C - A*B) mod (p, ideal, y^k) and thus divisible by y^current_d = current_power - zp_polynomial_ref f(zp_pm); - f = zp_pm.mul(A, B); - - TRACE("polynomial::factorization::multivariate", - tout << "zp_pm = Z_" << nm.to_string(zp_pm.m().p()) << endl; - tout << "ideal = " << ideal << endl; - tout << "C = " << C << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - tout << "f = " << f << endl; - ); - - f = zp_pm.sub(C, f); - f = zp_pm.exact_div(f, current_power); - f = zp_pm.mod_d(f, ideal); - - TRACE("polynomial::factorization::multivariate", - tout << "A = " << A << endl; - tout << "B = " << B << endl; - ); - - // get the S, T, solution to A*S+B*T = f, with d(T, x) < d(A, x) - // but we know that S = U*f + Bt, T = V*f - At, so we do division - zp_polynomial_ref S(zp_pm), T(zp_pm); - solve(zp_pm, x, ideal, A, U, B, V, f, zp_pm, S, T); - // now, lets lift A and B - // we want A1 = A + T*y^d, B1 = B + S*y^d with A1*B1 = C mod (ideal, y^(2*k)) - // hence A*B + y^d*(A*S+B*T) = C - S = zp_pm.mul(S, current_power); - T = zp_pm.mul(T, current_power); - A = zp_pm.add(A, T); - B = zp_pm.add(B, S); - - TRACE("polynomial::factorization::multivariate", - tout << "A = " << A << endl; - tout << "B = " << B << endl; - ); - - // again, classic quadratic hensel - // we need A*U1 + B*V1 = 1 mod (p, ideal, y^2), from above - // U1 = U + S*y^d, V1 = V + T*y^d, hence A*U + B*V + y^d(S + T) = 1 mod new ideal^2 - // we know that y^d divides (1-UA-BV) so we compute f = (1-UA-BV)/y^d - // UA + VB + y^d(SA + TB) = 1 (mod ideal^2) - // SA + TB = f (mod ideal) - // we solve for S, T again, and do as above - zp_polynomial_ref UA(zp_pm), BV(zp_pm); - f = zp_pm.mk_const(one); - UA = zp_pm.mul(U, A); - BV = zp_pm.mul(V, B); - f = zp_pm.sub(f, UA); f = zp_pm.sub(f, BV); - - TRACE("polynomial::factorization::multivariate", - tout << "ideal = " << ideal << endl; - tout << "current_power = " << current_power << endl; - tout << "UA = " << UA << endl; - tout << "BV = " << BV << endl; - tout << "f = " << f << endl; - tout << "x = x" << x << endl; - tout << "y = x" << y << endl; - ); - - f = zp_pm.exact_div(f, current_power); - f = zp_pm.mod_d(f, ideal); - - // get the S, T, solution to A*S+B*T = f, with d(T, x) < d(A, x) - solve(zp_pm, x, ideal, A, U, B, V, f, zp_pm, S, T); - // now, lets lift U and V - S = zp_pm.mul(S, current_power); - U = zp_pm.add(U, S); - T = zp_pm.mul(T, current_power); - V = zp_pm.add(V, T); - - // lift the ideal - current_d *= 2; - current_power = zp_pm.mul(current_power, current_power); - ideal.set_degree(y, current_d); - - // move, A, B, C, D into the ideal - A = zp_pm.mod_d(A, ideal); - B = zp_pm.mod_d(B, ideal); - S = zp_pm.mod_d(S, ideal); - T = zp_pm.mod_d(T, ideal); - - TRACE("polynomial::factorization::multivariate", - tout << "current_d = " << d << endl; - tout << "zp_pm is Z_" << zp_pm.m().m().to_string(zp_pm.m().p()) << endl; - tout << "x = x" << x << endl; - tout << "y = x" << y << endl; - tout << "C = " << C << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - tout << "U = " << U << endl; - tout << "V = " << V << endl; - tout << "ideal = " << ideal << endl; - ); - - SASSERT(check_solve(zp_pm, ideal, A, B, one_p, U, V)); - } -} - -template -bool are_equal_in( - manager_to_check pm, - typename manager_1::polynomial_ref const & A, - typename manager_2::polynomial_ref const & B) { - typename manager_to_check::polynomial_ref A_pm(pm), B_pm(pm); - - A_pm = convert(A.m(), A, pm); - B_pm = convert(B.m(), B, pm); - - bool equal = pm.eq(A_pm, B_pm); - return equal; -} - -/** - C: target multivariate polynomial mod ideal, p^e, the manager is in p^e - x: main variable - A, B, U, V: univariate polynomials in Z_p[x] such that U*A+B*V=1 mod ideal, these guys managers are in Z_p - - output: A_lifted, B_lifted, A = A_lifted mod ideal - A_lifted*B_lifted = f mod x_i^d_i, p^e -*/ -void multivariate_hansel_lift_zp( - manager & pm, zp_manager & zp_pm, zp_manager & zpe_pm, - zp_polynomial_ref const & C_pe, var x, unsigned e, - zp_polynomial_ref const & A_p, zp_polynomial_ref const & U_p, - zp_polynomial_ref const & B_p, zp_polynomial_ref const & V_p, - var2degree const & ideal, - zp_polynomial_ref & A_lifted, zp_polynomial_ref & B_lifted) { - TRACE("polynomial::factorization::multivariate", - tout << "polynomial::multiratiate_hensel_lift_zp:" << endl; - tout << "zp_pm = Z_" << zp_pm.m().m().to_string(zp_pm.m().p()) << endl; - tout << "zpe_pm = Z_" << zpe_pm.m().m().to_string(zpe_pm.m().p()) << endl; - tout << "x = x" << x << endl; - tout << "ideal = " << ideal << endl; - tout << "C_pe = " << C_pe << "," << endl; - tout << "A_p = " << A_p << "," << endl; - tout << "B_p = " << B_p << "," << endl; - ); - - // fixed zpe_pm - // upolynomial::zp_numeral_manager & zpe_nm = zpe_pm.m(); - // numeral const & pe = zpe_nm.p(); - // fixed zp_pm - upolynomial::zp_numeral_manager & zp_nm = zp_pm.m(); - numeral const & p = zp_nm.p(); - // regular numeral manager and mangager - numeral_manager & nm = zp_nm.m(); - - // sliding zpk_pm mod p^k - upolynomial::zp_numeral_manager zpk_nm(nm, p); - zp_manager zpk_pm(zpk_nm, &zp_pm.mm()); // in the end we copy the result over to zpe - unsigned k = 1; - upolynomial::scoped_numeral pk(nm); - nm.set(pk, zpk_nm.p()); - - // constant 1 - scoped_numeral one(nm); - nm.set(one, 1); - zp_polynomial_ref one_p(zpk_pm); - one_p = zpk_pm.mk_const(one); - - // lift until you get over the requested power of e - zp_polynomial_ref A_pk(zpk_pm), B_pk(zpk_pm), U_pk(zpk_pm), V_pk(zpk_pm); - - A_pk = convert(zp_pm, A_p, zpk_pm); - B_pk = convert(zp_pm, B_p, zpk_pm); - U_pk = convert(zp_pm, U_p, zpk_pm); - V_pk = convert(zp_pm, V_p, zpk_pm); - - TRACE("polynomial::factorization::multivariate", - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "A_pk = " << A_pk << endl; - tout << "B_pk = " << B_pk << endl; - tout << "U_pk = " << U_pk << endl; - tout << "V_pk = " << V_pk << endl; - ); - - SASSERT(check_solve(zpk_pm, ideal, A_pk, B_pk, one_p, U_pk, V_pk)); - - while (k < e) { - - // standard hensel: - // (C - AB) and is divisible by p^k, so we compute f = (C - AB)/p^k mod ideal in Z[...] - zp_polynomial_ref f_pk(zpk_pm); - polynomial_ref A_pk_in_Z(pm), B_pk_in_Z(pm), AB_in_Z(pm), f_in_Z(pm); - f_in_Z = convert(zpe_pm, C_pe, pm); - A_pk_in_Z = convert(zpk_pm, A_pk, pm); - B_pk_in_Z = convert(zpk_pm, B_pk, pm); - AB_in_Z = pm.mul(A_pk_in_Z, B_pk_in_Z); - AB_in_Z = pm.mod_d(AB_in_Z, ideal); - f_in_Z = pm.sub(f_in_Z, AB_in_Z); - f_in_Z = pm.exact_div(f_in_Z, pk); - f_in_Z = pm.mod_d(f_in_Z, ideal); - f_pk = convert(pm, f_in_Z, zpk_pm); - - TRACE("polynomial::factorization::multivariate", - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "f_pk = " << f_pk << endl; - ); - - // standard hensel we need to lift to p^(2k) - // we have U*A+V*B = 1, C = A*B, so p^k divides C - AB - // we want A1 = A + p^k*S, B1 = B + p^k*T, and also - // C - (A + p^k*S)*(B + p^k*T) = 0 mod (p^2k) - // C - A*B = p^k (T*A + S*B), i.e. - // f = (C - A*B)/p^k = (T*A + S*B), so we solve this equation in Z_p^k - polynomial_ref S_in_Z(pm), T_in_Z(pm); - solve(zpk_pm, x, ideal, A_pk, U_pk, B_pk, V_pk, f_pk, pm, T_in_Z, S_in_Z); - - TRACE("polynomial::factorization::multivariate", - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "S_in_Z = " << S_in_Z << endl; - tout << "T_in_Z = " << T_in_Z << endl; - ); - - // lift A and B to, A = A + p^k*S, B = B + p^k*T - polynomial_ref A_next_in_Z(pm), B_next_in_Z(pm); - S_in_Z = pm.mul(pk, S_in_Z); - S_in_Z = pm.mod_d(S_in_Z, ideal); - A_next_in_Z = convert(zpk_pm, A_pk, pm); - A_next_in_Z = pm.add(A_next_in_Z, S_in_Z); - T_in_Z = pm.mul(pk, T_in_Z); - T_in_Z = pm.mod_d(T_in_Z, ideal); - B_next_in_Z = convert(zpk_pm, B_pk, pm); - B_next_in_Z = pm.add(B_next_in_Z, T_in_Z); - - TRACE("polynomial::factorization::multivariate", - tout << "pk = " << nm.to_string(pk) << endl; - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "S_in_Z = " << S_in_Z << endl; - tout << "T_in_Z = " << T_in_Z << endl; - tout << "A_pk = " << A_pk << endl; - tout << "B_pk = " << B_pk << endl; - tout << "A_next_in_Z = " << A_next_in_Z << endl; - tout << "B_next_in_Z = " << B_next_in_Z << endl; - ); - - bool eq1 = are_equal_in(zpk_pm, A_next_in_Z, A_pk); - SASSERT(eq1); - bool eq2 = are_equal_in(zpk_pm, B_next_in_Z, B_pk); - SASSERT(eq2); - - // again, classic quadratic hensel - // we need A*U1 + B*V1 = 1 mod p^2k, from above - // U1 = U + p^k*S, V1 = V + p^k*T, hence A*U + B*V + p^k*(S + T) = 1 mod (p^2k) - // we know that p^k divides (1-UA-BV) so we compute f = (1-UA-BV)/p^k - // UA + VB + p^k(SA + TB) = 1 (mod p^k) - // SA + TB = f (mod ideal) - // we solve for S, T again, and do as above - polynomial_ref U_pk_in_Z(pm), V_pk_in_Z(pm), UA_in_Z(pm), BV_in_Z(pm); - U_pk_in_Z = convert(zpk_pm, U_pk, pm); - V_pk_in_Z = convert(zpk_pm, V_pk, pm); - f_in_Z = pm.mk_const(one); - UA_in_Z = pm.mul(U_pk_in_Z, A_next_in_Z); - UA_in_Z = pm.mod_d(UA_in_Z, ideal); - BV_in_Z = pm.mul(V_pk_in_Z, B_next_in_Z); - BV_in_Z = pm.mod_d(BV_in_Z, ideal); - f_in_Z = pm.sub(f_in_Z, UA_in_Z); - f_in_Z = pm.sub(f_in_Z, BV_in_Z); - - TRACE("polynomial::factorization::multivariate", - tout << "pk = " << nm.to_string(pk) << endl; - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "U_pk_in_Z = " << U_pk_in_Z << endl; - tout << "V_pk_in_Z = " << V_pk_in_Z << endl; - tout << "UA_in_Z = " << UA_in_Z << endl; - tout << "BV_in_Z = " << BV_in_Z << endl; - tout << "f_in_Z = " << f_in_Z << endl; - ); - - f_in_Z = pm.exact_div(f_in_Z, pk); - f_pk = convert(pm, f_in_Z, zpk_pm); - - // get the S, T, solution to A*S+B*T = f, with d(T, x) < d(A, x) - solve(zpk_pm, x, ideal, A_pk, U_pk, B_pk, V_pk, f_pk, pm, S_in_Z, T_in_Z); - - TRACE("polynomial::factorization::multivariate", - tout << "pk = " << nm.to_string(pk) << endl; - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "S_in_Z = " << S_in_Z << endl; - tout << "T_in_Z = " << T_in_Z << endl; - ); - - // go to the next zpk - scoped_numeral next_pk(nm); - nm.mul(pk, pk, next_pk); - zpk_nm.set_p(next_pk); - - TRACE("polynomial::factorization::multivariate", - tout << "zp_pk = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - ); - - // lift U - zp_polynomial_ref S_pk(zpk_pm); - S_in_Z = pm.mul(pk, S_in_Z); - S_pk = convert(pm, S_in_Z, zpk_pm); - - TRACE("polynomial::factorization::multivariate", - tout << "S_pk = " << S_pk << endl; - ); - - U_pk = zpk_pm.add(U_pk, S_pk); - // lift V - zp_polynomial_ref T_pk(zpk_pm); - T_in_Z = pm.mul(pk, T_in_Z); - T_pk = convert(pm, T_in_Z, zpk_pm); - - TRACE("polynomial::factorization::multivariate", - tout << "T_pk = " << T_pk << endl; - ); - - V_pk = zpk_pm.add(V_pk, T_pk); - - // lift A and B - TRACE("polynomial::factorization::multivariate", - tout << "A_pk_in_Z = " << A_pk_in_Z << endl; - tout << "B_pk_in_Z = " << B_pk_in_Z << endl; - ); - A_pk = convert(pm, A_pk_in_Z, zpk_pm); - B_pk = convert(pm, B_pk_in_Z, zpk_pm); - - // move to the next pk - k *= 2; - nm.set(pk, next_pk); - - TRACE("polynomial::factorization::multivariate", - tout << "zp_pk = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "A_pk = " << A_pk << endl; - tout << "B_pk = " << B_pk << endl; - tout << "U_pk = " << U_pk << endl; - tout << "V_pk = " << V_pk << endl; - tout << "C_pe = " << C_pe << endl; - ); - - SASSERT(check_solve(zpk_pm, ideal, A_pk, B_pk, one_p, U_pk, V_pk)); - } - - // now convert to the non-sliding zpe_manager - SASSERT(k == e); - A_lifted = convert(zpk_pm, A_pk, zpe_pm); - B_lifted = convert(zpk_pm, B_pk, zpe_pm); -} - -/** - f: target multivariate polynomial mod x_i^d_i, p^e - x: main variable - all_vars: all variables (including x) - A, B, U, V: univariate polynomials in Z_p[x] such that U*A+B*V=1 from ext gcd - - output: A_lifted, B_lifted d(A) = d(A_lifted), A = A_lifted mod x_i^d_i, p - A_lifted*B_lifted = f mod x_i^d_i, p^e -*/ -void multivariate_hensel_lift( - manager & pm, zp_manager & zp_pm, zp_manager & zpe_pm, - zp_polynomial_ref const & f, var x, unsigned e, var_vector const & all_vars, - upolynomial::zp_manager & zp_upm, - upolynomial::numeral_vector const & U, upolynomial::numeral_vector const & A, - upolynomial::numeral_vector const & V, upolynomial::numeral_vector const & B, - var2degree & target_ideal, zp_polynomial_ref & A_lifted, zp_polynomial_ref & B_lifted) { - upolynomial::zp_numeral_manager & zp_nm = zp_upm.m(); - upolynomial::numeral_manager & nm = zp_nm.m(); - - TRACE("polynomial::factorization::multivariate", - tout << "polynomial::multiratiate_hensel_lift(" << endl; - tout << "f = " << f << "," << endl; - tout << "x = x" << x << "," << endl; - tout << "e = " << e << "," << endl; - tout << "U = "; zp_upm.display(tout, U); tout << "," << endl; - tout << "A = "; zp_upm.display(tout, A); tout << "," << endl; - tout << "V = "; zp_upm.display(tout, V); tout << "," << endl; - tout << "B = "; zp_upm.display(tout, B); tout << "," << endl; - tout << "target_ideal = " << target_ideal << "," << endl; - tout << "p = " << nm.to_string(zp_pm.m().p()) << endl; - tout << "pe = " << nm.to_string(zpe_pm.m().p()) << endl; - ); - - // multivariate versions of A, B, U, V that we keep lifting over ideal x_i^d_i - zp_polynomial_ref A_m_p(zp_pm), B_m_p(zp_pm), U_m_p(zp_pm), V_m_p(zp_pm); - A_m_p = zp_pm.to_polynomial(A, x); - B_m_p = zp_pm.to_polynomial(B, x); - U_m_p = zp_pm.to_polynomial(U, x); - V_m_p = zp_pm.to_polynomial(V, x); - - TRACE("polynomial::factorization::multivariate", - tout << "A_m_p = " << A_m_p << endl; - tout << "B_m_p = " << B_m_p << endl; - tout << "U_m_p = " << U_m_p << endl; - tout << "V_m_p = " << V_m_p << endl; - ); - - // the the target in Z_p[...] - zp_polynomial_ref C_m_p(zp_pm); - C_m_p = convert(zpe_pm, f, zp_pm); - - // lift each variable individually - var2degree lifted_ideal; - unsigned_vector lifted_degs; - for (unsigned i = 0; i < all_vars.size(); ++ i) { - if (all_vars[i] == x) { - // skip the main variable - continue; - } - // current variable and degree we are lifting to, y^(d_y), at least - var y = all_vars[i]; - // lift to y^(d_y) - multivariate_hansel_lift_ideal(zp_pm, x, C_m_p, A_m_p, U_m_p, B_m_p, V_m_p, lifted_ideal, y, target_ideal.degree(y)); - } - - TRACE("polynomial::factorization::multivariate", - tout << "A_m_p = " << A_m_p << endl; - tout << "B_m_p = " << B_m_p << endl; - tout << "U_m_p = " << U_m_p << endl; - tout << "V_m_p = " << V_m_p << endl; - tout << "lifted_ideal = " << lifted_ideal << endl; - ); - - // now lift it all to p^e - multivariate_hansel_lift_zp(pm, zp_pm, zpe_pm, f, x, e, A_m_p, U_m_p, B_m_p, V_m_p, lifted_ideal, A_lifted, B_lifted); -} - - -/** - f: multivariate polynomial - x: main variable - all_vars: all variables (including x) - f_u: f mod x_1, ..., x_n (excluding mod x), i.e. this is f(0, x), f_u is square_free - f_u_zp_factors: monic factors of f_u (mod p), pairvise gcd = 1 - - we're lifting the factors to mod x_1^d_1, ..., x_n&d_n (excliding x), mod p^e - i.e. such that f congruent to the new factors. output goes to f_zpe factors. -*/ -void multivariate_hensel_lift( - manager & pm, zp_manager & zp_pm, zp_manager & zpe_pm, - polynomial_ref const & f, var x, unsigned e, var_vector const & all_vars, - upolynomial::manager & upm, upolynomial::numeral_vector const & f_u, - upolynomial::zp_factors const & f_u_zp_factors, - var2degree & target_ideal, - zp_factors & f_zpe_factors) { - SASSERT(f_u_zp_factors.distinct_factors() > 1); - - TRACE("polynomial::factorization::multivariate", - tout << "polynomial::multivariate_hensel_lift(" << endl; - tout << "f = " << f << "," << endl; - tout << "x = x" << x << "," << endl; - tout << "e = " << e << "," << endl; - tout << "f_u = "; upm.display(tout, f_u); tout << "," << endl; - tout << "f_u_zp_factors" << f_u_zp_factors << "," << endl; - tout << "target_ideal = " << target_ideal << "," << endl; - tout << "f_zpe_factors = " << f_zpe_factors << ")" << endl; - ); - - // managers and all - numeral_manager & nm = pm.m(); - upolynomial::zp_manager & zp_upm = f_u_zp_factors.upm(); - // upolynomial::zp_numeral_manager & zp_nm = zp_upm.m(); - upolynomial::zp_numeral_manager & zpe_nm = zpe_pm.m(); - upolynomial::zp_manager zpe_upm(zpe_nm); - - // the targed product we want (mod x_i^d_i, mod p^e) - zp_polynomial_ref f_target_zpe(zpe_pm); - f_target_zpe = convert(pm, f, zpe_pm); - f_target_zpe = zpe_pm.mod_d(f_target_zpe, target_ideal); - - TRACE("polynomial::factorization::multivariate", - tout << "target_ideal = " << target_ideal << endl; - tout << "f_target_zpe = " << f_target_zpe << endl; - ); - - // we do the product by doing individual lifting like in the univarate case - zp_polynomial_ref B(zp_pm), C_p(zp_pm); - zp_polynomial_ref A_lifted(zpe_pm), B_lifted(zpe_pm); - upolynomial::scoped_numeral_vector B_u(nm), C_u(nm), tmp_u(nm); - upolynomial::scoped_numeral_vector U(nm), V(nm); - for (int i = 0, i_end = f_u_zp_factors.distinct_factors() - 1; i < i_end; ++ i) - { - // get the univarate ones to lift now - upolynomial::numeral_vector const & A_u = f_u_zp_factors[i]; - // current starting product is f_target_zpe(0, x) in *Z_p* - zp_upm.to_numeral_vector(f_target_zpe, x, C_u); - // we get the rest into B (mod p) - zp_upm.exact_div(C_u, A_u, B_u); - - TRACE("polynomial::factorization::multivariate", - tout << "p = " << nm.to_string(zp_upm.m().p()) << endl; - tout << "f_target_zpe = " << f_target_zpe << endl; - tout << "A_u = "; upm.display(tout, A_u); tout << endl; - tout << "B_u = "; upm.display(tout, B_u); tout << endl; - tout << "C_u = "; upm.display(tout, C_u); tout << endl; - ); - - // and get the U, V, such that A*U+B*V = 1 - zp_upm.ext_gcd(A_u, B_u, U, V, tmp_u); - - TRACE("polynomial::factorization::multivariate", - tout << "U = "; upm.display(tout, U); tout << endl; - tout << "V = "; upm.display(tout, V); tout << endl; - tout << "gcd = "; upm.display(tout, tmp_u); tout << endl; - ); - - // do the lifting for this pair - multivariate_hensel_lift(pm, zp_pm, zpe_pm, f_target_zpe, x, e, all_vars, zp_upm, U, A_u, V, B_u, target_ideal, A_lifted, B_lifted); - - // add the lifted A to the output - f_zpe_factors.push_back(A_lifted, 1); - // move to the new target by dividing with the lifted A - f_target_zpe = zpe_pm.exact_div(f_target_zpe, A_lifted); - } - - // add the last f_target - f_zpe_factors.push_back(f_target_zpe, 1); -} - -class mfactorization_combination_iterator : public upolynomial::factorization_combination_iterator_base { - - /** main variable */ - var m_x; - -public: - - mfactorization_combination_iterator(zp_factors const & factors, var x) - : upolynomial::factorization_combination_iterator_base(factors) - {} - - /** - \brief Filter the ones not in the degree set. - */ - bool filter_current() const { - return false; - } - - /** - \brief Returns the degree of the current selection. - */ - unsigned current_degree() const { - unsigned degree = 0; - zp_manager & pm = m_factors.pm(); - for (unsigned i = 0; i < left_size(); ++ i) { - degree += pm.degree(m_factors[m_current[i]], m_x); - } - return degree; - } - - void left(zp_polynomial_ref & out) const { - SASSERT(m_current_size > 0); - zp_manager & zp_pm = m_factors.pm(); - out = m_factors[m_current[0]]; - for (int i = 1; i < m_current_size; ++ i) { - out = zp_pm.mul(out, m_factors[m_current[i]]); - } - } - - void get_left_tail_coeff(numeral const & m, numeral & out) { - zp_manager & zp_pm = m_factors.pm(); - upolynomial::zp_numeral_manager & zp_nm = zp_pm.m(); - zp_nm.set(out, m); - for (int i = 0; i < m_current_size; ++ i) { - zp_nm.mul(out, zp_pm.numeral_tc(m_factors[m_current[i]]), out); - } - } - - void get_right_tail_coeff(numeral const & m, numeral & out) { - zp_manager & zp_pm = m_factors.pm(); - upolynomial::zp_numeral_manager & zp_nm = zp_pm.m(); - zp_nm.set(out, m); - - unsigned current = 0; - unsigned selection_i = 0; - - // selection is ordered, so we just take the ones in between that are not disable - while (current < m_factors.distinct_factors()) { - if (!m_enabled[current]) { - // by skipping the disabled we never skip a selected one - current ++; - } else { - if (selection_i >= m_current.size() || (int) current < m_current[selection_i]) { - SASSERT(m_factors.get_degree(current) == 1); - zp_nm.mul(out, zp_pm.numeral_tc(m_factors[current]), out); - current ++; - } else { - current ++; - selection_i ++; - } - } - } - } - - void right(zp_polynomial_ref & out) const { - SASSERT(m_current_size > 0); - zp_manager & zp_pm = m_factors.pm(); - upolynomial::zp_numeral_manager & zp_nm = zp_pm.m(); - - unsigned current = 0; - unsigned selection_i = 0; - - numeral one; - zp_nm.set(one, 1); - out = zp_pm.mk_const(one); - - // selection is ordered, so we just take the ones in between that are not disable - while (current < m_factors.distinct_factors()) { - if (!m_enabled[current]) { - // by skipping the disabled we never skip a selected one - current ++; - } else { - if (selection_i >= m_current.size() || (int) current < m_current[selection_i]) { - SASSERT(m_factors.get_degree(current) == 1); - out = zp_pm.mul(out, m_factors[current]); - current ++; - } else { - current ++; - selection_i ++; - } - } - } - } -}; - - -// the multivariate factorization -bool factor_square_free_primitive(polynomial_ref const & f, factors & f_factors) { - - TRACE("polynomial::factorization", tout << "polynomial::factor_square_free_primitive(f = " << f << ", factors = " << f_factors << ")" << endl;); - - manager & pm = f.m(); - numeral_manager & nm = pm.m(); - - // to start with, maybe this should be part of input - var x = pm.max_var(f); - // get all the variables - var_vector vars, vars_no_x; - pm.vars(f, vars); - for(unsigned i = 0; i < vars.size(); ++ i) { - if (vars[i] != x) { - vars_no_x.push_back(vars[i]); - } - } - SASSERT(vars.size() > 1); - - // degree of the main variable - unsigned x_degree = pm.degree(f, x); - // the leading coefficient - polynomial_ref f_lc(pm); - f_lc = pm.coeff(f, x, x_degree); - - // the vector of values we substitute - upolynomial::scoped_numeral_vector a(nm); - - // the univariate polynomial - upolynomial::manager upm(nm); - upolynomial::scoped_numeral_vector f_u(upm); - - // generate the values to substitute and substitute them to get f_u(x) = f(a, x), the univariate version of f - unsigned size = 1; - a.resize(vars_no_x.size()); - for (unsigned i = 0; i < a.size(); ++ i) { nm.reset(a[i]); } - generate_substitution_values(f, x, f_lc, vars_no_x, size, a, upm, f_u); - - TRACE("polynomial::factorization::multivariate", - tout << "f_u = "; upm.display(tout, f_u); tout << endl; - tout << "substitution:" << endl; - for (unsigned i = 0; i < vars_no_x.size(); ++ i) { - tout << "x" << vars[i] << " -> " << nm.to_string(a[i]) << endl; - }); - - // the primitive part of f_u - scoped_numeral f_u_lc(nm); - upolynomial::scoped_numeral_vector f_u_pp(nm); - upm.get_primitive_and_content(f_u, f_u_pp, f_u_lc); - - TRACE("polynomial::factorization::multivariate", - tout << "f_u_lc" << nm.to_string(f_u_lc) << endl; - tout << "f_u_pp = "; upm.display(tout, f_u_pp); tout << endl; - ); - - // factor the univariate one - upolynomial::factors factors_u(upm); - upolynomial::factor_square_free(upm, f_u, factors_u); - - TRACE("polynomial::factorization::multivariate", - tout << "factors_u = " << factors_u << endl; - ); - - // if there is no univariate factors, it's irreducible - if (factors_u.distinct_factors() == 1) { - f_factors.push_back(f, 1); - return false; - } - - // translate f with a, so that we work modulo x_i^k and not (x_i - a_i)^k - polynomial_ref f_t(pm); - // Do the translation, we must have that a[x] = 0 - pm.translate(f, vars_no_x, a, f_t); - - TRACE("polynomial::factorization::multivariate", - tout << "f_t = " << f_t << endl; - ); - - // the zp manager stuff, we'll be changing the base - upolynomial::zp_numeral_manager zp_nm(nm, 2); - upolynomial::zp_manager zp_upm(zp_nm); - - // get the first prime number p that keeps f square-free - scoped_numeral p(nm); - prime_iterator prime_it; - upolynomial::scoped_numeral_vector f_u_pp_zp(nm); - do { - // create Z_p with the next prime - nm.set(p, prime_it.next()); - // translate to Zp[x] - zp_nm.set_p(p); - upolynomial::to_zp_manager(zp_upm, f_u_pp, f_u_pp_zp); - } while (!zp_upm.is_square_free(f_u_pp_zp)); - - TRACE("polynomial::factorization::multivariate", - tout << "p = " << p << endl; - tout << "f_t = " << f_t << endl; - ); - - // convert factors of f to factors modulo p (monic ones) - upolynomial::zp_factors factors_u_zp(zp_upm); - upolynomial::scoped_numeral_vector current_factor(nm); - for (unsigned i = 0; i < factors_u.distinct_factors(); ++ i) { - upolynomial::to_zp_manager(zp_upm, factors_u[i], current_factor); - zp_upm.mk_monic(current_factor); - factors_u_zp.push_back_swap(current_factor, 1); - } - - TRACE("polynomial::factorization::multivariate", - tout << "factors_u_zp = " << factors_u_zp << endl; - ); - - // compute factor coefficient bound (pover p^e) of the translated f with the leading coefficient added, i.e. - // f_t*lc(f_t, x) = f_t*lc(f, x) - unsigned e; - scoped_numeral p_e(nm); - var2degree target_ideal; - upolynomial::scoped_numeral f_t_lc(nm); - nm.set(f_t_lc, pm.numeral_lc(f_t, x)); - polynomial_ref f_t_with_lc(pm); - f_t_with_lc = pm.mul(f_t_lc, f_t); - multivariate_factor_coefficient_bound(f_t_with_lc, x, p, e, p_e, target_ideal); - - TRACE("polynomial::factorization::multivariate", - tout << "target_ideal = " << target_ideal << endl; - ); - - // do the multivariate lifting of the translated one f_t - upolynomial::zp_numeral_manager zpe_nm(nm, p_e); - zp_manager zpe_pm(zpe_nm, &pm.mm()); - zp_manager zp_pm(zp_nm, &pm.mm()); - zp_factors factors_zpe(zpe_pm); - multivariate_hensel_lift(pm, zp_pm, zpe_pm, f_t, x, e, vars, upm, f_u_pp_zp, factors_u_zp, target_ideal, factors_zpe); - - TRACE("polynomial::factorization::multivariate", - tout << "factors_zpe = " << factors_zpe << endl; - ); - - // try the factors from the lifted combinations - factors f_t_factors(pm); - bool remove = false; - mfactorization_combination_iterator it(factors_zpe, x); - unsigned max_degre = pm.degree(f_t, x) / 2; - zp_polynomial_ref zpe_trial_factor(zpe_pm); - while (it.next(remove)) { - // - // our bound ensures we can extract the right factors of degree at most 1/2 of the original - // so, if out trial factor has degree bigger than 1/2, we need to take the rest of the factors - // but, if we take the rest and it works, it doesn't meen that the rest is factorized, so we still take out - // the original factor - // - bool using_left = it.current_degree() <= max_degre; - if (using_left) { - // do a quick check first - it.left(zpe_trial_factor); - } else { - // do a quick check first - it.right(zpe_trial_factor); - } - // add the lc(f_pp) to the trial divisor - zpe_trial_factor = zpe_pm.mul(f_t_lc, zpe_trial_factor); - polynomial_ref trial_factor(pm), trial_factor_quo(pm); - trial_factor = convert(zpe_pm, zpe_trial_factor, pm); - bool true_factor = true; - trial_factor_quo = pm.exact_div(f_t_with_lc, trial_factor); - // if division is precise we have a factor - if (true_factor) { - if (!using_left) { - // as noted above, we still use the original factor - trial_factor.swap(trial_factor_quo); - } - // We need to get the content out of the factor - upolynomial::scoped_numeral trial_factor_cont(nm); - pm.int_content(f_t, trial_factor_cont); - trial_factor = pm.exact_div(trial_factor, trial_factor_cont); - // add the factor - f_t_factors.push_back(trial_factor, 1); - // we continue with the int-primitive quotient (with the lc added back) - // but we also have to keep lc(f_t)*f_t - pm.int_content(trial_factor_quo, f_t_lc); // content - trial_factor_quo = pm.exact_div(trial_factor_quo, f_t_lc); - nm.set(f_t_lc, pm.numeral_lc(trial_factor_quo, x)); - f_t = pm.mul(f_t_lc, trial_factor_quo); - // but we also remove it from the iterator - remove = true; - } else { - // don't remove this combination - remove = false; - } - } - - // translate the factor back - for (unsigned i = 0; i < a.size(); ++ i) { - nm.neg(a[i]); - } - for (unsigned i = 0; i < f_t_factors.distinct_factors(); ++ i) { - polynomial_ref factor(pm); - pm.translate(f_t_factors[i], vars_no_x, a, factor); - f_factors.push_back(factor, 1); - } - - TRACE("polynomial::factorization", tout << "polynomial::factor_square_free_primitive(f = " << f << ") => " << f_factors << endl;); - return true; -} - -}; // end polynomial namespace - -#endif diff --git a/src/math/polynomial/polynomial_factorization.h b/src/math/polynomial/polynomial_factorization.h deleted file mode 100644 index f069121ba..000000000 --- a/src/math/polynomial/polynomial_factorization.h +++ /dev/null @@ -1,65 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - polynomial_factorization.h - -Abstract: - - Methods for factoring polynomials. - -Author: - - Dejan (t-dejanj) 2011-11-29 - -Notes: - - [1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal, - 46(8-10):1853-1859, 1967. - [2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third - edition, 1997. - [3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993. - ---*/ - -#pragma once - -#if 0 -// Disabled for reorg -#include "polynomial.h" -#include "upolynomial.h" -#include "bit_vector.h" -#include "z3_exception.h" - -namespace polynomial { - - /** - \brief Something to throw when we are in trouble. - */ - class factorization_exception : public default_exception { - public: - factorization_exception(char const * msg) : default_exception(msg) {} - }; - - /** - \brief Factor the polynomial f from Z[x1, ..., x_n]. Returns the index of the last factor that is completely - factored. I.e., if the method returns m, then f_1, ..., f_m are true irreducible factors, and the rest might - be further reducible. - */ - unsigned factor(polynomial_ref & f, factors & factors); - - /** - \brief Factor the square-free primitive polynomial f from Z[x1, ..., x_n]. Returns true if the factorization - was sucesseful, i.e. it was completed and the result is complete. Otherwise the quarantee is that the all but - the last factor are irreducible. - */ - bool factor_square_free_primitive(polynomial_ref const & f, factors & factors); -} - -inline std::ostream & operator<<(std::ostream & out, polynomial::factors & factors) { - factors.display(out); - return out; -} - -#endif diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 32f8e1ef1..587488fc9 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -575,7 +575,7 @@ namespace pdr { // Predicates that are variable representatives. Other predicates at // positions the variables occur are made equivalent with these. expr_ref_vector conj(m); - app_ref_vector& var_reprs = *(alloc(app_ref_vector, m)); + app_ref_vector var_reprs(m); ptr_vector aux_vars; unsigned ut_size = rule.get_uninterpreted_tail_size(); @@ -584,8 +584,9 @@ namespace pdr { init_atom(pts, rule.get_head(), var_reprs, conj, UINT_MAX); for (unsigned i = 0; i < ut_size; ++i) { if (rule.is_neg_tail(i)) { - dealloc(&var_reprs); - throw default_exception("PDR does not support negated predicates in rule tails"); + char const* msg = "PDR does not supported negated predicates in rule tails"; + IF_VERBOSE(0, verbose_stream() << msg << "\n";); + throw default_exception(msg); } init_atom(pts, rule.get_tail(i), var_reprs, conj, i); } @@ -600,14 +601,14 @@ namespace pdr { flatten_and(tail); for (unsigned i = 0; i < tail.size(); ++i) { expr_ref tmp(m); - var_subst(m, false)(tail[i].get(), var_reprs.size(), (expr*const*)var_reprs.c_ptr(), tmp); + var_subst vs(m, false); + vs(tail[i].get(), var_reprs.size(), (expr*const*)var_reprs.c_ptr(), tmp); conj.push_back(tmp); TRACE("pdr", tout << mk_pp(tail[i].get(), m) << "\n" << mk_pp(tmp, m) << "\n";); if (!is_ground(tmp)) { std::stringstream msg; msg << "PDR cannot solve non-ground tails: " << tmp; IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); - dealloc(&var_reprs); throw default_exception(msg.str()); } } @@ -631,7 +632,7 @@ namespace pdr { m_rule2transition.insert(&rule, fml.get()); rules.push_back(&rule); } - m_rule2inst.insert(&rule, &var_reprs); + m_rule2inst.insert(&rule, alloc(app_ref_vector, var_reprs)); m_rule2vars.insert(&rule, aux_vars); TRACE("pdr", tout << rule.get_decl()->get_name() << "\n"; @@ -1468,13 +1469,20 @@ namespace pdr { reset(); } - void context::reset() { - TRACE("pdr", tout << "\n";); - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + void context::reset(decl2rel& rels) { + decl2rel::iterator it = rels.begin(), end = rels.end(); for (; it != end; ++it) { dealloc(it->m_value); } - m_rels.reset(); + rels.reset(); + } + + void context::reset(bool full) { + TRACE("pdr", tout << "reset\n";); + reset(m_rels); + if (full) { + reset(m_rels_tmp); + } m_search.reset(); m_query = 0; m_last_result = l_undef; @@ -1496,6 +1504,7 @@ namespace pdr { e->get_data().m_value->add_rule(pred_rules[i]); } } + TRACE("pdr", tout << "adding rules\n";); datalog::rule_set::iterator rit = rules.begin(), rend = rules.end(); for (; rit != rend; ++rit) { datalog::rule* r = *rit; @@ -1510,6 +1519,7 @@ namespace pdr { } } // Initialize use list dependencies + TRACE("pdr", tout << "initialize use list dependencies\n";); decl2rel::iterator it = rels.begin(), end = rels.end(); for (; it != end; ++it) { func_decl* pred = it->m_key; @@ -1523,9 +1533,11 @@ namespace pdr { } } + TRACE("pdr", tout << "initialize predicate transformers\n";); // Initialize the predicate transformers. it = rels.begin(), end = rels.end(); for (; it != end; ++it) { + SASSERT(it->m_value); pred_transformer& rel = *it->m_value; rel.initialize(rels); TRACE("pdr", rel.display(tout); ); @@ -1533,21 +1545,24 @@ namespace pdr { } void context::update_rules(datalog::rule_set& rules) { - decl2rel rels; + TRACE("pdr", tout << "update rules\n";); + reset(m_rels_tmp); init_core_generalizers(rules); - init_rules(rules, rels); - decl2rel::iterator it = rels.begin(), end = rels.end(); + init_rules(rules, m_rels_tmp); + decl2rel::iterator it = m_rels_tmp.begin(), end = m_rels_tmp.end(); for (; it != end; ++it) { pred_transformer* pt = 0; if (m_rels.find(it->m_key, pt)) { it->m_value->inherit_properties(*pt); } } - reset(); - it = rels.begin(), end = rels.end(); + reset(false); + it = m_rels_tmp.begin(), end = m_rels_tmp.end(); for (; it != end; ++it) { m_rels.insert(it->m_key, it->m_value); } + m_rels_tmp.reset(); + TRACE("pdr", tout << "done update rules\n";); } unsigned context::get_num_levels(func_decl* p) { @@ -1875,6 +1890,7 @@ namespace pdr { } lbool context::solve() { + TRACE("pdr", tout << "solve\n";); m_last_result = l_undef; try { solve_impl(); @@ -2090,6 +2106,7 @@ namespace pdr { } case l_undef: { TRACE("pdr", tout << "unknown state: " << mk_pp(m_pm.mk_and(cube), m) << "\n";); + IF_VERBOSE(1, verbose_stream() << "unknown state\n";); throw unknown_exception(); } } diff --git a/src/muz/pdr/pdr_context.h b/src/muz/pdr/pdr_context.h index c3567bdd8..a32a65c48 100644 --- a/src/muz/pdr/pdr_context.h +++ b/src/muz/pdr/pdr_context.h @@ -328,6 +328,7 @@ namespace pdr { datalog::context* m_context; manager m_pm; decl2rel m_rels; // Map from relation predicate to fp-operator. + decl2rel m_rels_tmp; func_decl_ref m_query_pred; pred_transformer* m_query; mutable model_search m_search; @@ -370,6 +371,8 @@ namespace pdr { void reset_core_generalizers(); + void reset(decl2rel& rels); + void validate(); void validate_proof(); void validate_search(); @@ -410,8 +413,7 @@ namespace pdr { lbool solve(); - - void reset(); + void reset(bool full = true); void set_query(func_decl* q) { m_query_pred = q; } diff --git a/src/muz/pdr/pdr_dl_interface.cpp b/src/muz/pdr/pdr_dl_interface.cpp index 761b730ce..5f4a200fc 100644 --- a/src/muz/pdr/pdr_dl_interface.cpp +++ b/src/muz/pdr/pdr_dl_interface.cpp @@ -19,12 +19,8 @@ Revision History: #include "dl_context.h" #include "dl_mk_coi_filter.h" -#include "dl_mk_interp_tail_simplifier.h" -#include "dl_mk_subsumption_checker.h" -#include "dl_mk_rule_inliner.h" #include "dl_rule.h" #include "dl_rule_transformer.h" -#include "smt2parser.h" #include "pdr_context.h" #include "pdr_dl_interface.h" #include "dl_rule_set.h" @@ -164,7 +160,7 @@ lbool dl_interface::query(expr * query) { m_context->set_proof_converter(m_ctx.get_proof_converter()); m_context->set_model_converter(m_ctx.get_model_converter()); m_context->set_query(query_pred); - m_context->set_axioms(bg_assertion); + m_context->set_axioms(bg_assertion); m_context->update_rules(m_pdr_rules); if (m_pdr_rules.get_rules().empty()) { diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 54e7f351c..7abbd48ee 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -93,7 +93,7 @@ private: mss m_mss; expr_ref_vector m_trail; strategy_t m_st; - rational m_max_upper; + rational m_max_upper; model_ref m_csmodel; unsigned m_correction_set_size; bool m_found_feasible_optimum; @@ -109,6 +109,7 @@ private: bool m_pivot_on_cs; // prefer smaller correction set to core. bool m_dump_benchmarks; // display benchmarks (into wcnf format) + std::string m_trace_id; typedef ptr_vector exprs; @@ -150,9 +151,7 @@ public: return is_uninterp_const(l) || (m.is_not(l, l) && is_uninterp_const(l)); - } - - + } void add_soft(expr* e, rational const& w) { TRACE("opt", tout << mk_pp(e, m) << " |-> " << w << "\n";); @@ -290,7 +289,7 @@ public: index = next_index(asms, index); } first = false; - IF_VERBOSE(3, verbose_stream() << "weight: " << get_weight(asms[0].get()) << " " << get_weight(asms[index-1].get()) << " num soft: " << index << "\n";); + // IF_VERBOSE(3, verbose_stream() << "weight: " << get_weight(asms[0].get()) << " " << get_weight(asms[index-1].get()) << " num soft: " << index << "\n";); m_last_index = index; is_sat = check_sat(index, asms.c_ptr()); } @@ -302,17 +301,7 @@ public: } lbool check_sat(unsigned sz, expr* const* asms) { - if (m_st == s_primal_dual && m_c.sat_enabled()) { - rational max_weight = m_upper; - vector weights; - for (unsigned i = 0; i < sz; ++i) { - weights.push_back(get_weight(asms[i])); - } - return inc_sat_check_sat(s(), sz, asms, weights.c_ptr(), max_weight); - } - else { - return s().check_sat(sz, asms); - } + return s().check_sat(sz, asms); } void found_optimum() { @@ -500,7 +489,7 @@ public: TRACE("opt", display_vec(tout << "minimized core: ", core);); IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core);); max_resolve(core, w); - fml = mk_not(m, mk_and(m, m_B.size(), m_B.c_ptr())); + fml = mk_not(m, mk_and(m, core.size(), core.c_ptr())); s().assert_expr(fml); m_lower += w; if (m_st == s_primal_dual) { @@ -540,7 +529,10 @@ public: } lbool minimize_core(exprs& core) { - if (m_c.sat_enabled() || core.empty()) { + if (core.empty()) { + return l_true; + } + if (m_c.sat_enabled()) { return l_true; } m_mus.reset(); @@ -617,8 +609,8 @@ public: // Soundness of this rule can be established using MaxRes // for (unsigned i = 1; i < core.size(); ++i) { - expr* b_i = m_B[i-1].get(); - expr* b_i1 = m_B[i].get(); + expr* b_i = core[i-1]; + expr* b_i1 = core[i]; if (i == 1) { d = to_app(b_i); } @@ -668,8 +660,8 @@ public: // d_i => d_{i-1} or b_{i-1} // for (unsigned i = 1; i < cs.size(); ++i) { - expr* b_i = m_B[i-1].get(); - expr* b_i1 = m_B[i].get(); + expr* b_i = cs[i - 1]; + expr* b_i1 = cs[i]; cls = m.mk_or(b_i, d); if (i > 2) { d = mk_fresh_bool("d"); @@ -690,10 +682,11 @@ public: s().assert_expr(fml); m_defs.push_back(fml); new_assumption(asum, w); + fml = m.mk_and(b_i1, cls); update_model(asum, fml); } - fml = m.mk_or(m_B.size(), m_B.c_ptr()); + fml = m.mk_or(cs.size(), cs.c_ptr()); s().assert_expr(fml); } @@ -749,7 +742,7 @@ public: nsoft.push_back(mk_not(m, m_soft[i])); } fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); - s().assert_expr(fml); + s().assert_expr(fml); } bool is_true(model* mdl, expr* e) { @@ -767,10 +760,9 @@ public: } bool is_true(expr_ref_vector const& es) { - for (unsigned i = 0; i < es.size(); ++i) { - if (!is_true(es[i])) return false; - } - return true; + unsigned i = 0; + for (; i < es.size() && is_true(es[i]); ++i) { } + return i == es.size(); } void remove_soft(exprs const& core, expr_ref_vector& asms) { @@ -790,7 +782,6 @@ public: virtual void updt_params(params_ref& p) { maxsmt_solver_base::updt_params(p); opt_params _p(p); - m_hill_climb = _p.maxres_hill_climb(); m_add_upper_bound_block = _p.maxres_add_upper_bound_block(); m_max_num_cores = _p.maxres_max_num_cores(); @@ -868,7 +859,6 @@ public: IF_VERBOSE(0, verbose_stream() << "assignment is infeasible\n";); } } - }; opt::maxsmt_solver_base* opt::mk_maxres( diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 97b6a5293..f93291599 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -55,15 +55,18 @@ namespace opt { void maxsmt_solver_base::commit_assignment() { expr_ref tmp(m); - rational k(0); + rational k(0), cost(0); for (unsigned i = 0; i < m_soft.size(); ++i) { if (get_assignment(i)) { k += m_weights[i]; } + else { + cost += m_weights[i]; + } } pb_util pb(m); tmp = pb.mk_ge(m_weights.size(), m_weights.c_ptr(), m_soft.c_ptr(), k); - TRACE("opt", tout << tmp << "\n";); + TRACE("opt", tout << "cost: " << cost << "\n" << tmp << "\n";); s().assert_expr(tmp); } @@ -140,7 +143,9 @@ namespace opt { m_wth = s.ensure_wmax_theory(); } maxsmt_solver_base::scoped_ensure_theory::~scoped_ensure_theory() { - //m_wth->reset_local(); + if (m_wth) { + m_wth->reset_local(); + } } smt::theory_wmaxsat& maxsmt_solver_base::scoped_ensure_theory::operator()() { return *m_wth; } @@ -226,7 +231,9 @@ namespace opt { m_msolver = 0; symbol const& maxsat_engine = m_c.maxsat_engine(); IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); - TRACE("opt", tout << "maxsmt\n";); + TRACE("opt", tout << "maxsmt\n"; + s().display(tout); tout << "\n"; + ); if (m_soft_constraints.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 42129be70..351141a3f 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -327,12 +327,7 @@ namespace opt { SASSERT(idx < get_num_assertions()); return m_context.get_formulas()[idx]; } - - std::ostream& opt_solver::display(std::ostream & out) const { - m_context.display(out); - return out; - } - + smt::theory_var opt_solver::add_objective(app* term) { smt::theory_var v = get_optimizer().add_objective(term); m_objective_vars.push_back(v); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index cdaad3cf2..27168e2ca 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -104,7 +104,6 @@ namespace opt { virtual void set_progress_callback(progress_callback * callback); virtual unsigned get_num_assertions() const; virtual expr * get_assertion(unsigned idx) const; - virtual std::ostream& display(std::ostream & out) const; virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index 95b489394..32c144652 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -20,9 +20,49 @@ Notes: #include "smt_literal.h" #include "ast_pp.h" #include "th_rewriter.h" -#include "sat_sls.h" +#include "sat_types.h" namespace smt { + + class index_set { + + unsigned_vector m_elems; + unsigned_vector m_index; + public: + unsigned num_elems() const { return m_elems.size(); } + unsigned operator[](unsigned idx) const { return m_elems[idx]; } + void reset() { m_elems.reset(); m_index.reset(); } + bool empty() const { return m_elems.empty(); } + + bool contains(unsigned idx) const { + return + (idx < m_index.size()) && + (m_index[idx] < m_elems.size()) && + (m_elems[m_index[idx]] == idx); + } + + void insert(unsigned idx) { + m_index.reserve(idx+1); + if (!contains(idx)) { + m_index[idx] = m_elems.size(); + m_elems.push_back(idx); + } + } + + void remove(unsigned idx) { + if (!contains(idx)) return; + unsigned pos = m_index[idx]; + m_elems[pos] = m_elems.back(); + m_index[m_elems[pos]] = pos; + m_elems.pop_back(); + } + + unsigned choose(random_gen& rnd) const { + SASSERT(!empty()); + return m_elems[rnd(num_elems())]; + } + }; + struct pb_sls::imp { struct clause { @@ -73,8 +113,8 @@ namespace smt { expr_ref_vector m_trail; obj_map m_decl2var; // map declarations to Boolean variables. ptr_vector m_var2decl; // reverse map - sat::index_set m_hard_false; // list of hard clauses that are false. - sat::index_set m_soft_false; // list of soft clauses that are false. + index_set m_hard_false; // list of hard clauses that are false. + index_set m_soft_false; // list of soft clauses that are false. unsigned m_max_flips; // maximal number of flips unsigned m_non_greedy_percent; // percent of moves to do non-greedy style random_gen m_rng; diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 228e14cd6..9708bdc8f 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -62,20 +62,22 @@ namespace opt { } m_upper = m_lower; bool was_sat = false; - expr_ref_vector disj(m), asms(m); + expr_ref_vector asms(m); vector cores; + obj_map::iterator it = soft.begin(), end = soft.end(); for (; it != end; ++it) { expr* c = assert_weighted(wth(), it->m_key, it->m_value); if (!is_true(it->m_key)) { - disj.push_back(m.mk_not(c)); m_upper += it->m_value; } } wth().init_min_cost(m_upper - m_lower); - s().assert_expr(mk_or(disj)); trace_bounds("wmax"); + TRACE("opt", + s().display(tout); tout << "\n"; + tout << "lower: " << m_lower << " upper: " << m_upper << "\n";); while (!m.canceled() && m_lower < m_upper) { //mk_assumptions(asms); //is_sat = s().preferred_sat(asms, cores); @@ -84,6 +86,7 @@ namespace opt { is_sat = l_undef; } if (is_sat == l_false) { + TRACE("opt", tout << "Unsat\n";); break; } if (is_sat == l_true) { diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index bb0c5bfb9..d2b55af1d 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -109,7 +109,6 @@ namespace smt2 { typedef std::pair named_expr; named_expr m_last_named_expr; - ast_manager & m() const { return m_ctx.m(); } pdecl_manager & pm() const { return m_ctx.pm(); } sexpr_manager & sm() const { return m_ctx.sm(); } @@ -117,7 +116,7 @@ namespace smt2 { bool m_ignore_user_patterns; bool m_ignore_bad_patterns; bool m_display_error_for_vs; - + bool ignore_user_patterns() const { return m_ignore_user_patterns; } bool ignore_bad_patterns() const { return m_ignore_bad_patterns; } bool use_vs_format() const { return m_display_error_for_vs; } @@ -129,7 +128,7 @@ namespace smt2 { m_decl(d), m_spos(spos) { } }; - + typedef psort_frame sort_frame; enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN }; @@ -138,17 +137,17 @@ namespace smt2 { expr_frame_kind m_kind; expr_frame(expr_frame_kind k):m_kind(k) {} }; - + struct app_frame : public expr_frame { symbol m_f; unsigned m_expr_spos; unsigned m_param_spos; bool m_as_sort; app_frame(symbol const & f, unsigned expr_spos, unsigned param_spos, bool as_sort): - expr_frame(EF_APP), - m_f(f), - m_expr_spos(expr_spos), - m_param_spos(param_spos), + expr_frame(EF_APP), + m_f(f), + m_expr_spos(expr_spos), + m_param_spos(param_spos), m_as_sort(as_sort) {} }; @@ -163,8 +162,8 @@ namespace smt2 { unsigned m_sort_spos; unsigned m_expr_spos; quant_frame(bool forall, unsigned pat_spos, unsigned nopat_spos, unsigned sym_spos, unsigned sort_spos, unsigned expr_spos): - expr_frame(EF_QUANT), m_forall(forall), m_weight(1), - m_pat_spos(pat_spos), m_nopat_spos(nopat_spos), + expr_frame(EF_QUANT), m_forall(forall), m_weight(1), + m_pat_spos(pat_spos), m_nopat_spos(nopat_spos), m_sym_spos(sym_spos), m_sort_spos(sort_spos), m_expr_spos(expr_spos) {} }; @@ -175,7 +174,7 @@ namespace smt2 { unsigned m_expr_spos; let_frame(unsigned sym_spos, unsigned expr_spos):expr_frame(EF_LET), m_in_decls(true), m_sym_spos(sym_spos), m_expr_spos(expr_spos) {} }; - + struct let_decl_frame : public expr_frame { let_decl_frame():expr_frame(EF_LET_DECL) {} }; @@ -186,9 +185,9 @@ namespace smt2 { unsigned m_expr_spos; symbol m_last_symbol; attr_expr_frame(expr_frame * prev, unsigned sym_spos, unsigned expr_spos): - expr_frame(EF_ATTR_EXPR), - m_prev(prev), - m_sym_spos(sym_spos), + expr_frame(EF_ATTR_EXPR), + m_prev(prev), + m_sym_spos(sym_spos), m_expr_spos(expr_spos) {} }; @@ -228,12 +227,12 @@ namespace smt2 { m_expr_stack = alloc(expr_ref_vector, m()); return *(m_expr_stack.get()); } - + template static unsigned size(scoped_ptr & v) { return v.get() == 0 ? 0 : v->size(); } - + template static void shrink(scoped_ptr & v, unsigned old_sz) { if (v.get() == 0) { @@ -255,7 +254,7 @@ namespace smt2 { m_nopattern_stack = alloc(expr_ref_vector, m()); return *(m_nopattern_stack.get()); } - + svector & symbol_stack() { return m_symbol_stack; } @@ -328,7 +327,7 @@ namespace smt2 { bool sync_after_error() { while (true) { try { - while (curr_is_rparen()) + while (curr_is_rparen()) next(); if (m_num_open_paren < 0) m_num_open_paren = 0; @@ -337,7 +336,7 @@ namespace smt2 { SASSERT(m_num_open_paren >= 0); while (m_num_open_paren > 0 || !curr_is_lparen()) { TRACE("sync", tout << "sync(): curr: " << curr() << "\n"; - tout << "m_num_open_paren: " << m_num_open_paren << ", line: " << m_scanner.get_line() << ", pos: " + tout << "m_num_open_paren: " << m_num_open_paren << ", line: " << m_scanner.get_line() << ", pos: " << m_scanner.get_pos() << "\n";); if (curr() == scanner::EOF_TOKEN) { return false; @@ -365,7 +364,7 @@ namespace smt2 { } throw parser_exception(msg); } - + symbol const & curr_id() const { return m_scanner.get_id(); } rational curr_numeral() const { return m_scanner.get_number(); } @@ -402,15 +401,20 @@ namespace smt2 { void check_int_or_float(char const * msg) { if (!curr_is_int() && !curr_is_float()) throw parser_exception(msg); } void check_float(char const * msg) { if (!curr_is_float()) throw parser_exception(msg); } + char const * m_current_file; + void set_current_file(char const * s) { m_current_file = s; } + void error(unsigned line, unsigned pos, char const * msg) { m_ctx.set_cancel(false); if (use_vs_format()) { m_ctx.diagnostic_stream() << "Z3(" << line << ", " << pos << "): ERROR: " << msg; if (msg[strlen(msg)-1] != '\n') - m_ctx.diagnostic_stream() << std::endl; + m_ctx.diagnostic_stream() << std::endl; } else { - m_ctx.regular_stream() << "(error \"line " << line << " column " << pos << ": " << escaped(msg, true) << "\")" << std::endl; + m_ctx.regular_stream() << "(error \""; + if (m_current_file) m_ctx.regular_stream() << m_current_file << ": "; + m_ctx.regular_stream()<< "line " << line << " column " << pos << ": " << escaped(msg, true) << "\")" << std::endl; } if (m_ctx.exit_on_error()) { exit(1); @@ -431,7 +435,7 @@ namespace smt2 { m_ctx.regular_stream() << "(error : " << escaped(msg, true) << "\")" << std::endl; } } - + void unknown_sort(symbol id, char const* context = "") { std::string msg = context; if (context[0]) msg += ": "; @@ -444,10 +448,10 @@ namespace smt2 { unsigned num_parens = 0; do { switch (curr()) { - case scanner::LEFT_PAREN: - num_parens++; + case scanner::LEFT_PAREN: + num_parens++; break; - case scanner::RIGHT_PAREN: + case scanner::RIGHT_PAREN: if (num_parens == 0) throw parser_exception("invalid s-expression, unexpected ')'"); num_parens--; @@ -565,7 +569,7 @@ namespace smt2 { else { if (ignore_unknow_sort) return 0; - unknown_sort(id); + unknown_sort(id); UNREACHABLE(); return 0; } @@ -579,7 +583,7 @@ namespace smt2 { check_identifier("invalid indexed sort, symbol expected"); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - if (d == 0) + if (d == 0) unknown_sort(id); next(); sbuffer args; @@ -604,13 +608,13 @@ namespace smt2 { SASSERT(curr_is_identifier()); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - if (d == 0) + if (d == 0) unknown_sort(id); next(); void * mem = m_stack.allocate(sizeof(psort_frame)); new (mem) psort_frame(*this, d, psort_stack().size()); } - + void pop_psort_app_frame() { SASSERT(curr_is_rparen()); psort_frame * fr = static_cast(m_stack.top()); @@ -647,7 +651,7 @@ namespace smt2 { else { check_lparen_next("invalid sort, symbol, '_' or '(' expected"); if (!curr_is_identifier()) - throw parser_exception("invalid sort, symbol or '_' expected"); + throw parser_exception("invalid sort, symbol or '_' expected"); if (curr_id_is_underscore()) { psort_stack().push_back(pm().mk_psort_cnst(parse_indexed_sort())); } @@ -665,13 +669,13 @@ namespace smt2 { SASSERT(curr_is_identifier()); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - if (d == 0) + if (d == 0) unknown_sort(id); next(); void * mem = m_stack.allocate(sizeof(sort_frame)); new (mem) sort_frame(*this, d, sort_stack().size()); } - + void pop_sort_app_frame() { SASSERT(curr_is_rparen()); sort_frame * fr = static_cast(m_stack.top()); @@ -710,8 +714,8 @@ namespace smt2 { } else { check_lparen_next("invalid sort, symbol, '_' or '(' expected"); - if (!curr_is_identifier()) - throw parser_exception(std::string(context) + " invalid sort, symbol or '_' expected"); + if (!curr_is_identifier()) + throw parser_exception(std::string(context) + " invalid sort, symbol or '_' expected"); if (curr_id_is_underscore()) { sort_stack().push_back(parse_indexed_sort()); } @@ -726,7 +730,7 @@ namespace smt2 { } unsigned parse_sorts(char const* context) { - unsigned sz = 0; + unsigned sz = 0; check_lparen_next(context); while (!curr_is_rparen()) { parse_sort(context); @@ -949,7 +953,7 @@ namespace smt2 { } // parse expression state - enum pe_state { + enum pe_state { PES_EXPR, // expecting PES_DECL, // expecting ( ) PES_PATTERN, @@ -1015,7 +1019,7 @@ namespace smt2 { else { // just consume pattern next(); - consume_sexpr(); + consume_sexpr(); } } else if (id == m_nopattern) { @@ -1036,7 +1040,7 @@ namespace smt2 { str << "unknown attribute " << id; warning_msg("%s", str.str().c_str()); next(); - // just consume the + // just consume the consume_sexpr(); } if (curr_is_rparen()) @@ -1051,13 +1055,13 @@ namespace smt2 { switch (fr->m_kind) { case EF_LET: return static_cast(fr)->m_in_decls ? PES_DECL : PES_EXPR; - case EF_ATTR_EXPR: + case EF_ATTR_EXPR: return consume_attributes(static_cast(fr)); default: return PES_EXPR; } } - + void parse_numeral(bool is_int) { SASSERT(!is_int || curr_is_int()); SASSERT(is_int || curr_is_float()); @@ -1095,7 +1099,7 @@ namespace smt2 { expr_stack().push_back(0); // empty pattern return; } - + if (curr_is_lparen()) { // multi-pattern void * mem = m_stack.allocate(sizeof(pattern_frame)); @@ -1185,9 +1189,9 @@ namespace smt2 { SASSERT(curr_id_is_forall() || curr_id_is_exists()); SASSERT(!is_forall || curr_id_is_forall()); SASSERT(is_forall || curr_id_is_exists()); - next(); + next(); void * mem = m_stack.allocate(sizeof(quant_frame)); - new (mem) quant_frame(is_forall, pattern_stack().size(), nopattern_stack().size(), symbol_stack().size(), + new (mem) quant_frame(is_forall, pattern_stack().size(), nopattern_stack().size(), symbol_stack().size(), sort_stack().size(), expr_stack().size()); m_num_expr_frames++; unsigned num_vars = parse_sorted_vars(); @@ -1229,11 +1233,11 @@ namespace smt2 { next(); return r; } - check_lparen_next("invalid (indexed) identifier, '(_' or symbol expected"); + check_lparen_next("invalid (indexed) identifier, '(_' or symbol expected"); return parse_indexed_identifier_core(); } - // parse: + // parse: // 'as' ')' // '_' + ')' // 'as' (|)+ ')' ')' @@ -1255,7 +1259,7 @@ namespace smt2 { } } - // parse: + // parse: // // '(' 'as' ')' // '(' '_' + ')' @@ -1281,8 +1285,8 @@ namespace smt2 { throw parser_exception(msg.c_str()); } - rational m_last_bv_numeral; // for bv, bvbin, bvhex - + rational m_last_bv_numeral; // for bv, bvbin, bvhex + // return true if *s == [0-9]+ bool is_bv_decimal(char const * s) { TRACE("is_bv_num", tout << "is_bv_decimal: " << s << "\n";); @@ -1321,7 +1325,7 @@ namespace smt2 { return false; return true; } - + // return true if *s == hex[0-9,a-f,A-F]+ bool is_bv_hex(char const * s) { SASSERT(*s == 'h'); @@ -1329,7 +1333,7 @@ namespace smt2 { if (*s != 'e') return false; ++s; if (*s != 'x') return false; - ++s; + ++s; rational & n = m_last_bv_numeral; unsigned i = 0; n = rational(0); @@ -1340,7 +1344,7 @@ namespace smt2 { } else if ('a' <= *s && *s <= 'f') { n *= rational(16); - n += rational(10 + (*s - 'a')); + n += rational(10 + (*s - 'a')); } else if ('A' <= *s && *s <= 'F') { n *= rational(16); @@ -1357,11 +1361,11 @@ namespace smt2 { } } - // Return true if + // Return true if // n == bv[0-9]+ OR // n == bvhex[0-9,a-f,A-F]+ OR - // n == bvbin[0-1]+ - // It store the bit-vector value in m_last_bv_numeral + // n == bvbin[0-1]+ + // It store the bit-vector value in m_last_bv_numeral bool is_bv_num(symbol const & n) { char const * s = n.bare_str(); if (*s != 'b') return false; @@ -1405,7 +1409,7 @@ namespace smt2 { } next(); } - + // if has_as == true, then the sort of t must be equal to sort_stack().pop_back() // if that is the case, pop the top of sort_stack() void check_qualifier(expr * t, bool has_as) { @@ -1543,7 +1547,7 @@ namespace smt2 { unsigned num_args = expr_stack().size() - fr->m_expr_spos; unsigned num_indices = m_param_stack.size() - fr->m_param_spos; expr_ref t_ref(m()); - m_ctx.mk_app(fr->m_f, + m_ctx.mk_app(fr->m_f, num_args, expr_stack().c_ptr() + fr->m_expr_spos, num_indices, @@ -1627,7 +1631,7 @@ namespace smt2 { fr->m_qid = symbol(m_scanner.get_line()); if (!m().is_bool(expr_stack().back())) throw parser_exception("quantifier body must be a Boolean expression"); - quantifier * new_q = m().mk_quantifier(fr->m_forall, + quantifier * new_q = m().mk_quantifier(fr->m_forall, num_decls, sort_stack().c_ptr() + fr->m_sort_spos, symbol_stack().c_ptr() + fr->m_sym_spos, @@ -1688,7 +1692,7 @@ namespace smt2 { case EF_APP: pop_app_frame(static_cast(fr)); break; - case EF_LET: + case EF_LET: pop_let_frame(static_cast(fr)); break; case EF_LET_DECL: @@ -1714,7 +1718,7 @@ namespace smt2 { void parse_expr() { m_num_expr_frames = 0; do { - TRACE("parse_expr", tout << "curr(): " << curr() << ", m_num_expr_frames: " << m_num_expr_frames + TRACE("parse_expr", tout << "curr(): " << curr() << ", m_num_expr_frames: " << m_num_expr_frames << ", expr_stack().size(): " << expr_stack().size() << "\n";); if (curr_is_rparen()) { if (m_num_expr_frames == 0) @@ -1798,7 +1802,7 @@ namespace smt2 { SASSERT(curr_is_identifier()); SASSERT(curr_id() == m_declare_sort); next(); - + check_identifier("invalid sort declaration, symbol expected"); symbol id = curr_id(); if (m_ctx.find_psort_decl(id) != 0) @@ -1812,7 +1816,7 @@ namespace smt2 { check_int("invalid sort declaration, arity () or ')' expected"); rational n = curr_numeral(); if (!n.is_unsigned()) - throw parser_exception("invalid sort declaration, arity is too big to fit in an unsigned machine integer"); + throw parser_exception("invalid sort declaration, arity is too big to fit in an unsigned machine integer"); psort_decl * decl = pm().mk_psort_user_decl(n.get_unsigned(), id, 0); m_ctx.insert(decl); next(); @@ -1872,12 +1876,12 @@ namespace smt2 { } void parse_define_fun_rec() { - // ( define-fun-rec hfun_defi ) + // ( define-fun-rec hfun_defi ) SASSERT(curr_is_identifier()); SASSERT(curr_id() == m_define_fun_rec); SASSERT(m_num_bindings == 0); next(); - + expr_ref_vector binding(m()); svector ids; func_decl_ref f(m()); @@ -1890,7 +1894,7 @@ namespace smt2 { } void parse_define_funs_rec() { - // ( define-funs-rec ( hfun_decin+1 ) ( htermin+1 ) ) + // ( define-funs-rec ( hfun_decin+1 ) ( htermin+1 ) ) SASSERT(curr_is_identifier()); SASSERT(curr_id() == m_define_funs_rec); SASSERT(m_num_bindings == 0); @@ -1920,14 +1924,14 @@ namespace smt2 { check_lparen("invalid recursive function definition, '(' expected"); next(); - + parse_rec_fun_decl(f, binding, id); decls.push_back(f); bindings.push_back(binding); ids.push_back(id); check_rparen("invalid recursive function definition, ')' expected"); - next(); + next(); } next(); } @@ -1950,7 +1954,7 @@ namespace smt2 { sort_stack().shrink(sort_spos); expr_stack().shrink(expr_spos); m_env.end_scope(); - m_num_bindings = 0; + m_num_bindings = 0; } void parse_rec_fun_bodies(func_decl_ref_vector const& decls, vector const& bindings, vector >const & ids) { @@ -1963,10 +1967,10 @@ namespace smt2 { } if (i != decls.size()) { - throw parser_exception("the number of declarations does not match number of supplied definitions"); + throw parser_exception("the number of declarations does not match number of supplied definitions"); } check_rparen("invalid recursive function definition, ')' expected"); - next(); + next(); } void parse_rec_fun_body(func_decl* f, expr_ref_vector const& bindings, svector const& ids) { @@ -1980,19 +1984,19 @@ namespace smt2 { for (unsigned i = 0; i < num_vars; ++i) { m_env.insert(ids[i], local(bindings[i], num_vars)); } - parse_expr(); + parse_expr(); body = expr_stack().back(); expr_stack().pop_back(); symbol_stack().shrink(sym_spos); m_env.end_scope(); - m_num_bindings = 0; + m_num_bindings = 0; if (m().get_sort(body) != f->get_range()) { std::ostringstream buffer; buffer << "invalid function definition, sort mismatch. Expcected " - << mk_pp(f->get_range(), m()) << " but function body has sort " + << mk_pp(f->get_range(), m()) << " but function body has sort " << mk_pp(m().get_sort(body), m()); throw parser_exception(buffer.str().c_str()); - } + } m_ctx.insert_rec_fun(f, bindings, ids, body); } @@ -2185,7 +2189,7 @@ namespace smt2 { unsigned spos = expr_stack().size(); check_lparen_next("invalid check-sat-assuming command, '(', expected"); parse_assumptions(); - check_rparen_next("invalid check-sat-assuming command, ')', expected"); + check_rparen_next("invalid check-sat-assuming command, ')', expected"); m_ctx.check_sat(expr_stack().size() - spos, expr_stack().c_ptr() + spos); next(); expr_stack().shrink(spos); @@ -2201,7 +2205,7 @@ namespace smt2 { m_scanner.start_caching(); m_cache_end = 0; m_cached_strings.resize(0); - + check_lparen_next("invalid get-value command, '(' expected"); while (!curr_is_rparen()) { parse_expr(); @@ -2241,7 +2245,7 @@ namespace smt2 { SASSERT(curr_id() == m_reset); next(); check_rparen("invalid reset command, ')' expected"); - m_ctx.reset(); + m_ctx.reset(); reset(); m_ctx.print_success(); next(); @@ -2323,7 +2327,7 @@ namespace smt2 { } next(); } - + void parse_next_cmd_arg() { SASSERT(m_curr_cmd != 0); cmd_arg_kind k = m_curr_cmd->next_arg_kind(m_ctx); @@ -2332,7 +2336,7 @@ namespace smt2 { check_int("invalid command argument, unsigned integer expected"); rational n = curr_numeral(); if (!n.is_unsigned()) - throw parser_exception("invalid command argument, numeral is too big to fit in an unsigned machine integer"); + throw parser_exception("invalid command argument, numeral is too big to fit in an unsigned machine integer"); m_curr_cmd->set_next_arg(m_ctx, n.get_unsigned()); next(); break; @@ -2445,7 +2449,7 @@ namespace smt2 { m_curr_cmd = m_ctx.find_cmd(s); if (m_curr_cmd == 0) { parse_unknown_cmd(); - return; + return; } next(); unsigned arity = m_curr_cmd->get_arity(); @@ -2475,14 +2479,14 @@ namespace smt2 { return; } else { - if (arity != VAR_ARITY && i == arity) + if (arity != VAR_ARITY && i == arity) throw parser_exception("invalid command, too many arguments"); parse_next_cmd_arg(); } i++; } } - + void parse_cmd() { SASSERT(curr_is_lparen()); int line = m_scanner.get_line(); @@ -2531,7 +2535,7 @@ namespace smt2 { return; } if (s == m_declare_datatypes) { - parse_declare_datatypes(); + parse_declare_datatypes(); return; } if (s == m_get_value) { @@ -2558,8 +2562,8 @@ namespace smt2 { } public: - parser(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & p): - m_ctx(ctx), + parser(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & p, char const * filename=0): + m_ctx(ctx), m_params(p), m_scanner(ctx, is, interactive), m_curr(scanner::NULL_TOKEN), @@ -2597,14 +2601,15 @@ namespace smt2 { m_check_sat_assuming("check-sat-assuming"), m_define_fun_rec("define-fun-rec"), m_define_funs_rec("define-funs-rec"), - m_underscore("_"), - m_num_open_paren(0) { + m_underscore("_"), + m_num_open_paren(0), + m_current_file(filename) { // the following assertion does not hold if ctx was already attached to an AST manager before the parser object is created. // SASSERT(!m_ctx.has_manager()); - + updt_params(); } - + ~parser() { reset_stack(); } @@ -2615,7 +2620,7 @@ namespace smt2 { m_ignore_bad_patterns = p.ignore_bad_patterns(); m_display_error_for_vs = p.error_for_visual_studio(); } - + void reset() { reset_stack(); m_num_bindings = 0; @@ -2630,7 +2635,7 @@ namespace smt2 { m_env .reset(); m_sort_id2param_idx .reset(); m_dt_name2idx .reset(); - + m_bv_util = 0; m_arith_util = 0; m_seq_util = 0; @@ -2680,9 +2685,9 @@ namespace smt2 { return !found_errors; } catch (parser_exception & ex) { - if (ex.has_pos()) + if (ex.has_pos()) error(ex.line(), ex.pos(), ex.msg()); - else + else error(ex.msg()); } catch (ast_exception & ex) { @@ -2705,8 +2710,8 @@ namespace smt2 { }; }; -bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps) { - smt2::parser p(ctx, is, interactive, ps); +bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps, char const * filename) { + smt2::parser p(ctx, is, interactive, ps, filename); return p(); } diff --git a/src/parsers/smt2/smt2parser.h b/src/parsers/smt2/smt2parser.h index 5b4384917..77fd41d5d 100644 --- a/src/parsers/smt2/smt2parser.h +++ b/src/parsers/smt2/smt2parser.h @@ -21,6 +21,6 @@ Revision History: #include"cmd_context.h" -bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive = false, params_ref const & p = params_ref()); +bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive = false, params_ref const & p = params_ref(), char const * filename = 0); #endif diff --git a/src/sat/sat_bceq.cpp b/src/sat/sat_bceq.cpp deleted file mode 100644 index fa0309327..000000000 --- a/src/sat/sat_bceq.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - sat_bceq.cpp - -Abstract: - - Find equivalent literals based on blocked clause decomposition. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-09-27. - - -Revision History: - ---*/ -#include"sat_bceq.h" -#include"sat_solver.h" -#include"trace.h" -#include"bit_vector.h" -#include"map.h" -#include"sat_elim_eqs.h" - -namespace sat { - - void bceq::use_list::init(unsigned num_vars) { - m_clauses.reset(); - m_clauses.resize(2*num_vars); - } - - void bceq::use_list::insert(clause& c) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - m_clauses[c[i].index()].push_back(&c); - } - } - - void bceq::use_list::erase(clause& c) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - m_clauses[c[i].index()].erase(&c); - } - } - - ptr_vector& bceq::use_list::get(literal lit) { - return m_clauses[lit.index()]; - } - - bceq::bceq(solver & s): - m_solver(s) { - } - - void bceq::register_clause(clause* cls) { - m_clauses.setx(cls->id(), cls, 0); - } - - void bceq::unregister_clause(clause* cls) { - m_clauses.setx(cls->id(), 0, 0); - } - - void bceq::init() { - m_clauses.reset(); - m_bin_clauses.reset(); - m_L.reset(); - m_R.reset(); - m_L_blits.reset(); - m_R_blits.reset(); - m_bce_use_list.reset(); - clause * const* it = m_solver.begin_clauses(); - clause * const* end = m_solver.end_clauses(); - for (; it != end; ++it) { - clause* cls = *it; - if (!cls->was_removed()) { - m_use_list->insert(*cls); - register_clause(cls); - } - } - bin_clauses bc; - m_solver.collect_bin_clauses(bc, false); // exclude roots. - literal lits[2]; - for (unsigned i = 0; i < bc.size(); ++i) { - lits[0] = bc[i].first; - lits[1] = bc[i].second; - clause* cls = m_solver.m_cls_allocator.mk_clause(2, lits, false); - m_use_list->insert(*cls); - m_bin_clauses.push_back(cls); - register_clause(cls); - } - TRACE("sat", - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause const* cls = m_clauses[i]; - if (cls) tout << *cls << "\n"; - }); - } - - void bceq::pure_decompose() { - // while F != empty - // pick a clause and variable x in clause. - // get use list U1 of x and U2 of ~x - // assume |U1| >= |U2| - // add U1 to clause set. - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause* cls = m_clauses[i]; - if (cls) { - SASSERT(i == cls->id()); - pure_decompose((*cls)[0]); - SASSERT(!m_clauses[i]); - } - } - m_L.reverse(); - m_L_blits.reverse(); - } - - void bceq::pure_decompose(literal lit) { - clause_use_list& pos = m_use_list->get(lit); - clause_use_list& neg = m_use_list->get(~lit); - unsigned sz1 = m_L.size(); - unsigned sz2 = m_R.size(); - pure_decompose(pos, m_L); - pure_decompose(neg, m_R); - unsigned delta1 = m_L.size() - sz1; - unsigned delta2 = m_R.size() - sz2; - if (delta1 < delta2) { - m_L_blits.resize(sz1+delta2, ~lit); - m_R_blits.resize(sz2+delta1, lit); - for (unsigned i = 0; i < delta1; ++i) { - std::swap(m_L[sz1 + i], m_R[sz2 + i]); - } - for (unsigned i = delta1; i < delta2; ++i) { - m_L.push_back(m_R[sz2 + i]); - } - m_R.resize(sz2 + delta1); - std::swap(delta1, delta2); - } - else { - m_L_blits.resize(sz1+delta1, lit); - m_R_blits.resize(sz2+delta2, ~lit); - } - TRACE("bceq", tout << lit << " " << "pos: " << delta1 << " " << "neg: " << delta2 << "\n";); - } - - void bceq::pure_decompose(clause_use_list& uses, svector& clauses) { - unsigned sz = uses.size(); - for (unsigned i = 0; i < sz; ++i) { - clause& cls = *uses[i]; - if (!cls.was_removed() && m_clauses[cls.id()]) { - clauses.push_back(&cls); - m_clauses[cls.id()] = 0; - } - } - } - - void bceq::post_decompose() { - m_marked.reset(); - m_marked.resize(2*m_solver.num_vars(), false); - use_list ul; - use_list* save = m_use_list; - m_use_list = &ul; - ul.init(m_solver.num_vars()); - for (unsigned i = 0; i < m_L.size(); ++i) { - ul.insert(*m_L[i]); - } - - // cheap pass: add clauses from R in order - // such that they are blocked with respect to - // predecessors. - m_removed.reset(); - for (unsigned i = 0; i < m_R.size(); ++i) { - literal lit = find_blocked(*m_R[i]); - if (lit != null_literal) { - m_L.push_back(m_R[i]); - m_L_blits.push_back(lit); - ul.insert(*m_R[i]); - m_R[i] = m_R.back(); - m_R_blits[i] = m_R_blits.back(); - m_R.pop_back(); - m_R_blits.pop_back(); - --i; - } - } - // expensive pass: add clauses from R as long - // as BCE produces the empty set of clauses. - m_bce_use_list.init(m_solver.num_vars()); - for (unsigned i = 0; i < m_L.size(); ++i) { - m_bce_use_list.insert(*m_L[i]); - } - for (unsigned i = 0; i < m_R.size(); ++i) { - if (bce(*m_R[i])) { - m_R[i] = m_R.back(); - m_R_blits[i] = m_R_blits.back(); - m_R.pop_back(); - m_R_blits.pop_back(); - --i; - } - } - m_use_list = save; - } - - - // Note: replay blocked clause elimination: - // Suppose C u { c1 } is blocked. - // annotate each clause by blocking literal. - // for new clause c2, check if C u { c2 } is blocked. - // For each c in C record which literal it is blocked. - // (Order the clauses in C by block ordering) - // l | c is blocked, - // -> c2 contains ~l => check if c c2 is blocked - // - bool bceq::bce(clause& cls0) { - IF_VERBOSE(1, verbose_stream() << "bce " << m_L.size() << " " << m_R.size() << " " << cls0 << "\n";); - unsigned_vector& live_clauses = m_live_clauses; - live_clauses.reset(); - m_use_list = &m_bce_use_list; - m_bce_use_list.insert(cls0); - svector& clauses = m_L; - literal_vector& blits = m_L_blits; - clauses.push_back(&cls0); - blits.push_back(null_literal); - bool removed = false; - m_removed.reset(); - for (unsigned i = 0; i < clauses.size(); ++i) { - clause& cls1 = *clauses[i]; - literal lit = find_blocked(cls1); - if (lit == null_literal) { - live_clauses.push_back(i); - } - else { - m_removed.setx(cls1.id(), true, false); - removed = true; - } - } - while (removed) { - removed = false; - //std::cout << live_clauses.size() << " "; - for (unsigned i = 0; i < live_clauses.size(); ++i) { - clause& cls1 = *clauses[live_clauses[i]]; - literal lit = find_blocked(cls1); - if (lit != null_literal) { - m_removed.setx(cls1.id(), true, false); - removed = true; - live_clauses[i] = live_clauses.back(); - live_clauses.pop_back(); - --i; - } - } - } - //std::cout << "\n"; - m_bce_use_list.erase(cls0); - clauses.pop_back(); - blits.pop_back(); - return live_clauses.empty(); - } - - literal bceq::find_blocked(clause const& cls) { - TRACE("bceq", tout << cls << "\n";); - - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; ++i) { - m_marked[(~cls[i]).index()] = true; - } - literal result = null_literal; - for (unsigned i = 0; i < sz; ++i) { - literal lit = cls[i]; - if (is_blocked(lit)) { - TRACE("bceq", tout << "is blocked " << lit << " : " << cls << "\n";); - result = lit; - break; - } - } - for (unsigned i = 0; i < sz; ++i) { - m_marked[(~cls[i]).index()] = false; - } - return result; - } - - bool bceq::is_blocked(literal lit) const { - clause_use_list& uses = m_use_list->get(~lit); - unsigned sz = uses.size(); - for (unsigned i = 0; i < sz; ++i) { - clause const& cls = *uses[i]; - unsigned sz = cls.size(); - bool is_axiom = m_removed.get(cls.id(), false); - for (unsigned i = 0; !is_axiom && i < sz; ++i) { - is_axiom = m_marked[cls[i].index()] && cls[i] != ~lit; - } - - TRACE("bceq", tout << "resolvent " << lit << " : " << cls << " " << (is_axiom?"axiom":"non-axiom") << "\n";); - if (!is_axiom) { - return false; - } - } - return true; - } - - - void bceq::init_rbits() { - m_rbits.reset(); - for (unsigned i = 0; i < m_solver.num_vars(); ++i) { - uint64 lo = m_rand() + (m_rand() << 16); - uint64 hi = m_rand() + (m_rand() << 16); - m_rbits.push_back(lo + (hi << 32ULL)); - } - } - - void bceq::init_reconstruction_stack() { - m_rstack.reset(); - m_bstack.reset(); - // decomposition already creates a blocked stack in the proper order. - m_rstack.append(m_L); - m_bstack.append(m_L_blits); - } - - uint64 bceq::eval_clause(clause const& cls) const { - uint64 b = 0; - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; ++i) { - literal lit = cls[i]; - uint64 val = m_rbits[lit.var()]; - if (lit.sign()) { - val = ~val; - } - b |= val; - } - return b; - } - - void bceq::sat_sweep() { - init_rbits(); - init_reconstruction_stack(); - for (unsigned i = 0; i < m_rstack.size(); ++i) { - clause const& cls = *m_rstack[i]; - literal block_lit = m_bstack[i]; - uint64 b = eval_clause(cls); - // v = 0, b = 0 -> v := 1 - // v = 0, b = 1 -> v := 0 - // v = 1, b = 0 -> v := 0 - // v = 1, b = 1 -> v := 1 - m_rbits[block_lit.var()] ^= ~b; - - } - DEBUG_CODE(verify_sweep();); - } - - void bceq::verify_sweep() { - DEBUG_CODE( - for (unsigned i = 0; i < m_L.size(); ++i) { - uint64 b = eval_clause(*m_L[i]); - SASSERT((~b) == 0); - }); - } - - struct u64_hash { unsigned operator()(uint64 u) const { return (unsigned)u; } }; - - struct u64_eq { bool operator()(uint64 u1, uint64 u2) const { return u1 == u2; } }; - - void bceq::extract_partition() { - unsigned num_vars = m_solver.num_vars(); - map table; - union_find<> union_find(m_union_find_ctx); - for (unsigned i = 0; i < num_vars; ++i) { - m_s->mk_var(true, true); - union_find.mk_var(); - } - for (unsigned i = 0; i < m_L.size(); ++i) { - m_s->mk_clause(m_L[i]->size(), m_L[i]->begin()); - } - for (unsigned i = 0; i < num_vars; ++i) { - uint64 val = m_rbits[i]; - unsigned index; - if (table.find(val, index)) { - union_find.merge(i, index); - } - else if (table.find(~val, index)) { - union_find.merge(i, index); - } - else { - table.insert(val, i); - } - } - TRACE("sat", union_find.display(tout);); - - // - // Preliminary version: - // A more appropriate is to walk each pair, - // and refine partition based on SAT results. - // - for (unsigned i = 0; i < num_vars; ++i) { - if (!union_find.is_root(i)) continue; - unsigned v = union_find.next(i); - unsigned last_v = UINT_MAX; - if (!m_solver.was_eliminated(i)) { - last_v = i; - } - while (v != i) { - if (!m_solver.was_eliminated(v)) { - if (last_v != UINT_MAX) { - if (check_equality(v, last_v)) { - // last_v was eliminated. - - } - else { - // TBD: refine partition. - } - } - last_v = v; - } - v = union_find.next(v); - } - } - } - - bool bceq::check_equality(unsigned v1, unsigned v2) { - TRACE("sat", tout << "check: " << v1 << " = " << v2 << "\n";); - uint64 val1 = m_rbits[v1]; - uint64 val2 = m_rbits[v2]; - literal l1 = literal(v1, false); - literal l2 = literal(v2, false); - if (val1 != val2) { - SASSERT(val1 == ~val2); - l2.neg(); - } - if (is_already_equiv(l1, l2)) { - TRACE("sat", tout << "Already equivalent: " << l1 << " " << l2 << "\n";); - return false; - } - - literal lits[2]; - lits[0] = l1; - lits[1] = ~l2; - lbool is_sat = m_s->check(2, lits); - if (is_sat == l_false) { - lits[0] = ~l1; - lits[1] = l2; - is_sat = m_s->check(2, lits); - } - if (is_sat == l_false) { - TRACE("sat", tout << "Found equivalent: " << l1 << " " << l2 << "\n";); - assert_equality(l1, l2); - } - else { - TRACE("sat", tout << "Not equivalent: " << l1 << " " << l2 << "\n";); - // TBD: if is_sat == l_true, then refine partition. - } - return is_sat == l_false; - } - - bool bceq::is_already_equiv(literal l1, literal l2) { - watch_list const& w1 = m_solver.get_wlist(l1); - bool found = false; - for (unsigned i = 0; !found && i < w1.size(); ++i) { - watched const& w = w1[i]; - found = w.is_binary_clause() && w.get_literal() == ~l2; - } - if (!found) return false; - found = false; - watch_list const& w2 = m_solver.get_wlist(~l1); - for (unsigned i = 0; !found && i < w2.size(); ++i) { - watched const& w = w2[i]; - found = w.is_binary_clause() && w.get_literal() == l2; - } - return found; - } - - void bceq::assert_equality(literal l1, literal l2) { - if (l2.sign()) { - l1.neg(); - l2.neg(); - } - literal_vector roots; - bool_var_vector vars; - for (unsigned i = 0; i < m_solver.num_vars(); ++i) { - roots.push_back(literal(i, false)); - } - roots[l2.var()] = l1; - vars.push_back(l2.var()); - elim_eqs elim(m_solver); - IF_VERBOSE(1, - for (unsigned i = 0; i < vars.size(); ++i) { - verbose_stream() << "var: " << vars[i] << " root: " << roots[vars[i]] << "\n"; - }); - elim(roots, vars); - } - - void bceq::cleanup() { - m_solver.del_clauses(m_bin_clauses.begin(), m_bin_clauses.end()); - m_bin_clauses.reset(); - } - - - void bceq::operator()() { - if (!m_solver.m_config.m_bcd) return; - flet _disable_bcd(m_solver.m_config.m_bcd, false); - flet _disable_min(m_solver.m_config.m_core_minimize, false); - flet _disable_opt(m_solver.m_config.m_optimize_model, false); - flet _bound_maxc(m_solver.m_config.m_max_conflicts, 1500); - - use_list ul; - solver s(m_solver.m_params, m_solver.rlimit(), 0); - s.m_config.m_bcd = false; - s.m_config.m_core_minimize = false; - s.m_config.m_optimize_model = false; - s.m_config.m_max_conflicts = 1500; - m_use_list = &ul; - m_s = &s; - ul.init(m_solver.num_vars()); - init(); - pure_decompose(); - post_decompose(); - IF_VERBOSE(1, verbose_stream() << "Decomposed set " << m_L.size() << " rest: " << m_R.size() << "\n";); - - TRACE("sat", - tout << "Decomposed set " << m_L.size() << "\n"; - for (unsigned i = 0; i < m_L.size(); ++i) { - clause const* cls = m_L[i]; - if (cls) tout << *cls << "\n"; - } - tout << "remainder " << m_R.size() << "\n"; - for (unsigned i = 0; i < m_R.size(); ++i) { - clause const* cls = m_R[i]; - if (cls) tout << *cls << "\n"; - } - ); - sat_sweep(); - extract_partition(); - cleanup(); - } -}; diff --git a/src/sat/sat_bceq.h b/src/sat/sat_bceq.h deleted file mode 100644 index c9d01e78b..000000000 --- a/src/sat/sat_bceq.h +++ /dev/null @@ -1,89 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - sat_bceq.h - -Abstract: - - Find equivalent literals based on blocked clause decomposition. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-09-27. - -Revision History: - ---*/ -#ifndef SAT_BCEQ_H_ -#define SAT_BCEQ_H_ - -#include"sat_types.h" -#include"union_find.h" - - -namespace sat { - class solver; - - class bceq { - typedef ptr_vector clause_use_list; - class use_list { - vector > m_clauses; - public: - use_list() {} - void init(unsigned num_vars); - void reset() { m_clauses.reset(); } - void erase(clause& c); - void insert(clause& c); - ptr_vector& get(literal lit); - }; - typedef std::pair bin_clause; - typedef svector bin_clauses; - solver & m_solver; - use_list* m_use_list; - use_list m_bce_use_list; - solver* m_s; - random_gen m_rand; - svector m_clauses; - svector m_L; - svector m_R; - literal_vector m_L_blits; - literal_vector m_R_blits; - svector m_bin_clauses; - svector m_rbits; - svector m_rstack; // stack of blocked clauses - literal_vector m_bstack; // stack of blocking literals - svector m_marked; - svector m_removed; // set of clauses removed (not considered in clause set during BCE) - union_find_default_ctx m_union_find_ctx; - unsigned_vector m_live_clauses; - - void init(); - void register_clause(clause* cls); - void unregister_clause(clause* cls); - void pure_decompose(); - void pure_decompose(literal lit); - void pure_decompose(ptr_vector& uses, svector& clauses); - void post_decompose(); - literal find_blocked(clause const& cls); - bool bce(clause& cls); - bool is_blocked(literal lit) const; - void init_rbits(); - void init_reconstruction_stack(); - void sat_sweep(); - void cleanup(); - uint64 eval_clause(clause const& cls) const; - void verify_sweep(); - void extract_partition(); - bool check_equality(unsigned v1, unsigned v2); - bool is_already_equiv(literal l1, literal l2); - void assert_equality(literal l1, literal l2); - public: - bceq(solver & s); - void operator()(); - }; - -}; - -#endif diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 58505f8ac..4e01bfe55 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -23,10 +23,10 @@ Revision History: namespace sat { config::config(params_ref const & p): + m_restart_max(0), m_always_true("always_true"), m_always_false("always_false"), m_caching("caching"), - m_restart_max(0), m_random("random"), m_geometric("geometric"), m_luby("luby"), @@ -111,8 +111,6 @@ namespace sat { m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); - m_optimize_model = p.optimize_model(); - m_bcd = p.bcd(); m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 1cdabddef..910ca0360 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -72,8 +72,6 @@ namespace sat { bool m_dyn_sub_res; bool m_core_minimize; bool m_core_minimize_partial; - bool m_optimize_model; - bool m_bcd; symbol m_always_true; diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 7b3277b6c..380b8ee94 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -20,11 +20,10 @@ Notes: #include "sat_solver.h" #include "sat_mus.h" -#include "sat_sls.h" namespace sat { - mus::mus(solver& s):s(s), m_is_active(false), m_best_value(0), m_restart(0), m_max_restarts(0) {} + mus::mus(solver& s):s(s), m_is_active(false),m_restart(0), m_max_restarts(0) {} mus::~mus() {} @@ -32,7 +31,6 @@ namespace sat { m_core.reset(); m_mus.reset(); m_model.reset(); - m_best_value = 0; m_max_restarts = (s.m_stats.m_restart - m_restart) + 10; m_restart = s.m_stats.m_restart; } @@ -45,21 +43,13 @@ namespace sat { } void mus::update_model() { - double new_value = s.m_wsls.evaluate_model(s.m_model); if (m_model.empty()) { m_model.append(s.m_model); - m_best_value = new_value; - } - else if (m_best_value > new_value) { - m_model.reset(); - m_model.append(s.m_model); - m_best_value = new_value; } } lbool mus::operator()() { flet _disable_min(s.m_config.m_core_minimize, false); - flet _disable_opt(s.m_config.m_optimize_model, false); flet _is_active(m_is_active, true); IF_VERBOSE(3, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";); reset(); @@ -120,9 +110,6 @@ namespace sat { SASSERT(value_at(lit, s.get_model()) == l_false); mus.push_back(lit); update_model(); - if (!core.empty()) { - // mr(); // TBD: measure - } break; } case l_false: @@ -262,27 +249,5 @@ namespace sat { IF_VERBOSE(3, verbose_stream() << "core verification: " << is_sat << " " << core << "\n";); } - void mus::mr() { - sls sls(s); - literal_vector tabu; - tabu.append(m_mus); - tabu.append(m_core); - bool reuse_model = false; - for (unsigned i = m_mus.size(); i < tabu.size(); ++i) { - tabu[i] = ~tabu[i]; - lbool is_sat = sls(tabu.size(), tabu.c_ptr(), reuse_model); - tabu[i] = ~tabu[i]; - if (is_sat == l_true) { - m_mus.push_back(tabu[i]); - m_core.erase(tabu[i]); - IF_VERBOSE(3, verbose_stream() << "in core " << tabu[i] << "\n";); - reuse_model = true; - } - else { - IF_VERBOSE(3, verbose_stream() << "NOT in core " << tabu[i] << "\n";); - reuse_model = false; - } - } - } } diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index 617bbc757..74f6d75f0 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -26,7 +26,6 @@ namespace sat { literal_vector m_mus; bool m_is_active; model m_model; // model obtained during minimal unsat core - double m_best_value; unsigned m_restart; unsigned m_max_restarts; @@ -41,7 +40,6 @@ namespace sat { lbool mus1(); lbool mus2(); lbool qx(literal_set& assignment, literal_set& support, bool has_support); - void mr(); void reset(); void set_core(); void update_model(); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 80e6f403f..21a50bea2 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -7,7 +7,7 @@ def_module_params('sat', ('phase.caching.off', UINT, 100, 'phase caching off period (in number of conflicts)'), ('restart', SYMBOL, 'luby', 'restart strategy: luby or geometric'), ('restart.initial', UINT, 100, 'initial restart (number of conflicts)'), - ('restart.max', UINT, 0, 'maximal number of restarts. Ignored if set to 0'), + ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), ('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'), ('random_freq', DOUBLE, 0.01, 'frequency of random case splits'), ('random_seed', UINT, 0, 'random seed'), @@ -22,6 +22,4 @@ def_module_params('sat', ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('core.minimize', BOOL, False, 'minimize computed core'), ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), - ('optimize_model', BOOL, False, 'enable optimization of soft constraints'), - ('bcd', BOOL, False, 'enable blocked clause decomposition for equality extraction'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp deleted file mode 100644 index 7efc0ce0b..000000000 --- a/src/sat/sat_sls.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - sat_sls.cpp - -Abstract: - - SLS for clauses in SAT solver - -Author: - - Nikolaj Bjorner (nbjorner) 2014-12-8 - -Notes: - ---*/ - -#include "sat_sls.h" -#include "sat_solver.h" - -namespace sat { - - bool index_set::contains(unsigned idx) const { - return - (idx < m_index.size()) && - (m_index[idx] < m_elems.size()) && - (m_elems[m_index[idx]] == idx); - } - - void index_set::insert(unsigned idx) { - m_index.reserve(idx+1); - if (!contains(idx)) { - m_index[idx] = m_elems.size(); - m_elems.push_back(idx); - } - } - - void index_set::remove(unsigned idx) { - if (!contains(idx)) return; - unsigned pos = m_index[idx]; - m_elems[pos] = m_elems.back(); - m_index[m_elems[pos]] = pos; - m_elems.pop_back(); - } - - unsigned index_set::choose(random_gen& rnd) const { - SASSERT(!empty()); - return m_elems[rnd(num_elems())]; - } - - sls::sls(solver& s): s(s) { - m_prob_choose_min_var = 43; - m_clause_generation = 0; - } - - sls::~sls() { - for (unsigned i = 0; i < m_bin_clauses.size(); ++i) { - m_alloc.del_clause(m_bin_clauses[i]); - } - } - - lbool sls::operator()(unsigned sz, literal const* tabu, bool reuse_model) { - init(sz, tabu, reuse_model); - unsigned i; - for (i = 0; !m_false.empty() && !s.canceled() && i < m_max_tries; ++i) { - flip(); - } - IF_VERBOSE(2, verbose_stream() << "tries " << i << "\n";); - if (m_false.empty()) { - SASSERT(s.check_model(m_model)); - return l_true; - } - return l_undef; - } - - void sls::init(unsigned sz, literal const* tabu, bool reuse_model) { - bool same_generation = (m_clause_generation == s.m_stats.m_non_learned_generation); - if (!same_generation) { - init_clauses(); - init_use(); - IF_VERBOSE(0, verbose_stream() << s.m_stats.m_non_learned_generation << " " << m_clause_generation << "\n";); - } - if (!reuse_model) { - init_model(); - } - init_tabu(sz, tabu); - m_clause_generation = s.m_stats.m_non_learned_generation; - - m_max_tries = 10*(s.num_vars() + m_clauses.size()); - - } - - void sls::init_clauses() { - for (unsigned i = 0; i < m_bin_clauses.size(); ++i) { - m_alloc.del_clause(m_bin_clauses[i]); - } - m_bin_clauses.reset(); - m_clauses.reset(); - clause * const * it = s.begin_clauses(); - clause * const * end = s.end_clauses(); - for (; it != end; ++it) { - m_clauses.push_back(*it); - } - svector bincs; - s.collect_bin_clauses(bincs, false); - literal lits[2]; - for (unsigned i = 0; i < bincs.size(); ++i) { - lits[0] = bincs[i].first; - lits[1] = bincs[i].second; - clause* cl = m_alloc.mk_clause(2, lits, false); - m_clauses.push_back(cl); - m_bin_clauses.push_back(cl); - } - } - - void sls::init_model() { - m_num_true.reset(); - m_model.reset(); - m_model.append(s.get_model()); - unsigned sz = m_clauses.size(); - for (unsigned i = 0; i < sz; ++i) { - clause const& c = *m_clauses[i]; - unsigned n = 0; - unsigned csz = c.size(); - for (unsigned j = 0; j < csz; ++j) { - lbool val = value_at(c[j], m_model); - switch (val) { - case l_true: - ++n; - break; - case l_undef: - ++n; - m_model[c[j].var()] = c[j].sign()?l_false:l_true; - SASSERT(value_at(c[j], m_model) == l_true); - break; - default: - break; - } - } - m_num_true.push_back(n); - if (n == 0) { - m_false.insert(i); - } - } - } - - void sls::init_tabu(unsigned sz, literal const* tabu) { - // our main use is where m_model satisfies all the hard constraints. - // SASSERT(s.check_model(m_model)); - // SASSERT(m_false.empty()); - // ASSERT: m_num_true is correct count. - m_tabu.reset(); - m_tabu.resize(s.num_vars(), false); - for (unsigned i = 0; i < sz; ++i) { - literal lit = tabu[i]; - if (s.m_level[lit.var()] == 0) continue; - if (value_at(lit, m_model) == l_false) { - flip(lit); - } - m_tabu[lit.var()] = true; - } - for (unsigned i = 0; i < s.m_trail.size(); ++i) { - literal lit = s.m_trail[i]; - if (s.m_level[lit.var()] > 0) break; - if (value_at(lit, m_model) != l_true) { - flip(lit); - } - m_tabu[lit.var()] = true; - } - } - - void sls::init_use() { - m_use_list.reset(); - m_use_list.resize(s.num_vars()*2); - unsigned sz = m_clauses.size(); - for (unsigned i = 0; i < sz; ++i) { - clause const& c = *m_clauses[i]; - unsigned csz = c.size(); - for (unsigned j = 0; j < csz; ++j) { - m_use_list[c[j].index()].push_back(i); - } - } - DEBUG_CODE(check_use_list();); - } - - unsigned_vector const& sls::get_use(literal lit) { - SASSERT(lit.index() < m_use_list.size()); - return m_use_list[lit.index()]; - } - - unsigned sls::get_break_count(literal lit, unsigned min_break) { - SASSERT(value_at(lit, m_model) == l_false); - unsigned result = 0; - unsigned_vector const& uses = get_use(~lit); - unsigned sz = uses.size(); - for (unsigned i = 0; i < sz; ++i) { - if (m_num_true[uses[i]] == 1) { - ++result; - if (result > min_break) return result; - } - } - return result; - } - - bool sls::pick_flip(literal& lit) { - unsigned clause_idx = m_false.choose(m_rand); - clause const& c = *m_clauses[clause_idx]; - SASSERT(!c.satisfied_by(m_model)); - unsigned min_break = UINT_MAX; - unsigned sz = c.size(); - m_min_vars.reset(); - for (unsigned i = 0; i < sz; ++i) { - lit = c[i]; - if (m_tabu[lit.var()]) continue; - unsigned break_count = get_break_count(lit, min_break); - if (break_count < min_break) { - min_break = break_count; - m_min_vars.reset(); - m_min_vars.push_back(lit); - } - else if (break_count == min_break) { - m_min_vars.push_back(lit); - } - } - if (min_break == 0 || (!m_min_vars.empty() && m_rand(100) >= m_prob_choose_min_var)) { - lit = m_min_vars[m_rand(m_min_vars.size())]; - return true; - } - else if (min_break == UINT_MAX) { - return false; - } - else { - lit = c[m_rand(c.size())]; - return !m_tabu[lit.var()]; - } - } - - void sls::flip() { - literal lit; - if (pick_flip(lit)) { - flip(lit); - } - } - - void sls::flip(literal lit) { - //IF_VERBOSE(0, verbose_stream() << lit << " ";); - SASSERT(value_at(lit, m_model) == l_false); - SASSERT(!m_tabu[lit.var()]); - m_model[lit.var()] = lit.sign()?l_false:l_true; - SASSERT(value_at(lit, m_model) == l_true); - unsigned_vector const& use1 = get_use(lit); - unsigned sz = use1.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use1[i]; - m_num_true[cl]++; - SASSERT(m_num_true[cl] <= m_clauses[cl]->size()); - if (m_num_true[cl] == 1) m_false.remove(cl); - } - unsigned_vector const& use2 = get_use(~lit); - sz = use2.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use2[i]; - SASSERT(m_num_true[cl] > 0); - m_num_true[cl]--; - if (m_num_true[cl] == 0) m_false.insert(cl); - } - } - - void sls::check_invariant() { - DEBUG_CODE( - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause const& c = *m_clauses[i]; - bool is_sat = c.satisfied_by(m_model); - SASSERT(is_sat != m_false.contains(i)); - SASSERT(is_sat == (m_num_true[i] > 0)); - }); - } - - void sls::check_use_list() { - DEBUG_CODE( - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause const& c = *m_clauses[i]; - for (unsigned j = 0; j < c.size(); ++j) { - unsigned idx = c[j].index(); - SASSERT(m_use_list[idx].contains(i)); - } - } - - for (unsigned i = 0; i < m_use_list.size(); ++i) { - literal lit = to_literal(i); - for (unsigned j = 0; j < m_use_list[i].size(); ++j) { - clause const& c = *m_clauses[m_use_list[i][j]]; - bool found = false; - for (unsigned k = 0; !found && k < c.size(); ++k) { - found = c[k] == lit; - } - SASSERT(found); - } - }); - } - - void sls::display(std::ostream& out) const { - out << "Model\n"; - for (bool_var v = 0; v < m_model.size(); ++v) { - out << v << ": " << m_model[v] << "\n"; - } - out << "Clauses\n"; - unsigned sz = m_false.num_elems(); - for (unsigned i = 0; i < sz; ++i) { - out << *m_clauses[m_false[i]] << "\n"; - } - for (unsigned i = 0; i < m_clauses.size(); ++i) { - if (m_false.contains(i)) continue; - clause const& c = *m_clauses[i]; - out << c << " " << m_num_true[i] << "\n"; - } - bool has_tabu = false; - for (unsigned i = 0; !has_tabu && i < m_tabu.size(); ++i) { - has_tabu = m_tabu[i]; - } - if (has_tabu) { - out << "Tabu: "; - for (unsigned i = 0; i < m_tabu.size(); ++i) { - if (m_tabu[i]) { - literal lit(i, false); - if (value_at(lit, m_model) == l_false) lit.neg(); - out << lit << " "; - } - } - out << "\n"; - } - } - - - wsls::wsls(solver& s): - sls(s) - { - m_smoothing_probability = 1; // 1/1000 - } - - wsls::~wsls() {} - - void wsls::set_soft(unsigned sz, literal const* lits, double const* weights) { - m_soft.reset(); - m_weights.reset(); - m_soft.append(sz, lits); - m_weights.append(sz, weights); - } - - void wsls::opt(unsigned sz, literal const* tabu, bool reuse_model) { - init(sz, tabu, reuse_model); - - // - // Initialize m_clause_weights, m_hscore, m_sscore. - // - m_best_value = m_false.empty()?evaluate_model(m_model):-1.0; - m_best_model.reset(); - m_clause_weights.reset(); - m_hscore.reset(); - m_sscore.reset(); - m_H.reset(); - m_S.reset(); - m_best_model.append(s.get_model()); - m_clause_weights.resize(m_clauses.size(), 1); - m_sscore.resize(s.num_vars(), 0.0); - m_hscore.resize(s.num_vars(), 0); - for (unsigned i = 0; i < m_soft.size(); ++i) { - literal lit = m_soft[i]; - m_sscore[lit.var()] = m_weights[i]; - if (value_at(lit, m_model) == l_true) { - m_sscore[lit.var()] = -m_sscore[lit.var()]; - } - } - for (bool_var i = 0; i < s.num_vars(); ++i) { - m_hscore[i] = compute_hscore(i); - refresh_scores(i); - } - DEBUG_CODE(check_invariant();); - unsigned i = 0; - for (; !s.canceled() && m_best_value > 0 && i < m_max_tries; ++i) { - wflip(); - if (m_false.empty()) { - double val = evaluate_model(m_model); - if (val < m_best_value || m_best_value < 0.0) { - m_best_value = val; - m_best_model.reset(); - m_best_model.append(m_model); - s.set_model(m_best_model); - IF_VERBOSE(1, verbose_stream() << "new value: " << val << " @ " << i << "\n";); - if (i*2 > m_max_tries) { - m_max_tries *= 2; - } - } - } - } - TRACE("sat", display(tout);); - IF_VERBOSE(0, verbose_stream() << "tries " << i << "\n";); - } - - void wsls::wflip() { - literal lit; - if (pick_wflip(lit)) { - // IF_VERBOSE(0, verbose_stream() << lit << " ";); - wflip(lit); - } - } - - bool wsls::pick_wflip(literal & lit) { - unsigned idx; - if (!m_H.empty()) { - idx = m_H.choose(m_rand); - lit = literal(idx, false); - if (value_at(lit, m_model) == l_true) lit.neg(); - SASSERT(value_at(lit, m_model) == l_false); - TRACE("sat", tout << "flip H(" << m_H.num_elems() << ") " << lit << "\n";); - } - else if (!m_S.empty()) { - double score = 0.0; - m_min_vars.reset(); - for (unsigned i = 0; i < m_S.num_elems(); ++i) { - unsigned v = m_S[i]; - SASSERT(m_sscore[v] > 0.0); - if (m_sscore[v] > score) { - m_min_vars.reset(); - m_min_vars.push_back(literal(v, false)); - score = m_sscore[v]; - } - else if (m_sscore[v] == score) { - m_min_vars.push_back(literal(v, false)); - } - } - lit = m_min_vars[m_rand(m_min_vars.size())]; // pick with largest sscore. - SASSERT(value_at(lit, m_model) == l_false); - TRACE("sat", tout << "flip S(" << m_min_vars.size() << "," << score << ") " << lit << "\n";); - } - else { - update_hard_weights(); - if (!m_false.empty()) { - unsigned cls_idx = m_false.choose(m_rand); - clause const& c = *m_clauses[cls_idx]; - lit = c[m_rand(c.size())]; - TRACE("sat", tout << "flip hard(" << m_false.num_elems() << "," << c.size() << ") " << lit << "\n";); - } - else { - m_min_vars.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - lit = m_soft[i]; - if (value_at(lit, m_model) == l_false) { - m_min_vars.push_back(lit); - } - } - if (m_min_vars.empty()) { - SASSERT(m_best_value == 0.0); - UNREACHABLE(); // we should have exited the main loop before. - return false; - } - else { - lit = m_min_vars[m_rand(m_min_vars.size())]; - } - TRACE("sat", tout << "flip soft(" << m_min_vars.size() << ", " << m_sscore[lit.var()] << ") " << lit << "\n";); - - } - SASSERT(value_at(lit, m_model) == l_false); - } - return !m_tabu[lit.var()]; - } - - void wsls::wflip(literal lit) { - flip(lit); - unsigned v = lit.var(); - m_sscore[v] = -m_sscore[v]; - m_hscore[v] = compute_hscore(v); - refresh_scores(v); - recompute_hscores(lit); - } - - void wsls::update_hard_weights() { - unsigned csz = m_clauses.size(); - if (m_smoothing_probability >= m_rand(1000)) { - for (unsigned i = 0; i < csz; ++i) { - if (m_clause_weights[i] > 1 && !m_false.contains(i)) { - --m_clause_weights[i]; - if (m_num_true[i] == 1) { - clause const& c = *m_clauses[i]; - unsigned sz = c.size(); - for (unsigned j = 0; j < sz; ++j) { - if (value_at(c[j], m_model) == l_true) { - ++m_hscore[c[j].var()]; - refresh_scores(c[j].var()); - break; - } - } - } - } - } - } - else { - for (unsigned i = 0; i < csz; ++i) { - if (m_false.contains(i)) { - ++m_clause_weights[i]; - clause const& c = *m_clauses[i]; - unsigned sz = c.size(); - for (unsigned j = 0; j < sz; ++j) { - ++m_hscore[c[j].var()]; - refresh_scores(c[j].var()); - } - } - } - } - DEBUG_CODE(check_invariant();); - } - - double wsls::evaluate_model(model& mdl) { - SASSERT(m_false.empty()); - double result = 0.0; - for (unsigned i = 0; i < m_soft.size(); ++i) { - literal lit = m_soft[i]; - if (value_at(lit, mdl) != l_true) { - result += m_weights[i]; - } - } - return result; - } - - int wsls::compute_hscore(bool_var v) { - literal lit(v, false); - if (value_at(lit, m_model) == l_false) { - lit.neg(); - } - SASSERT(value_at(lit, m_model) == l_true); - int hs = 0; - unsigned_vector const& use1 = get_use(~lit); - unsigned sz = use1.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use1[i]; - if (m_num_true[cl] == 0) { - SASSERT(m_false.contains(cl)); - hs += m_clause_weights[cl]; - } - else { - SASSERT(!m_false.contains(cl)); - } - } - unsigned_vector const& use2 = get_use(lit); - sz = use2.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use2[i]; - if (m_num_true[cl] == 1) { - SASSERT(!m_false.contains(cl)); - hs -= m_clause_weights[cl]; - } - } - return hs; - } - - void wsls::recompute_hscores(literal lit) { - SASSERT(value_at(lit, m_model) == l_true); - TRACE("sat", tout << lit.var() << " := " << m_hscore[lit.var()] << "\n";); - unsigned_vector const& use1 = get_use(lit); - unsigned sz = use1.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use1[i]; - TRACE("sat", tout << *m_clauses[cl] << " " << m_num_true[cl] << "\n";); - SASSERT(m_num_true[cl] > 0); - if (m_num_true[cl] == 1) { - // num_true 0 -> 1 - // other literals don't have upside any more. - // subtract one from all other literals - adjust_all_values(lit, cl, -static_cast(m_clause_weights[cl])); - } - else if (m_num_true[cl] == 2) { - // num_true 1 -> 2, previous critical literal is no longer critical - adjust_pivot_value(lit, cl, +m_clause_weights[cl]); - } - } - unsigned_vector const& use2 = get_use(~lit); - sz = use2.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use2[i]; - TRACE("sat", tout << *m_clauses[cl] << " " << m_num_true[cl] << "\n";); - if (m_num_true[cl] == 0) { - // num_true 1 -> 0 - // all variables became critical. - adjust_all_values(~lit, cl, +m_clause_weights[cl]); - } - else if (m_num_true[cl] == 1) { - adjust_pivot_value(~lit, cl, -static_cast(m_clause_weights[cl])); - } - // else n+1 -> n >= 2 - } - } - - void wsls::adjust_all_values(literal lit, unsigned cl, int delta) { - clause const& c = *m_clauses[cl]; - unsigned sz = c.size(); - TRACE("sat", tout << lit << " " << c << " delta: " << delta << " nt: " << m_num_true[cl] << "\n";); - for (unsigned i = 0; i < sz; ++i) { - literal lit2 = c[i]; - if (lit2 != lit) { - TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); - m_hscore[lit2.var()] += delta; - TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); - refresh_scores(lit2.var()); - } - } - } - - void wsls::adjust_pivot_value(literal lit, unsigned cl, int delta) { - clause const& c = *m_clauses[cl]; - unsigned csz = c.size(); - for (unsigned j = 0; j < csz; ++j) { - literal lit2 = c[j]; - if (lit2 != lit && value_at(lit2, m_model) == l_true) { - TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); - m_hscore[lit2.var()] += delta; - TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); - refresh_scores(lit2.var()); - break; - } - } - } - - void wsls::refresh_scores(bool_var v) { - if (m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) { - m_H.insert(v); - } - else { - m_H.remove(v); - } - if (m_sscore[v] > 0) { - if (m_hscore[v] == 0 && !m_tabu[v]) { - m_S.insert(v); - } - else { - m_S.remove(v); - } - } - else if (m_sscore[v] < 0) { - m_S.remove(v); - } - } - - void wsls::check_invariant() { - sls::check_invariant(); - // The hscore is the reward for flipping the truth value of variable v. - // hscore(v) = Sum weight(c) for num_true(c) = 0 and v in c - // - Sum weight(c) for num_true(c) = 1 and (v in c, M(v) or !v in c and !M(v)) - DEBUG_CODE( - for (unsigned v = 0; v < s.num_vars(); ++v) { - int hs = compute_hscore(v); - CTRACE("sat", hs != m_hscore[v], display(tout << v << " - computed: " << hs << " - assigned: " << m_hscore[v] << "\n");); - SASSERT(m_hscore[v] == hs); - } - - // The score(v) is the reward on soft clauses for flipping v. - for (unsigned j = 0; j < m_soft.size(); ++j) { - unsigned v = m_soft[j].var(); - double ss = (l_true == value_at(m_soft[j], m_model))?(-m_weights[j]):m_weights[j]; - SASSERT(m_sscore[v] == ss); - } - - // m_H are values such that m_hscore > 0 and sscore = 0. - for (bool_var v = 0; v < m_hscore.size(); ++v) { - SASSERT((m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) == m_H.contains(v)); - } - - // m_S are values such that hscore = 0, sscore > 0 - for (bool_var v = 0; v < m_sscore.size(); ++v) { - SASSERT((m_hscore[v] == 0 && m_sscore[v] > 0 && !m_tabu[v]) == m_S.contains(v)); - }); - } - - void wsls::display(std::ostream& out) const { - sls::display(out); - out << "Best model\n"; - for (bool_var v = 0; v < m_best_model.size(); ++v) { - out << v << ": " << m_best_model[v] << " h: " << m_hscore[v]; - if (m_sscore[v] != 0.0) out << " s: " << m_sscore[v]; - out << "\n"; - } - } - -}; - diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h deleted file mode 100644 index f1bf55543..000000000 --- a/src/sat/sat_sls.h +++ /dev/null @@ -1,115 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - sat_sls.h - -Abstract: - - SLS for clauses in SAT solver - -Author: - - Nikolaj Bjorner (nbjorner) 2014-12-8 - -Notes: - ---*/ -#ifndef SAT_SLS_H_ -#define SAT_SLS_H_ - -#include "util.h" -#include "sat_simplifier.h" - -namespace sat { - - class index_set { - unsigned_vector m_elems; - unsigned_vector m_index; - public: - unsigned num_elems() const { return m_elems.size(); } - unsigned operator[](unsigned idx) const { return m_elems[idx]; } - void reset() { m_elems.reset(); m_index.reset(); } - bool empty() const { return m_elems.empty(); } - bool contains(unsigned idx) const; - void insert(unsigned idx); - void remove(unsigned idx); - unsigned choose(random_gen& rnd) const; - }; - - class sls { - protected: - solver& s; - random_gen m_rand; - unsigned m_max_tries; - unsigned m_prob_choose_min_var; // number between 0 and 99. - unsigned m_clause_generation; - ptr_vector m_clauses; // vector of all clauses. - index_set m_false; // clauses currently false - vector m_use_list; // use lists for literals - unsigned_vector m_num_true; // per clause, count of # true literals - svector m_min_vars; // literals with smallest break count - model m_model; // current model - clause_allocator m_alloc; // clause allocator - clause_vector m_bin_clauses; // binary clauses - svector m_tabu; // variables that cannot be swapped - public: - sls(solver& s); - virtual ~sls(); - lbool operator()(unsigned sz, literal const* tabu, bool reuse_model); - void set_max_tries(unsigned mx) { m_max_tries = mx; } - virtual void display(std::ostream& out) const; - protected: - void init(unsigned sz, literal const* tabu, bool reuse_model); - void init_tabu(unsigned sz, literal const* tabu); - void init_model(); - void init_use(); - void init_clauses(); - unsigned_vector const& get_use(literal lit); - void flip(literal lit); - virtual void check_invariant(); - void check_use_list(); - private: - bool pick_flip(literal& lit); - void flip(); - unsigned get_break_count(literal lit, unsigned min_break); - }; - - /** - \brief sls with weighted soft clauses. - */ - class wsls : public sls { - unsigned_vector m_clause_weights; - svector m_hscore; - svector m_sscore; - literal_vector m_soft; - svector m_weights; - double m_best_value; - model m_best_model; - index_set m_H, m_S; - unsigned m_smoothing_probability; - public: - wsls(solver& s); - virtual ~wsls(); - void set_soft(unsigned sz, literal const* lits, double const* weights); - bool has_soft() const { return !m_soft.empty(); } - void opt(unsigned sz, literal const* tabu, bool reuse_model); - virtual void display(std::ostream& out) const; - double evaluate_model(model& mdl); - private: - void wflip(); - void wflip(literal lit); - void update_hard_weights(); - bool pick_wflip(literal & lit); - virtual void check_invariant(); - void refresh_scores(bool_var v); - int compute_hscore(bool_var v); - void recompute_hscores(literal lit); - void adjust_all_values(literal lit, unsigned cl, int delta); - void adjust_pivot_value(literal lit, unsigned cl, int delta); - }; - -}; - -#endif diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a5c9005df..37fb971fd 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -20,7 +20,6 @@ Revision History: #include"sat_integrity_checker.h" #include"luby.h" #include"trace.h" -#include"sat_bceq.h" #include"max_cliques.h" // define to update glue during propagation @@ -42,7 +41,6 @@ namespace sat { m_asymm_branch(*this, p), m_probing(*this, p), m_mus(*this), - m_wsls(*this), m_inconsistent(false), m_num_frozen(0), m_activity_inc(128), @@ -55,7 +53,6 @@ namespace sat { m_conflicts = 0; m_next_simplify = 0; m_num_checkpoints = 0; - m_initializing_preferred = false; } solver::~solver() { @@ -123,6 +120,7 @@ namespace sat { // ----------------------- bool_var solver::mk_var(bool ext, bool dvar) { + m_model_is_current = false; m_stats.m_mk_var++; bool_var v = m_level.size(); m_watches.push_back(watch_list()); @@ -148,6 +146,7 @@ namespace sat { } void solver::mk_clause(unsigned num_lits, literal * lits) { + m_model_is_current = false; DEBUG_CODE({ for (unsigned i = 0; i < num_lits; i++) SASSERT(m_eliminated[lits[i].var()] == false); @@ -212,7 +211,7 @@ namespace sat { if (propagate_bin_clause(l1, l2)) { if (scope_lvl() == 0) return; - if (!learned) + if (!learned) m_clauses_to_reinit.push_back(clause_wrapper(l1, l2)); } m_stats.m_mk_bin_clause++; @@ -235,19 +234,18 @@ namespace sat { } void solver::push_reinit_stack(clause & c) { + TRACE("sat_reinit", tout << "adding to reinit stack: " << c << "\n";); m_clauses_to_reinit.push_back(clause_wrapper(c)); - c.set_reinit_stack(true); + c.set_reinit_stack(true); } + clause * solver::mk_ter_clause(literal * lits, bool learned) { m_stats.m_mk_ter_clause++; clause * r = m_cls_allocator.mk_clause(3, lits, learned); - bool reinit; - attach_ter_clause(*r, reinit); - if (!learned && reinit) { - TRACE("sat_reinit", tout << "adding to reinit stack: " << *r << "\n";); - push_reinit_stack(*r); - } + bool reinit = attach_ter_clause(*r); + if (reinit && !learned) push_reinit_stack(*r); + if (learned) m_learned.push_back(r); else @@ -255,8 +253,8 @@ namespace sat { return r; } - void solver::attach_ter_clause(clause & c, bool & reinit) { - reinit = false; + bool solver::attach_ter_clause(clause & c) { + bool reinit = false; m_watches[(~c[0]).index()].push_back(watched(c[1], c[2])); m_watches[(~c[1]).index()].push_back(watched(c[0], c[2])); m_watches[(~c[2]).index()].push_back(watched(c[0], c[1])); @@ -277,18 +275,15 @@ namespace sat { reinit = true; } } + return reinit; } clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, bool learned) { m_stats.m_mk_clause++; clause * r = m_cls_allocator.mk_clause(num_lits, lits, learned); SASSERT(!learned || r->is_learned()); - bool reinit; - attach_nary_clause(*r, reinit); - if (!learned && reinit) { - TRACE("sat_reinit", tout << "adding to reinit stack: " << *r << "\n";); - push_reinit_stack(*r); - } + bool reinit = attach_nary_clause(*r); + if (reinit && !learned) push_reinit_stack(*r); if (learned) m_learned.push_back(r); else @@ -296,8 +291,8 @@ namespace sat { return r; } - void solver::attach_nary_clause(clause & c, bool & reinit) { - reinit = false; + bool solver::attach_nary_clause(clause & c) { + bool reinit = false; clause_offset cls_off = m_cls_allocator.get_offset(&c); if (scope_lvl() > 0) { if (c.is_learned()) { @@ -326,15 +321,16 @@ namespace sat { literal block_lit = c[some_idx]; 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; } void solver::attach_clause(clause & c, bool & reinit) { SASSERT(c.size() > 2); reinit = false; if (c.size() == 3) - attach_ter_clause(c, reinit); + reinit = attach_ter_clause(c); else - attach_nary_clause(c, reinit); + reinit = attach_nary_clause(c); } /** @@ -711,7 +707,7 @@ namespace sat { // Search // // ----------------------- - lbool solver::check(unsigned num_lits, literal const* lits, double const* weights, double max_weight) { + lbool solver::check(unsigned num_lits, literal const* lits) { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(scope_lvl() == 0); @@ -726,7 +722,7 @@ namespace sat { init_search(); propagate(false); if (inconsistent()) return l_false; - init_assumptions(num_lits, lits, weights, max_weight); + init_assumptions(num_lits, lits); propagate(false); if (check_inconsistent()) return l_false; cleanup(); @@ -766,7 +762,7 @@ namespace sat { if (check_inconsistent()) return l_false; gc(); - if (m_config.m_restart_max != 0 && m_config.m_restart_max <= m_restarts) { + if (m_config.m_restart_max <= m_restarts) { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";); return l_undef; } @@ -912,12 +908,11 @@ namespace sat { } } - void solver::init_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight) { + void solver::init_assumptions(unsigned num_lits, literal const* lits) { if (num_lits == 0 && m_user_scope_literals.empty()) { return; } - retry_init_assumptions: reset_assumptions(); push(); @@ -941,16 +936,6 @@ namespace sat { assign(nlit, justification()); } - if (weights && !inconsistent()) { - if (m_config.m_optimize_model) { - m_wsls.set_soft(num_lits, lits, weights); - } - if (!init_weighted_assumptions(num_lits, lits, weights, max_weight)) { - goto retry_init_assumptions; - } - return; - } - for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { literal lit = lits[i]; SASSERT(is_external(lit.var())); @@ -960,109 +945,6 @@ namespace sat { } - bool solver::init_weighted_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight) { - flet _min1(m_config.m_core_minimize, false); - m_weight = 0; - m_blocker.reset(); - svector values; - unsigned num_cores = 0; - for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { - literal lit = lits[i]; - SASSERT(is_external(lit.var())); - TRACE("sat", tout << "propagate: " << lit << " " << value(lit) << "\n";); - SASSERT(m_scope_lvl == 1); - add_assumption(lit); - switch(value(lit)) { - case l_undef: - values.push_back(l_true); - assign(lit, justification()); - if (num_cores*2 >= num_lits) { - break; - } - propagate(false); - if (inconsistent()) { - flet _init(m_initializing_preferred, true); - while (inconsistent()) { - if (!resolve_conflict()) { - return true; - } - propagate(true); - } - if (m_scope_lvl == 0) { - return false; - } - // backjump to last consistent assumption: - unsigned j; - m_weight = 0; - m_blocker.reset(); - for (j = 0; j < i && value(lits[j]) == values[j]; ++j) { - if (values[j] == l_false) { - m_weight += weights[j]; - m_blocker.push_back(lits[j]); - } - } - SASSERT(value(lits[j]) != values[j]); - SASSERT(j <= i); - SASSERT(j == 0 || value(lits[j-1]) == values[j-1]); - for (unsigned k = i; k >= j; --k) { - if (is_assumption(lits[k])) { - pop_assumption(); - } - } - values.resize(j); - TRACE("sat", tout << "backjump " << (i - j + 1) << " steps " << num_cores << "\n";); - i = j - 1; - } - break; - - case l_false: - ++num_cores; - values.push_back(l_false); - SASSERT(!inconsistent()); - set_conflict(justification(), ~lit); - m_conflict_lvl = scope_lvl(); - resolve_conflict_for_unsat_core(); - IF_VERBOSE(3, verbose_stream() << "(sat.core: " << m_core << ")\n";); - update_min_core(); - SASSERT(m_min_core_valid); - m_weight += weights[i]; - if (m_weight <= max_weight) { - m_blocker.push_back(lit); - } - TRACE("sat", tout << "core: " << m_core << "\nassumptions: " << m_assumptions << "\n";); - SASSERT(m_core.size() <= m_assumptions.size()); - SASSERT(m_assumptions.size() <= i+1); - if (m_core.size() <= 3) { - m_inconsistent = true; - TRACE("opt", tout << "found small core: " << m_core << "\n";); - IF_VERBOSE(11, verbose_stream() << "(sat.core: " << m_core << ")\n";); - return true; - } - pop_assumption(); - m_inconsistent = false; - break; - case l_true: - values.push_back(l_true); - SASSERT(m_justification[lit.var()].get_kind() != justification::NONE || lvl(lit) == 0); - break; - } - } - TRACE("sat", tout << "initialized\n";); - IF_VERBOSE(11, verbose_stream() << "(sat.blocker: " << m_blocker << "\nCore: " << m_min_core << ")\n";); - if (m_weight >= max_weight) { - // block the current correction set candidate. - ++m_stats.m_blocked_corr_sets; - TRACE("opt", tout << "blocking soft correction set: " << m_blocker << "\n";); - IF_VERBOSE(11, verbose_stream() << "blocking " << m_blocker << "\n";); - pop_to_base_level(); - mk_clause_core(m_blocker); - return false; - } - return true; - } - - - void solver::update_min_core() { if (!m_min_core_valid || m_core.size() < m_min_core.size()) { m_min_core.reset(); @@ -1112,6 +994,13 @@ namespace sat { for (unsigned i = 0; !inconsistent() && i < m_assumptions.size(); ++i) { assign(m_assumptions[i], justification()); } + TRACE("sat", + for (unsigned i = 0; i < m_assumptions.size(); ++i) { + index_set s; + if (m_antecedents.find(m_assumptions[i].var(), s)) { + tout << m_assumptions[i] << ": "; display_index_set(tout, s) << "\n"; + } + }); } } @@ -1139,11 +1028,6 @@ namespace sat { m_min_core_valid = false; m_min_core.reset(); TRACE("sat", display(tout);); - - if (m_config.m_bcd) { - bceq bc(*this); - bc(); - } } /** @@ -1235,9 +1119,6 @@ namespace sat { m_model[v] = value(v); } TRACE("sat_mc_bug", m_mc.display(tout);); - if (m_config.m_optimize_model) { - m_wsls.opt(0, 0, false); - } m_mc(m_model); TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); @@ -1664,10 +1545,6 @@ namespace sat { if (m_not_l == literal()) tout << "null literal\n"; else tout << m_not_l << "\n";); - if (m_initializing_preferred) { - SASSERT(m_conflict_lvl <= 1); - return resolve_conflict_for_init(); - } if (m_conflict_lvl <= 1 && tracking_assumptions()) { resolve_conflict_for_unsat_core(); return false; @@ -3118,7 +2995,14 @@ namespace sat { lbool solver::get_consequences(literal_vector const& asms, bool_var_vector const& vars, vector& conseq) { literal_vector lits; - lbool is_sat = check(asms.size(), asms.c_ptr()); + lbool is_sat = l_true; + + if (m_config.m_restart_max != UINT_MAX && !m_model_is_current) { + return get_bounded_consequences(asms, vars, conseq); + } + if (!m_model_is_current) { + is_sat = check(asms.size(), asms.c_ptr()); + } if (is_sat != l_true) { return is_sat; } @@ -3136,9 +3020,94 @@ namespace sat { return is_sat; } - lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector& conseq) { + void solver::fixup_consequence_core() { + index_set s; + TRACE("sat", tout << m_core << "\n";); + for (unsigned i = 0; i < m_core.size(); ++i) { + TRACE("sat", tout << m_core[i] << ": "; display_index_set(tout, m_antecedents.find(m_core[i].var())) << "\n";); + s |= m_antecedents.find(m_core[i].var()); + } + m_core.reset(); + index_set::iterator it = s.begin(), end = s.end(); + for (; it != end; ++it) { + m_core.push_back(to_literal(*it)); + } + TRACE("sat", tout << m_core << "\n";); + } + + + lbool solver::get_bounded_consequences(literal_vector const& asms, bool_var_vector const& vars, vector& conseq) { + bool_var_set unfixed_vars; + unsigned num_units = 0, num_iterations = 0; + for (unsigned i = 0; i < vars.size(); ++i) { + unfixed_vars.insert(vars[i]); + } + TRACE("sat", tout << asms << "\n";); m_antecedents.reset(); - literal_set vars(lits), assumptions(asms); + pop_to_base_level(); + if (inconsistent()) return l_false; + init_search(); + propagate(false); + if (inconsistent()) return l_false; + if (asms.empty()) { + bool_var v = mk_var(true, false); + literal lit(v, false); + init_assumptions(1, &lit); + } + else { + init_assumptions(asms.size(), asms.c_ptr()); + } + propagate(false); + if (check_inconsistent()) return l_false; + + extract_fixed_consequences(num_units, asms, unfixed_vars, conseq); + + simplify_problem(); + if (check_inconsistent()) { + fixup_consequence_core(); + return l_false; + } + + while (true) { + ++num_iterations; + SASSERT(!inconsistent()); + + lbool r = bounded_search(); + if (r != l_undef) { + fixup_consequence_core(); + return r; + } + + extract_fixed_consequences(num_units, asms, unfixed_vars, conseq); + + if (m_conflicts > m_config.m_max_conflicts) { + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts << "\")\n";); + return l_undef; + } + + restart(); + simplify_problem(); + if (check_inconsistent()) { + fixup_consequence_core(); + return l_false; + } + gc(); + + if (m_config.m_restart_max <= num_iterations) { + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";); + return l_undef; + } + } + } + + lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector& conseq) { + TRACE("sat", tout << asms << "\n";); + m_antecedents.reset(); + literal_set unfixed_lits(lits), assumptions(asms); + bool_var_set unfixed_vars; + for (unsigned i = 0; i < lits.size(); ++i) { + unfixed_vars.insert(lits[i].var()); + } pop_to_base_level(); if (inconsistent()) return l_false; @@ -3148,20 +3117,24 @@ namespace sat { if (asms.empty()) { bool_var v = mk_var(true, false); literal lit(v, false); - init_assumptions(1, &lit, 0, 0); + init_assumptions(1, &lit); } else { - init_assumptions(asms.size(), asms.c_ptr(), 0, 0); + init_assumptions(asms.size(), asms.c_ptr()); } propagate(false); if (check_inconsistent()) return l_false; unsigned num_units = 0, num_iterations = 0; - extract_fixed_consequences(num_units, assumptions, vars, conseq); - while (!vars.empty()) { + extract_fixed_consequences(num_units, assumptions, unfixed_vars, conseq); + update_unfixed_literals(unfixed_lits, unfixed_vars); + while (!unfixed_lits.empty()) { + if (scope_lvl() > 1) { + pop(scope_lvl() - 1); + } ++num_iterations; checkpoint(); - literal_set::iterator it = vars.begin(), end = vars.end(); + literal_set::iterator it = unfixed_lits.begin(), end = unfixed_lits.end(); unsigned num_resolves = 0; lbool is_sat = l_true; for (; it != end; ++it) { @@ -3202,53 +3175,84 @@ namespace sat { m_inconsistent = false; } if (is_sat == l_true) { - delete_unfixed(vars); + delete_unfixed(unfixed_lits, unfixed_vars); } - extract_fixed_consequences(num_units, assumptions, vars, conseq); + extract_fixed_consequences(num_units, assumptions, unfixed_vars, conseq); + update_unfixed_literals(unfixed_lits, unfixed_vars); IF_VERBOSE(1, verbose_stream() << "(sat.get-consequences" << " iterations: " << num_iterations - << " variables: " << vars.size() + << " variables: " << unfixed_lits.size() << " fixed: " << conseq.size() - << " unfixed: " << lits.size() - conseq.size() - vars.size() + << " unfixed: " << lits.size() - conseq.size() - unfixed_lits.size() << ")\n";); + if (!unfixed_lits.empty() && m_config.m_restart_max <= num_iterations) { + return l_undef; + } } return l_true; } - void solver::delete_unfixed(literal_set& unfixed) { + void solver::delete_unfixed(literal_set& unfixed_lits, bool_var_set& unfixed_vars) { literal_set to_keep; - literal_set::iterator it = unfixed.begin(), end = unfixed.end(); + literal_set::iterator it = unfixed_lits.begin(), end = unfixed_lits.end(); for (; it != end; ++it) { literal lit = *it; if (value(lit) == l_true) { to_keep.insert(lit); } + else { + unfixed_vars.remove(lit.var()); + } } - unfixed = to_keep; + unfixed_lits = to_keep; } - void solver::extract_fixed_consequences(unsigned& start, literal_set const& assumptions, literal_set& unfixed, vector& conseq) { - if (scope_lvl() > 1) { - pop(scope_lvl() - 1); + void solver::update_unfixed_literals(literal_set& unfixed_lits, bool_var_set& unfixed_vars) { + literal_vector to_delete; + literal_set::iterator it = unfixed_lits.begin(), end = unfixed_lits.end(); + for (; it != end; ++it) { + literal lit = *it; + if (!unfixed_vars.contains(lit.var())) { + to_delete.push_back(lit); + } } + for (unsigned i = 0; i < to_delete.size(); ++i) { + unfixed_lits.remove(to_delete[i]); + } + } + + + void solver::extract_fixed_consequences(unsigned& start, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq) { SASSERT(!inconsistent()); unsigned sz = m_trail.size(); - for (unsigned i = start; i < sz; ++i) { - extract_fixed_consequences(m_trail[i], assumptions, unfixed, conseq); + for (unsigned i = start; i < sz && lvl(m_trail[i]) <= 1; ++i) { + if (!extract_fixed_consequences(m_trail[i], assumptions, unfixed, conseq)) { + for (i = 0; i < sz && lvl(m_trail[i]) <= 1; ++i) { + VERIFY(extract_fixed_consequences(m_trail[i], assumptions, unfixed, conseq)); + } + break; + } } start = sz; } - void solver::extract_assumptions(literal lit, index_set& s) { + bool solver::check_domain(literal lit, literal lit2) { + return m_antecedents.contains(lit2.var()); + } + + bool solver::extract_assumptions(literal lit, index_set& s) { justification js = m_justification[lit.var()]; switch (js.get_kind()) { case justification::NONE: break; case justification::BINARY: + if (!check_domain(lit, js.get_literal())) return false; s |= m_antecedents.find(js.get_literal().var()); break; case justification::TERNARY: + if (!check_domain(lit, js.get_literal1())) return false; + if (!check_domain(lit, js.get_literal2())) return false; s |= m_antecedents.find(js.get_literal1().var()); s |= m_antecedents.find(js.get_literal2().var()); break; @@ -3256,6 +3260,7 @@ namespace sat { clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); for (unsigned i = 0; i < c.size(); ++i) { if (c[i] != lit) { + if (!check_domain(lit, c[i])) return false; s |= m_antecedents.find(c[i].var()); } } @@ -3266,6 +3271,7 @@ namespace sat { literal_vector::iterator it = m_ext_antecedents.begin(); literal_vector::iterator end = m_ext_antecedents.end(); for (; it != end; ++it) { + if (!check_domain(lit, *it)) return false; s |= m_antecedents.find(it->var()); } break; @@ -3274,28 +3280,46 @@ namespace sat { UNREACHABLE(); break; } + TRACE("sat", display_index_set(tout << lit << ": " , s) << "\n";); + return true; } - void solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, literal_set& unfixed, vector& conseq) { + std::ostream& solver::display_index_set(std::ostream& out, index_set const& s) const { + index_set::iterator it = s.begin(); + index_set::iterator end = s.end(); + for (; it != end; ++it) { + out << to_literal(*it) << " "; + } + return out; + } + + + bool solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq) { index_set s; + if (m_antecedents.contains(lit.var())) { + return true; + } if (assumptions.contains(lit)) { s.insert(lit.index()); } else { + if (!extract_assumptions(lit, s)) { + return false; + } add_assumption(lit); - extract_assumptions(lit, s); } m_antecedents.insert(lit.var(), s); - if (unfixed.contains(lit)) { + if (unfixed.contains(lit.var())) { literal_vector cons; cons.push_back(lit); index_set::iterator it = s.begin(), end = s.end(); for (; it != end; ++it) { cons.push_back(to_literal(*it)); } - unfixed.remove(lit); + unfixed.remove(lit.var()); conseq.push_back(cons); } + return true; } void solver::asymmetric_branching() { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index aa45a1043..dcf7e2acb 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -33,7 +33,6 @@ Revision History: #include"sat_iff3_finder.h" #include"sat_probing.h" #include"sat_mus.h" -#include"sat_sls.h" #include"params.h" #include"statistics.h" #include"stopwatch.h" @@ -86,7 +85,6 @@ namespace sat { asymm_branch m_asymm_branch; probing m_probing; mus m_mus; // MUS for minimal core extraction - wsls m_wsls; // SLS facility for MaxSAT use bool m_inconsistent; // A conflict is usually a single justification. That is, a justification // for false. If m_not_l is not null_literal, then m_conflict is a @@ -141,9 +139,6 @@ namespace sat { friend class probing; friend class iff3_finder; friend class mus; - friend class sls; - friend class wsls; - friend class bceq; friend struct mk_stat; public: solver(params_ref const & p, reslimit& l, extension * ext); @@ -189,11 +184,9 @@ namespace sat { void mk_bin_clause(literal l1, literal l2, bool learned); bool propagate_bin_clause(literal l1, literal l2); clause * mk_ter_clause(literal * lits, bool learned); - void attach_ter_clause(clause & c, bool & reinit); - void attach_ter_clause(clause & c) { bool reinit; attach_ter_clause(c, reinit); } + bool attach_ter_clause(clause & c); clause * mk_nary_clause(unsigned num_lits, literal * lits, bool learned); - void attach_nary_clause(clause & c, bool & reinit); - void attach_nary_clause(clause & c) { bool reinit; attach_nary_clause(c, reinit); } + bool attach_nary_clause(clause & c); void attach_clause(clause & c, bool & reinit); void attach_clause(clause & c) { bool reinit; attach_clause(c, reinit); } unsigned select_watch_lit(clause const & cls, unsigned starting_at) const; @@ -280,10 +273,7 @@ namespace sat { // // ----------------------- public: - lbool check(unsigned num_lits = 0, literal const* lits = 0) { - return check(num_lits, lits, 0, 0); - } - lbool check(unsigned num_lits, literal const* lits, double const* weights, double max_weight); + lbool check(unsigned num_lits = 0, literal const* lits = 0); model const & get_model() const { return m_model; } bool model_is_current() const { return m_model_is_current; } @@ -311,11 +301,7 @@ namespace sat { literal_vector m_min_core; bool m_min_core_valid; - literal_vector m_blocker; - double m_weight; - bool m_initializing_preferred; - void init_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight); - bool init_weighted_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight); + void init_assumptions(unsigned num_lits, literal const* lits); void reassert_min_core(); void update_min_core(); void resolve_weighted(); @@ -453,15 +439,25 @@ namespace sat { u_map m_antecedents; vector m_binary_clause_graph; - void extract_assumptions(literal lit, index_set& s); + bool extract_assumptions(literal lit, index_set& s); + + bool check_domain(literal lit, literal lit2); + + std::ostream& display_index_set(std::ostream& out, index_set const& s) const; lbool get_consequences(literal_vector const& assms, literal_vector const& lits, vector& conseq); - void delete_unfixed(literal_set& unfixed); + lbool get_bounded_consequences(literal_vector const& assms, bool_var_vector const& vars, vector& conseq); - void extract_fixed_consequences(unsigned& start, literal_set const& assumptions, literal_set& unfixed, vector& conseq); + void delete_unfixed(literal_set& unfixed_lits, bool_var_set& unfixed_vars); - void extract_fixed_consequences(literal lit, literal_set const& assumptions, literal_set& unfixed, vector& conseq); + void extract_fixed_consequences(unsigned& start, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq); + + bool extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq); + + void update_unfixed_literals(literal_set& unfixed_lits, bool_var_set& unfixed_vars); + + void fixup_consequence_core(); // ----------------------- // diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index e3a220cd2..33d10f428 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -105,13 +105,8 @@ public: virtual void set_progress_callback(progress_callback * callback) {} - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { - return check_sat(num_assumptions, assumptions, 0, 0); - } - void display_weighted(std::ostream& out, unsigned sz, expr * const * assumptions, unsigned const* weights) { - m_weights.reset(); if (weights != 0) { for (unsigned i = 0; i < sz; ++i) m_weights.push_back(weights[i]); } @@ -131,15 +126,11 @@ public: for (unsigned i = 0; i < m_asms.size(); ++i) { nweights.push_back((unsigned) m_weights[i]); } + m_weights.reset(); m_solver.display_wcnf(out, m_asms.size(), m_asms.c_ptr(), nweights.c_ptr()); } - lbool check_sat(unsigned sz, expr * const * assumptions, double const* weights, double max_weight) { - m_weights.reset(); - if (weights != 0) { - m_weights.append(sz, weights); - } - SASSERT(m_weights.empty() == (m_weights.c_ptr() == 0)); + virtual lbool check_sat(unsigned sz, expr * const * assumptions) { m_solver.pop_to_base_level(); dep2asm_t dep2asm; m_model = 0; @@ -148,10 +139,10 @@ public: r = internalize_assumptions(sz, assumptions, dep2asm); if (r != l_true) return r; - r = m_solver.check(m_asms.size(), m_asms.c_ptr(), m_weights.c_ptr(), max_weight); + r = m_solver.check(m_asms.size(), m_asms.c_ptr()); switch (r) { case l_true: - if (sz > 0 && !weights) { + if (sz > 0) { check_assumptions(dep2asm); } break; @@ -252,12 +243,17 @@ public: m_solver.pop_to_base_level(); lbool r = internalize_formulas(); if (r != l_true) return r; + r = internalize_vars(vars, bvars); + if (r != l_true) return r; r = internalize_assumptions(assumptions.size(), assumptions.c_ptr(), dep2asm); if (r != l_true) return r; - r = internalize_vars(vars, bvars); - r = m_solver.get_consequences(m_asms, bvars, lconseq); - if (r != l_true) return r; + if (r == l_false) { + if (!m_asms.empty()) { + extract_core(dep2asm); + } + return r; + } // build map from bound variables to // the consequences that cover them. @@ -670,18 +666,6 @@ solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p) { } -lbool inc_sat_check_sat(solver& _s, unsigned sz, expr*const* soft, rational const* _weights, rational const& max_weight) { - inc_sat_solver& s = dynamic_cast(_s); - vector weights; - for (unsigned i = 0; _weights && i < sz; ++i) { - weights.push_back(_weights[i].get_double()); - } - params_ref p; - p.set_bool("minimize_core", false); - s.updt_params(p); - return s.check_sat(sz, soft, weights.c_ptr(), max_weight.get_double()); -} - void inc_sat_display(std::ostream& out, solver& _s, unsigned sz, expr*const* soft, rational const* _weights) { inc_sat_solver& s = dynamic_cast(_s); vector weights; diff --git a/src/sat/sat_solver/inc_sat_solver.h b/src/sat/sat_solver/inc_sat_solver.h index 028f71b06..4b0bea50e 100644 --- a/src/sat/sat_solver/inc_sat_solver.h +++ b/src/sat/sat_solver/inc_sat_solver.h @@ -24,7 +24,6 @@ Notes: solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p); -lbool inc_sat_check_sat(solver& s, unsigned sz, expr*const* soft, rational const* weights, rational const& max_weight); void inc_sat_display(std::ostream& out, solver& s, unsigned sz, expr*const* soft, rational const* _weights); diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index 31c964ae0..c9fa69221 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -29,6 +29,7 @@ Revision History: #include"opt_cmds.h" #include"polynomial_cmds.h" #include"subpaving_cmds.h" +#include"smt2_extra_cmds.h" #include"smt_strategic_solver.h" #include"smt_solver.h" @@ -113,6 +114,7 @@ unsigned read_smtlib2_commands(char const * file_name) { install_polynomial_cmds(ctx); install_subpaving_cmds(ctx); install_opt_cmds(ctx); + install_smt2_extra_cmds(ctx); g_cmd_context = &ctx; signal(SIGINT, on_ctrl_c); diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 3c67cadcf..26395f9ab 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -184,13 +184,13 @@ void asserted_formulas::get_assertions(ptr_vector & result) { } void asserted_formulas::push_scope() { - SASSERT(inconsistent() || m_asserted_qhead == m_asserted_formulas.size()); + SASSERT(inconsistent() || m_asserted_qhead == m_asserted_formulas.size() || m_manager.canceled()); TRACE("asserted_formulas_scopes", tout << "push:\n"; display(tout);); m_scopes.push_back(scope()); m_macro_manager.push_scope(); scope & s = m_scopes.back(); s.m_asserted_formulas_lim = m_asserted_formulas.size(); - SASSERT(inconsistent() || s.m_asserted_formulas_lim == m_asserted_qhead); + SASSERT(inconsistent() || s.m_asserted_formulas_lim == m_asserted_qhead || m_manager.canceled()); s.m_inconsistent_old = m_inconsistent; m_defined_names.push(); m_bv_sharing.push_scope(); diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 739af8bfe..178b2117f 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -1,4 +1,4 @@ -def_module_params(module_name='smt', +def_module_params(module_name='smt', class_name='smt_params_helper', description='smt solver based on lazy smt', export=True, @@ -17,7 +17,7 @@ def_module_params(module_name='smt', ('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'), ('refine_inj_axioms', BOOL, True, 'refine injectivity axioms'), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), - ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), + ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), ('max_conflicts', UINT, UINT_MAX, 'maximum number of conflicts before giving up.'), ('mbqi', BOOL, True, 'model based quantifier instantiation (MBQI)'), ('mbqi.max_cexs', UINT, 1, 'initial maximal number of counterexamples used in MBQI, each counterexample generates a quantifier instantiation'), @@ -62,5 +62,6 @@ def_module_params(module_name='smt', ('dack.gc_inv_decay', DOUBLE, 0.8, 'Dynamic ackermannization garbage collection decay'), ('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded'), ('core.validate', BOOL, False, 'validate unsat core produced by SMT context'), - ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context') + ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'), + ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances') )) diff --git a/src/smt/smt2_extra_cmds.cpp b/src/smt/smt2_extra_cmds.cpp new file mode 100644 index 000000000..901810442 --- /dev/null +++ b/src/smt/smt2_extra_cmds.cpp @@ -0,0 +1,47 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + smt2_extra_cmds.cpp + +Abstract: + + Additional SMT-specific commands. + +Author: + + Christoph (cwinter) 2017-01-16 + +Notes: + +--*/ +#include"cmd_context.h" +#include"smt2parser.h" +#include"smt2_extra_cmds.h" + +class include_cmd : public cmd { + char const * m_filename; +public: + include_cmd() : cmd("include"), m_filename(0) {} + virtual char const * get_usage() const { return ""; } + virtual char const * get_descr(cmd_context & ctx) const { return "include a file"; } + virtual unsigned get_arity() const { return 1; } + virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_STRING; } + virtual void set_next_arg(cmd_context & ctx, char const * val) { m_filename = val; } + virtual void failure_cleanup(cmd_context & ctx) {} + virtual void execute(cmd_context & ctx) { + std::ifstream is(m_filename); + if (is.bad() || is.fail()) + throw cmd_exception(std::string("failed to open file '") + m_filename + "'"); + parse_smt2_commands(ctx, is, false, params_ref(), m_filename); + is.close(); + } + virtual void prepare(cmd_context & ctx) { reset(ctx); } + virtual void reset(cmd_context & ctx) { m_filename = 0; } + virtual void finalize(cmd_context & ctx) { reset(ctx); } +}; + +void install_smt2_extra_cmds(cmd_context & ctx) { + ctx.insert(alloc(include_cmd)); +} \ No newline at end of file diff --git a/src/smt/smt2_extra_cmds.h b/src/smt/smt2_extra_cmds.h new file mode 100644 index 000000000..947f5ed7a --- /dev/null +++ b/src/smt/smt2_extra_cmds.h @@ -0,0 +1,26 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + smt2_extra_cmds.h + +Abstract: + + Additional SMT-specific commands. + +Author: + + Christoph (cwinter) 2017-01-16 + +Notes: + +--*/ +#ifndef SMT2_EXTRA_CMDS_H_ +#define SMT2_EXTRA_CMDS_H_ + +class cmd_context; + +void install_smt2_extra_cmds(cmd_context & ctx); + +#endif /* SMT2_EXTRA_CMDS_H_ */ diff --git a/src/smt/smt_bool_var_data.h b/src/smt/smt_bool_var_data.h index e65036d9c..af0b7f9d2 100644 --- a/src/smt/smt_bool_var_data.h +++ b/src/smt/smt_bool_var_data.h @@ -24,7 +24,9 @@ Revision History: namespace smt { struct bool_var_data { + private: b_justification m_justification; + public: unsigned m_scope_lvl:24; //!< scope level of when the variable was assigned. unsigned m_mark:1; unsigned m_assumption:1; @@ -45,6 +47,14 @@ namespace smt { public: unsigned get_intern_level() const { return m_iscope_lvl; } + + b_justification justification() const { return m_justification; } + + void set_axiom() { m_justification = b_justification::mk_axiom(); } + + void set_null_justification() { m_justification = null_b_justification; } + + void set_justification(b_justification const& j) { m_justification = j; } bool is_atom() const { return m_atom; } diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 4568abb55..7dd9144fe 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -496,13 +496,15 @@ namespace smt { unsigned idx = skip_literals_above_conflict_level(); + TRACE("conflict", m_ctx.display_literal_verbose(tout, not_l); m_ctx.display(tout << " ", conflict);); + // save space for first uip m_lemma.push_back(null_literal); m_lemma_atoms.push_back(0); unsigned num_marks = 0; if (not_l != null_literal) { - TRACE("conflict", tout << "not_l: "; m_ctx.display_literal(tout, not_l); tout << "\n";); + TRACE("conflict", tout << "not_l: "; m_ctx.display_literal_verbose(tout, not_l); tout << "\n";); process_antecedent(not_l, num_marks); } @@ -514,7 +516,7 @@ namespace smt { get_manager().trace_stream() << "\n"; } - TRACE("conflict", tout << "processing consequent: "; m_ctx.display_literal(tout, consequent); tout << "\n"; + TRACE("conflict", tout << "processing consequent: "; m_ctx.display_literal_verbose(tout, consequent); tout << "\n"; tout << "num_marks: " << num_marks << ", js kind: " << js.get_kind() << "\n";); SASSERT(js != null_b_justification); switch (js.get_kind()) { @@ -1076,6 +1078,7 @@ namespace smt { return true; SASSERT(js.get_kind() != b_justification::BIN_CLAUSE); CTRACE("visit_b_justification_bug", js.get_kind() == b_justification::AXIOM, tout << "l: " << l << "\n"; m_ctx.display(tout);); + if (js.get_kind() == b_justification::AXIOM) return true; SASSERT(js.get_kind() != b_justification::AXIOM); @@ -1089,14 +1092,17 @@ namespace smt { i = 1; } else { + SASSERT(cls->get_literal(1) == l); if (get_proof(~cls->get_literal(0)) == 0) visited = false; i = 2; } } - for (; i < num_lits; i++) + for (; i < num_lits; i++) { + SASSERT(cls->get_literal(i) != l); if (get_proof(~cls->get_literal(i)) == 0) visited = false; + } return visited; } else @@ -1251,14 +1257,19 @@ namespace smt { } tout << "\n";); init_mk_proof(); - literal consequent = false_literal; - if (not_l != null_literal) - consequent = ~not_l; - visit_b_justification(consequent, conflict); - if (not_l != null_literal) + literal consequent; + if (not_l == null_literal) { + consequent = false_literal; + } + else { + consequent = ~not_l; m_todo_pr.push_back(tp_elem(not_l)); + } + visit_b_justification(consequent, conflict); + while (!m_todo_pr.empty()) { tp_elem & elem = m_todo_pr.back(); + switch (elem.m_kind) { case tp_elem::EQUALITY: { enode * lhs = elem.m_lhs; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 05baff532..3bb4996c7 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -261,10 +261,11 @@ namespace smt { m_assignment[false_literal.index()] = l_false; if (m_manager.proofs_enabled()) { proof * pr = m_manager.mk_true_proof(); - m_bdata[true_bool_var].m_justification = b_justification(mk_justification(justification_proof_wrapper(*this, pr))); + + set_justification(true_bool_var, m_bdata[true_bool_var], b_justification(mk_justification(justification_proof_wrapper(*this, pr)))); } else { - m_bdata[true_bool_var].m_justification = b_justification::mk_axiom(); + m_bdata[true_bool_var].set_axiom(); } m_true_enode = mk_enode(t, true, true, false); // internalizer is marking enodes as interpreted whenever the associated ast is a value and a constant. @@ -292,6 +293,12 @@ namespace smt { std::swap(lhs, rhs); return m_manager.mk_eq(lhs, rhs); } + + void context::set_justification(bool_var v, bool_var_data& d, b_justification const& j) { + SASSERT(validate_justification(v, d, j)); + d.set_justification(j); + } + void context::assign_core(literal l, b_justification j, bool decision) { TRACE("assign_core", tout << (decision?"decision: ":"propagating: ") << l << " "; @@ -302,7 +309,7 @@ namespace smt { m_assignment[l.index()] = l_true; m_assignment[(~l).index()] = l_false; bool_var_data & d = get_bdata(l.var()); - d.m_justification = j; + set_justification(l.var(), d, j); d.m_scope_lvl = m_scope_lvl; if (m_fparams.m_restart_adaptive && d.m_phase_available) { m_agility *= m_fparams.m_agility_factor; @@ -1406,7 +1413,8 @@ namespace smt { else { TRACE("add_diseq", display_eq_detail(tout, bool_var2enode(v));); if (!add_diseq(get_enode(lhs), get_enode(rhs)) && !inconsistent()) { - set_conflict(b_justification(mk_justification(eq_propagation_justification(get_enode(lhs), get_enode(rhs)))), ~l); + literal n_eq = literal(l.var(), true); + set_conflict(b_justification(mk_justification(eq_propagation_justification(get_enode(lhs), get_enode(rhs)))), n_eq); } } } @@ -1787,6 +1795,7 @@ namespace smt { void context::set_conflict(b_justification js, literal not_l) { if (!inconsistent()) { + TRACE("set_conflict", display_literal_verbose(tout, not_l); display(tout, js); ); m_conflict = js; m_not_l = not_l; } @@ -2042,7 +2051,7 @@ namespace smt { m_assignment[(~l).index()] = l_undef; bool_var v = l.var(); bool_var_data & d = get_bdata(v); - d.m_justification = null_b_justification; + d.set_null_justification(); m_case_split_queue->unassign_var_eh(v); } @@ -2593,10 +2602,10 @@ namespace smt { cls->set_justification(0); m_justifications.push_back(js); } - m_bdata[v0].m_justification = b_justification(js); + set_justification(v0, m_bdata[v0], b_justification(js)); } else - m_bdata[v0].m_justification = b_justification::mk_axiom(); + m_bdata[v0].set_axiom(); } } del_clause(cls); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index c63d0614d..b9b068442 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -50,9 +50,9 @@ Revision History: #include"statistics.h" #include"progress_callback.h" -// there is a significant space overhead with allocating 1000+ contexts in +// there is a significant space overhead with allocating 1000+ contexts in // the case that each context only references a few expressions. -// Using a map instead of a vector for the literals can compress space +// Using a map instead of a vector for the literals can compress space // consumption. #ifdef SPARSE_MAP #define USE_BOOL_VAR_VECTOR 0 @@ -98,7 +98,7 @@ namespace smt { // Remark: boolean expressions can also be internalized as // enodes. Examples: boolean expression nested in an // uninterpreted function. - expr_ref_vector m_e_internalized_stack; // stack of the expressions already internalized as enodes. + expr_ref_vector m_e_internalized_stack; // stack of the expressions already internalized as enodes. ptr_vector m_justifications; @@ -116,7 +116,7 @@ namespace smt { plugin_manager m_theories; // mapping from theory_id -> theory ptr_vector m_theory_set; // set of theories for fast traversal vector m_decl2enodes; // decl -> enode (for decls with arity > 0) - cg_table m_cg_table; + cg_table m_cg_table; dyn_ack_manager m_dyn_ack_manager; struct new_eq { enode * m_lhs; @@ -140,7 +140,7 @@ namespace smt { svector m_propagated_th_eqs; svector m_propagated_th_diseqs; svector m_diseq_vector; -#endif +#endif enode * m_is_diseq_tmp; // auxiliary enode used to find congruent equality atoms. tmp_enode m_tmp_enode; @@ -161,8 +161,8 @@ namespace smt { vector m_watches; //!< per literal vector m_lit_occs; //!< index for backward subsumption svector m_bdata; //!< mapping bool_var -> data - svector m_activity; - clause_vector m_aux_clauses; + svector m_activity; + clause_vector m_aux_clauses; clause_vector m_lemmas; vector m_clauses_to_reinit; expr_ref_vector m_units_to_reassert; @@ -176,7 +176,7 @@ namespace smt { bool m_phase_cache_on; unsigned m_phase_counter; //!< auxiliary variable used to decide when to turn on/off phase caching bool m_phase_default; //!< default phase when using phase caching - + // A conflict is usually a single justification. That is, a justification // for false. If m_not_l is not null_literal, then m_conflict is a // justification for l, and the conflict is union of m_no_l and m_conflict; @@ -220,10 +220,10 @@ namespace smt { // Unsat core extraction // // ----------------------------------- - typedef u_map literal2assumption; + typedef u_map literal2assumption; literal_vector m_assumptions; literal2assumption m_literal2assumption; // maps an expression associated with a literal to the original assumption - expr_ref_vector m_unsat_core; + expr_ref_vector m_unsat_core; // ----------------------------------- // @@ -261,7 +261,7 @@ namespace smt { SASSERT(e_internalized(n)); return m_app2enode[n->get_id()]; } - + /** \brief Similar to get_enode, but returns 0 if n is to e_internalized. */ @@ -323,7 +323,7 @@ namespace smt { literal enode2literal(enode const * n) const { SASSERT(n->is_bool()); return n == m_false_enode ? false_literal : literal(enode2bool_var(n)); - } + } unsigned get_num_bool_vars() const { return m_b_internalized_stack.size(); @@ -336,7 +336,7 @@ namespace smt { bool_var_data const & get_bdata(bool_var v) const { return m_bdata[v]; } - + lbool get_lit_assignment(unsigned lit_idx) const { return static_cast(m_assignment[lit_idx]); } @@ -349,8 +349,8 @@ namespace smt { return get_assignment(literal(v)); } - literal_vector const & assigned_literals() const { - return m_assigned_literals; + literal_vector const & assigned_literals() const { + return m_assigned_literals; } lbool get_assignment(expr * n) const; @@ -363,9 +363,11 @@ namespace smt { void get_assignments(expr_ref_vector& assignments); b_justification get_justification(bool_var v) const { - return get_bdata(v).m_justification; + return get_bdata(v).justification(); } + void set_justification(bool_var v, bool_var_data& d, b_justification const& j); + bool has_th_justification(bool_var v, theory_id th_id) const { b_justification js = get_justification(v); return js.get_kind() == b_justification::JUSTIFICATION && js.get_justification()->get_from_theory() == th_id; @@ -423,7 +425,7 @@ namespace smt { unsigned get_assign_level(literal l) const { return get_assign_level(l.var()); } - + /** \brief Return the scope level when v was internalized. */ @@ -434,7 +436,7 @@ namespace smt { theory * get_theory(theory_id th_id) const { return m_theories.get_plugin(th_id); } - + ptr_vector::const_iterator begin_theories() const { return m_theories.begin(); } @@ -448,7 +450,7 @@ namespace smt { } unsigned get_base_level() const { - return m_base_lvl; + return m_base_lvl; } bool at_base_level() const { @@ -468,11 +470,11 @@ namespace smt { } expr * bool_var2expr(bool_var v) const { - return m_bool_var2expr[v]; + return m_bool_var2expr[v]; } - + void literal2expr(literal l, expr_ref & result) const { - if (l == true_literal) + if (l == true_literal) result = m_manager.mk_true(); else if (l == false_literal) result = m_manager.mk_false(); @@ -499,7 +501,7 @@ namespace smt { unsigned id = decl->get_decl_id(); return id < m_decl2enodes.size() ? m_decl2enodes[id].begin() : 0; } - + enode_vector::const_iterator end_enodes_of(func_decl const * decl) const { unsigned id = decl->get_decl_id(); return id < m_decl2enodes.size() ? m_decl2enodes[id].end() : 0; @@ -589,7 +591,7 @@ namespace smt { void push_scope(); unsigned pop_scope_core(unsigned num_scopes); - + void pop_scope(unsigned num_scopes); void undo_trail_stack(unsigned old_size); @@ -615,13 +617,13 @@ namespace smt { bool is_empty_clause(clause const * c) const; void cache_generation(unsigned new_scope_lvl); - + void cache_generation(clause const * cls, unsigned new_scope_lvl); void cache_generation(unsigned num_lits, literal const * lits, unsigned new_scope_lvl); void cache_generation(expr * n, unsigned new_scope_lvl); - + void reset_cache_generation(); void reinit_clauses(unsigned num_scopes, unsigned num_bool_vars); @@ -630,14 +632,14 @@ namespace smt { // ----------------------------------- // - // Internalization + // Internalization // // ----------------------------------- public: bool b_internalized(expr const * n) const { return get_bool_var_of_id_option(n->get_id()) != null_bool_var; } - + bool lit_internalized(expr const * n) const { return m_manager.is_false(n) || (m_manager.is_not(n) ? b_internalized(to_app(n)->get_arg(0)) : b_internalized(n)); } @@ -646,7 +648,7 @@ namespace smt { return m_app2enode.get(n->get_id(), 0) != 0; } - unsigned get_num_b_internalized() const { + unsigned get_num_b_internalized() const { return m_b_internalized_stack.size(); } @@ -654,7 +656,7 @@ namespace smt { return m_b_internalized_stack.get(idx); } - unsigned get_num_e_internalized() const { + unsigned get_num_e_internalized() const { return m_e_internalized_stack.size(); } @@ -691,9 +693,9 @@ namespace smt { void ts_visit_child(expr * n, bool gate_ctx, svector & tcolors, svector & fcolors, svector & todo, bool & visited); bool ts_visit_children(expr * n, bool gate_ctx, svector & tcolors, svector & fcolors, svector & todo); - + void top_sort_expr(expr * n, svector & sorted_exprs); - + void assert_default(expr * n, proof * pr); void assert_distinct(app * n, proof * pr); @@ -721,7 +723,7 @@ namespace smt { void internalize_term(app * n); void internalize_ite_term(app * n); - + bool internalize_theory_term(app * n); void internalize_uninterpreted(app * n); @@ -752,7 +754,7 @@ namespace smt { bool simplify_aux_lemma_literals(unsigned & num_lits, literal * lits); void mark_for_reinit(clause * cls, unsigned scope_lvl, bool reinternalize_atoms); - + unsigned get_max_iscope_lvl(unsigned num_lits, literal const * lits) const; bool use_binary_clause_opt(literal l1, literal l2, bool lemma) const; @@ -784,7 +786,7 @@ namespace smt { void add_and_rel_watches(app * n); void add_or_rel_watches(app * n); - + void add_ite_rel_watches(app * n); void mk_not_cnstr(app * n); @@ -796,7 +798,7 @@ namespace smt { void mk_iff_cnstr(app * n); void mk_ite_cnstr(app * n); - + bool lit_occs_enabled() const { return m_fparams.m_phase_selection==PS_OCCURRENCE; } void add_lit_occs(clause * cls); @@ -819,7 +821,7 @@ namespace smt { bool_var mk_bool_var(expr * n); - + enode * mk_enode(app * n, bool suppress_args, bool merge_tf, bool cgc_enabled); void attach_th_var(enode * n, theory * th, theory_var v); @@ -828,7 +830,7 @@ namespace smt { justification * mk_justification(Justification const & j) { justification * js = new (m_region) Justification(j); SASSERT(js->in_region()); - if (js->has_del_eh()) + if (js->has_del_eh()) m_justifications.push_back(js); return js; } @@ -849,10 +851,10 @@ namespace smt { unsigned m_num_conflicts_since_lemma_gc; unsigned m_restart_threshold; unsigned m_restart_outer_threshold; - unsigned m_luby_idx; + unsigned m_luby_idx; double m_agility; unsigned m_lemma_gc_threshold; - + void assign_core(literal l, b_justification j, bool decision = false); void trace_assign(literal l, b_justification j, bool decision) const; @@ -878,7 +880,7 @@ namespace smt { friend class set_true_first_trail; void set_true_first_flag(bool_var v); - + bool try_true_first(bool_var v) const { return get_bdata(v).try_true_first(); } bool assume_eq(enode * lhs, enode * rhs); @@ -899,13 +901,13 @@ namespace smt { d.m_phase = phase; } - void force_phase(literal l) { + void force_phase(literal l) { force_phase(l.var(), !l.sign()); } bool contains_instance(quantifier * q, unsigned num_bindings, enode * const * bindings); - bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, + bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes); void set_global_generation(unsigned generation) { m_generation = generation; } @@ -958,7 +960,7 @@ namespace smt { void assign_quantifier(quantifier * q); - void set_conflict(b_justification js, literal not_l); + void set_conflict(b_justification js, literal not_l); void set_conflict(b_justification js) { set_conflict(js, null_literal); @@ -997,12 +999,12 @@ namespace smt { #define INV_ACTIVITY_LIMIT 1e-100 void rescale_bool_var_activity(); - + public: void inc_bvar_activity(bool_var v) { double & act = m_activity[v]; act += m_bvar_inc; - if (act > ACTIVITY_LIMIT) + if (act > ACTIVITY_LIMIT) rescale_bool_var_activity(); m_case_split_queue->activity_increased_eh(v); } @@ -1031,7 +1033,7 @@ namespace smt { } return false; } - + bool can_delete(clause * cls) const { if (cls->in_reinit_stack()) return false; @@ -1053,7 +1055,7 @@ namespace smt { bool validate_assumptions(unsigned num_assumptions, expr * const * assumptions); void init_assumptions(unsigned num_assumptions, expr * const * assumptions); - + void reset_assumptions(); void mk_unsat_core(); @@ -1073,9 +1075,9 @@ namespace smt { void tick(unsigned & counter) const; lbool bounded_search(); - + final_check_status final_check(); - + void check_proof(proof * pr); void forget_phase_of_vars_in_current_level(); @@ -1102,7 +1104,7 @@ namespace smt { public: // event handler for relevancy_propagator class - void relevant_eh(expr * n); + void relevant_eh(expr * n); bool is_relevant(expr * n) const { return !relevancy() || is_relevant_core(n); @@ -1126,9 +1128,9 @@ namespace smt { void mark_as_relevant(enode * n) { mark_as_relevant(n->get_owner()); } void mark_as_relevant(bool_var v) { mark_as_relevant(bool_var2expr(v)); } - + void mark_as_relevant(literal l) { mark_as_relevant(l.var()); } - + template relevancy_eh * mk_relevancy_eh(Eh const & eh) { return m_relevancy_propagator->mk_relevancy_eh(eh); @@ -1149,9 +1151,9 @@ namespace smt { void propagate_th_eqs(); void propagate_th_diseqs(); - + bool can_theories_propagate() const; - + bool propagate(); public: @@ -1167,7 +1169,7 @@ namespace smt { // ----------------------------------- // - // Pretty Printing + // Pretty Printing // // ----------------------------------- protected: @@ -1215,7 +1217,7 @@ namespace smt { void display_binary_clauses(std::ostream & out) const; void display_assignment(std::ostream & out) const; - + void display_eqc(std::ostream & out) const; void display_app_enode_map(std::ostream & out) const; @@ -1235,15 +1237,15 @@ 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; - void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, - unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs, + 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 num_antecedent_eqs, enode_pair const * antecedent_eqs, + void 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; - void display_assignment_as_smtlib2(std::ostream& out, symbol const& logic = symbol::null) const; + void display_assignment_as_smtlib2(std::ostream& out, symbol const& logic = symbol::null) const; void display_normalized_enodes(std::ostream & out) const; @@ -1289,13 +1291,13 @@ namespace smt { bool check_invariant() const; bool check_eqc_bool_assignment() const; - + bool check_missing_clause_propagation(clause_vector const & v) const; bool check_missing_bin_clause_propagation() const; bool check_missing_eq_propagation() const; - + bool check_missing_congruence() const; bool check_missing_bool_enode_propagation() const; @@ -1357,7 +1359,7 @@ namespace smt { static literal translate_literal( literal lit, context& src_ctx, context& dst_ctx, vector b2v, ast_translation& tr); - + /* \brief Utilities for consequence finding. */ @@ -1366,7 +1368,7 @@ namespace smt { u_map m_antecedents; void extract_fixed_consequences(literal lit, obj_map& var2val, index_set const& assumptions, expr_ref_vector& conseq); void extract_fixed_consequences(unsigned& idx, obj_map& var2val, index_set const& assumptions, expr_ref_vector& conseq); - + void display_consequence_progress(std::ostream& out, unsigned it, unsigned nv, unsigned fixed, unsigned unfixed, unsigned eq); unsigned delete_unfixed(obj_map& var2val, expr_ref_vector& unfixed); @@ -1378,9 +1380,11 @@ namespace smt { literal mk_diseq(expr* v, expr* val); - void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, + void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector const& conseq, expr_ref_vector const& unfixed); + bool validate_justification(bool_var v, bool_var_data const& d, b_justification const& j); + void justify(literal lit, index_set& s); void extract_cores(expr_ref_vector const& asms, vector& cores, unsigned& min_core_size); @@ -1426,18 +1430,18 @@ namespace smt { void pop(unsigned num_scopes); - lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true); + lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true); lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); lbool preferred_sat(expr_ref_vector const& asms, vector& cores); - + lbool setup_and_check(bool reset_cancel = true); - + // return 'true' if assertions are inconsistent. - bool reduce_assertions(); + bool reduce_assertions(); bool resource_limits_exceeded(); @@ -1462,15 +1466,15 @@ namespace smt { } bool already_internalized() const { return m_e_internalized_stack.size() > 2 || m_b_internalized_stack.size() > 1; } - + unsigned get_unsat_core_size() const { return m_unsat_core.size(); } - + expr * get_unsat_core_expr(unsigned idx) const { return m_unsat_core.get(idx); } - + void get_model(model_ref & m) const; bool update_model(bool refinalize); @@ -1478,17 +1482,17 @@ namespace smt { void get_proto_model(proto_model_ref & m) const; bool validate_model(); - + unsigned get_num_asserted_formulas() const { return m_asserted_formulas.get_num_formulas(); } unsigned get_asserted_formulas_last_level() const { return m_asserted_formulas.get_formulas_last_level(); } expr * get_asserted_formula(unsigned idx) const { return m_asserted_formulas.get_formula(idx); } - + proof * get_asserted_formula_proof(unsigned idx) const { return m_asserted_formulas.get_formula_proof(idx); } - + expr * const * get_asserted_formulas() const { return m_asserted_formulas.get_formulas(); } - + proof * const * get_asserted_formula_proofs() const { return m_asserted_formulas.get_formula_proofs(); } void get_assumptions_core(ptr_vector & result); @@ -1500,7 +1504,7 @@ namespace smt { void display_unsat_core(std::ostream & out) const; void collect_statistics(::statistics & st) const; - + void display_statistics(std::ostream & out) const; void display_istatistics(std::ostream & out) const; diff --git a/src/smt/smt_context_inv.cpp b/src/smt/smt_context_inv.cpp index 5e3b091bc..7d009a037 100644 --- a/src/smt/smt_context_inv.cpp +++ b/src/smt/smt_context_inv.cpp @@ -402,6 +402,20 @@ namespace smt { #endif + bool context::validate_justification(bool_var v, bool_var_data const& d, b_justification const& j) { + if (j.get_kind() == b_justification::CLAUSE && v != true_bool_var) { + clause* cls = j.get_clause(); + unsigned num_lits = cls->get_num_literals(); + literal l = cls->get_literal(0); + if (l.var() != v) { + l = cls->get_literal(1); + } + SASSERT(l.var() == v); + SASSERT(m_assignment[l.index()] == l_true); + } + return true; + } + bool context::validate_model() { if (!m_proto_model) { return true; diff --git a/src/smt/smt_literal.cpp b/src/smt/smt_literal.cpp index d510027f0..e6e795ed4 100644 --- a/src/smt/smt_literal.cpp +++ b/src/smt/smt_literal.cpp @@ -27,6 +27,8 @@ namespace smt { out << "true"; else if (*this == false_literal) out << "false"; + else if (*this == null_literal) + out << "null"; else if (sign()) out << "(not " << mk_pp(bool_var2expr_map[var()], m) << ")"; else diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 2ea4fea20..f80ff09f4 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -22,42 +22,62 @@ Notes: #include"smt_params.h" #include"smt_params_helper.hpp" #include"mus.h" - +#include"for_each_expr.h" +#include"ast_smt2_pp.h" +#include"func_decl_dependencies.h" +#include"dec_ref_util.h" namespace smt { class solver : public solver_na2as { - smt_params m_smt_params; - params_ref m_params; - smt::kernel m_context; - progress_callback * m_callback; - symbol m_logic; - bool m_minimizing_core; + smt_params m_smt_params; + params_ref m_params; + smt::kernel m_context; + progress_callback * m_callback; + symbol m_logic; + bool m_minimizing_core; + bool m_core_extend_patterns; + obj_map m_name2assertion; + public: - solver(ast_manager & m, params_ref const & p, symbol const & l): + solver(ast_manager & m, params_ref const & p, symbol const & l) : solver_na2as(m), m_smt_params(p), m_params(p), m_context(m, m_smt_params), - m_minimizing_core(false) { + m_minimizing_core(false), + m_core_extend_patterns(false) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); + smt_params_helper smth(p); + m_core_extend_patterns = smth.core_extend_patterns(); } - virtual solver* translate(ast_manager& m, params_ref const& p) { - solver* result = alloc(solver, m, p, m_logic); + virtual solver * translate(ast_manager & m, params_ref const & p) { + solver * result = alloc(solver, m, p, m_logic); smt::kernel::copy(m_context, result->m_context); + + ast_translation translator(get_manager(), m); + obj_map::iterator it = m_name2assertion.begin(); + obj_map::iterator end = m_name2assertion.end(); + for (; it != end; it++) + result->m_name2assertion.insert(translator(it->m_key), + translator(it->m_value)); + return result; } - + virtual ~solver() { + dec_ref_values(get_manager(), m_name2assertion); } virtual void updt_params(params_ref const & p) { m_smt_params.updt_params(p); m_params.copy(p); m_context.updt_params(p); + smt_params_helper smth(p); + m_core_extend_patterns = smth.core_extend_patterns(); } virtual void collect_param_descrs(param_descrs & r) { @@ -81,11 +101,32 @@ namespace smt { m_context.assert_expr(t); } + virtual void assert_expr(expr * t, expr * a) { + solver_na2as::assert_expr(t, a); + SASSERT(!m_name2assertion.contains(a)); + get_manager().inc_ref(t); + m_name2assertion.insert(a, t); + } + virtual void push_core() { m_context.push(); } virtual void pop_core(unsigned n) { + unsigned cur_sz = m_assumptions.size(); + if (n > 0 && cur_sz > 0) { + unsigned lvl = m_scopes.size(); + SASSERT(n <= lvl); + unsigned new_lvl = lvl - n; + unsigned old_sz = m_scopes[new_lvl]; + for (unsigned i = cur_sz - 1; i >= old_sz; i--) { + expr * key = m_assumptions[i].get(); + SASSERT(m_name2assertion.contains(key)); + expr * value = m_name2assertion.find(key); + m.dec_ref(value); + m_name2assertion.erase(key); + } + } m_context.pop(n); } @@ -97,7 +138,7 @@ namespace smt { struct scoped_minimize_core { solver& s; expr_ref_vector m_assumptions; - scoped_minimize_core(solver& s): s(s), m_assumptions(s.m_assumptions) { + scoped_minimize_core(solver& s) : s(s), m_assumptions(s.m_assumptions) { s.m_minimizing_core = true; s.m_assumptions.reset(); } @@ -114,17 +155,19 @@ namespace smt { r.push_back(m_context.get_unsat_core_expr(i)); } - if (m_minimizing_core || smt_params_helper(m_params).core_minimize() == false) { - return; - } - scoped_minimize_core scm(*this); - mus mus(*this); - mus.add_soft(r.size(), r.c_ptr()); - ptr_vector r2; - if (l_true == mus.get_mus(r2)) { - r.reset(); - r.append(r2); + if (m_minimizing_core && smt_params_helper(m_params).core_minimize()) { + scoped_minimize_core scm(*this); + mus mus(*this); + mus.add_soft(r.size(), r.c_ptr()); + ptr_vector r2; + if (l_true == mus.get_mus(r2)) { + r.reset(); + r.append(r2); + } } + + if (m_core_extend_patterns) + add_pattern_literals_to_core(r); } virtual void get_model(model_ref & m) { @@ -149,7 +192,7 @@ namespace smt { r.append(tmp.size(), tmp.c_ptr()); } - virtual ast_manager& get_manager() const { return m_context.m(); } + virtual ast_manager & get_manager() const { return m_context.m(); } virtual void set_progress_callback(progress_callback * callback) { m_callback = callback; @@ -159,12 +202,115 @@ namespace smt { virtual unsigned get_num_assertions() const { return m_context.size(); } - + virtual expr * get_assertion(unsigned idx) const { SASSERT(idx < get_num_assertions()); return m_context.get_formulas()[idx]; - } + } + struct collect_fds_proc { + ast_manager & m; + func_decl_set & m_fds; + collect_fds_proc(ast_manager & m, func_decl_set & fds) : + m(m), m_fds(fds) { + } + void operator()(var * n) {} + void operator()(app * n) { + func_decl * fd = n->get_decl(); + if (fd->get_family_id() == null_family_id) + m_fds.insert_if_not_there(fd); + } + void operator()(quantifier * n) {} + }; + + struct collect_pattern_fds_proc { + ast_manager & m; + expr_fast_mark1 m_visited; + func_decl_set & m_fds; + collect_pattern_fds_proc(ast_manager & m, func_decl_set & fds) : + m(m), m_fds(fds) { + m_visited.reset(); + } + void operator()(var * n) {} + void operator()(app * n) {} + void operator()(quantifier * n) { + collect_fds_proc p(m, m_fds); + + unsigned sz = n->get_num_patterns(); + for (unsigned i = 0; i < sz; i++) + quick_for_each_expr(p, m_visited, n->get_pattern(i)); + + sz = n->get_num_no_patterns(); + for (unsigned i = 0; i < sz; i++) + quick_for_each_expr(p, m_visited, n->get_no_pattern(i)); + } + }; + + void collect_pattern_func_decls(expr_ref & e, func_decl_set & fds) { + collect_pattern_fds_proc p(get_manager(), fds); + expr_mark visited; + for_each_expr(p, visited, e); + } + + void compute_assrtn_fds(ptr_vector & core, vector & assrtn_fds) { + assrtn_fds.resize(m_name2assertion.size()); + obj_map::iterator ait = m_name2assertion.begin(); + obj_map::iterator aend = m_name2assertion.end(); + for (unsigned i = 0; ait != aend; ait++, i++) { + if (core.contains(ait->m_key)) + continue; + collect_fds_proc p(m, assrtn_fds[i]); + expr_fast_mark1 visited; + quick_for_each_expr(p, visited, ait->m_value); + } + } + + bool fds_intersect(func_decl_set & pattern_fds, func_decl_set & assrtn_fds) { + func_decl_set::iterator it = pattern_fds.begin(); + func_decl_set::iterator end = pattern_fds.end(); + for (; it != end; it++) { + func_decl * fd = *it; + if (assrtn_fds.contains(fd)) + return true; + } + return false; + } + + void add_pattern_literals_to_core(ptr_vector & core) { + ast_manager & m = get_manager(); + expr_ref_vector new_core_literals(m); + + func_decl_set pattern_fds; + vector assrtn_fds; + + do { + new_core_literals.reset(); + + unsigned sz = core.size(); + for (unsigned i = 0; i < sz; i++) { + expr_ref name(core[i], m); + SASSERT(m_name2assertion.contains(name)); + expr_ref assrtn(m_name2assertion.find(name), m); + collect_pattern_func_decls(assrtn, pattern_fds); + } + + if (!pattern_fds.empty()) { + if (assrtn_fds.empty()) + compute_assrtn_fds(core, assrtn_fds); + + obj_map::iterator ait = m_name2assertion.begin(); + obj_map::iterator aend = m_name2assertion.end(); + for (unsigned i = 0; ait != aend; ait++, i++) { + if (!core.contains(ait->m_key) && + fds_intersect(pattern_fds, assrtn_fds[i])) + new_core_literals.push_back(ait->m_key); + } + } + + core.append(new_core_literals.size(), new_core_literals.c_ptr()); + } + while (!new_core_literals.empty()); + } }; }; diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index e396b67cc..3f153f500 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -180,7 +180,7 @@ namespace smt { final_check_status theory_wmaxsat::final_check_eh() { if (m_normalize) normalize(); - // std::cout << "cost: " << m_zcost << " min cost: " << m_zmin_cost << "\n"; + TRACE("opt", tout << "cost: " << m_zcost << " min cost: " << m_zmin_cost << "\n";); return FC_DONE; } diff --git a/src/test/main.cpp b/src/test/main.cpp index 320eddd7b..9239d0119 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -193,7 +193,6 @@ int main(int argc, char ** argv) { TST(polynomial); TST(upolynomial); TST(algebraic); - TST(polynomial_factorization); TST(prime_generator); TST(permutation); TST(nlsat); diff --git a/src/test/polynomial.cpp b/src/test/polynomial.cpp index 56eb61a11..03eb321cd 100644 --- a/src/test/polynomial.cpp +++ b/src/test/polynomial.cpp @@ -18,7 +18,6 @@ Notes: --*/ #if !defined(__clang__) #include"polynomial.h" -#include"polynomial_factorization.h" #include"polynomial_var2value.h" #include"polynomial_cache.h" #include"linear_eq_solver.h" diff --git a/src/test/polynomial_factorization.cpp b/src/test/polynomial_factorization.cpp deleted file mode 100644 index 361ca4630..000000000 --- a/src/test/polynomial_factorization.cpp +++ /dev/null @@ -1,746 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - polynomial_factorization.cpp - -Abstract: - - Testing of factorization. - -Author: - - Dejan (t-dejanj) 2011-11-29 - -Notes: - ---*/ -#include"upolynomial_factorization_int.h" -#include"timeit.h" -#include"polynomial.h" -#include"rlimit.h" -#if 0 -#include"polynomial_factorization.h" -#endif - -using std::cout; -using std::endl; - -// some prime numbers -unsigned primes[] = { - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 -}; - -// [i,l]: how many factors the Knuth example has over p_i, when i = 0 it's Z, p_1 = 2, for l=0 distinct, for l = 1 total -unsigned knuth_factors[2][11] = { - // x^8 + x^6 + 10*x^4 + 10*x^3 + 8*x^2 + 2*x + 8 - {2, 2, 3, 3, 2, 3, 1, 4, 3, 1, 1}, - {8, 2, 3, 3, 2, 3, 1, 4, 3, 1, 1}, -}; - -// [k,l,i]: how many factors the S_k has over p_i, when i = 0 it's Z, p_1 = 2, for l=0 distinct, for l = 1 total -unsigned swinnerton_dyer_factors[5][2][11] = { - // S1 = (x^2) - 2 - { - // 2, 3, 5, 7,11,13,17,19,23,29, Z - {1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1}, - {2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1} - }, - // S2 = (x^4) - 10*(x^2) + 1 - { - {1, 1, 2, 2, 2, 2, 2, 2, 4, 2, 1}, - {4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 1} - }, - // S3 = (x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576 - { - {1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 1}, - {8, 6, 4, 4, 4, 4, 4, 4, 4, 4, 1} - }, - // S4 = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225 - { - {1, 4, 3, 4, 8, 8, 8, 8, 8, 8, 1}, - {16, 12, 10, 8, 8, 8, 8, 8, 8, 8, 1} - }, - // SA = S1*S2*S3*S4 - { - //p = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, Z - { 2, 6, 3, 6, 15, 11, 16, 15, 18, 15, 1}, - {30, 21, 17, 16, 15, 15, 16, 15, 18, 15, 1} - } -}; - -int random_polynomial[20][2][11] = { - { - // 3*x^10 + 2*x^9 + 4*x^8 + 4*x^7 + 4*x^6 + x^5 + 3*x^2 + 3*x - { 4, 3, 4, 4, 3, 4, 4, 4, 3, 4, 2 }, - { 7, 7, 4, 4, 3, 4, 4, 4, 3, 4, 2 }, - }, - { - // 4*x^9 + 4*x^8 + x^7 + x^6 + 2*x^5 + 3*x^4 + 4*x^2 + 4*x - { 2, 2, 3, 3, 4, 2, 5, 3, 4, 2, 2 }, - { 5, 2, 3, 3, 4, 2, 5, 3, 5, 2, 2 }, - }, - { - // 3*x^10 + 4*x^9 + 3*x^8 + x^6 + 4*x^5 + 4*x^4 + x^2 - { 3, 2, 4, 4, 5, 3, 4, 2, 4, 5, 2 }, - { 6, 3, 5, 5, 6, 4, 5, 3, 5, 7, 3 }, - }, - { - // x^10 + 4*x^9 + x^8 + 3*x^7 + 3*x^4 + 3*x^3 + x^2 + 4*x - { 3, 4, 4, 3, 3, 3, 4, 4, 5, 3, 2 }, - { 8, 4, 4, 3, 3, 3, 4, 4, 5, 3, 2 }, - }, - { - // x^9 + 2*x^8 + 3*x^7 + x^6 + 2*x^5 + 4*x^4 + 3*x^2 - { 3, 3, 3, 3, 4, 4, 4, 3, 3, 4, 2 }, - { 5, 6, 4, 5, 5, 6, 5, 4, 4, 5, 3 }, - }, - { - // x^10 + x^9 + 4*x^7 + x^6 + 3*x^5 + x^4 + x^3 + x - { 3, 2, 3, 3, 3, 5, 3, 2, 4, 4, 2 }, - { 3, 2, 3, 3, 3, 5, 3, 2, 4, 4, 2 }, - }, - { - // 4*x^10 + 4*x^9 + x^8 + 2*x^7 + 3*x^6 + 4*x^5 + 3*x^4 + x^3 + 2*x^2 + 4*x - { 3, 3, 2, 5, 3, 4, 2, 4, 5, 5, 2 }, - { 5, 3, 2, 5, 3, 4, 2, 4, 5, 5, 2 }, - }, - { - // 3*x^10 + 4*x^9 + 3*x^8 + x^7 + x^6 + 2*x^5 + x^4 + 2*x^3 + 2*x^2 + x - { 3, 4, 6, 4, 4, 4, 4, 6, 6, 4, 3 }, - { 4, 4, 7, 4, 4, 4, 4, 6, 6, 4, 3 }, - }, - { - // 4*x^10 + x^9 + x^7 + 2*x^5 + 3*x^3 + x^2 + 4*x - { 3, 3, 3, 4, 4, 5, 4, 5, 2, 4, 2 }, - { 4, 4, 3, 4, 4, 5, 4, 5, 2, 4, 2 }, - }, - { - // x^10 + 3*x^9 + 3*x^8 + x^7 + 3*x^6 + 3*x^5 + 3*x^4 + x^2 + 3*x - { 2, 3, 4, 4, 3, 3, 4, 3, 3, 4, 2 }, - { 2, 4, 5, 4, 3, 3, 4, 3, 3, 4, 2 }, - }, - { - // x^10 + x^9 + 2*x^8 + x^7 + 4*x^6 + 2*x^5 + 3*x^4 + 4*x^3 + x^2 + 2*x - { 3, 4, 4, 3, 3, 3, 3, 4, 5, 3, 2 }, - { 4, 4, 4, 3, 3, 3, 3, 4, 5, 3, 2 }, - }, - { - // 3*x^9 + x^8 + 3*x^7 + 3*x^6 + x^5 + 2*x^4 + 4*x^3 + 4*x^2 + 3*x - { 4, 3, 3, 3, 5, 3, 6, 4, 2, 2, 2 }, - { 6, 4, 3, 3, 5, 3, 6, 4, 2, 2, 2 }, - }, - { - // 2*x^10 + 3*x^9 + 2*x^8 + 4*x^7 + x^6 + 3*x^5 + 2*x^3 + 3*x^2 + 2*x + 2 - { 3, 3, 3, 5, 4, 5, 6, 7, 4, 6, 3 }, - { 8, 4, 3, 7, 4, 5, 6, 7, 4, 7, 3 }, - }, - { - // 3*x^10 + x^9 + 4*x^8 + 2*x^7 + x^6 + 4*x^5 + x^4 + 3*x^3 + x + 2 - { 3, 3, 3, 2, 6, 4, 4, 4, 3, 3, 2 }, - { 3, 3, 3, 2, 6, 5, 4, 5, 3, 3, 2 }, - }, - { - // 4*x^10 + 2*x^9 + x^8 + x^6 + x^5 + 3*x^4 + 4*x^3 + x^2 + x - { 3, 4, 2, 4, 4, 4, 4, 2, 3, 3, 2 }, - { 6, 4, 2, 4, 4, 4, 4, 2, 3, 3, 2 }, - }, - { - // 4*x^10 + 2*x^7 + 4*x^6 + 2*x^3 + x - { 1, 3, 3, 3, 4, 4, 4, 3, 3, 2, 2 }, - { 1, 3, 3, 3, 4, 4, 4, 3, 3, 2, 2 }, - }, - { - // 4*x^10 + x^9 + x^8 + 4*x^7 + 4*x^4 + 2*x^2 + x + 4 - { 3, 4, 2, 5, 3, 6, 3, 6, 3, 3, 2 }, - { 3, 6, 2, 5, 3, 6, 3, 6, 3, 3, 2 }, - }, - { - // 3*x^10 + 2*x^8 + x^7 + x^6 + 3*x^4 + 3*x^3 + 4*x^2 + 3*x - { 4, 3, 4, 3, 3, 3, 2, 4, 4, 3, 2 }, - { 5, 4, 4, 3, 3, 3, 2, 4, 4, 3, 2 }, - }, - { - // x^10 + 2*x^9 + 2*x^6 + 4*x^3 + 4*x^2 - { 1, 2, 2, 3, 3, 4, 3, 3, 3, 3, 2 }, - { 10, 3, 3, 4, 4, 6, 4, 4, 4, 4, 3 }, - }, - { - // x^10 + 2*x^9 + 2*x^8 + 4*x^7 + 4*x^6 + x^5 + x^3 + x^2 + 3*x - { 2, 4, 2, 3, 3, 3, 5, 5, 6, 2, 2 }, - { 2, 5, 2, 3, 3, 3, 5, 5, 6, 2, 2 }, - } -}; - -#if 0 -static void tst_square_free_finite_1() { - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - // example from Knuth, p. 442 - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - // polynomials \prod_{i < p} (x - i)^i - for (unsigned prime_i = 0; prime_i < 5; ++ prime_i) - { - int p = primes[prime_i]; - - // make the polynomial - polynomial_ref f(pm); - f = x - 1; - for (int i = 2; i < p; ++ i) { - f = f*((x + (-i))^i); - } - cout << "Factoring " << f << " into square-free over Z_" << p << endl; - - // convert to univariate over Z_p - upolynomial::zp_manager upm(nm); - upm.set_zp(p); - upolynomial::numeral_vector f_u; - upm.to_numeral_vector(f, f_u); - - cout << "Input: "; upm.display(cout, f_u); cout << endl; - - // factor it - upolynomial::zp_factors f_factors(upm); - cout << "Start: " << f_factors << endl; - - upolynomial::zp_square_free_factor(upm, f_u, f_factors); - - upolynomial::numeral_vector mult; - f_factors.multiply(mult); - cout << "Multiplied: "; upm.display(cout, mult); cout << endl; - - SASSERT(upm.eq(mult, f_u)); - - // remove the temps - upm.reset(f_u); - upm.reset(mult); - } -} - -static void tst_factor_finite_1() { - - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - // example from Knuth, p. 442 - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - polynomial_ref K(pm); - K = (x^8) + (x^6) + 10*(x^4) + 10*(x^3) + 8*(x^2) + 2*x + 8; - - // factor them for all the prime numbers - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) - { - // make the Z_p - unsigned prime = primes[prime_i]; - upolynomial::zp_manager upm(nm); - upm.set_zp(prime); - - // make the polynomial in Z_p - upolynomial::numeral_vector K_u; - upm.to_numeral_vector(K, K_u); - - cout << "Factoring " << K << "("; upm.display(cout, K_u); cout << ") in Z_" << prime << endl; - cout << "Expecting " << knuth_factors[0][prime_i] << " distinct factors, " << knuth_factors[1][prime_i] << " total" << endl; - - // factor it - upolynomial::zp_factors factors(upm); - /* bool factorized = */ upolynomial::zp_factor(upm, K_u, factors); - - // check the result - unsigned distinct = factors.distinct_factors(); - unsigned total = factors.total_factors(); - - cout << "Got " << factors << endl; - cout << "Thats " << distinct << " distinct factors, " << total << " total" << endl; - - SASSERT(knuth_factors[0][prime_i] == distinct); - SASSERT(knuth_factors[1][prime_i] == total); - - upolynomial::numeral_vector multiplied; - factors.multiply(multiplied); - SASSERT(upm.eq(K_u, multiplied)); - upm.reset(multiplied); - - // remove the temp - upm.reset(K_u); - } -} - -static void tst_factor_finite_2() { - - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - // Swinnerton-Dyer polynomials (irreducible, modular factors of degree at most 2) - polynomial_ref S1 = (x^2) - 2; - polynomial_ref S2 = (x^4) - 10*(x^2) + 1; - polynomial_ref S3 = (x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576; - polynomial_ref S4 = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225; - - vector S; - S.push_back(S1); - S.push_back(S2); - S.push_back(S3); - S.push_back(S4); - S.push_back(S1*S2*S3*S4); - - // factor all the S_i them for all the prime numbers - for (unsigned S_i = 0; S_i < S.size(); ++ S_i) { - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { - unsigned prime = primes[prime_i]; - - upolynomial::zp_manager upm(nm); - upm.set_zp(prime); - - upolynomial::numeral_vector S_i_u; - upm.to_numeral_vector(S[S_i], S_i_u); - - cout << "Factoring "; upm.display(cout, S_i_u); cout << " over Z_" << prime << endl; - cout << "Expecting " << swinnerton_dyer_factors[S_i][0][prime_i] << " distinct factors, " << swinnerton_dyer_factors[S_i][1][prime_i] << " total" << endl; - - upolynomial::zp_factors factors(upm); - upolynomial::zp_factor(upm, S_i_u, factors); - - // check the result - unsigned distinct = factors.distinct_factors(); - unsigned total = factors.total_factors(); - - cout << "Got " << factors << endl; - cout << "Thats " << distinct << " distinct factors, " << total << " total" << endl; - - SASSERT(swinnerton_dyer_factors[S_i][0][prime_i] == distinct); - SASSERT(swinnerton_dyer_factors[S_i][1][prime_i] == total); - - upolynomial::numeral_vector multiplied; - factors.multiply(multiplied); - SASSERT(upm.eq(S_i_u, multiplied)); - upm.reset(multiplied); - - // remove the temp - upm.reset(S_i_u); - } - } -} - -static void tst_factor_finite_3() { - - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - // random polynomials - vector random_p; - random_p.push_back( 3*(x^10) + 2*(x^9) + 4*(x^8) + 4*(x^7) + 4*(x^6) + 1*(x^5) + 3*(x^2) + 3*x + 0 ); - random_p.push_back( 4*(x^9) + 4*(x^8) + 1*(x^7) + 1*(x^6) + 2*(x^5) + 3*(x^4) + 4*(x^2) + 4*x + 0 ); - random_p.push_back( 3*(x^10) + 4*(x^9) + 3*(x^8) + 1*(x^6) + 4*(x^5) + 4*(x^4) + 1*(x^2) + 0 ); - random_p.push_back( 1*(x^10) + 4*(x^9) + 1*(x^8) + 3*(x^7) + 3*(x^4) + 3*(x^3) + 1*(x^2) + 4*x + 0 ); - random_p.push_back( 1*(x^9) + 2*(x^8) + 3*(x^7) + 1*(x^6) + 2*(x^5) + 4*(x^4) + 3*(x^2) + 0 ); - random_p.push_back( 1*(x^10) + 1*(x^9) + 4*(x^7) + 1*(x^6) + 3*(x^5) + 1*(x^4) + 1*(x^3) + 1*x + 0 ); - random_p.push_back( 4*(x^10) + 4*(x^9) + 1*(x^8) + 2*(x^7) + 3*(x^6) + 4*(x^5) + 3*(x^4) + 1*(x^3) + 2*(x^2) + 4*x + 0 ); - random_p.push_back( 3*(x^10) + 4*(x^9) + 3*(x^8) + 1*(x^7) + 1*(x^6) + 2*(x^5) + 1*(x^4) + 2*(x^3) + 2*(x^2) + 1*x + 0 ); - random_p.push_back( 4*(x^10) + 1*(x^9) + 1*(x^7) + 2*(x^5) + 3*(x^3) + 1*(x^2) + 4*x + 0 ); - random_p.push_back( 1*(x^10) + 3*(x^9) + 3*(x^8) + 1*(x^7) + 3*(x^6) + 3*(x^5) + 3*(x^4) + 1*(x^2) + 3*x + 0 ); - random_p.push_back( 1*(x^10) + 1*(x^9) + 2*(x^8) + 1*(x^7) + 4*(x^6) + 2*(x^5) + 3*(x^4) + 4*(x^3) + 1*(x^2) + 2*x + 0 ); - random_p.push_back( 3*(x^9) + 1*(x^8) + 3*(x^7) + 3*(x^6) + 1*(x^5) + 2*(x^4) + 4*(x^3) + 4*(x^2) + 3*x + 0 ); - random_p.push_back( 2*(x^10) + 3*(x^9) + 2*(x^8) + 4*(x^7) + 1*(x^6) + 3*(x^5) + 2*(x^3) + 3*(x^2) + 2*x + 2 ); - random_p.push_back( 3*(x^10) + 1*(x^9) + 4*(x^8) + 2*(x^7) + 1*(x^6) + 4*(x^5) + 1*(x^4) + 3*(x^3) + 1*x + 2 ); - random_p.push_back( 4*(x^10) + 2*(x^9) + 1*(x^8) + 1*(x^6) + 1*(x^5) + 3*(x^4) + 4*(x^3) + 1*(x^2) + 1*x + 0 ); - random_p.push_back( 4*(x^10) + 2*(x^7) + 4*(x^6) + 2*(x^3) + 1*x + 0 ); - random_p.push_back( 4*(x^10) + 1*(x^9) + 1*(x^8) + 4*(x^7) + 4*(x^4) + 2*(x^2) + 1*x + 4 ); - random_p.push_back( 3*(x^10) + 2*(x^8) + 1*(x^7) + 1*(x^6) + 3*(x^4) + 3*(x^3) + 4*(x^2) + 3*x + 0 ); - random_p.push_back( 1*(x^10) + 2*(x^9) + 2*(x^6) + 4*(x^3) + 4*(x^2) + 0 ); - random_p.push_back( 1*(x^10) + 2*(x^9) + 2*(x^8) + 4*(x^7) + 4*(x^6) + 1*(x^5) + 1*(x^3) + 1*(x^2) + 3*x + 0 ); - - // factor all the randoms them for all the prime numbers - for (unsigned random_i = 0; random_i < random_p.size(); ++ random_i) { - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { - unsigned prime = primes[prime_i]; - - upolynomial::zp_manager upm(nm); - upm.set_zp(prime); - - upolynomial::numeral_vector poly; - upm.to_numeral_vector(random_p[random_i], poly); - - cout << "Factoring "; upm.display(cout, poly); cout << " over Z_" << prime << endl; - cout << "Expecting " << swinnerton_dyer_factors[random_i][0][prime_i] << " distinct factors, " << random_polynomial[random_i][1][prime_i] << " total" << endl; - - upolynomial::zp_factors factors(upm); - upolynomial::zp_factor(upm, poly, factors); - - // check the result - unsigned distinct = factors.distinct_factors(); - unsigned total = factors.total_factors(); - - cout << "Got " << factors << endl; - cout << "Thats " << distinct << " distinct factors, " << total << " total" << endl; - - // SASSERT(random_polynomial[random_i][0][prime_i] == distinct); - // SASSERT(random_polynomial[random_i][1][prime_i] == total); - - upolynomial::numeral_vector multiplied; - factors.multiply(multiplied); - bool equal = upm.eq(poly, multiplied); - cout << (equal ? "equal" : "not equal") << endl; - SASSERT(equal); - upm.reset(multiplied); - - // remove the temp - upm.reset(poly); - } - } -} - -static void tst_factor_enumeration() { - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - vector factors; - for (int i = 0; i < 5; ++ i) { - polynomial_ref factor(pm); - factor = x + i; - factors.push_back(factor); - } - - upolynomial::manager upm(nm); - - upolynomial::zp_manager upm_13(nm); - upm_13.set_zp(13); - upolynomial::zp_factors factors_13(upm_13); - - upolynomial::numeral constant; - nm.set(constant, 10); - factors_13.set_constant(constant); - - for (unsigned i = 0; i < 5; ++ i) { - upolynomial::numeral_vector ufactor; - upm_13.to_numeral_vector(factors[i], ufactor); - factors_13.push_back(ufactor, 1); - upm.reset(ufactor); - } - - cout << "All: " << factors_13 << endl; - - upolynomial::factorization_degree_set degrees(factors_13); - degrees.display(cout); cout << endl; - - scoped_mpz_vector left(nm), right(nm); - upolynomial::ufactorization_combination_iterator it(factors_13, degrees); - unsigned i = 0; - it.display(cout); - bool remove = false; - while (it.next(remove)) { - it.left(left); - it.right(right); - cout << "Left " << i << ": "; upm.display(cout, left); cout << endl; - cout << "Right " << i << ": "; upm.display(cout, right); cout << endl; - i ++; - if (i % 3 == 0) { - remove = true; - } else { - remove = false; - } - it.display(cout); - } - // SASSERT(i == 15); - - return; - - for (unsigned i = 0; i < 5; ++ i) { - factors_13.set_degree(i, factors_13.get_degree(i) + i); - } - cout << "Different: " << factors_13 << " of degree " << factors_13.get_degree() << endl; - upolynomial::factorization_degree_set degrees1(factors_13); - degrees1.display(cout); cout << endl; // [0, ..., 15] - - polynomial_ref tmp1 = (x^3) + 1; - polynomial_ref tmp2 = (x^5) + 2; - polynomial_ref tmp3 = (x^7) + 3; - upolynomial::numeral_vector up1, up2, up3; - upm_13.to_numeral_vector(tmp1, up1); - upm_13.to_numeral_vector(tmp2, up2); - upm_13.to_numeral_vector(tmp3, up3); - upolynomial::zp_factors tmp(upm_13); - tmp.push_back(up1, 1); - tmp.push_back(up2, 1); - tmp.push_back(up3, 1); - upm_13.reset(up1); - upm_13.reset(up2); - upm_13.reset(up3); - - cout << "Different: " << tmp << " of degree " << tmp.get_degree() << endl; - upolynomial::factorization_degree_set degrees2(tmp); - degrees2.display(cout); cout << endl; - - tmp1 = (x^2) + 1; - tmp2 = (x^10) + 2; - tmp3 = x + 3; - upm_13.to_numeral_vector(tmp1, up1); - upm_13.to_numeral_vector(tmp2, up2); - upm_13.to_numeral_vector(tmp3, up3); - tmp.clear(); - tmp.push_back(up1, 2); - tmp.push_back(up2, 1); - tmp.push_back(up3, 1); - cout << "Different: " << tmp << " of degree " << tmp.get_degree() << endl; - upm_13.reset(up1); - upm_13.reset(up2); - upm_13.reset(up3); - upolynomial::factorization_degree_set degrees3(tmp); - degrees3.display(cout); cout << endl; - degrees1.intersect(degrees3); - degrees1.display(cout); cout << endl; -} - -static void tst_factor_square_free_univariate_1(unsigned max_length) { - - polynomial::numeral_manager nm; - upolynomial::numeral test; - upolynomial::numeral p; - nm.set(test, -9); - nm.set(p, 5); - nm.mod(test, p, test); - - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - cout << "R. = QQ['x']" << endl; - - // let's start with \prod (p_i x^{p_{i+1} - p_{i+1}) - unsigned n_primes = sizeof(primes)/sizeof(unsigned); - max_length = std::min(max_length, n_primes); - for(unsigned length = 1; length < max_length; ++ length) { - - // starting from prime_i going for length - for(unsigned start_i = 0; start_i < n_primes; ++ start_i) { - - polynomial_ref f(pm); - - bool first = true; - for (unsigned prime_i = 0; prime_i < length; ++ prime_i) { - int p1 = primes[(start_i + prime_i) % n_primes]; - int p2 = primes[(start_i + prime_i + 1) % n_primes]; - if (first) { - f = (p1*(x^p2) - p2); - first = false; - } else { - f = f*(p1*(x^p2) - p2); - } - } - - upolynomial::manager upm(nm); - scoped_mpz_vector f_u(nm); - upm.to_numeral_vector(f, f_u); - - cout << "factoring "; upm.display(cout, f_u); cout << endl; - cout << "expecting " << length << " factors "; - upolynomial::factors factors(upm); - /* bool ok = */ upolynomial::factor_square_free(upm, f_u, factors); - cout << "got " << factors << endl; - - SASSERT(factors.distinct_factors() == length); - } - } -} - -static void tst_factor_square_free_univariate_2() { - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - // Swinnerton-Dyer polynomials (irreducible, modular factors of degree at most 2) - polynomial_ref S1 = (x^2) - 2; - polynomial_ref S2 = (x^4) - 10*(x^2) + 1; - polynomial_ref S3 = (x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576; - polynomial_ref S4 = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225; - - vector S; - S.push_back(S1); - S.push_back(S2); - S.push_back(S3); - S.push_back(S4); - - upolynomial::manager upm(nm); - - // factor all the S_i them for all the prime numbers - for (unsigned S_i = 0; S_i < S.size(); ++ S_i) { - upolynomial::numeral_vector S_i_u; - upm.to_numeral_vector(S[S_i], S_i_u); - - cout << "Factoring "; upm.display(cout, S_i_u); cout << " over Z " << endl; - upolynomial::factors factors(upm); - upolynomial::factor_square_free(upm, S_i_u, factors); - - // check the result - cout << "Got " << factors << endl; - - // remove the temp - upm.reset(S_i_u); - } -} - -static void tst_factor_square_free_univariate_3() { - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - polynomial_ref deg70 = (x^70) - 6*(x^65) - (x^60) + 60*(x^55) - 54*(x^50) - 230*(x^45) + 274*(x^40) + 542*(x^35) - 615*(x^30) - 1120*(x^25) + 1500*(x^20) - 160*(x^15) - 395*(x^10) + 76*(x^5) + 34; - - upolynomial::manager upm(nm); - upolynomial::numeral_vector deg70_u; - - upm.to_numeral_vector(deg70, deg70_u); - - cout << "Factoring "; upm.display(cout, deg70_u); cout << " over Z " << endl; - upolynomial::factors factors(upm); - upolynomial::factor_square_free(upm, deg70_u, factors); - - cout << "Got " << factors << endl; - - upm.reset(deg70_u); -} -#endif - -void tst_factor_swinnerton_dyer_big(unsigned max) { - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - vector roots; - vector vars; - - unsigned n = std::min(max, static_cast(sizeof(primes)/sizeof(unsigned))); - for(unsigned prime_i = 0; prime_i < n; ++ prime_i) { - - int prime = primes[prime_i]; - - cout << "Computing Swinnerton-Dyer[" << prime_i + 1 << "]" << endl; - - polynomial_ref y(pm); - vars.push_back(pm.mk_var()); - y = pm.mk_polynomial(vars.back()); - - polynomial_ref p(pm); - p = (y^2) - prime; - roots.push_back(p); - - polynomial_ref computation = x; - for (unsigned i = 0; i < roots.size(); ++ i) { - polynomial_ref var(pm); - var = pm.mk_polynomial(vars[i]); - computation = computation - var; - } - - { - timeit timer(true, "computing swinnerton-dyer"); - - for (unsigned i = 0; i < roots.size(); ++ i) { - polynomial_ref tmp(pm); - pm.resultant(computation, roots[i], vars[i], tmp); - computation = tmp; - } - } - - cout << "Computed Swinnerton-Dyer[" << prime_i + 1 << "], degree = " << pm.total_degree(computation) << ", size = " << pm.size(computation) << endl; - - cout << "Starting factoring " << endl; - - { - timeit timer(true, "factoring swinnerton-dyer"); - - reslimit rl; - upolynomial::manager upm(rl, nm); - scoped_mpz_vector sd_u(nm); - upm.to_numeral_vector(computation, sd_u); - upolynomial::factors factors(upm); - upolynomial::factor_square_free(upm, sd_u, factors); - cout << "Got " << factors.distinct_factors() << " factors" << endl; - } - - } -} - -static void tst_factor_square_free_multivariate_1(unsigned max_n) { -#if 0 - polynomial::numeral_manager nm; - upolynomial::numeral test; - upolynomial::numeral p; - nm.set(test, -9); - nm.set(p, 5); - nm.mod(test, p, test); - - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - polynomial_ref y(pm); - y = pm.mk_polynomial(pm.mk_var()); - - // lets start simple x^n - y^n - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { - unsigned prime = primes[prime_i]; - - if (prime > max_n) { - break; - } - - polynomial_ref f = (x^prime) - (y^prime); - cout << "factoring: " << f << endl; - - // factor - polynomial::factors factors(pm); - polynomial::factor_square_free_primitive(f, factors); - - cout << "got: " << factors << endl; - } -#endif -} - - -void tst_polynomial_factorization() { - - enable_trace("polynomial::factorization"); - // enable_trace("polynomial::factorization::bughunt"); - enable_trace("polynomial::factorization::multivariate"); - // enable_trace("upolynomial"); - - // Z_p square-free factorization tests - // tst_square_free_finite_1(); - - // Z_p factorization tests - // tst_factor_finite_1(); - // tst_factor_finite_2(); - // tst_factor_finite_3(); - - // Z factorization - // tst_factor_enumeration(); - // tst_factor_square_free_univariate_1(3); - // tst_factor_square_free_univariate_2(); - // tst_factor_square_free_univariate_3(); - // tst_factor_swinnerton_dyer_big(3); - - // Multivariate factorization - tst_factor_square_free_multivariate_1(3); -}