diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 7ac026673..2c8d93acd 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -26,6 +26,10 @@ Version 4.3.2 - Fixed crash reported at http://z3.codeplex.com/workitem/10 +- Removed auxiliary constants created by the nnf tactic from Z3 models. + +- Fixed problem in the pretty printer. It was not introducing quotes for attribute names such as |foo:10|. + Version 4.3.1 ============= diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 381f92def..3ffa7e313 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -75,6 +75,8 @@ VER_BUILD=None VER_REVISION=None PREFIX='/usr' GMP=False +VS_PAR=False +VS_PAR_NUM=8 def is_windows(): return IS_WINDOWS @@ -362,6 +364,8 @@ def display_help(exit_code): if not IS_WINDOWS: print " -p <dir>, --prefix=<dir> installation prefix (default: %s)." % PREFIX print " -y <dir>, --pydir=<dir> installation prefix for Z3 python bindings (default: %s)." % PYTHON_PACKAGE_DIR + else: + print " --parallel=num use cl option /MP with 'num' parallel processes" print " -b <sudir>, --build=<subdir> subdirectory where Z3 will be built (default: build)." print " -d, --debug compile Z3 in debug mode." print " -t, --trace enable tracing in release mode." @@ -391,13 +395,13 @@ def display_help(exit_code): # Parse configuration option for mk_make script def parse_options(): - global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE + global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM global DOTNET_ENABLED, JAVA_ENABLED, STATIC_LIB, PREFIX, GMP, PYTHON_PACKAGE_DIR try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:dsxhmcvtnp:gjy:', ['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', - 'trace', 'nodotnet', 'staticlib', 'prefix=', 'gmp', 'java', 'pydir=']) + 'trace', 'nodotnet', 'staticlib', 'prefix=', 'gmp', 'java', 'pydir=', 'parallel=']) except: print "ERROR: Invalid command line option" display_help(1) @@ -429,8 +433,11 @@ def parse_options(): DOTNET_ENABLED = False elif opt in ('--staticlib'): STATIC_LIB = True - elif opt in ('-p', '--prefix'): + elif not IS_WINDOWS and opt in ('-p', '--prefix'): PREFIX = arg + elif IS_WINDOWS and opt == '--parallel': + VS_PAR = True + VS_PAR_NUM = int(arg) elif opt in ('-y', '--pydir'): PYTHON_PACKAGE_DIR = arg mk_dir(PYTHON_PACKAGE_DIR) @@ -656,8 +663,32 @@ class Component: out.write(' -I%s' % get_component(dep).to_src_dir) out.write('\n') mk_dir(os.path.join(BUILD_DIR, self.build_dir)) - for cppfile in get_cpp_files(self.src_dir): - self.add_cpp_rules(out, include_defs, cppfile) + if VS_PAR and IS_WINDOWS: + cppfiles = get_cpp_files(self.src_dir) + dependencies = set() + for cppfile in cppfiles: + dependencies.add(os.path.join(self.to_src_dir, cppfile)) + self.add_rule_for_each_include(out, cppfile) + includes = extract_c_includes(os.path.join(self.src_dir, cppfile)) + for include in includes: + owner = self.find_file(include, cppfile) + dependencies.add('%s.node' % os.path.join(owner.build_dir, include)) + for cppfile in cppfiles: + out.write('%s$(OBJ_EXT) ' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])) + out.write(': ') + for dep in dependencies: + out.write(dep) + out.write(' ') + out.write('\n') + out.write('\t@$(CXX) $(CXXFLAGS) /MP%s $(%s)' % (VS_PAR_NUM, include_defs)) + for cppfile in cppfiles: + out.write(' ') + out.write(os.path.join(self.to_src_dir, cppfile)) + out.write('\n') + out.write('\tmove *.obj %s\n' % self.build_dir) + else: + for cppfile in get_cpp_files(self.src_dir): + self.add_cpp_rules(out, include_defs, cppfile) # Return true if the component should be included in the all: rule def main_component(self): @@ -933,10 +964,8 @@ class DLLComponent(Component): mk_dir(os.path.join(dist_path, 'bin')) shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name), '%s.dll' % os.path.join(dist_path, 'bin', self.dll_name)) - if self.static: - mk_dir(os.path.join(dist_path, 'bin')) - shutil.copy('%s.lib' % os.path.join(build_path, self.dll_name), - '%s.lib' % os.path.join(dist_path, 'bin', self.dll_name)) + shutil.copy('%s.lib' % os.path.join(build_path, self.dll_name), + '%s.lib' % os.path.join(dist_path, 'bin', self.dll_name)) class DotNetDLLComponent(Component): def __init__(self, name, dll_name, path, deps, assembly_info_dir): @@ -1042,6 +1071,11 @@ class JavaDLLComponent(Component): def main_component(self): return is_java_enabled() + def mk_win_dist(self, build_path, dist_path): + if JAVA_ENABLED: + mk_dir(os.path.join(dist_path, 'bin')) + shutil.copy('%s.jar' % os.path.join(build_path, self.package_name), + '%s.jar' % os.path.join(dist_path, 'bin', self.package_name)) class ExampleComponent(Component): def __init__(self, name, path): @@ -1250,12 +1284,12 @@ def mk_config(): 'SLINK_FLAGS=/nologo /LDd\n') if not VS_X64: config.write( - 'CXXFLAGS=/c /Zi /nologo /openmp /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- /arch:SSE2\n' + 'CXXFLAGS=/c /Zi /nologo /openmp /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- /arch:SSE2\n' 'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') else: config.write( - 'CXXFLAGS=/c /Zi /nologo /openmp /W3 /WX- /Od /Oy- /D WIN32 /D _AMD64_ /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze-\n' + 'CXXFLAGS=/c /Zi /nologo /openmp /W3 /WX- /Od /Oy- /D WIN32 /D _AMD64_ /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze-\n' 'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') else: diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 57ae66b03..dd50a3977 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -16,13 +16,15 @@ import subprocess import zipfile from mk_exception import * from mk_project import * +import mk_util BUILD_DIR='build-dist' -BUILD_X64_DIR='build-dist/x64' -BUILD_X86_DIR='build-dist/x86' +BUILD_X64_DIR=os.path.join('build-dist', 'x64') +BUILD_X86_DIR=os.path.join('build-dist', 'x86') VERBOSE=True DIST_DIR='dist' FORCE_MK=False +JAVA_ENABLED=True def set_verbose(flag): global VERBOSE @@ -38,8 +40,8 @@ def mk_dir(d): def set_build_dir(path): global BUILD_DIR BUILD_DIR = path - BUILD_X86_DIR = '%s/x86' % path - BUILD_X64_DIR = '%s/x64' % path + BUILD_X86_DIR = os.path.join(path, 'x86') + BUILD_X64_DIR = os.path.join(path, 'x64') mk_dir(BUILD_X86_DIR) mk_dir(BUILD_X64_DIR) @@ -52,16 +54,18 @@ def display_help(): print " -s, --silent do not print verbose messages." print " -b <sudir>, --build=<subdir> subdirectory where x86 and x64 Z3 versions will be built (default: build-dist)." print " -f, --force force script to regenerate Makefiles." + print " --nojava do not include Java bindings in the binary distribution files." exit(0) # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK + global FORCE_MK, JAVA_ENABLED path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', 'silent', - 'force' + 'force', + 'nojava' ]) for opt, arg in options: if opt in ('-b', '--build'): @@ -74,18 +78,22 @@ def parse_options(): display_help() elif opt in ('-f', '--force'): FORCE_MK = True + elif opt == '--nojava': + JAVA_ENABLED = False else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) # Check whether build directory already exists or not def check_build_dir(path): - return os.path.exists(path) and os.path.exists('%s/Makefile' % path) + return os.path.exists(path) and os.path.exists(os.path.join(path, 'Makefile')) # 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", "scripts/mk_make.py", "-b", path] + opts = ["python", os.path.join('scripts', 'mk_make.py'), "-b", path] + if JAVA_ENABLED: + opts.append('--java') if x64: opts.append('-x') if subprocess.call(opts) != 0: @@ -147,8 +155,12 @@ def mk_dist_dir_core(x64): else: platform = "x86" build_path = BUILD_X86_DIR - dist_path = '%s/z3-%s.%s.%s-%s' % (DIST_DIR, major, minor, build, platform) + dist_path = os.path.join(DIST_DIR, 'z3-%s.%s.%s-%s' % (major, minor, build, platform)) mk_dir(dist_path) + if JAVA_ENABLED: + # HACK: Propagate JAVA_ENABLED flag to mk_util + # TODO: fix this hack + mk_util.JAVA_ENABLED = JAVA_ENABLED mk_win_dist(build_path, dist_path) if is_verbose(): print "Generated %s distribution folder at '%s'" % (platform, dist_path) @@ -225,7 +237,7 @@ def cp_vs_runtime_core(x64): path = '%sredist\\%s' % (vcdir, platform) VS_RUNTIME_FILES = [] os.path.walk(path, cp_vs_runtime_visitor, '*.dll') - bin_dist_path = '%s/%s/bin' % (DIST_DIR, get_dist_path(x64)) + bin_dist_path = os.path.join(DIST_DIR, get_dist_path(x64), 'bin') for f in VS_RUNTIME_FILES: shutil.copy(f, bin_dist_path) if is_verbose(): @@ -236,8 +248,8 @@ def cp_vs_runtime(): cp_vs_runtime_core(False) def cp_license(): - shutil.copy("LICENSE.txt", "%s/%s" % (DIST_DIR, get_dist_path(True))) - shutil.copy("LICENSE.txt", "%s/%s" % (DIST_DIR, get_dist_path(False))) + 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))) # Entry point def main(): diff --git a/scripts/trackall.sh b/scripts/trackall.sh new file mode 100755 index 000000000..d8351af24 --- /dev/null +++ b/scripts/trackall.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Script for "cloning" (and tracking) all branches at codeplex. +# On Windows, this script must be executed in the "git Bash" console. +for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do + git branch --track ${branch##*/} $branch +done +git fetch --all +git pull --all diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index afe301ddf..1ad2b8222 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -501,7 +501,12 @@ class smt2_printer { } format * pp_simple_attribute(char const * attr, symbol const & s) { - return mk_compose(m(), mk_string(m(), attr), mk_string(m(), s.str().c_str())); + std::string str; + if (is_smt2_quoted_symbol(s)) + str = mk_smt2_quoted_symbol(s); + else + str = s.str(); + return mk_compose(m(), mk_string(m(), attr), mk_string(m(), str.c_str())); } format * pp_labels(bool is_pos, buffer<symbol> const & names, format * f) { @@ -851,7 +856,7 @@ class smt2_printer { buf.push_back(pp_simple_attribute(":weight ", q->get_weight())); } if (q->get_skid() != symbol::null) { - buf.push_back(pp_simple_attribute(":skid ", q->get_skid())); + buf.push_back(pp_simple_attribute(":skolemid ", q->get_skid())); } if (q->get_qid() != symbol::null) { #if 0 diff --git a/src/ast/normal_forms/defined_names.cpp b/src/ast/normal_forms/defined_names.cpp index dab0ca0d8..16e9098fc 100644 --- a/src/ast/normal_forms/defined_names.cpp +++ b/src/ast/normal_forms/defined_names.cpp @@ -17,11 +17,67 @@ Revision History: --*/ #include"defined_names.h" +#include"obj_hashtable.h" #include"used_vars.h" #include"var_subst.h" #include"ast_smt2_pp.h" #include"ast_pp.h" +struct defined_names::impl { + typedef obj_map<expr, app *> expr2name; + typedef obj_map<expr, proof *> expr2proof; + ast_manager & m_manager; + symbol m_z3name; + + /** + \brief Mapping from expressions to their names. A name is an application. + If the expression does not have free variables, then the name is just a constant. + */ + expr2name m_expr2name; + /** + \brief Mapping from expressions to the apply-def proof. + That is, for each expression e, m_expr2proof[e] is the + proof e and m_expr2name[2] are observ. equivalent. + + This mapping is not used if proof production is disabled. + */ + expr2proof m_expr2proof; + + /** + \brief Domain of m_expr2name. It is used to keep the expressions + alive and for backtracking + */ + expr_ref_vector m_exprs; + expr_ref_vector m_names; //!< Range of m_expr2name. It is used to keep the names alive. + proof_ref_vector m_apply_proofs; //!< Range of m_expr2proof. It is used to keep the def-intro proofs alive. + + + unsigned_vector m_lims; //!< Backtracking support. + + impl(ast_manager & m, char const * prefix); + virtual ~impl(); + + app * gen_name(expr * e, sort_ref_buffer & var_sorts, buffer<symbol> & var_names); + void cache_new_name(expr * e, app * name); + void cache_new_name_intro_proof(expr * e, proof * pr); + void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result); + void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result); + virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def); + bool mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr); + void push_scope(); + void pop_scope(unsigned num_scopes); + void reset(); + + unsigned get_num_names() const { return m_names.size(); } + func_decl * get_name_decl(unsigned i) const { return to_app(m_names.get(i))->get_decl(); } +}; + +struct defined_names::pos_impl : public defined_names::impl { + pos_impl(ast_manager & m, char const * fresh_prefix):impl(m, fresh_prefix) {} + virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def); +}; + + defined_names::impl::impl(ast_manager & m, char const * prefix): m_manager(m), m_exprs(m), @@ -222,5 +278,50 @@ void defined_names::impl::reset() { m_lims.reset(); } +defined_names::defined_names(ast_manager & m, char const * fresh_prefix) { + m_impl = alloc(impl, m, fresh_prefix); + m_pos_impl = alloc(pos_impl, m, fresh_prefix); +} + +defined_names::~defined_names() { + dealloc(m_impl); + dealloc(m_pos_impl); +} + +bool defined_names::mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr) { + return m_impl->mk_name(e, new_def, new_def_pr, n, pr); +} + +bool defined_names::mk_pos_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr) { + return m_pos_impl->mk_name(e, new_def, new_def_pr, n, pr); +} + +void defined_names::push() { + m_impl->push_scope(); + m_pos_impl->push_scope(); +} + +void defined_names::pop(unsigned num_scopes) { + m_impl->pop_scope(num_scopes); + m_pos_impl->pop_scope(num_scopes); +} + +void defined_names::reset() { + m_impl->reset(); + m_pos_impl->reset(); +} + +unsigned defined_names::get_num_names() const { + return m_impl->get_num_names() + m_pos_impl->get_num_names(); +} + +func_decl * defined_names::get_name_decl(unsigned i) const { + SASSERT(i < get_num_names()); + unsigned n1 = m_impl->get_num_names(); + return i < n1 ? m_impl->get_name_decl(i) : m_pos_impl->get_name_decl(i - n1); +} + + + diff --git a/src/ast/normal_forms/defined_names.h b/src/ast/normal_forms/defined_names.h index c5e4a116f..0b9f04569 100644 --- a/src/ast/normal_forms/defined_names.h +++ b/src/ast/normal_forms/defined_names.h @@ -21,7 +21,6 @@ Revision History: #define _DEFINED_NAMES_H_ #include"ast.h" -#include"obj_hashtable.h" /** \brief Mapping from expressions to skolem functions that are used to name them. @@ -29,62 +28,13 @@ Revision History: The mapping supports backtracking using the methods #push_scope and #pop_scope. */ class defined_names { - - struct impl { - typedef obj_map<expr, app *> expr2name; - typedef obj_map<expr, proof *> expr2proof; - ast_manager & m_manager; - symbol m_z3name; - - /** - \brief Mapping from expressions to their names. A name is an application. - If the expression does not have free variables, then the name is just a constant. - */ - expr2name m_expr2name; - /** - \brief Mapping from expressions to the apply-def proof. - That is, for each expression e, m_expr2proof[e] is the - proof e and m_expr2name[2] are observ. equivalent. - - This mapping is not used if proof production is disabled. - */ - expr2proof m_expr2proof; - - /** - \brief Domain of m_expr2name. It is used to keep the expressions - alive and for backtracking - */ - expr_ref_vector m_exprs; - expr_ref_vector m_names; //!< Range of m_expr2name. It is used to keep the names alive. - proof_ref_vector m_apply_proofs; //!< Range of m_expr2proof. It is used to keep the def-intro proofs alive. - - - unsigned_vector m_lims; //!< Backtracking support. - - impl(ast_manager & m, char const * prefix); - virtual ~impl(); - - app * gen_name(expr * e, sort_ref_buffer & var_sorts, buffer<symbol> & var_names); - void cache_new_name(expr * e, app * name); - void cache_new_name_intro_proof(expr * e, proof * pr); - void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result); - void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result); - virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def); - bool mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr); - void push_scope(); - void pop_scope(unsigned num_scopes); - void reset(); - }; - - struct pos_impl : public impl { - pos_impl(ast_manager & m, char const * fresh_prefix):impl(m, fresh_prefix) {} - virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def); - }; - - impl m_impl; - pos_impl m_pos_impl; + struct impl; + struct pos_impl; + impl * m_impl; + pos_impl * m_pos_impl; public: - defined_names(ast_manager & m, char const * fresh_prefix = "z3name"):m_impl(m, fresh_prefix), m_pos_impl(m, fresh_prefix) {} + defined_names(ast_manager & m, char const * fresh_prefix = "z3name"); + ~defined_names(); // ----------------------------------- // @@ -113,9 +63,7 @@ public: Remark: the definitions are closed with an universal quantifier if e contains free variables. */ - bool mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr) { - return m_impl.mk_name(e, new_def, new_def_pr, n, pr); - } + bool mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr); /** \brief Create a name for a positive occurrence of the expression \c e. @@ -127,24 +75,14 @@ public: Remark: the definitions are closed with an universal quantifier if e contains free variables. */ - bool mk_pos_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr) { - return m_pos_impl.mk_name(e, new_def, new_def_pr, n, pr); - } + bool mk_pos_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr); - void push_scope() { - m_impl.push_scope(); - m_pos_impl.push_scope(); - } + void push(); + void pop(unsigned num_scopes); + void reset(); - void pop_scope(unsigned num_scopes) { - m_impl.pop_scope(num_scopes); - m_pos_impl.pop_scope(num_scopes); - } - - void reset() { - m_impl.reset(); - m_pos_impl.reset(); - } + unsigned get_num_names() const; + func_decl * get_name_decl(unsigned i) const; }; #endif /* _DEFINED_NAMES_H_ */ diff --git a/src/muz_qe/dl_mk_extract_quantifiers2.cpp b/src/muz_qe/dl_mk_extract_quantifiers2.cpp index 33b33f0aa..cd13bb44b 100644 --- a/src/muz_qe/dl_mk_extract_quantifiers2.cpp +++ b/src/muz_qe/dl_mk_extract_quantifiers2.cpp @@ -333,7 +333,7 @@ namespace datalog { smt::quantifier_manager* qm = ctx.get_quantifier_manager(); qm->get_plugin()->set_instance_plugin(alloc(instance_plugin, *this)); #endif - lbool res = solver.check(); + solver.check(); for (unsigned i = 0; i < m_bindings.size(); ++i) { expr_ref_vector& binding = m_bindings[i]; diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index ca58b15af..460e07f58 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -981,6 +981,14 @@ namespace nlsat { bool atom_val = a->get_kind() == atom::EQ; bool lit_val = l.sign() ? !atom_val : atom_val; new_lit = lit_val ? true_literal : false_literal; + if (!info.m_lc_const) { + // We have essentially shown the current factor must be zero If the leading coefficient is not zero. + // Note that, if the current factor is zero, then the whole polynomial is zero. + // The atom is true if it is an equality, and false otherwise. + // The sign of the leading coefficient (info.m_lc) of info.m_eq doesn't matter. + // However, we have to store the fact it is not zero. + info.add_lc_diseq(); + } return; } else if (s == -1 && !is_even) { @@ -1341,3 +1349,32 @@ namespace nlsat { } }; + +#ifdef Z3DEBUG +void pp(nlsat::explain::imp & ex, unsigned num, nlsat::literal const * ls) { + ex.display(std::cout, num, ls); +} +void pp(nlsat::explain::imp & ex, nlsat::scoped_literal_vector & ls) { + ex.display(std::cout, ls); +} +void pp(nlsat::explain::imp & ex, polynomial_ref const & p) { + ex.display(std::cout, p); + std::cout << std::endl; +} +void pp(nlsat::explain::imp & ex, polynomial::polynomial * p) { + polynomial_ref _p(p, ex.m_pm); + ex.display(std::cout, _p); + std::cout << std::endl; +} +void pp(nlsat::explain::imp & ex, polynomial_ref_vector const & ps) { + ex.display(std::cout, ps); +} +void pp_var(nlsat::explain::imp & ex, nlsat::var x) { + ex.display(std::cout, x); + std::cout << std::endl; +} +void pp_lit(nlsat::explain::imp & ex, nlsat::literal l) { + ex.display(std::cout, l); + std::cout << std::endl; +} +#endif diff --git a/src/nlsat/nlsat_explain.h b/src/nlsat/nlsat_explain.h index 08f6201be..5ecb9d385 100644 --- a/src/nlsat/nlsat_explain.h +++ b/src/nlsat/nlsat_explain.h @@ -27,7 +27,9 @@ namespace nlsat { class evaluator; class explain { + public: struct imp; + private: imp * m_imp; public: explain(solver & s, assignment const & x2v, polynomial::cache & u, atom_vector const & atoms, atom_vector const & x2eq, diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 6da2c15f5..5552050db 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -189,7 +189,7 @@ void asserted_formulas::push_scope() { s.m_asserted_formulas_lim = m_asserted_formulas.size(); SASSERT(inconsistent() || s.m_asserted_formulas_lim == m_asserted_qhead); s.m_inconsistent_old = m_inconsistent; - m_defined_names.push_scope(); + m_defined_names.push(); m_bv_sharing.push_scope(); commit(); } @@ -201,7 +201,7 @@ void asserted_formulas::pop_scope(unsigned num_scopes) { unsigned new_lvl = m_scopes.size() - num_scopes; scope & s = m_scopes[new_lvl]; m_inconsistent = s.m_inconsistent_old; - m_defined_names.pop_scope(num_scopes); + m_defined_names.pop(num_scopes); m_asserted_formulas.shrink(s.m_asserted_formulas_lim); if (m_manager.proofs_enabled()) m_asserted_formula_prs.shrink(s.m_asserted_formulas_lim); diff --git a/src/smt/params/qi_params.h b/src/smt/params/qi_params.h index b0a21e75b..0cd817f22 100644 --- a/src/smt/params/qi_params.h +++ b/src/smt/params/qi_params.h @@ -52,8 +52,6 @@ struct qi_params { bool m_mbqi_trace; unsigned m_mbqi_force_template; - bool m_instgen; - qi_params(params_ref const & p = params_ref()): /* The "weight 0" performance bug @@ -99,8 +97,7 @@ struct qi_params { m_mbqi_max_cexs_incr(1), m_mbqi_max_iterations(1000), m_mbqi_trace(false), - m_mbqi_force_template(10), - m_instgen(false) { + m_mbqi_force_template(10) { updt_params(p); } diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index e62a3de21..519302c19 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include"smt_params.h" #include"smt_params_helper.hpp" +#include"model_params.hpp" void smt_params::updt_local_params(params_ref const & _p) { smt_params_helper p(_p); @@ -33,6 +34,8 @@ void smt_params::updt_local_params(params_ref const & _p) { m_delay_units_threshold = p.delay_units_threshold(); m_preprocess = _p.get_bool("preprocess", true); // hidden parameter m_soft_timeout = p.soft_timeout(); + model_params mp(_p); + m_model_compact = mp.compact(); if (_p.get_bool("arith.greatest_error_pivot", false)) m_arith_pivot_strategy = ARITH_PIVOT_GREATEST_ERROR; else if (_p.get_bool("arith.least_error_pivot", false)) @@ -50,5 +53,4 @@ void smt_params::updt_params(params_ref const & p) { void smt_params::updt_params(context_params const & p) { m_auto_config = p.m_auto_config; m_model = p.m_model; - m_model_validate = p.m_model_validate; } diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index 3d823cb51..256c5a646 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -177,7 +177,6 @@ struct smt_params : public preprocessor_params, // ----------------------------------- bool m_model; bool m_model_compact; - bool m_model_validate; bool m_model_on_timeout; bool m_model_on_final_check; @@ -264,7 +263,6 @@ struct smt_params : public preprocessor_params, m_abort_after_preproc(false), m_model(true), m_model_compact(false), - m_model_validate(false), m_model_on_timeout(false), m_model_on_final_check(false), m_progress_sampling_freq(0), diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index b3f16a3ce..42e761b61 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -23,7 +23,6 @@ Revision History: #include"ast_smt2_pp.h" #include"smt_model_finder.h" #include"for_each_expr.h" -#include"theory_instgen.h" namespace smt { @@ -530,11 +529,6 @@ namespace smt { SASSERT(!b_internalized(q)); SASSERT(q->is_forall()); SASSERT(check_patterns(q)); - if (m_fparams.m_instgen) { - theory* th = m_theories.get_plugin(m_manager.get_family_id("inst_gen")); - static_cast<theory_instgen*>(th)->internalize_quantifier(q); - return; - } bool_var v = mk_bool_var(q); unsigned generation = m_generation; unsigned _generation; diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index ac31eb1a9..f0dc1f5a6 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -28,7 +28,6 @@ Revision History: #include"theory_datatype.h" #include"theory_dummy.h" #include"theory_dl.h" -#include"theory_instgen.h" #include"theory_seq_empty.h" namespace smt { @@ -772,11 +771,6 @@ namespace smt { void setup::setup_seq() { m_context.register_plugin(alloc(theory_seq_empty, m_manager)); } - void setup::setup_instgen() { - if (m_params.m_instgen) { - m_context.register_plugin(mk_theory_instgen(m_manager, m_params)); - } - } void setup::setup_unknown() { setup_arith(); @@ -784,7 +778,6 @@ namespace smt { setup_bv(); setup_datatypes(); setup_dl(); - setup_instgen(); setup_seq(); } diff --git a/src/smt/theory_instgen.cpp b/src/smt/theory_instgen.cpp deleted file mode 100644 index 68e04aab0..000000000 --- a/src/smt/theory_instgen.cpp +++ /dev/null @@ -1,1494 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - theory_instgen.cpp - -Abstract: - - iProver style theory solver. - It provides an instantiation based engine - based on InstGen methods together with - unit propagation. - -Author: - - Krystof Hoder (t-khoder) - Nikolaj Bjorner (nbjorner) 2011-10-6 - -Revision History: - -Main data-structures: - -- Instantiation = Var -> Expr -- MatchingSet = Instantiation-set - operations: - - has_instance : Instantiation -> Bool - has_instance(i) = exists j in MatchingSet . j <= i -- UnificationIndex - operations: - - insert : Expr - - remove : Expr - - unify : Expr -> Expr-set - - set of inserted expressions that unify -- RootClauseMap : Expr -> Quantifier - where RootClauseMap(clause) = The quantifier that originated clause -- Occurs : Expr -> Quantifier-set - the set of quantifiers where non-ground literal occurs. -- LiteralMeanings : Literal -> Expr-set - - set of non-ground literals that were grounded to Literal -- InternalizedFoLits : Expr-set - - forall e in InternalizedFoLits . e \in LiteralMeanings(ground(e)) -- MatchingSets : Quantifier -> MatchingSet - - -Main operation: - - - insert all assigned literals into UnificationIndex - - for l' in LiteralMeanings(l) do: - for m',theta in UnificationIndex.unify(not l') do: - for q in Occurs(l') do: - for q' in Occurs(m') do: - instantiate q with theta - instantiate q' with theta - - instantiate q with theta: - -Discussion of plans: - -- Efficient unit propagation using the tables from dl_ - See addittional notes under unit propagation. - The idea is to perfrm unit propagation using the tables - provided in the dl_ module. This is similar to unit - propagation from the EPR solver and retains succinctness - features, but does not carry over the splitting component. - The efficient propagator is aimed at solving ground problems more efficiently, - for example - -- Reduce set of selected literals when clause already has on selected literal. - -- Subsumption module: - - simplify clause using already asserted clauses. - - check for variants. - -- Completeness for EPR with equality: - The relevant equality clause for EPR are C \/ x = y and C \/ a = x - Destructive E-resolution (DER) removes disequalities. - Two approaches: - 1. Rely on super-position/hyper-resolution of ordinary literals - in the clause. - 2. Instantiate based on congruence closure. - The instantiation based approach takes a clause of the form C \/ x = y, - where all other non-equality literals in C are assigned false by the - current assignment, and (the grounded version U = U' of) x = y is - assigned true. Take the equivalence classes of the type of x and - instantiate x, y using representatives for different equivalence - classes. The number of instantiations is potentially quadratic - in the number of terms. One reduction considers symmetries: - instantiate x by a smaller representative than y. -- Unit propagation: - - Why should unit-propagation matter: hunch: similar role as - theory propagation where conflicts are created close to root - of search tree. - - Add theory identifiers to literals so that assign_eh is invoked. - - Produce explanation objects for unit propagation. - - Unit propagation index. - - Idea only propagate known literals -- Exchange unit literals with super position engine for equalities. - iProver approach: perform unit super-position proof, get instances - by labeling equalities by clauses + substitution (set-labeling) - portfolio approach: exchange unit literals to super-position - (or hypotheses as suggested in more general setting). - ---*/ - -#include "theory_instgen.h" -#include "value_factory.h" -#include "smt_model_generator.h" -#include "smt_context.h" -#include "ast_smt2_pp.h" -#include "substitution.h" -#include "substitution_tree.h" -#include "uint_set.h" -#include "unifier.h" -#include "matcher.h" -#include "rewriter.h" -#include "rewriter_def.h" -#include "var_subst.h" - -#define PP mk_pp - -namespace smt { - - - // - // expression grounding for passing to the SMT solver - // - class grounder { - ast_manager& m; - vector<obj_map<sort,expr*> > m_defaults; - expr_ref_vector m_ref_holder; - - class grounding_rewriter_cfg; - - void reserve(unsigned idx) { - if (m_defaults.size() <= idx) { - m_defaults.resize(idx+1); - } - } - - expr* mk_default(sort* s) { - return mk_default(0, s); - } - - expr* mk_default(unsigned i, sort* s) { - expr* d; - reserve(i); - if (!m_defaults[i].find(s, d)) { - d = m.mk_fresh_const("U",s); - m_defaults[i].insert(s, d); - m_ref_holder.push_back(d); - } - return d; - } - - class grounding_rewriter_cfg : public default_rewriter_cfg { - grounder& m_parent; - bool m_collapse; - public: - grounding_rewriter_cfg(grounder& parent, bool collapse) - : m_parent(parent), m_collapse(collapse) {} - - bool get_subst(expr * s, expr * & t, proof * & t_pr) { - SASSERT(is_app(s) || is_var(s)); - if (is_var(s)) { - var* v = to_var(s); - if (m_collapse) { - t = m_parent.mk_default(v->get_sort()); - } - else { - t = m_parent.mk_default(v->get_idx(), v->get_sort()); - } - } - return is_var(s); - } - }; - - void mk(expr * e, app_ref& res, bool collapse) { - if(is_ground(e)) { - res = to_app(e); - } - else { - while (is_quantifier(e)) { - e = to_quantifier(e)->get_expr(); - } - SASSERT(is_app(e)); - grounding_rewriter_cfg r_cfg(*this, collapse); - rewriter_tpl<grounding_rewriter_cfg> rwr(m, false, r_cfg); - expr_ref res_e(m); - rwr(e, res_e); - res = to_app(res_e); - } - SASSERT(is_ground(res.get())); - } - - public: - grounder(ast_manager& m): m(m), m_ref_holder(m) { - reserve(0); - } - - /** - create a grounding that recycles the same constant for - different variables of the same sort. - - This function can be called either with whole clauses (incl. quantifier), - or with literals one by one (without a quantifier) - */ - void operator()(expr * e, app_ref& res) { - mk(e, res, true); - } - - // - // create a grounding where different variables have different names - // - void mk_diff(expr * e, app_ref& res) { - mk(e, res, false); - } - }; - - // - // Class for first-order subsumption checking. - // if clause[renaming] is a superset of existing clause in context, then clause is subsumed. - // if context => clause then clause is subsumed. - // if context & clause => ~ lit then lit is subsumed from clause - // - // TBD: - // - check unit propagation - // - use internalizer functions directly. The assertions have already been pre-processed. - // - class clause_subsumption { - ast_manager& m; - grounder m_grounder; - smt_params m_params; - context m_ctx; - quantifier_ref_vector m_assumptions; - unsigned_vector m_limit; - public: - clause_subsumption(ast_manager& m, smt_params& p): - m(m), m_grounder(m), m_params(p), m_ctx(m,m_params), m_assumptions(m) { - m_params.m_instgen = false; - } - - void simplify(quantifier* new_clause, expr_ref& result, ptr_vector<quantifier>& assumptions) { -#if 1 - result = new_clause; - return; -#endif - - SASSERT(new_clause->is_forall()); - expr* body = new_clause->get_expr(); - app_ref ground_clause(m); - m_grounder.mk_diff(new_clause, ground_clause); - if (is_subsumed(ground_clause)) { - TRACE("theory_instgen", tout << "subsumed: " << PP(new_clause,m) << "\n";); - result = m.mk_true(); - return; - } - if (is_homomorphic_image(body)) { - result = m.mk_true(); - return; - } - // Assert the current clause. - m_ctx.internalize(ground_clause, true); - m_ctx.assign(m_ctx.get_literal(ground_clause), b_justification()); - TRACE("theory_instgen", tout << "Asserting: " << PP(ground_clause,m) << "\n";); - m_assumptions.push_back(new_clause); - SASSERT(m.is_or(body) == m.is_or(ground_clause)); - if (!m.is_or(body)) { - result = new_clause; - return; - } - SASSERT(to_app(body)->get_num_args() == ground_clause->get_num_args()); - ptr_vector<expr> lits; - for (unsigned i = 0; i < to_app(body)->get_num_args(); ++i) { - m_ctx.push(); - m_ctx.assign(m_ctx.get_literal(ground_clause->get_arg(i)), b_justification()); - lbool is_sat = m_ctx.check(); - m_ctx.pop(1); - if (is_sat != l_false) { - lits.push_back(to_app(body)->get_arg(i)); - } - else { - TRACE("theory_instgen", tout << "subsumed literal: " << PP(to_app(body)->get_arg(i),m) << "\n";); - } - } - if (lits.size() == ground_clause->get_num_args()) { - result = new_clause; - } - else { - SASSERT(!lits.empty()); - result = lits.size()==1?lits[0]:m.mk_or(lits.size(), lits.c_ptr()); - result = m.update_quantifier(new_clause, result); - TRACE("theory_instgen", tout << "simplified: " << PP(new_clause,m) << "\n"; - tout << PP(result.get(), m) << "\n"; - ); - //overapproximation of required assumptions - //( m_assumptions.size()-1 ... the -1 is not to make ourselves as an assumption) - assumptions.append(m_assumptions.size()-1, m_assumptions.c_ptr()); - } - } - - void push() { - m_ctx.push(); - m_limit.push_back(m_assumptions.size()); - } - - void pop(unsigned num_scopes) { - m_ctx.pop(num_scopes); - - unsigned last_idx = m_limit.size()-num_scopes; - unsigned restored_assumptions_size = m_limit[last_idx]; - m_limit.resize(last_idx); - m_assumptions.resize(restored_assumptions_size); - } - - private: - - bool is_subsumed(expr* ground_clause) { - m_ctx.push(); - m_ctx.internalize(ground_clause, true); - m_ctx.assign(~m_ctx.get_literal(ground_clause), b_justification()); - lbool is_sat = m_ctx.check(); - m_ctx.pop(1); - TRACE("theory_instgen", - tout << PP(ground_clause, m) << " " << - ((is_sat==l_false)?"unsat":"sat") << "\n";); - return (is_sat == l_false); - } - - bool is_homomorphic_image(expr* body) { - // TBD - return false; - } - - }; - - class fo_clause_internalizer; - class instantiator; - class theory_instgen_impl; - typedef expr_ref_vector inst; - - class instantiation_result { - quantifier_ref m_clause; - inst m_subst; - public: - instantiation_result(ast_manager& m) : m_clause(m), m_subst(m) {} - - void init(quantifier * q, const inst& subst) { - SASSERT(!m_clause); //we init each object at most once - SASSERT(m_subst.empty()); - SASSERT(q); - m_clause = q; - m_subst.append(subst); - } - quantifier * clause() const { return m_clause; } - const inst& subst() const { return m_subst; } - }; - - typedef vector<instantiation_result> instantiation_result_vector; - - // TBD: replace this by the substitution tree index. - // It should do the trick of identifying instances and generalizers. - // see matching_set2.. - // - class matching_set { - ast_manager& m; - vector<inst> m_inst; - - //used in the has_instance function - mutable substitution m_subst; - - public: - matching_set(ast_manager& m) : m(m), m_subst(m) {} - unsigned size() const { return m_inst.size(); } - inst const& operator[](unsigned i) const { return m_inst[i]; } - - void insert(inst const& inst) { - SASSERT(m_inst.empty() || m_inst.back().size() == inst.size()); - TRACE("theory_instgen_verbose", - for (unsigned i = 0; i < inst.size(); ++i) { - tout << PP(inst[i], m) << " "; - } - tout << "\n"; - ); - m_inst.push_back(inst); - } - void insert(unsigned sz, expr* const* exprs) { - insert(inst(m, sz, exprs)); - } - void pop_insert() { m_inst.pop_back(); } - - bool has_instance(inst const& inst) { - unsigned dont_care; - return has_instance(inst, dont_care); - } - - bool has_instance(inst const& new_inst, unsigned& index) { - for (unsigned i = 0; i < size(); ++i) { - if (has_instance(new_inst, m_inst[i])) { - index = i; - return true; - } - } - return false; - } - - class insert_inst : public trail<smt::context> { - matching_set& m_ms; - public: - insert_inst(matching_set& m): m_ms(m) {} - virtual void undo(smt::context& ctx) { m_ms.pop_insert(); } - }; - - static bool is_identity(const inst& subst) { - uint_set vars; - vars.reset(); - unsigned sz = subst.size(); - for(unsigned i=0; i<sz; i++) { - expr * val = subst[i]; - if(!is_var(val)) { return false; } - unsigned var_idx = to_var(val)->get_idx(); - if(vars.contains(var_idx)) { - return false; - } - vars.insert(var_idx); - } - return true; - } - - private: - // check if old_instance is an instance of new_instance. - bool has_instance(inst const& new_instance, inst const& old_instance) const { - SASSERT(new_instance.size() == old_instance.size()); - unsigned sz = new_instance.size(); - m_subst.reset(); - m_subst.reserve_vars(sz); - m_subst.reserve_offsets(2); - matcher mtchr(m); - for(unsigned i = 0; i < sz; i++) { - TRACE("theory_instgen_verbose", tout << PP(new_instance[i], m) << " " << PP(old_instance[i], m) << "\n";); - if(!mtchr(new_instance[i], old_instance[i], m_subst)) { - return false; - } - } - return true; - } - }; - - - class matching_set2 { - class inst_visitor : public st_visitor { - bool m_found; - public: - inst_visitor(substitution& s): st_visitor(s), m_found(false) {} - virtual bool operator()(expr * e) { - m_found = true; - return false; - } - void reset() { m_found = false; } - bool found() const { return m_found; } - }; - - ast_manager& m; - substitution_tree m_st; - func_decl_ref m_f; - app_ref_vector m_trail; - substitution m_dummy; - inst_visitor m_visitor; - - public: - matching_set2(ast_manager& m) : m(m), m_st(m), m_f(m), m_trail(m), m_dummy(m), m_visitor(m_dummy) {} - - void insert(inst const& inst) { - if (!m_f.get()) { - ptr_buffer<sort> domain; - for (unsigned i = 0; i < inst.size(); ++i) { - domain.push_back(m.get_sort(inst[i])); - } - m_f = m.mk_func_decl(symbol("tuple"),inst.size(), domain.c_ptr(), m.mk_bool_sort()); - m_trail.push_back(m.mk_app(m_f, inst.size(), inst.c_ptr())); - m_st.insert(m_trail.back()); - } - } - void insert(unsigned sz, expr* const* exprs) { - insert(inst(m, sz, exprs)); - } - void pop_insert() { - m_st.erase(m_trail.back()); - m_trail.pop_back(); - } - - bool has_instance(inst const& inst) { - app_ref f(m); - f = m.mk_app(m_f, inst.size(), inst.c_ptr()); - m_visitor.reset(); - m_st.inst(f, m_visitor); - return m_visitor.found(); - } - - class insert_inst : public trail<smt::context> { - matching_set& m_ms; - public: - insert_inst(matching_set& m): m_ms(m) {} - virtual void undo(smt::context& ctx) { m_ms.pop_insert(); } - }; - - static bool is_identity(const inst& subst) { - uint_set vars; - vars.reset(); - unsigned sz = subst.size(); - for(unsigned i=0; i<sz; i++) { - expr * val = subst[i]; - if(!is_var(val)) { return false; } - unsigned var_idx = to_var(val)->get_idx(); - if(vars.contains(var_idx)) { - return false; - } - vars.insert(var_idx); - } - return true; - } - }; - - - ///////////////////////// - // inst_gen_unif_index - // - - class inst_gen_unif_index { - ast_manager & m; - substitution_tree m_st; - unsigned m_num_vars; - app_ref_vector m_ref_holder; - unsigned_vector m_lim; - - class collecting_visitor : public st_visitor { - app_ref_vector& m_acc; - public: - collecting_visitor(app_ref_vector& acc, substitution& subst) - : st_visitor(subst), m_acc(acc) {} - virtual bool operator()(expr * e) { - SASSERT(is_app(e)); - m_acc.push_back(to_app(e)); - return true; - } - }; - - - class st_contains_visitor : public st_visitor { - expr* m_e; - bool m_found; - public: - st_contains_visitor(substitution& s, expr* e): st_visitor(s), m_e(e), m_found(false) {} - virtual bool operator()(expr* e) { - if (e == m_e) { - m_found = true; - return false; - } - return true; - } - bool found() const { return m_found; } - }; - - void debug_st(char const* cmd, app* l) { - expr_ref e(m); - ptr_vector<sort> sorts; - svector<symbol> names; - get_free_vars(l, sorts); - for (unsigned i = 0; i < sorts.size(); ++i) { - if (!sorts[i]) { - sorts[i] = m.mk_bool_sort(); - } - names.push_back(symbol(i)); - } - sorts.reverse(); - if (!sorts.empty()) { - e = m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), l); - } - else { - e = l; - } - std::cout << ":" << cmd << " " << PP(e.get(),m) << "\n"; - } - - public: - inst_gen_unif_index(ast_manager & m) : - m(m), m_st(m), m_num_vars(0), m_ref_holder(m) {} - - void insert_literal(app * lit) { - // debug_st("st_insert", lit); - m_ref_holder.push_back(lit); - m_st.insert(lit); - } - - void get_unifications(app * lit, app_ref_vector& res) { - substitution subst(m); - subst.reserve_vars(m_num_vars); - subst.reserve_offsets(m_st.get_approx_num_regs()); - collecting_visitor visitor(res, subst); - // TRACE("theory_instgen", m_st.display(tout); ); - m_st.unify(lit, visitor); - } - void reserve_num_vars(unsigned num_vars) { - if (num_vars > m_num_vars) m_num_vars = num_vars; - } - - void push() { - m_lim.push_back(m_ref_holder.size()); - } - - void pop() { - unsigned sz = m_lim.back(); - m_ref_holder.resize(sz); - m_lim.pop_back(); - m_st.reset(); - } - - void pop_orig() { - unsigned sz = m_lim.back(); - while (m_ref_holder.size() > sz) { - debug_st("st_erase", m_ref_holder.back()); - m_st.erase(m_ref_holder.back()); - - substitution subst(m); - subst.reserve_vars(m_num_vars); - subst.reserve_offsets(m_st.get_approx_num_regs()); - st_contains_visitor cv(subst, m_ref_holder.back()); - m_st.unify(m_ref_holder.back(), cv); - if (cv.found()) { - m_st.display(std::cout); - m_st.erase(m_ref_holder.back()); - } - SASSERT(!cv.found()); - m_ref_holder.pop_back(); - } - m_lim.pop_back(); - } - - void display(std::ostream& out) { - m_st.display(out); - } - - bool empty() const{ - return m_st.empty(); - } - }; - - - /////////////////////////// - // fo_clause_internalizer - // - - class fo_clause_internalizer { - private: - typedef map<literal, app_ref_vector*, obj_hash<literal>, default_eq<literal> > literal_meaning_map; - typedef obj_map<expr,quantifier_ref_vector*> occurs; - typedef obj_map<expr,quantifier*> root_clause_map; //for any clause instance it gives us the clause from the original problem - - theory_instgen_impl& m_parent; - expr_ref_vector m_vars; - var_subst m_subst; - occurs m_occurs; - grounder m_grounder; - /** - For each clause which is a result of instantiation contains the - original problem clause from which it derives. - */ - root_clause_map m_root_clause_map; - - - /** - For each SMT literal contains a vector of first-order literals - that are represented by this literal. - */ - literal_meaning_map m_literal_meanings; - - /** - fo literals that have been internalized by this object. - Invariant: any app* fol in this set has a literal l such that - m_literal_meanings[l].contains(fol). - Particularly, l==get_context().get_literal(gnd_fol) where gnd_fol - is a grounded version of this literal - */ - obj_hashtable<expr> m_internalized_fo_lits; - - - ast_manager& m() const; - smt::context& get_context() const; - - class insert_occurs_trail : public trail<smt::context> { - occurs& m_occ; - quantifier_ref_vector* m_qs; - expr_ref m_lit; - public: - insert_occurs_trail(occurs& o, expr_ref& lit, quantifier* q): m_occ(o), m_qs(0), m_lit(lit) { - occurs::obj_map_entry* e = m_occ.insert_if_not_there2(lit,0); - m_qs = e->get_data().m_value; - if (!m_qs) { - m_qs = alloc(quantifier_ref_vector, lit.get_manager()); - e->get_data().m_value = m_qs; - } - m_qs->push_back(q); - } - - virtual void undo(smt::context& ctx) { - SASSERT(m_qs && !m_qs->empty()); - SASSERT(m_qs == m_occ.find_core(m_lit)->get_data().m_value); - m_qs->pop_back(); - if (m_qs->empty()) { - m_occ.remove(m_lit); - dealloc(m_qs); - } - } - }; - - class lit_meaning_trail : public trail<smt::context> { - literal_meaning_map& m_map; - app_ref_vector* m_apps; - smt::literal m_smtlit; - public: - - lit_meaning_trail(literal_meaning_map& map, ast_manager& m, smt::literal l, app* lit): - m_map(map), m_smtlit(l) { - literal_meaning_map::entry* e = map.insert_if_not_there2(l, 0); - m_apps = e->get_data().m_value; - if (!m_apps) { - m_apps = alloc(app_ref_vector, m); - e->get_data().m_value = m_apps; - } - m_apps->push_back(lit); - } - - virtual void undo(smt::context& ctx) { - SASSERT(m_apps && !m_apps->empty()); - SASSERT(m_apps == m_map.find_core(m_smtlit)->get_data().m_value); - m_apps->pop_back(); - if (m_apps->empty()) { - m_map.remove(m_smtlit); - dealloc(m_apps); - } - } - }; - - quantifier * get_root_clause(expr* clause) const { - quantifier * root; - if(!m_root_clause_map.find(clause, root)) { - SASSERT(is_forall(clause)); - root = to_quantifier(clause); - } - return root; - } - - void replace_by_root_clauses(ptr_vector<quantifier>& vect) const { - unsigned sz = vect.size(); - for(unsigned i=0; i<sz; ++i) { - vect[i] = get_root_clause(vect[i]); - } - } - - literal get_root_clause_control_literal(quantifier* root_clause) { - get_context().internalize(root_clause, true); - return get_context().get_literal(root_clause); - } - - // - // Grounding - // - - void insert_occurs(app * lit, quantifier* clause) { - SASSERT(clause); - TRACE("theory_instgen", tout << PP(lit, m()) << " occurs in " << PP(clause, m()) << "\n";); - expr_ref t(lit,m()); - get_context().push_trail(insert_occurs_trail(m_occurs, t, clause)); - } - - literal ground_fo_literal(app * lit, quantifier* q) { - - literal smt_lit; - - if (is_ground(lit)) { - get_context().internalize(lit, true); - smt_lit = get_context().get_literal(lit); - get_context().mark_as_relevant(smt_lit); - return smt_lit; - } - insert_occurs(lit, q); - - app_ref grounded_lit(m()); - m_grounder(lit, grounded_lit); - - if(m_internalized_fo_lits.contains(lit)) { - smt_lit = get_context().get_literal(grounded_lit); - } - else { - get_context().internalize(grounded_lit, true); - smt_lit = get_context().get_literal(grounded_lit); - m_internalized_fo_lits.insert(lit); - - expr_ref t(lit, m()); - get_context().push_trail(obj_ref_trail<smt::context,ast_manager,expr>(t)); - get_context().push_trail(insert_obj_trail<smt::context,expr>(m_internalized_fo_lits, lit)); - get_context().push_trail(lit_meaning_trail(m_literal_meanings, m(), smt_lit, lit)); - TRACE("theory_instgen", tout << smt_lit << " "<< PP(grounded_lit, m()) << " |-> " << PP(lit, m()) << "\n";); - } - get_context().mark_as_relevant(smt_lit); - return smt_lit; - } - - void add_clause_to_smt(expr * clause, quantifier* root_clause, ptr_vector<quantifier> const& assumptions=ptr_vector<quantifier>()); - - void get_instance_clause(instantiation_result const& ir, expr_ref& res); - - /** - return false if nothing was done - - assumptions are instantiated clauses (to get a correct assumption for the SMT solver, we need - to convert the vector to root clauses). - */ - bool simplify_clause(quantifier * clause, expr_ref& result, ptr_vector<quantifier>& assumptions); - - public: - - fo_clause_internalizer(theory_instgen_impl& parent): - m_parent(parent), - m_vars(m()), - m_subst(m()), - m_grounder(m()) { - } - - ~fo_clause_internalizer() { - reset_dealloc_values(m_occurs); - } - - void get_literal_meanings(literal l, ptr_vector<app>& fo_lits) { - app_ref_vector* lits = 0; - m_literal_meanings.find(l, lits); - if (lits) { - fo_lits.append(lits->size(), lits->c_ptr()); - } - } - - void add_initial_clause(quantifier* q) { - add_clause_to_smt(q, 0); - } - - quantifier_ref_vector* find_occurs(app * l) { - quantifier_ref_vector* result = 0; - m_occurs.find(l, result); - return result; - } - - void add_new_instance(instantiation_result const& ir) { - quantifier * root_clause = get_root_clause(ir.clause()); - expr_ref inst_clause(m()); - get_instance_clause(ir, inst_clause); - - ptr_vector<quantifier> assumptions; - if(is_quantifier(inst_clause.get())) { - quantifier * q_clause = to_quantifier(inst_clause.get()); - bool simplified = simplify_clause(q_clause, inst_clause, assumptions); - SASSERT(simplified || assumptions.empty()); - } - replace_by_root_clauses(assumptions); - - if(!m_root_clause_map.contains(inst_clause)) { - m_root_clause_map.insert(inst_clause, root_clause); - get_context().push_trail(insert_obj_map<smt::context,expr,quantifier*>(m_root_clause_map, inst_clause)); - } - add_clause_to_smt(inst_clause, root_clause, assumptions); - } - }; - - - ///////////////// - // instantiator - // - - class instantiator { - private: - typedef quantifier clause_type; - typedef ptr_vector<clause_type> clause_vector; - typedef obj_map<quantifier,matching_set*> matching_sets; - - ast_manager& m; - theory_instgen_impl& m_parent; - fo_clause_internalizer& m_internalizer; - inst_gen_unif_index m_unif_index; - matching_sets m_matching; - unifier m_unifier; //used in the unify method, but we don't want to recreate over and over - - class var_rename_rewriter_cfg : public default_rewriter_cfg { - ast_manager& m; - u_map<unsigned> m_index_rename; - public: - var_rename_rewriter_cfg(ast_manager& m) : m(m) {} - - bool get_subst(expr * s, expr * & t, proof * & t_pr) { - if (is_var(s)) { - unsigned idx = to_var(s)->get_idx(); - unsigned new_idx = 0; - if (!m_index_rename.find(idx, new_idx)) { - new_idx = m_index_rename.size(); - m_index_rename.insert(idx, new_idx); - } - t = m.mk_var(new_idx, to_var(s)->get_sort()); - return true; - } - else { - return false; - } - } - }; - - static void extract_substitution(substitution& s, quantifier * q, unsigned subst_var_cnt, bool is_first_bank, expr_ref_vector& tgt) { - // unsigned var_increment = is_first_bank ? 0 : subst_var_cnt; - unsigned var_offset = is_first_bank ? 0 : 1; - - unsigned deltas[2] = {0, subst_var_cnt}; - ast_manager& m = s.get_manager(); - unsigned var_cnt = q->get_num_decls(); - var_rename_rewriter_cfg r_cfg(m); - rewriter_tpl<var_rename_rewriter_cfg> rwr(m, false, r_cfg); - for(unsigned i=0; i<var_cnt; i++) { - sort * var_sort = q->get_decl_sort(i); - unsigned var_idx = var_cnt-1-i; - var_ref v(m.mk_var(var_idx, var_sort), m); - expr_ref tmp(m), subst_result(m); - s.apply(2, deltas, expr_offset(v.get(), var_offset), tmp); - rwr(tmp, subst_result); - tgt.push_back(subst_result); - } - } - - - // just to be sure there's not misunderstanding with the caller, we require the res to be empty:) - void get_literal_occurrences(app * lit, clause_vector& res) { - SASSERT(res.empty()); - quantifier_ref_vector * occurrences = m_internalizer.find_occurs(lit); - if(occurrences) { - res.append(occurrences->size(), occurrences->c_ptr()); - } - } - - /** - check substitution wrt dismatching constraints of clause - (variable offset is to deal with how variable banks are shifted on each - other in the substitution) - */ - bool is_allowed_instantiation(clause_type * clause, const inst& subst) { - matching_set * ms; - return !m_matching.find(clause, ms) || !ms->has_instance(subst); - } - - class new_ms : public trail<smt::context> { - matching_sets& m_ms; - matching_set* m_s; - quantifier* m_q; - public: - new_ms(matching_sets& m, matching_set* s, quantifier* q): m_ms(m), m_s(s), m_q(q) {} - virtual void undo(smt::context& ctx) { dealloc(m_s); m_ms.remove(m_q); } - }; - - // add instantiating substitution among the dismatching constraints - void record_instantiation(instantiation_result const& inst) { - quantifier * cl = inst.clause(); - matching_set * ms; - if(!m_matching.find(cl, ms)) { - ms = alloc(matching_set, m); - m_matching.insert(cl, ms); - get_context().push_trail(new_ms(m_matching, ms, cl)); - } - ms->insert(inst.subst()); - get_context().push_trail(matching_set::insert_inst(*ms)); - } - - void get_result_from_subst(clause_type * clause, const inst& subst, instantiation_result& res) { - res.init(clause, subst); - record_instantiation(res); - } - - void display_vector(expr_ref_vector const& v, std::ostream& out) { - for (unsigned i = 0; i < v.size(); ++i) { - out << PP(v[i], m) << " "; - } - out << "\n"; - } - - - void add_lit(literal lit) { - ptr_vector<app> fo_lits; - m_internalizer.get_literal_meanings(lit, fo_lits); - expr_ref e(m); - get_context().literal2expr(lit, e); - if (is_ground(e.get())) { - fo_lits.push_back(to_app(e)); - } - for (unsigned i = 0; i < fo_lits.size(); ++i) { - app * fol = fo_lits[i]; - m_unif_index.insert_literal(fol); - } - } - - void mk_folit_neg(app * lit, app_ref& res) { - expr * arg; - if(m.is_not(lit, arg)) { - SASSERT(is_app(arg)); - res = to_app(arg); - } - else { - res = m.mk_not(lit); - } - } - - ast_manager& get_manager() const; - context& get_context() const; - - public: - instantiator(fo_clause_internalizer& internalizer, theory_instgen_impl& parent, ast_manager& m) : - m(m), - m_parent(parent), - m_internalizer(internalizer), - m_unif_index(m), - m_unifier(m) {} - - ~instantiator() { - reset_dealloc_values(m_matching); - } - - bool unif_is_empty() const { - return m_unif_index.empty(); - } - - void display(std::ostream& out) { - m_unif_index.display(out); - } - - void add_true_lit(literal lit) { - add_lit(lit); - } - - void push() { - m_unif_index.push(); - } - - void pop() { - m_unif_index.pop(); - } - - void reserve_num_vars(unsigned num_vars) { - m_unif_index.reserve_num_vars(num_vars); - } - - bool instantiate_clauses( - app * lit1, clause_type * clause1, - app * lit2, clause_type * clause2, - instantiation_result_vector& result); - - bool instantiate_clause( - app * lit1, clause_type * clause1, app * lit2, - instantiation_result_vector& result); - - void do_instantiating(literal lit, instantiation_result_vector& res) { - ptr_vector<app> folits; - clause_vector folit_clauses; // clauses in which the first-order literal appears - app_ref_vector unifs(m); // unifying complementary literals - clause_vector comp_clauses; // clauses in which the unifying complementary literal appears - - m_internalizer.get_literal_meanings(lit, folits); - - while(!folits.empty()) { - app * folit = folits.back(); - - folits.pop_back(); - folit_clauses.reset(); - get_literal_occurrences(folit, folit_clauses); - SASSERT(!folit_clauses.empty()); //if we have a literal it should be in some clause (or not?) - - SASSERT(folit->get_ref_count() > 0); - app_ref complementary(m); - mk_folit_neg(folit, complementary); - m_unif_index.get_unifications(complementary, unifs); - - while(!unifs.empty()) { - app * comp_lit = unifs.back(); - unifs.pop_back(); - SASSERT(comp_lit->get_ref_count() > 0); - comp_clauses.reset(); - get_literal_occurrences(comp_lit, comp_clauses); - TRACE("theory_instgen", tout << "Literal " << lit << " meaning: " << PP(folit, m) << "\n"; - tout << "Unifies with: " << PP(comp_lit, m) << "\n";); - // - //if a literal is in the unification index (i.e. was assigned true sometime before), - //it should be in some clause or it is a ground literal. - - //iterate through all clauses that contain the query literal - // - clause_vector::const_iterator fc_end = folit_clauses.end(); - for(clause_vector::const_iterator fc_it = folit_clauses.begin(); fc_it!=fc_end; ++fc_it) { - - //iterate through all clauses that contain the complementary unifying literal - clause_vector::const_iterator end = comp_clauses.end(); - for(clause_vector::const_iterator it = comp_clauses.begin(); it!=end; ++it) { - - instantiate_clauses(folit, *fc_it, comp_lit, *it, res); - } - if (comp_clauses.empty()) { - instantiate_clause(folit, *fc_it, comp_lit, res); - } - } - } - complementary.reset(); - } - } - }; - - - /////////////////////////// - // theory_instgen_impl - // - - class theory_instgen_impl : public theory_instgen { - - friend class instantiator; - friend class fo_clause_internalizer; - - struct stats { - unsigned m_num_axioms; - unsigned m_num_subsumptions; - unsigned m_num_pruned; - stats() { memset(this, 0, sizeof(*this)); } - }; - - ast_manager& m_manager; - smt_params& m_params; - fo_clause_internalizer m_internalizer; - instantiator m_instantiator; - clause_subsumption m_subsumer; - stats m_stats; - - final_check_status instantiate_all_possible() { - // traverse instantiation queue and create initial instances. - - ast_manager& m = get_manager(); - context& ctx = get_context(); - instantiation_result_vector generated_clauses; - unsigned bv_cnt = ctx.get_num_bool_vars(); - - m_instantiator.push(); - - TRACE("theory_instgen", - tout << "Literals:\n"; - for (unsigned v = 0; v < bv_cnt; ++v) { - if (l_undef == ctx.get_assignment(v)) continue; - literal lit(v, ctx.get_assignment(v) == l_false); - expr_ref e(m); - ctx.literal2expr(lit, e); - tout << PP(e.get(),m) << "\n"; - } - ); - - SASSERT(m_instantiator.unif_is_empty()); - - for(unsigned bvi=0; bvi < bv_cnt; ++bvi) { - lbool asgn_val = ctx.get_assignment(bvi); - if(asgn_val==l_undef) { - continue; - } - literal lit(bvi, asgn_val==l_false); - m_instantiator.add_true_lit(lit); - m_instantiator.do_instantiating(lit, generated_clauses); - } - - bool change = !generated_clauses.empty(); - - while(!generated_clauses.empty()) { - m_internalizer.add_new_instance(generated_clauses.back()); - generated_clauses.pop_back(); - } - - m_instantiator.pop(); - - return change?FC_CONTINUE:FC_DONE; - } - - - public: - theory_instgen_impl(ast_manager& m, smt_params& p): - theory_instgen(m.get_family_id("inst_gen")), - m_manager(m), - m_params(p), - m_internalizer(*this), - m_instantiator(m_internalizer, *this, m), - m_subsumer(m, p) - {} - - ast_manager& m() { return m_manager; } - - virtual void internalize_quantifier(quantifier* q) { - TRACE("theory_instgen", tout << PP(q, m()) << "\n";); - context& ctx = get_context(); - if (!ctx.b_internalized(q)) { - bool_var v = ctx.mk_bool_var(q); - ctx.set_var_theory(v, get_id()); - m_instantiator.reserve_num_vars(q->get_num_decls()); - } - } - - virtual bool internalize_atom(app * atom, bool gate_ctx) { - UNREACHABLE(); - return false; - } - - virtual bool internalize_term(app * term) { - UNREACHABLE(); - return false; - } - - virtual void new_eq_eh(theory_var v1, theory_var v2) {} - - virtual void new_diseq_eh(theory_var v1, theory_var v2) {} - - virtual theory * mk_fresh(context * new_ctx) { - return alloc(theory_instgen_impl, get_manager(), m_params); - } - - virtual void assign_eh(bool_var v, bool is_true) { - context& ctx = get_context(); - expr* e = ctx.bool_var2expr(v); - if (is_quantifier(e)) { - if (is_true) { - m_internalizer.add_initial_clause(to_quantifier(e)); - } - else { - // TBD: handle existential force later. - } - } - } - - virtual final_check_status final_check_eh() { - TRACE("theory_instgen", tout << "Final check\n";); - return instantiate_all_possible(); - } - - virtual void init_model(smt::model_generator & m) { } - - virtual smt::model_value_proc * mk_value(smt::enode * n, smt::model_generator & m) { - UNREACHABLE(); - return 0; - } - - virtual void relevant_eh(app * n) { } - - virtual void push_scope_eh() { - m_subsumer.push(); - } - - virtual void pop_scope_eh(unsigned num_scopes) { - m_subsumer.pop(num_scopes); - } - - virtual void collect_statistics(::statistics & st) const { - st.update("inst axiom", m_stats.m_num_axioms); - st.update("inst subsump", m_stats.m_num_subsumptions); - } - - void inc_subsumptions() { - ++m_stats.m_num_subsumptions; - } - - void inc_axioms() { - ++m_stats.m_num_axioms; - } - - void inc_pruned() { - ++m_stats.m_num_pruned; - } - - }; - - theory_instgen* mk_theory_instgen(ast_manager& m, smt_params& p) { - return alloc(theory_instgen_impl, m, p); - } - - ast_manager& instantiator::get_manager() const { - return m_parent.m(); - } - - smt::context& instantiator::get_context() const { - return m_parent.get_context(); - } - - bool instantiator::instantiate_clauses( - app * lit1, clause_type * clause1, - app * lit2, clause_type * clause2, - instantiation_result_vector& result) { - TRACE("theory_instgen", tout << PP(lit1, m) << " " << PP(clause1, m) << "\n"; - tout << PP(lit2, m) << " " << PP(clause2, m) << "\n";); - substitution subst(m); - unsigned var_cnt = std::max(clause1->get_num_decls(), clause2->get_num_decls()); - subst.reserve(2, var_cnt); - //don't trust there offset values too much, it's just what i expect the substitution does:) - app_ref complementary(m); - mk_folit_neg(lit1, complementary); - TRUSTME(m_unifier(complementary, lit2, subst)); - - inst subst1(m); - extract_substitution(subst, clause1, var_cnt, true, subst1); - inst subst2(m); - extract_substitution(subst, clause2, var_cnt, false, subst2); - - bool s1_identity = matching_set::is_identity(subst1); - bool s2_identity = matching_set::is_identity(subst2); - - if((!s1_identity && !is_allowed_instantiation(clause1, subst1)) || - (!s2_identity && !is_allowed_instantiation(clause2, subst2))) { - TRACE("theory_instgen", - tout << "Pruned instantiation\n"; - tout << PP(clause1, m) << "\n"; - display_vector(subst1, tout); - tout << PP(clause2, m) << "\n"; - display_vector(subst2, tout); - ); - m_parent.inc_pruned(); - return false; - } - - // - // both substitutions cannot be identity as then the two complementary - // literals would correspond to the same SAT solver variable - // - SASSERT(!s1_identity || !s2_identity); - - if(!s1_identity) { - instantiation_result res1(m); - get_result_from_subst(clause1, subst1, res1); - result.push_back(res1); - } - - if(!s2_identity) { - instantiation_result res2(m); - get_result_from_subst(clause2, subst2, res2); - result.push_back(res2); - } - return true; - } - - // literal lit2 is ground. It is not associated with a clause. - // literal lit1 is associatd with a non-ground clause. - bool instantiator::instantiate_clause( - app * lit1, clause_type * clause1, app * lit2, - instantiation_result_vector& result) { - TRACE("theory_instgen", tout << PP(lit1, m) << " " << PP(clause1, m) << "\n"; - tout << PP(lit2, m) << "\n";); - if (!is_ground(lit2)) { - // TBD: remove. Debug code. - std::cout << PP(lit1, m) << " " << PP(clause1, m) << "\n"; - std::cout << PP(lit2, m) << "\n"; - m_unif_index.display(std::cout); - } - SASSERT(is_ground(lit2)); - substitution subst(m); - unsigned var_cnt = clause1->get_num_decls(); - subst.reserve(2, var_cnt); - app_ref complementary(m); - mk_folit_neg(lit1, complementary); - - TRUSTME(m_unifier(complementary, lit2, subst)); - - inst subst1(m); - extract_substitution(subst, clause1, var_cnt, true, subst1); - - if(matching_set::is_identity(subst1) || - !is_allowed_instantiation(clause1, subst1)) { - TRACE("theory_instgen", - tout << "Pruned instantiation\n"; - tout << PP(clause1, m) << "\n"; - display_vector(subst1, tout); - ); - m_parent.inc_pruned(); - return false; - } - - instantiation_result res1(m); - get_result_from_subst(clause1, subst1, res1); - result.push_back(res1); - return true; - } - - - //-------------------------- - // - // fo_clause_internalizer - // - //-------------------------- - - smt::context& fo_clause_internalizer::get_context() const { - return m_parent.get_context(); - } - - ast_manager& fo_clause_internalizer::m() const { - return m_parent.m(); - } - - bool fo_clause_internalizer::simplify_clause(quantifier * clause, expr_ref& result, ptr_vector<quantifier>& assumptions) { - m_parent.m_subsumer.simplify(clause, result, assumptions); - bool change = clause!=result.get(); - if (change) { - m_parent.inc_subsumptions(); - } - return change; - } - - void fo_clause_internalizer::get_instance_clause(instantiation_result const& ir, expr_ref& res) { - expr * orig_cl = ir.clause()->get_expr(); - SASSERT(is_app(orig_cl)); - - expr_ref res_inner(m()); //the clause after substitution, we might still need to quantify it - m_subst(orig_cl, ir.subst().size(), ir.subst().c_ptr(), res_inner); - SASSERT(is_app(res_inner.get())); - - if(is_ground(res_inner.get())) { - res = res_inner; - return; //we made it ground! - } - - ptr_vector<sort> free_var_sorts; - svector<symbol> quant_names; - get_free_vars(res_inner.get(), free_var_sorts); - unsigned free_var_cnt = free_var_sorts.size(); - for(unsigned i=0; i<free_var_cnt; i++) { - if(!free_var_sorts[i]) { - free_var_sorts[i] = m().mk_bool_sort(); //get a dummy variable - } - quant_names.push_back(symbol(free_var_cnt-i-1)); - } - free_var_sorts.reverse(); - - quantifier_ref q_with_unused(m().mk_quantifier(true, free_var_cnt, free_var_sorts.c_ptr(), quant_names.c_ptr(), res_inner.get()), m()); - elim_unused_vars(m(), q_with_unused, res); - } - - /** - Clause can be either ground (app) or non-ground (quantifier). Root clause - should be the original input clause from which the current clause was - instantiated, or zero if this clause is initial - */ - void fo_clause_internalizer::add_clause_to_smt(expr * clause, quantifier* root_clause, ptr_vector<quantifier> const& assumptions) { - SASSERT(!root_clause || root_clause->is_forall()); - SASSERT(is_quantifier(clause) || root_clause); - context& ctx = get_context(); - buffer<literal> lits; - ptr_buffer<expr> todo; - - bool is_q_clause = is_quantifier(clause); - quantifier * q_clause = is_q_clause ? to_quantifier(clause) : 0; - if (!root_clause) root_clause = q_clause; - - lits.push_back(~get_root_clause_control_literal(root_clause)); - - for(unsigned i=0; i<assumptions.size(); ++i) { - lits.push_back(~get_root_clause_control_literal(assumptions[i])); - } - - todo.push_back(is_q_clause?(q_clause->get_expr()):clause); - - while (!todo.empty()) { - expr* e = todo.back(); - todo.pop_back(); - if (m().is_or(e)) { - todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); - } - else if (is_app(e)) { - lits.push_back(ground_fo_literal(to_app(e), q_clause)); - } - else { - SASSERT(is_var(e) || is_quantifier(e)); - UNREACHABLE(); - //by skipping part of the disjunction we may get unsound - } - } - TRACE("theory_instgen", - tout << "Axiom: \n"; - for (unsigned i = 0; i < lits.size(); ++i) { - expr_ref e(m()); - get_context().literal2expr(lits[i], e); - tout << PP(e.get(), m()) << "\n"; - } - ); - m_parent.inc_axioms(); - ctx.mk_th_axiom(m_parent.get_id(), lits.size(), lits.c_ptr()); - } - - -}; diff --git a/src/smt/theory_instgen.h b/src/smt/theory_instgen.h deleted file mode 100644 index c32636e9b..000000000 --- a/src/smt/theory_instgen.h +++ /dev/null @@ -1,45 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - theory_instgen.h - -Abstract: - - InstGen (iProver) style theory solver. - It provides an instantiation based engine - based on InstGen methods together with - unit propagation. - - -Author: - - Krystof Hoder (t-khoder) - Nikolaj Bjorner (nbjorner) 2011-10-6 - -Revision History: - ---*/ -#ifndef _THEORY_INST_GEN_H_ -#define _THEORY_INST_GEN_H_ - -#include "smt_theory.h" -#include "smt_params.h" - -namespace smt { - - class theory_instgen : public theory { - public: - theory_instgen(family_id fid) : theory(fid) {} - virtual ~theory_instgen() {} - virtual void internalize_quantifier(quantifier* q) = 0; - virtual char const * get_name() const { return "instgen"; } - }; - - theory_instgen* mk_theory_instgen(ast_manager& m, smt_params& p); - -}; - -#endif /* _THEORY_INST_GEN_H_ */ - diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index cca21b90e..831efa087 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -18,7 +18,7 @@ Notes: --*/ #include"ctx_simplify_tactic.h" #include"mk_simplified_app.h" -#include"num_occurs_goal.h" +#include"goal_num_occurs.h" #include"cooperate.h" #include"ast_ll_pp.h" #include"ast_smt2_pp.h" @@ -51,7 +51,7 @@ struct ctx_simplify_tactic::imp { unsigned m_scope_lvl; unsigned m_depth; unsigned m_num_steps; - num_occurs_goal m_occs; + goal_num_occurs m_occs; mk_simplified_app m_mk_app; unsigned long long m_max_memory; unsigned m_max_depth; diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index a79a4ed06..19190c299 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include"nnf.h" #include"tactical.h" +#include"filter_model_converter.h" class nnf_tactic : public tactic { params_ref m_params; @@ -100,6 +101,13 @@ public: } g->inc_depth(); result.push_back(g.get()); + unsigned num_extra_names = dnames.get_num_names(); + if (num_extra_names > 0) { + filter_model_converter * fmc = alloc(filter_model_converter, m); + mc = fmc; + for (unsigned i = 0; i < num_extra_names; i++) + fmc->insert(dnames.get_name_decl(i)); + } TRACE("nnf", g->display(tout);); SASSERT(g->is_well_sorted()); } diff --git a/src/tactic/num_occurs_goal.cpp b/src/tactic/goal_num_occurs.cpp similarity index 75% rename from src/tactic/num_occurs_goal.cpp rename to src/tactic/goal_num_occurs.cpp index adc412434..6c94e307c 100644 --- a/src/tactic/num_occurs_goal.cpp +++ b/src/tactic/goal_num_occurs.cpp @@ -3,7 +3,7 @@ Copyright (c) 2012 Microsoft Corporation Module Name: - num_occurs_goal.cpp + goal_num_occurs.cpp Abstract: @@ -15,10 +15,10 @@ Author: Revision History: --*/ -#include"num_occurs_goal.h" +#include"goal_num_occurs.h" #include"goal.h" -void num_occurs_goal::operator()(goal const & g) { +void goal_num_occurs::operator()(goal const & g) { expr_fast_mark1 visited; unsigned sz = g.size(); for (unsigned i = 0; i < sz; i++) { diff --git a/src/tactic/num_occurs_goal.h b/src/tactic/goal_num_occurs.h similarity index 64% rename from src/tactic/num_occurs_goal.h rename to src/tactic/goal_num_occurs.h index 5e6e0cc94..33a25e03f 100644 --- a/src/tactic/num_occurs_goal.h +++ b/src/tactic/goal_num_occurs.h @@ -3,7 +3,7 @@ Copyright (c) 2012 Microsoft Corporation Module Name: - num_occurs_goal.h + goal_num_occurs.h Abstract: @@ -15,16 +15,16 @@ Author: Revision History: --*/ -#ifndef _NUM_OCCURS_GOAL_H_ -#define _NUM_OCCURS_GOAL_H_ +#ifndef _GOAL_NUM_OCCURS_H_ +#define _GOAL_NUM_OCCURS_H_ #include"num_occurs.h" class goal; -class num_occurs_goal : public num_occurs { +class goal_num_occurs : public num_occurs { public: - num_occurs_goal(bool ignore_ref_count1 = false, bool ignore_quantifiers = false): + goal_num_occurs(bool ignore_ref_count1 = false, bool ignore_quantifiers = false): num_occurs(ignore_ref_count1, ignore_quantifiers) { }