diff --git a/README b/README
index 42f6b1e58..13f3d4fa4 100644
--- a/README
+++ b/README
@@ -20,9 +20,10 @@ Execute:
It will install z3 executable at /usr/bin, libraries at /usr/lib, and include files at /usr/include.
You can change the installation p
-Use the following commands to install in a different prefix (e.g., /home/leo).
+Use the following commands to install in a different prefix (e.g., /home/leo), and the Z3 python
+bindings in a different python package directory.
- python scripts/mk_make.py --prefix=/home/leo
+ python scripts/mk_make.py --prefix=/home/leo --pydir=/home/leo/python
cd build
make
sudo make install
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index 4c74b41a5..7ac026673 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -3,6 +3,8 @@ RELEASE NOTES
Version 4.3.2
=============
+- New parameter setting infrastructure. Now, it is possible to set parameter for Z3 internal modules. Several parameter names changed. Execute `z3 -p` for the new parameter list.
+
- Added get_version() and get_version_string() to Z3Py
- Added support for FreeBSD. Z3 can be compiled on FreeBSD using g++.
@@ -20,6 +22,10 @@ Version 4.3.2
- Fixed crash when parsing incorrect formulas. The crash was introduced when support for "arithmetic coercions" was added in Z3 4.3.0.
+- Added new option to mk_make to allow users to specify where python bindings (Z3Py) will be installed. (Thanks to Dejan Jovanovic for reporting the problem).
+
+- Fixed crash reported at http://z3.codeplex.com/workitem/10
+
Version 4.3.1
=============
diff --git a/doc/website.dox b/doc/website.dox
index efbf71f56..6936b4f77 100644
--- a/doc/website.dox
+++ b/doc/website.dox
@@ -13,6 +13,7 @@
- \ref capi
- \ref cppapi
- .NET API
+ - Java API
- Python API (also available in pydoc format).
- Try Z3 online at RiSE4Fun using Python or SMT 2.0.
*/
diff --git a/doc/z3api.dox b/doc/z3api.dox
index 07c7fe0dc..0233e6d83 100644
--- a/doc/z3api.dox
+++ b/doc/z3api.dox
@@ -687,6 +687,7 @@ WARN_LOGFILE =
# with spaces.
INPUT = ../src/api/dotnet \
+ ../src/api/java \
../src/api/c++ \
./tmp
@@ -740,7 +741,8 @@ FILE_PATTERNS = website.dox \
Util.cs \
Version.cs \
Z3Exception.cs \
- Z3Object.cs
+ Z3Object.cs \
+ *.java
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
diff --git a/scripts/mk_project.py b/scripts/mk_project.py
index 707d067e2..0ebcfe45d 100644
--- a/scripts/mk_project.py
+++ b/scripts/mk_project.py
@@ -58,11 +58,11 @@ def init_project_def():
add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv')
add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'muz_qe', 'sls_tactic', 'subpaving_tactic'], 'tactic/portfolio')
add_lib('smtparser', ['portfolio'], 'parsers/smt')
+ API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h']
add_lib('api', ['portfolio', 'user_plugin', 'smtparser'],
- includes2install=['z3.h', 'z3_api.h', 'z3_v1.h', 'z3_macros.h'])
+ includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files)
add_exe('shell', ['api', 'sat', 'extra_cmds'], exe_name='z3')
add_exe('test', ['api', 'fuzzing'], exe_name='test-z3', install=False)
- API_files = ['z3_api.h']
add_dll('api_dll', ['api', 'sat', 'extra_cmds'], 'api/dll',
reexports=['api'],
dll_name='libz3',
diff --git a/scripts/mk_util.py b/scripts/mk_util.py
index 98fae665a..381f92def 100644
--- a/scripts/mk_util.py
+++ b/scripts/mk_util.py
@@ -85,8 +85,9 @@ def is_linux():
def is_osx():
return IS_OSX
-def unix_path2dos(path):
- return string.join(path.split('/'), '\\')
+def norm_path(p):
+ # We use '/' on mk_project for convenience
+ return os.path.join(*(p.split('/')))
def which(program):
import os
@@ -138,7 +139,9 @@ def exec_cmd(cmd):
if e != "":
se = e.split(' ')
if len(se) > 1:
- new_cmd.extend(se)
+ for e2 in se:
+ if e2 != "":
+ new_cmd.append(e2)
else:
new_cmd.append(e)
cmd = new_cmd
@@ -178,10 +181,18 @@ def test_c_compiler(cc):
def test_gmp(cc):
if is_verbose():
print "Testing GMP..."
- t = TempFile('tst.cpp')
+ t = TempFile('tstgmp.cpp')
t.add('#include\nint main() { mpz_t t; mpz_init(t); mpz_clear(t); return 0; }\n')
t.commit()
- return exec_compiler_cmd([cc, CPPFLAGS, CXXFLAGS, 'tst.cpp', LDFLAGS, '-lgmp']) == 0
+ return exec_compiler_cmd([cc, CPPFLAGS, 'tstgmp.cpp', LDFLAGS, '-lgmp']) == 0
+
+def test_openmp(cc):
+ if is_verbose():
+ print "Testing OpenMP..."
+ t = TempFile('tstomp.cpp')
+ t.add('#include\nint main() { return omp_in_parallel() ? 1 : 0; }\n')
+ t.commit()
+ return exec_compiler_cmd([cc, CPPFLAGS, 'tstomp.cpp', LDFLAGS, '-fopenmp']) == 0
def check_java():
t = TempFile('Hello.java')
@@ -200,12 +211,19 @@ def check_java():
raise MKException('Failed testing Java program. Set environment variable JAVA with the path to the Java virtual machine')
find_java_home()
+def find_jni_h(path):
+ for root, dirs, files in os.walk(path):
+ for f in files:
+ if f == 'jni.h':
+ return root
+ return False
+
def find_java_home():
global JAVA_HOME
if JAVA_HOME != None:
if is_verbose():
print "Checking jni.h..."
- if os.path.exists('%s%sinclude%sjni.h' % (JAVA_HOME, os.sep, os.sep)):
+ if os.path.exists(os.path.join(JAVA_HOME, 'include', 'jni.h')):
return
if is_verbose():
print "Finding JAVA_HOME..."
@@ -227,9 +245,12 @@ def find_java_home():
path = string.join(tmp[:len(tmp) - 3], os.sep)
if is_verbose():
print "Checking jni.h..."
- if not os.path.exists('%s%sinclude%sjni.h' % (path, os.sep, os.sep)):
- raise MKException("Failed to detect jni.h at '%s%sinclude'" % (path, os.sep))
- JAVA_HOME = path
+ jni_dir = find_jni_h(path)
+ if not jni_dir:
+ raise MKException("Failed to detect jni.h at '%s'.Possible solution: set JAVA_HOME with the path to JDK." % os.path.join(path, 'include'))
+ JAVA_HOME = os.path.split(jni_dir)[0]
+ if is_verbose():
+ print 'JAVA_HOME=%s' % JAVA_HOME
return
raise MKException('Failed to find JAVA_HOME')
@@ -340,6 +361,7 @@ def display_help(exit_code):
print " -s, --silent do not print verbose messages."
if not IS_WINDOWS:
print " -p , --prefix= installation prefix (default: %s)." % PREFIX
+ print " -y , --pydir= installation prefix for Z3 python bindings (default: %s)." % PYTHON_PACKAGE_DIR
print " -b , --build= subdirectory where Z3 will be built (default: build)."
print " -d, --debug compile Z3 in debug mode."
print " -t, --trace enable tracing in release mode."
@@ -370,52 +392,56 @@ 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 DOTNET_ENABLED, JAVA_ENABLED, STATIC_LIB, PREFIX, GMP
+ global DOTNET_ENABLED, JAVA_ENABLED, STATIC_LIB, PREFIX, GMP, PYTHON_PACKAGE_DIR
try:
options, remainder = getopt.gnu_getopt(sys.argv[1:],
- 'b:dsxhmcvtnp:gj',
+ 'b:dsxhmcvtnp:gjy:',
['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj',
- 'trace', 'nodotnet', 'staticlib', 'prefix=', 'gmp', 'java'])
- for opt, arg in options:
- if opt in ('-b', '--build'):
- if arg == 'src':
- raise MKException('The src directory should not be used to host the Makefile')
- set_build_dir(arg)
- elif opt in ('-s', '--silent'):
- VERBOSE = False
- elif opt in ('-d', '--debug'):
- DEBUG_MODE = True
- elif opt in ('-x', '--x64'):
- if not IS_WINDOWS:
- raise MKException('x64 compilation mode can only be specified when using Visual Studio')
- VS_X64 = True
- elif opt in ('-h', '--help'):
- display_help(0)
- elif opt in ('-m', '--onlymakefiles'):
- ONLY_MAKEFILES = True
- elif opt in ('-c', '--showcpp'):
- SHOW_CPPS = True
- elif opt in ('-v', '--vsproj'):
- VS_PROJ = True
- elif opt in ('-t', '--trace'):
- TRACE = True
- elif opt in ('-n', '--nodotnet'):
- DOTNET_ENABLED = False
- elif opt in ('--staticlib'):
- STATIC_LIB = True
- elif opt in ('-p', '--prefix'):
- PREFIX = arg
- elif opt in ('-g', '--gmp'):
- GMP = True
- elif opt in ('-j', '--java'):
- JAVA_ENABLED = True
- else:
- print "ERROR: Invalid command line option '%s'" % opt
- display_help(1)
+ 'trace', 'nodotnet', 'staticlib', 'prefix=', 'gmp', 'java', 'pydir='])
except:
print "ERROR: Invalid command line option"
display_help(1)
+ for opt, arg in options:
+ if opt in ('-b', '--build'):
+ if arg == 'src':
+ raise MKException('The src directory should not be used to host the Makefile')
+ set_build_dir(arg)
+ elif opt in ('-s', '--silent'):
+ VERBOSE = False
+ elif opt in ('-d', '--debug'):
+ DEBUG_MODE = True
+ elif opt in ('-x', '--x64'):
+ if not IS_WINDOWS:
+ raise MKException('x64 compilation mode can only be specified when using Visual Studio')
+ VS_X64 = True
+ elif opt in ('-h', '--help'):
+ display_help(0)
+ elif opt in ('-m', '--onlymakefiles'):
+ ONLY_MAKEFILES = True
+ elif opt in ('-c', '--showcpp'):
+ SHOW_CPPS = True
+ elif opt in ('-v', '--vsproj'):
+ VS_PROJ = True
+ elif opt in ('-t', '--trace'):
+ TRACE = True
+ elif opt in ('-n', '--nodotnet'):
+ DOTNET_ENABLED = False
+ elif opt in ('--staticlib'):
+ STATIC_LIB = True
+ elif opt in ('-p', '--prefix'):
+ PREFIX = arg
+ elif opt in ('-y', '--pydir'):
+ PYTHON_PACKAGE_DIR = arg
+ mk_dir(PYTHON_PACKAGE_DIR)
+ elif opt in ('-g', '--gmp'):
+ GMP = True
+ elif opt in ('-j', '--java'):
+ JAVA_ENABLED = True
+ else:
+ print "ERROR: Invalid command line option '%s'" % opt
+ display_help(1)
+
# Return a list containing a file names included using '#include' in
# the given C/C++ file named fname.
def extract_c_includes(fname):
@@ -440,11 +466,11 @@ def extract_c_includes(fname):
# Given a path dir1/subdir2/subdir3 returns ../../..
def reverse_path(p):
- l = p.split('/')
+ l = p.split(os.sep)
n = len(l)
r = '..'
for i in range(1, n):
- r = '%s/%s' % (r, '..')
+ r = os.path.join(r, '..')
return r
def mk_dir(d):
@@ -453,12 +479,13 @@ def mk_dir(d):
def set_build_dir(d):
global BUILD_DIR, REV_BUILD_DIR
- BUILD_DIR = d
+ BUILD_DIR = norm_path(d)
REV_BUILD_DIR = reverse_path(d)
def set_z3py_dir(p):
global SRC_DIR, Z3PY_SRC_DIR
- full = '%s/%s' % (SRC_DIR, p)
+ p = norm_path(p)
+ full = os.path.join(SRC_DIR, p)
if not os.path.exists(full):
raise MKException("Python bindings directory '%s' does not exist" % full)
Z3PY_SRC_DIR = full
@@ -556,22 +583,23 @@ class Component:
if path == None:
path = name
self.name = name
+ path = norm_path(path)
self.path = path
self.deps = find_all_deps(name, deps)
self.build_dir = path
- self.src_dir = '%s/%s' % (SRC_DIR, path)
- self.to_src_dir = '%s/%s' % (REV_BUILD_DIR, self.src_dir)
+ self.src_dir = os.path.join(SRC_DIR, path)
+ self.to_src_dir = os.path.join(REV_BUILD_DIR, self.src_dir)
# Find fname in the include paths for the given component.
# ownerfile is only used for creating error messages.
# That is, we were looking for fname when processing ownerfile
def find_file(self, fname, ownerfile):
- full_fname = '%s/%s' % (self.src_dir, fname)
+ full_fname = os.path.join(self.src_dir, fname)
if os.path.exists(full_fname):
return self
for dep in self.deps:
c_dep = get_component(dep)
- full_fname = '%s/%s' % (c_dep.src_dir, fname)
+ full_fname = os.path.join(c_dep.src_dir, fname)
if os.path.exists(full_fname):
return c_dep
raise MKException("Failed to find include file '%s' for '%s' when processing '%s'." % (fname, ownerfile, self.name))
@@ -579,15 +607,15 @@ class Component:
# Display all dependencies of file basename located in the given component directory.
# The result is displayed at out
def add_cpp_h_deps(self, out, basename):
- includes = extract_c_includes('%s/%s' % (self.src_dir, basename))
- out.write('%s/%s' % (self.to_src_dir, basename))
+ includes = extract_c_includes(os.path.join(self.src_dir, basename))
+ out.write(os.path.join(self.to_src_dir, basename))
for include in includes:
owner = self.find_file(include, basename)
- out.write(' %s/%s.node' % (owner.build_dir, include))
+ out.write(' %s.node' % os.path.join(owner.build_dir, include))
# Add a rule for each #include directive in the file basename located at the current component.
def add_rule_for_each_include(self, out, basename):
- fullname = '%s/%s' % (self.src_dir, basename)
+ fullname = os.path.join(self.src_dir, basename)
includes = extract_c_includes(fullname)
for include in includes:
owner = self.find_file(include, fullname)
@@ -599,12 +627,12 @@ class Component:
# ast/ast_pp.h.node : ../src/util/ast_pp.h util/util.h.node ast/ast.h.node
# @echo "done" > ast/ast_pp.h.node
def add_h_rule(self, out, include):
- include_src_path = '%s/%s' % (self.to_src_dir, include)
+ include_src_path = os.path.join(self.to_src_dir, include)
if include_src_path in _Processed_Headers:
return
_Processed_Headers.add(include_src_path)
self.add_rule_for_each_include(out, include)
- include_node = '%s/%s.node' % (self.build_dir, include)
+ include_node = '%s.node' % os.path.join(self.build_dir, include)
out.write('%s: ' % include_node)
self.add_cpp_h_deps(out, include)
out.write('\n')
@@ -612,13 +640,13 @@ class Component:
def add_cpp_rules(self, out, include_defs, cppfile):
self.add_rule_for_each_include(out, cppfile)
- objfile = '%s/%s$(OBJ_EXT)' % (self.build_dir, os.path.splitext(cppfile)[0])
- srcfile = '%s/%s' % (self.to_src_dir, cppfile)
+ objfile = '%s$(OBJ_EXT)' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])
+ srcfile = os.path.join(self.to_src_dir, cppfile)
out.write('%s: ' % objfile)
self.add_cpp_h_deps(out, cppfile)
out.write('\n')
if SHOW_CPPS:
- out.write('\t@echo %s/%s\n' % (self.src_dir, cppfile))
+ out.write('\t@echo %s\n' % os.path.join(self.src_dir, cppfile))
out.write('\t@$(CXX) $(CXXFLAGS) $(%s) $(CXX_OUT_FLAG)%s %s\n' % (include_defs, objfile, srcfile))
def mk_makefile(self, out):
@@ -627,7 +655,7 @@ class Component:
for dep in self.deps:
out.write(' -I%s' % get_component(dep).to_src_dir)
out.write('\n')
- mk_dir('%s/%s' % (BUILD_DIR, self.build_dir))
+ 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)
@@ -676,10 +704,10 @@ class LibComponent(Component):
# generate rule for lib
objs = []
for cppfile in get_cpp_files(self.src_dir):
- objfile = '%s/%s$(OBJ_EXT)' % (self.build_dir, os.path.splitext(cppfile)[0])
+ objfile = '%s$(OBJ_EXT)' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])
objs.append(objfile)
- libfile = '%s/%s$(LIB_EXT)' % (self.build_dir, self.name)
+ libfile = '%s$(LIB_EXT)' % os.path.join(self.build_dir, self.name)
out.write('%s:' % libfile)
for obj in objs:
out.write(' ')
@@ -694,17 +722,17 @@ class LibComponent(Component):
def mk_install(self, out):
for include in self.includes2install:
- out.write('\t@cp %s/%s $(PREFIX)/include/%s\n' % (self.to_src_dir, include, include))
+ out.write('\t@cp %s %s\n' % (os.path.join(self.to_src_dir, include), os.path.join('$(PREFIX)', 'include', include)))
def mk_uninstall(self, out):
for include in self.includes2install:
- out.write('\t@rm -f $(PREFIX)/include/%s\n' % include)
+ out.write('\t@rm -f %s\n' % os.path.join('$(PREFIX)', 'include', include))
def mk_win_dist(self, build_path, dist_path):
- mk_dir('%s/include' % dist_path)
+ mk_dir(os.path.join(dist_path, 'include'))
for include in self.includes2install:
- shutil.copy('%s/%s' % (self.src_dir, include),
- '%s/include/%s' % (dist_path, include))
+ shutil.copy(os.path.join(self.src_dir, include),
+ os.path.join(dist_path, 'include', include))
# "Library" containing only .h files. This is just a placeholder for includes files to be installed.
class HLibComponent(LibComponent):
@@ -741,14 +769,14 @@ class ExeComponent(Component):
deps = sort_components(self.deps)
objs = []
for cppfile in get_cpp_files(self.src_dir):
- objfile = '%s/%s$(OBJ_EXT)' % (self.build_dir, os.path.splitext(cppfile)[0])
+ objfile = '%s$(OBJ_EXT)' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])
objs.append(objfile)
for obj in objs:
out.write(' ')
out.write(obj)
for dep in deps:
c_dep = get_component(dep)
- out.write(' %s/%s$(LIB_EXT)' % (c_dep.build_dir, c_dep.name))
+ out.write(' %s$(LIB_EXT)' % os.path.join(c_dep.build_dir, c_dep.name))
out.write('\n')
out.write('\t$(LINK) $(LINK_OUT_FLAG)%s $(LINK_FLAGS)' % exefile)
for obj in objs:
@@ -756,7 +784,7 @@ class ExeComponent(Component):
out.write(obj)
for dep in deps:
c_dep = get_component(dep)
- out.write(' %s/%s$(LIB_EXT)' % (c_dep.build_dir, c_dep.name))
+ out.write(' %s$(LIB_EXT)' % os.path.join(c_dep.build_dir, c_dep.name))
out.write(' $(LINK_EXTRA_FLAGS)\n')
out.write('%s: %s\n\n' % (self.name, exefile))
@@ -773,17 +801,17 @@ class ExeComponent(Component):
def mk_install(self, out):
if self.install:
exefile = '%s$(EXE_EXT)' % self.exe_name
- out.write('\t@cp %s $(PREFIX)/bin/%s\n' % (exefile, exefile))
+ out.write('\t@cp %s %s\n' % (exefile, os.path.join('$(PREFIX)', 'bin', exefile)))
def mk_uninstall(self, out):
exefile = '%s$(EXE_EXT)' % self.exe_name
- out.write('\t@rm -f $(PREFIX)/bin/%s\n' % exefile)
+ out.write('\t@rm -f %s\n' % os.path.join('$(PREFIX)', 'bin', exefile))
def mk_win_dist(self, build_path, dist_path):
if self.install:
- mk_dir('%s/bin' % dist_path)
- shutil.copy('%s/%s.exe' % (build_path, self.exe_name),
- '%s/bin/%s.exe' % (dist_path, self.exe_name))
+ mk_dir(os.path.join(dist_path, 'bin'))
+ shutil.copy('%s.exe' % os.path.join(build_path, self.exe_name),
+ '%s.exe' % os.path.join(dist_path, 'bin', self.exe_name))
class ExtraExeComponent(ExeComponent):
@@ -812,13 +840,13 @@ class DLLComponent(Component):
deps = sort_components(self.deps)
objs = []
for cppfile in get_cpp_files(self.src_dir):
- objfile = '%s/%s$(OBJ_EXT)' % (self.build_dir, os.path.splitext(cppfile)[0])
+ objfile = '%s$(OBJ_EXT)' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])
objs.append(objfile)
# Explicitly include obj files of reexport. This fixes problems with exported symbols on Linux and OSX.
for reexport in self.reexports:
reexport = get_component(reexport)
for cppfile in get_cpp_files(reexport.src_dir):
- objfile = '%s/%s$(OBJ_EXT)' % (reexport.build_dir, os.path.splitext(cppfile)[0])
+ objfile = '%s$(OBJ_EXT)' % os.path.join(reexport.build_dir, os.path.splitext(cppfile)[0])
objs.append(objfile)
for obj in objs:
out.write(' ')
@@ -826,7 +854,7 @@ class DLLComponent(Component):
for dep in deps:
if not dep in self.reexports:
c_dep = get_component(dep)
- out.write(' %s/%s$(LIB_EXT)' % (c_dep.build_dir, c_dep.name))
+ out.write(' %s$(LIB_EXT)' % os.path.join(c_dep.build_dir, c_dep.name))
out.write('\n')
out.write('\t$(LINK) $(SLINK_OUT_FLAG)%s $(SLINK_FLAGS)' % dllfile)
for obj in objs:
@@ -835,10 +863,10 @@ class DLLComponent(Component):
for dep in deps:
if not dep in self.reexports:
c_dep = get_component(dep)
- out.write(' %s/%s$(LIB_EXT)' % (c_dep.build_dir, c_dep.name))
+ out.write(' %s$(LIB_EXT)' % os.path.join(c_dep.build_dir, c_dep.name))
out.write(' $(SLINK_EXTRA_FLAGS)')
if IS_WINDOWS:
- out.write(' /DEF:%s/%s.def' % (self.to_src_dir, self.name))
+ out.write(' /DEF:%s.def' % os.path.join(self.to_src_dir, self.name))
out.write('\n')
if self.static:
self.mk_static(out)
@@ -851,13 +879,13 @@ class DLLComponent(Component):
# generate rule for lib
objs = []
for cppfile in get_cpp_files(self.src_dir):
- objfile = '%s/%s$(OBJ_EXT)' % (self.build_dir, os.path.splitext(cppfile)[0])
+ objfile = '%s$(OBJ_EXT)' % os.path.join(self.build_dir, os.path.splitext(cppfile)[0])
objs.append(objfile)
# we have to "reexport" all object files
for dep in self.deps:
dep = get_component(dep)
for cppfile in get_cpp_files(dep.src_dir):
- objfile = '%s/%s$(OBJ_EXT)' % (dep.build_dir, os.path.splitext(cppfile)[0])
+ objfile = '%s$(OBJ_EXT)' % os.path.join(dep.build_dir, os.path.splitext(cppfile)[0])
objs.append(objfile)
libfile = '%s$(LIB_EXT)' % self.dll_name
out.write('%s:' % libfile)
@@ -886,29 +914,29 @@ class DLLComponent(Component):
def mk_install(self, out):
if self.install:
dllfile = '%s$(SO_EXT)' % self.dll_name
- out.write('\t@cp %s $(PREFIX)/lib/%s\n' % (dllfile, dllfile))
- out.write('\t@cp %s %s/%s\n' % (dllfile, PYTHON_PACKAGE_DIR, dllfile))
+ out.write('\t@cp %s %s\n' % (dllfile, os.path.join('$(PREFIX)', 'lib', dllfile)))
+ out.write('\t@cp %s %s\n' % (dllfile, os.path.join(PYTHON_PACKAGE_DIR, dllfile)))
if self.static:
libfile = '%s$(LIB_EXT)' % self.dll_name
- out.write('\t@cp %s $(PREFIX)/lib/%s\n' % (libfile, libfile))
+ out.write('\t@cp %s %s\n' % (libfile, os.path.join('$(PREFIX)', 'lib', libfile)))
def mk_uninstall(self, out):
dllfile = '%s$(SO_EXT)' % self.dll_name
- out.write('\t@rm -f $(PREFIX)/lib/%s\n' % dllfile)
- out.write('\t@rm -f %s/%s\n' % (PYTHON_PACKAGE_DIR, dllfile))
+ out.write('\t@rm -f %s\n' % os.path.join('$(PREFIX)', 'lib', dllfile))
+ out.write('\t@rm -f %s\n' % os.path.join(PYTHON_PACKAGE_DIR, dllfile))
libfile = '%s$(LIB_EXT)' % self.dll_name
- out.write('\t@rm -f $(PREFIX)/lib/%s\n' % libfile)
+ out.write('\t@rm -f %s\n' % os.path.join('$(PREFIX)', 'lib', libfile))
def mk_win_dist(self, build_path, dist_path):
if self.install:
- mk_dir('%s/bin' % dist_path)
- shutil.copy('%s/%s.dll' % (build_path, self.dll_name),
- '%s/bin/%s.dll' % (dist_path, self.dll_name))
+ 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('%s/bin' % dist_path)
- shutil.copy('%s/%s.lib' % (build_path, self.dll_name),
- '%s/bin/%s.lib' % (dist_path, self.dll_name))
+ 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))
class DotNetDLLComponent(Component):
def __init__(self, name, dll_name, path, deps, assembly_info_dir):
@@ -925,12 +953,12 @@ class DotNetDLLComponent(Component):
cs_fp_files = []
cs_files = []
for cs_file in get_cs_files(self.src_dir):
- cs_fp_files.append('%s/%s' % (self.to_src_dir, cs_file))
+ cs_fp_files.append(os.path.join(self.to_src_dir, cs_file))
cs_files.append(cs_file)
if self.assembly_info_dir != '.':
- for cs_file in get_cs_files('%s/%s' % (self.src_dir, self.assembly_info_dir)):
- cs_fp_files.append('%s/%s/%s' % (self.to_src_dir, self.assembly_info_dir, cs_file))
- cs_files.append('%s\%s' % (self.assembly_info_dir, cs_file))
+ for cs_file in get_cs_files(os.path.join(self.src_dir, self.assembly_info_dir)):
+ cs_fp_files.append(os.path.join(self.to_src_dir, self.assembly_info_dir, cs_file))
+ cs_files.append(os.path.join(self.assembly_info_dir, cs_file))
dllfile = '%s.dll' % self.dll_name
out.write('%s:' % dllfile)
for cs_file in cs_fp_files:
@@ -944,8 +972,8 @@ class DotNetDLLComponent(Component):
out.write('\n')
# HACK
win_to_src_dir = self.to_src_dir.replace('/', '\\')
- out.write(' move %s\%s\n' % (win_to_src_dir, dllfile))
- out.write(' move %s\%s.pdb\n' % (win_to_src_dir, self.dll_name))
+ out.write(' move %s\n' % os.path.join(win_to_src_dir, dllfile))
+ out.write(' move %s.pdb\n' % os.path.join(win_to_src_dir, self.dll_name))
out.write('%s: %s\n\n' % (self.name, dllfile))
return
@@ -958,9 +986,9 @@ class DotNetDLLComponent(Component):
def mk_win_dist(self, build_path, dist_path):
if DOTNET_ENABLED:
# Assuming all DotNET dll should be in the distribution
- mk_dir('%s/bin' % dist_path)
- shutil.copy('%s/%s.dll' % (build_path, self.dll_name),
- '%s/bin/%s.dll' % (dist_path, self.dll_name))
+ 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))
class JavaDLLComponent(Component):
@@ -974,9 +1002,9 @@ class JavaDLLComponent(Component):
def mk_makefile(self, out):
if is_java_enabled():
- mk_dir(BUILD_DIR+'/api/java/classes')
+ mk_dir(os.path.join(BUILD_DIR, 'api', 'java', 'classes'))
dllfile = '%s$(SO_EXT)' % self.dll_name
- out.write('libz3java$(SO_EXT): libz3$(SO_EXT) %s/Native.cpp\n' % self.to_src_dir)
+ out.write('libz3java$(SO_EXT): libz3$(SO_EXT) %s\n' % os.path.join(self.to_src_dir, 'Native.cpp'))
t = '\t$(CXX) $(CXXFLAGS) $(CXX_OUT_FLAG)api/java/Native$(OBJ_EXT) -I"%s/include" -I"%s/include/PLATFORM" -I%s %s/Native.cpp\n' % (JAVA_HOME, JAVA_HOME, get_component('api').to_src_dir, self.to_src_dir)
if IS_OSX:
t = t.replace('PLATFORM', 'darwin')
@@ -986,25 +1014,29 @@ class JavaDLLComponent(Component):
t = t.replace('PLATFORM', 'win32')
out.write(t)
if IS_WINDOWS: # On Windows, CL creates a .lib file to link against.
- out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) api/java/Native$(OBJ_EXT) libz3$(LIB_EXT)\n')
+ out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) %s$(OBJ_EXT) libz3$(LIB_EXT)\n' %
+ os.path.join('api', 'java', 'Native'))
else:
- out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) api/java/Native$(OBJ_EXT) libz3$(SO_EXT)\n')
+ out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) %s$(OBJ_EXT) libz3$(SO_EXT)\n' %
+ os.path.join('api', 'java', 'Native'))
out.write('%s.jar: libz3java$(SO_EXT) ' % self.package_name)
deps = ''
for jfile in get_java_files(self.src_dir):
- deps += ('%s/%s ' % (self.to_src_dir, jfile))
- for jfile in get_java_files((self.src_dir + "/enumerations")):
- deps += ('%s/enumerations/%s ' % (self.to_src_dir, jfile))
- if IS_WINDOWS: deps = deps.replace('/', '\\')
+ deps += ('%s ' % os.path.join(self.to_src_dir, jfile))
+ for jfile in get_java_files(os.path.join(self.src_dir, "enumerations")):
+ deps += '%s ' % os.path.join(self.to_src_dir, 'enumerations', jfile)
out.write(deps)
out.write('\n')
- t = ('\t%s %s/enumerations/*.java -d api/java/classes\n' % (JAVAC, self.to_src_dir))
- if IS_WINDOWS: t = t.replace('/','\\')
+ t = ('\t%s %s.java -d %s\n' % (JAVAC, os.path.join(self.to_src_dir, 'enumerations', '*'), os.path.join('api', 'java', 'classes')))
out.write(t)
- t = ('\t%s -cp api/java/classes %s/*.java -d api/java/classes\n' % (JAVAC, self.to_src_dir))
- if IS_WINDOWS: t = t.replace('/','\\')
+ t = ('\t%s -cp %s %s.java -d %s\n' % (JAVAC,
+ os.path.join('api', 'java', 'classes'),
+ os.path.join(self.to_src_dir, '*'),
+ os.path.join('api', 'java', 'classes')))
out.write(t)
- out.write('\tjar cfm %s.jar %s/manifest -C api/java/classes .\n' % (self.package_name, self.to_src_dir))
+ out.write('\tjar cfm %s.jar %s -C %s .\n' % (self.package_name,
+ os.path.join(self.to_src_dir, 'manifest'),
+ os.path.join('api', 'java', 'classes')))
out.write('java: %s.jar\n\n' % self.package_name)
def main_component(self):
@@ -1014,8 +1046,8 @@ class JavaDLLComponent(Component):
class ExampleComponent(Component):
def __init__(self, name, path):
Component.__init__(self, name, path, [])
- self.ex_dir = '%s/%s' % (EXAMPLE_DIR, self.path)
- self.to_ex_dir = '%s/%s' % (REV_BUILD_DIR, self.ex_dir)
+ self.ex_dir = os.path.join(EXAMPLE_DIR, self.path)
+ self.to_ex_dir = os.path.join(REV_BUILD_DIR, self.ex_dir)
def is_example(self):
return True
@@ -1038,7 +1070,7 @@ class CppExampleComponent(ExampleComponent):
out.write('%s: %s' % (exefile, dll))
for cppfile in self.src_files():
out.write(' ')
- out.write('%s/%s' % (self.to_ex_dir, cppfile))
+ out.write(os.path.join(self.to_ex_dir, cppfile))
out.write('\n')
out.write('\t%s $(LINK_OUT_FLAG)%s $(LINK_FLAGS)' % (self.compiler(), exefile))
# Add include dir components
@@ -1046,7 +1078,7 @@ class CppExampleComponent(ExampleComponent):
out.write(' -I%s' % get_component(CPP_COMPONENT).to_src_dir)
for cppfile in self.src_files():
out.write(' ')
- out.write('%s/%s' % (self.to_ex_dir, cppfile))
+ out.write(os.path.join(self.to_ex_dir, cppfile))
out.write(' ')
if IS_WINDOWS:
out.write('%s.lib' % dll_name)
@@ -1080,7 +1112,7 @@ class DotNetExampleComponent(ExampleComponent):
out.write('%s: %s' % (exefile, dll))
for csfile in get_cs_files(self.ex_dir):
out.write(' ')
- out.write('%s/%s' % (self.to_ex_dir, csfile))
+ out.write(os.path.join(self.to_ex_dir, csfile))
out.write('\n')
out.write('\tcsc /out:%s /reference:%s /debug:full /reference:System.Numerics.dll' % (exefile, dll))
if VS_X64:
@@ -1091,7 +1123,7 @@ class DotNetExampleComponent(ExampleComponent):
out.write(' ')
# HACK
win_ex_dir = self.to_ex_dir.replace('/', '\\')
- out.write('%s\\%s' % (win_ex_dir, csfile))
+ out.write(os.path.join(win_ex_dir, csfile))
out.write('\n')
out.write('_ex_%s: %s\n\n' % (self.name, exefile))
@@ -1108,7 +1140,7 @@ class JavaExampleComponent(ExampleComponent):
out.write('_ex_%s: %s' % (self.name, pkg))
deps = ''
for jfile in get_java_files(self.ex_dir):
- out.write(' %s/%s' % (self.to_ex_dir, jfile))
+ out.write(' %s' % os.path.join(self.to_ex_dir, jfile))
if IS_WINDOWS:
deps = deps.replace('/', '\\')
out.write('%s\n' % deps)
@@ -1116,7 +1148,7 @@ class JavaExampleComponent(ExampleComponent):
win_ex_dir = self.to_ex_dir
for javafile in get_java_files(self.ex_dir):
out.write(' ')
- out.write('%s/%s' % (win_ex_dir, javafile))
+ out.write(os.path.join(win_ex_dir, javafile))
out.write(' -d .\n\n')
class PythonExampleComponent(ExampleComponent):
@@ -1126,9 +1158,9 @@ class PythonExampleComponent(ExampleComponent):
# Python examples are just placeholders, we just copy the *.py files when mk_makefile is invoked.
# We don't need to include them in the :examples rule
def mk_makefile(self, out):
- full = '%s/%s' % (EXAMPLE_DIR, self.path)
+ full = os.path.join(EXAMPLE_DIR, self.path)
for py in filter(lambda f: f.endswith('.py'), os.listdir(full)):
- shutil.copyfile('%s/%s' % (full, py), '%s/%s' % (BUILD_DIR, py))
+ shutil.copyfile(os.path.join(full, py), os.path.join(BUILD_DIR, py))
if is_verbose():
print "Copied Z3Py example '%s' to '%s'" % (py, BUILD_DIR)
out.write('_ex_%s: \n\n' % self.name)
@@ -1195,7 +1227,7 @@ def add_z3py_example(name, path=None):
def mk_config():
if ONLY_MAKEFILES:
return
- config = open('%s/config.mk' % BUILD_DIR, 'w')
+ config = open(os.path.join(BUILD_DIR, 'config.mk'), 'w')
if IS_WINDOWS:
config.write(
'CC=cl\n'
@@ -1268,22 +1300,26 @@ def mk_config():
else:
CPPFLAGS = '%s -D_MP_INTERNAL' % CPPFLAGS
CXXFLAGS = '%s -c' % CXXFLAGS
- if is_CXX_gpp():
+ HAS_OMP = test_openmp(CXX)
+ if HAS_OMP:
CXXFLAGS = '%s -fopenmp -mfpmath=sse' % CXXFLAGS
LDFLAGS = '%s -fopenmp' % LDFLAGS
SLIBEXTRAFLAGS = '-fopenmp'
else:
- # CLang does not support OMP
CXXFLAGS = '%s -D_NO_OMP_' % CXXFLAGS
SLIBEXTRAFLAGS = ''
+ if DEBUG_MODE:
+ CXXFLAGS = '%s -g -Wall' % CXXFLAGS
+ else:
+ 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]
if sysname == 'Darwin':
SO_EXT = '.dylib'
SLIBFLAGS = '-dynamiclib'
elif sysname == 'Linux':
CXXFLAGS = '%s -fno-strict-aliasing -D_LINUX_' % CXXFLAGS
- if is_CXX_clangpp():
- CXXFLAGS = '%s -Wno-unknown-pragmas -Wno-overloaded-virtual -Wno-unused-value' % CXXFLAGS
SO_EXT = '.so'
LDFLAGS = '%s -lrt' % LDFLAGS
SLIBFLAGS = '-shared'
@@ -1309,10 +1345,6 @@ def mk_config():
CPPFLAGS = '%s -DZ3DEBUG' % CPPFLAGS
if TRACE or DEBUG_MODE:
CPPFLAGS = '%s -D_TRACE' % CPPFLAGS
- if DEBUG_MODE:
- CXXFLAGS = '%s -g -Wall' % CXXFLAGS
- else:
- CXXFLAGS = '%s -O3 -D _EXTERNAL_RELEASE -fomit-frame-pointer' % CXXFLAGS
CXXFLAGS = '%s -msse -msse2' % CXXFLAGS
config.write('PREFIX=%s\n' % PREFIX)
config.write('CC=%s\n' % CC)
@@ -1339,6 +1371,7 @@ def mk_config():
print 'C++ Compiler: %s' % CXX
print 'C Compiler : %s' % CC
print 'Arithmetic: %s' % ARITH
+ print 'OpenMP: %s' % HAS_OMP
print 'Prefix: %s' % PREFIX
print '64-bit: %s' % is64()
if is_java_enabled():
@@ -1348,9 +1381,9 @@ def mk_config():
def mk_install(out):
out.write('install:\n')
- out.write('\t@mkdir -p $(PREFIX)/bin\n')
- out.write('\t@mkdir -p $(PREFIX)/include\n')
- out.write('\t@mkdir -p $(PREFIX)/lib\n')
+ out.write('\t@mkdir -p %s\n' % os.path.join('$(PREFIX)', 'bin'))
+ out.write('\t@mkdir -p %s\n' % os.path.join('$(PREFIX)', 'include'))
+ out.write('\t@mkdir -p %s\n' % os.path.join('$(PREFIX)', 'lib'))
for c in get_components():
c.mk_install(out)
out.write('\t@cp z3*.pyc %s\n' % PYTHON_PACKAGE_DIR)
@@ -1361,7 +1394,7 @@ def mk_uninstall(out):
out.write('uninstall:\n')
for c in get_components():
c.mk_uninstall(out)
- out.write('\t@rm -f %s/z3*.pyc\n' % PYTHON_PACKAGE_DIR)
+ out.write('\t@rm -f %s*.pyc\n' % os.path.join(PYTHON_PACKAGE_DIR, 'z3'))
out.write('\t@echo Z3 was successfully uninstalled.\n')
out.write('\n')
@@ -1370,9 +1403,9 @@ def mk_makefile():
mk_dir(BUILD_DIR)
mk_config()
if VERBOSE:
- print "Writing %s/Makefile" % BUILD_DIR
- out = open('%s/Makefile' % BUILD_DIR, 'w')
- out.write('# Automatically generated file. Generator: scripts/mk_make.py\n')
+ print "Writing %s" % os.path.join(BUILD_DIR, 'Makefile')
+ out = open(os.path.join(BUILD_DIR, 'Makefile'), 'w')
+ out.write('# Automatically generated file.\n')
out.write('include config.mk\n')
# Generate :all rule
out.write('all:')
@@ -1412,7 +1445,7 @@ def mk_makefile():
else:
print " platform: x86"
print "To build Z3, open a [Visual Studio Command Prompt], then"
- print "type 'cd %s/%s && nmake'\n" % (os.getcwd(), BUILD_DIR)
+ print "type 'cd %s && nmake'\n" % os.path.join(os.getcwd(), BUILD_DIR)
print 'Remark: to open a Visual Studio Command Prompt, go to: "Start > All Programs > Visual Studio > Visual Studio Tools"'
else:
print "Type 'cd %s; make' to build Z3" % BUILD_DIR
@@ -1459,7 +1492,10 @@ def pyg_default_as_c_literal(p):
return '"%s"' % p[2]
elif p[1] == SYMBOL:
return 'symbol("%s")' % p[2]
- return p[2]
+ elif p[1] == UINT:
+ return '%su' % p[2]
+ else:
+ return p[2]
def to_c_method(s):
return s.replace('.', '_')
@@ -1472,6 +1508,8 @@ def def_module_params(module_name, export, params, class_name=None, description=
hpp = os.path.join(dirname, '%s.hpp' % class_name)
out = open(hpp, 'w')
out.write('// Automatically generated file\n')
+ out.write('#ifndef __%s_HPP_\n' % class_name.upper())
+ out.write('#define __%s_HPP_\n' % class_name.upper())
out.write('#include"params.h"\n')
if export:
out.write('#include"gparams.h"\n')
@@ -1479,7 +1517,7 @@ def def_module_params(module_name, export, params, class_name=None, description=
out.write(' params_ref const & p;\n')
if export:
out.write(' params_ref g;\n')
- out.write(' %s(params_ref const & _p = params_ref()):\n' % class_name)
+ out.write(' %s(params_ref const & _p = params_ref::get_empty()):\n' % class_name)
out.write(' p(_p)')
if export:
out.write(', g(gparams::get_module("%s"))' % module_name)
@@ -1503,6 +1541,7 @@ def def_module_params(module_name, export, params, class_name=None, description=
out.write(' %s %s() const { return p.%s("%s", %s); }\n' %
(TYPE2CTYPE[param[1]], to_c_method(param[0]), TYPE2GETTER[param[1]], param[0], pyg_default_as_c_literal(param)))
out.write('};\n')
+ out.write('#endif\n')
if is_verbose():
print "Generated '%s'" % hpp
@@ -1532,14 +1571,14 @@ def exec_pyg_scripts():
# database.smt ==> database.h
def mk_pat_db():
c = get_component(PATTERN_COMPONENT)
- fin = open('%s/database.smt2' % c.src_dir, 'r')
- fout = open('%s/database.h' % c.src_dir, 'w')
+ fin = open(os.path.join(c.src_dir, 'database.smt2'), 'r')
+ fout = open(os.path.join(c.src_dir, 'database.h'), 'w')
fout.write('char const * g_pattern_database =\n')
for line in fin:
fout.write('"%s\\n"\n' % line.strip('\n'))
fout.write(';\n')
if VERBOSE:
- print "Generated '%s/database.h'" % c.src_dir
+ print "Generated '%s'" % os.path.join(c.src_dir, 'database.h')
# Update version numbers
def update_version():
@@ -1557,32 +1596,32 @@ def update_version():
# Update files with the version number
def mk_version_dot_h(major, minor, build, revision):
c = get_component(UTIL_COMPONENT)
- fout = open('%s/version.h' % c.src_dir, 'w')
+ fout = open(os.path.join(c.src_dir, 'version.h'), 'w')
fout.write('// automatically generated file.\n')
fout.write('#define Z3_MAJOR_VERSION %s\n' % major)
fout.write('#define Z3_MINOR_VERSION %s\n' % minor)
fout.write('#define Z3_BUILD_NUMBER %s\n' % build)
fout.write('#define Z3_REVISION_NUMBER %s\n' % revision)
if VERBOSE:
- print "Generated '%s/version.h'" % c.src_dir
+ print "Generated '%s'" % os.path.join(c.src_dir, 'version.h')
# Update version number in AssemblyInfo.cs files
def update_all_assembly_infos(major, minor, build, revision):
for c in get_components():
if c.has_assembly_info():
- assembly = '%s/%s/AssemblyInfo.cs' % (c.src_dir, c.assembly_info_dir)
+ assembly = os.path.join(c.src_dir, c.assembly_info_dir, 'AssemblyInfo.cs')
if os.path.exists(assembly):
# It is a CS file
update_assembly_info_version(assembly,
major, minor, build, revision, False)
else:
- assembly = '%s/%s/AssemblyInfo.cpp' % (c.src_dir, c.assembly_info_dir)
+ assembly = os.path.join(c.src_dir, c.assembly_info_dir, 'AssemblyInfo.cs')
if os.path.exists(assembly):
# It is a cpp file
update_assembly_info_version(assembly,
major, minor, build, revision, True)
else:
- raise MKException("Failed to find assembly info file at '%s/%s'" % (c.src_dir, c.assembly_info_dir))
+ raise MKException("Failed to find assembly info file at '%s'" % os.path.join(c.src_dir, c.assembly_info_dir))
# Update version number in the given AssemblyInfo.cs files
@@ -1641,7 +1680,7 @@ def mk_install_tactic_cpp(cnames, path):
global ADD_TACTIC_DATA, ADD_PROBE_DATA
ADD_TACTIC_DATA = []
ADD_PROBE_DATA = []
- fullname = '%s/install_tactic.cpp' % path
+ fullname = os.path.join(path, 'install_tactic.cpp')
fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n')
fout.write('#include"tactic.h"\n')
@@ -1654,7 +1693,7 @@ def mk_install_tactic_cpp(cnames, path):
h_files = filter(lambda f: f.endswith('.h') or f.endswith('.hpp'), os.listdir(c.src_dir))
for h_file in h_files:
added_include = False
- fin = open("%s/%s" % (c.src_dir, h_file), 'r')
+ fin = open(os.path.join(c.src_dir, h_file), 'r')
for line in fin:
if tactic_pat.match(line):
if not added_include:
@@ -1707,7 +1746,7 @@ def mk_all_install_tactic_cpps():
def mk_mem_initializer_cpp(cnames, path):
initializer_cmds = []
finalizer_cmds = []
- fullname = '%s/mem_initializer.cpp' % path
+ fullname = os.path.join(path, 'mem_initializer.cpp')
fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n')
initializer_pat = re.compile('[ \t]*ADD_INITIALIZER\(\'([^\']*)\'\)')
@@ -1719,7 +1758,7 @@ def mk_mem_initializer_cpp(cnames, path):
h_files = filter(lambda f: f.endswith('.h') or f.endswith('.hpp'), os.listdir(c.src_dir))
for h_file in h_files:
added_include = False
- fin = open("%s/%s" % (c.src_dir, h_file), 'r')
+ fin = open(os.path.join(c.src_dir, h_file), 'r')
for line in fin:
m = initializer_pat.match(line)
if m:
@@ -1770,7 +1809,7 @@ def mk_gparams_register_modules(cnames, path):
cmds = []
mod_cmds = []
mod_descrs = []
- fullname = '%s/gparams_register_modules.cpp' % path
+ fullname = os.path.join(path, 'gparams_register_modules.cpp')
fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n')
fout.write('#include"gparams.h"\n')
@@ -1782,7 +1821,7 @@ def mk_gparams_register_modules(cnames, path):
h_files = filter(lambda f: f.endswith('.h') or f.endswith('.hpp'), os.listdir(c.src_dir))
for h_file in h_files:
added_include = False
- fin = open("%s/%s" % (c.src_dir, h_file), 'r')
+ fin = open(os.path.join(c.src_dir, h_file), 'r')
for line in fin:
m = reg_pat.match(line)
if m:
@@ -1822,13 +1861,13 @@ def mk_all_gparams_register_modules():
# Generate a .def based on the files at c.export_files slot.
def mk_def_file(c):
pat1 = re.compile(".*Z3_API.*")
- defname = '%s/%s.def' % (c.src_dir, c.name)
+ defname = '%s.def' % os.path.join(c.src_dir, c.name)
fout = open(defname, 'w')
fout.write('LIBRARY "%s"\nEXPORTS\n' % c.dll_name)
num = 1
for dot_h in c.export_files:
dot_h_c = c.find_file(dot_h, c.name)
- api = open('%s/%s' % (dot_h_c.src_dir, dot_h), 'r')
+ api = open(os.path.join(dot_h_c.src_dir, dot_h), 'r')
for line in api:
m = pat1.match(line)
if m:
@@ -1855,11 +1894,11 @@ def cp_z3pyc_to_build():
raise MKException("failed to compile Z3Py sources")
for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(Z3PY_SRC_DIR)):
try:
- os.remove('%s/%s' % (BUILD_DIR, pyc))
+ os.remove(os.path.join(BUILD_DIR, pyc))
except:
pass
- shutil.copyfile('%s/%s' % (Z3PY_SRC_DIR, pyc), '%s/%s' % (BUILD_DIR, pyc))
- os.remove('%s/%s' % (Z3PY_SRC_DIR, pyc))
+ shutil.copyfile(os.path.join(Z3PY_SRC_DIR, pyc), os.path.join(BUILD_DIR, pyc))
+ os.remove(os.path.join(Z3PY_SRC_DIR, pyc))
if is_verbose():
print "Generated '%s'" % pyc
@@ -1871,13 +1910,13 @@ def mk_bindings(api_files):
api = get_component(API_COMPONENT)
for api_file in api_files:
api_file_path = api.find_file(api_file, api.name)
- new_api_files.append('%s/%s' % (api_file_path.src_dir, api_file))
+ new_api_files.append(os.path.join(api_file_path.src_dir, api_file))
g = {}
g["API_FILES"] = new_api_files
if is_java_enabled():
check_java()
mk_z3consts_java(api_files)
- execfile('scripts/update_api.py', g) # HACK
+ execfile(os.path.join('scripts', 'update_api.py'), g) # HACK
cp_z3pyc_to_build()
# Extract enumeration types from API files, and add python definitions.
@@ -1892,14 +1931,14 @@ def mk_z3consts_py(api_files):
openbrace_pat = re.compile("{ *")
closebrace_pat = re.compile("}.*;")
- z3consts = open('%s/z3consts.py' % Z3PY_SRC_DIR, 'w')
+ z3consts = open(os.path.join(Z3PY_SRC_DIR, 'z3consts.py'), 'w')
z3consts.write('# Automatically generated file\n\n')
api_dll = get_component(Z3_DLL_COMPONENT)
for api_file in api_files:
api_file_c = api_dll.find_file(api_file, api_dll.name)
- api_file = '%s/%s' % (api_file_c.src_dir, api_file)
+ api_file = os.path.join(api_file_c.src_dir, api_file)
api = open(api_file, 'r')
SEARCHING = 0
@@ -1955,7 +1994,7 @@ def mk_z3consts_py(api_files):
idx = idx + 1
linenum = linenum + 1
if VERBOSE:
- print "Generated '%s'" % ('%s/z3consts.py' % Z3PY_SRC_DIR)
+ print "Generated '%s'" % os.path.join(Z3PY_SRC_DIR, 'z3consts.py')
# Extract enumeration types from z3_api.h, and add .Net definitions
@@ -1970,7 +2009,7 @@ def mk_z3consts_dotnet(api_files):
dotnet = get_component(DOTNET_COMPONENT)
DeprecatedEnums = [ 'Z3_search_failure' ]
- z3consts = open('%s/Enumerations.cs' % dotnet.src_dir, 'w')
+ z3consts = open(os.path.join(dotnet.src_dir, 'Enumerations.cs'), 'w')
z3consts.write('// Automatically generated file\n\n')
z3consts.write('using System;\n\n'
'#pragma warning disable 1591\n\n'
@@ -1979,7 +2018,7 @@ def mk_z3consts_dotnet(api_files):
for api_file in api_files:
api_file_c = dotnet.find_file(api_file, dotnet.name)
- api_file = '%s/%s' % (api_file_c.src_dir, api_file)
+ api_file = os.path.join(api_file_c.src_dir, api_file)
api = open(api_file, 'r')
@@ -2040,7 +2079,7 @@ def mk_z3consts_dotnet(api_files):
linenum = linenum + 1
z3consts.write('}\n');
if VERBOSE:
- print "Generated '%s'" % ('%s/Enumerations.cs' % dotnet.src_dir)
+ print "Generated '%s'" % os.path.join(dotnet.src_dir, 'Enumerations.cs')
# Extract enumeration types from z3_api.h, and add Java definitions
@@ -2055,13 +2094,13 @@ def mk_z3consts_java(api_files):
java = get_component(JAVA_COMPONENT)
DeprecatedEnums = [ 'Z3_search_failure' ]
- gendir = java.src_dir + "/enumerations"
+ gendir = os.path.join(java.src_dir, "enumerations")
if not os.path.exists(gendir):
os.mkdir(gendir)
for api_file in api_files:
api_file_c = java.find_file(api_file, java.name)
- api_file = '%s/%s' % (api_file_c.src_dir, api_file)
+ api_file = os.path.join(api_file_c.src_dir, api_file)
api = open(api_file, 'r')
@@ -2104,7 +2143,7 @@ def mk_z3consts_java(api_files):
if m:
name = words[1]
if name not in DeprecatedEnums:
- efile = open('%s/%s.java' % (gendir, name), 'w')
+ efile = open('%s.java' % os.path.join(gendir, name), 'w')
efile.write('/**\n * Automatically generated file\n **/\n\n')
efile.write('package %s.enumerations;\n\n' % java.package_name);
@@ -2153,7 +2192,7 @@ def mk_gui_str(id):
def mk_vs_proj(name, components):
if not VS_PROJ:
return
- proj_name = '%s/%s.vcxproj' % (BUILD_DIR, name)
+ proj_name = '%s.vcxproj' % os.path.join(BUILD_DIR, name)
modes=['Debug', 'Release']
PLATFORMS=['Win32']
f = open(proj_name, 'w')
@@ -2225,7 +2264,7 @@ def mk_vs_proj(name, components):
for dep in deps:
dep = get_component(dep)
for cpp in filter(lambda f: f.endswith('.cpp'), os.listdir(dep.src_dir)):
- f.write(' \n' % (dep.to_src_dir, cpp))
+ f.write(' \n' % os.path.join(dep.to_src_dir, cpp))
f.write(' \n')
f.write(' \n')
f.write(' \n')
@@ -2239,8 +2278,8 @@ def mk_win_dist(build_path, dist_path):
c.mk_win_dist(build_path, dist_path)
# Add Z3Py to lib directory
for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(build_path)):
- shutil.copy('%s/%s' % (build_path, pyc),
- '%s/bin/%s' % (dist_path, pyc))
+ shutil.copy(os.path.join(build_path, pyc),
+ os.path.join(dist_path, 'bin', pyc))
if __name__ == '__main__':
diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py
index 3cebce7f6..57ae66b03 100644
--- a/scripts/mk_win_dist.py
+++ b/scripts/mk_win_dist.py
@@ -100,7 +100,7 @@ def mk_build_dirs():
def check_vc_cmd_prompt():
try:
DEVNULL = open(os.devnull, 'wb')
- subprocess.call(['cl'], stdin=DEVNULL, stderr=DEVNULL)
+ subprocess.call(['cl'], stdout=DEVNULL, stderr=DEVNULL)
except:
raise MKException("You must execute the mk_win_dist.py script on a Visual Studio Command Prompt")
diff --git a/scripts/update_api.py b/scripts/update_api.py
index d7dbb7bcf..a636a1a02 100644
--- a/scripts/update_api.py
+++ b/scripts/update_api.py
@@ -24,11 +24,11 @@ from mk_exception import *
api_dir = get_component('api').src_dir
dotnet_dir = get_component('dotnet').src_dir
-log_h = open('%s/api_log_macros.h' % api_dir, 'w')
-log_c = open('%s/api_log_macros.cpp' % api_dir, 'w')
-exe_c = open('%s/api_commands.cpp' % api_dir, 'w')
-core_py = open('%s/z3core.py' % get_z3py_dir(), 'w')
-dotnet_fileout = '%s/Native.cs' % dotnet_dir
+log_h = open(os.path.join(api_dir, 'api_log_macros.h'), 'w')
+log_c = open(os.path.join(api_dir, 'api_log_macros.cpp'), 'w')
+exe_c = open(os.path.join(api_dir, 'api_commands.cpp'), 'w')
+core_py = open(os.path.join(get_z3py_dir(), 'z3core.py'), 'w')
+dotnet_fileout = os.path.join(dotnet_dir, 'Native.cs')
##
log_h.write('// Automatically generated file\n')
log_h.write('#include\"z3.h\"\n')
@@ -479,8 +479,8 @@ def mk_java():
if not is_java_enabled():
return
java_dir = get_component('java').src_dir
- java_nativef = '%s/Native.java' % java_dir
- java_wrapperf = '%s/Native.cpp' % java_dir
+ java_nativef = os.path.join(java_dir, 'Native.java')
+ java_wrapperf = os.path.join(java_dir, 'Native.cpp')
java_native = open(java_nativef, 'w')
java_native.write('// Automatically generated file\n')
java_native.write('package %s;\n' % get_component('java').package_name)
@@ -981,8 +981,8 @@ exe_c.close()
core_py.close()
if is_verbose():
- print "Generated '%s'" % ('%s/api_log_macros.h' % api_dir)
- print "Generated '%s'" % ('%s/api_log_macros.cpp' % api_dir)
- print "Generated '%s'" % ('%s/api_commands.cpp' % api_dir)
- print "Generated '%s'" % ('%s/z3core.py' % get_z3py_dir())
- print "Generated '%s'" % ('%s/Native.cs' % dotnet_dir)
+ print "Generated '%s'" % os.path.join(api_dir, 'api_log_macros.h')
+ print "Generated '%s'" % os.path.join(api_dir, 'api_log_macros.cpp')
+ print "Generated '%s'" % os.path.join(api_dir, 'api_commands.cpp')
+ print "Generated '%s'" % os.path.join(get_z3py_dir(), 'z3core.py')
+ print "Generated '%s'" % os.path.join(dotnet_dir, 'Native.cs')
diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp
new file mode 100644
index 000000000..7716cbb59
--- /dev/null
+++ b/src/api/api_algebraic.cpp
@@ -0,0 +1,422 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ api_algebraic.cpp
+
+Abstract:
+
+ Additional APIs for handling Z3 algebraic numbers encoded as
+ Z3_ASTs
+
+Author:
+
+ Leonardo de Moura (leonardo) 2012-12-07
+
+Notes:
+
+--*/
+#include
+#include"z3.h"
+#include"api_log_macros.h"
+#include"api_context.h"
+#include"api_ast_vector.h"
+#include"algebraic_numbers.h"
+#include"expr2polynomial.h"
+#include"cancel_eh.h"
+#include"scoped_timer.h"
+
+
+#define CHECK_IS_ALGEBRAIC(ARG, RET) { \
+ if (!Z3_algebraic_is_value_core(c, ARG)) { \
+ SET_ERROR_CODE(Z3_INVALID_ARG); \
+ return RET; \
+ } \
+}
+
+#define CHECK_IS_ALGEBRAIC_X(ARG, RET) { \
+ if (!Z3_algebraic_is_value_core(c, ARG)) { \
+ SET_ERROR_CODE(Z3_INVALID_ARG); \
+ RETURN_Z3(RET); \
+ } \
+}
+
+static arith_util & au(Z3_context c) {
+ return mk_c(c)->autil();
+}
+
+static algebraic_numbers::manager & am(Z3_context c) {
+ return au(c).am();
+}
+
+static bool is_rational(Z3_context c, Z3_ast a) {
+ return au(c).is_numeral(to_expr(a));
+}
+
+static bool is_irrational(Z3_context c, Z3_ast a) {
+ return au(c).is_irrational_algebraic_numeral(to_expr(a));
+}
+
+static rational get_rational(Z3_context c, Z3_ast a) {
+ SASSERT(is_rational(c, a));
+ rational r;
+ VERIFY(au(c).is_numeral(to_expr(a), r));
+ return r;
+}
+
+static algebraic_numbers::anum const & get_irrational(Z3_context c, Z3_ast a) {
+ SASSERT(is_irrational(c, a));
+ return au(c).to_irrational_algebraic_numeral(to_expr(a));
+}
+
+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)) ||
+ _c->autil().is_irrational_algebraic_numeral(to_expr(a)));
+ }
+
+ Z3_bool Z3_API Z3_algebraic_is_value(Z3_context c, Z3_ast a) {
+ Z3_TRY;
+ LOG_Z3_algebraic_is_value(c, a);
+ RESET_ERROR_CODE();
+ return Z3_algebraic_is_value_core(c, a) ? Z3_TRUE : Z3_FALSE;
+ Z3_CATCH_RETURN(Z3_FALSE);
+ }
+
+ Z3_bool Z3_API Z3_algebraic_is_pos(Z3_context c, Z3_ast a) {
+ return Z3_algebraic_sign(c, a) > 0;
+ }
+
+ Z3_bool Z3_API Z3_algebraic_is_neg(Z3_context c, Z3_ast a) {
+ return Z3_algebraic_sign(c, a) < 0;
+ }
+
+ Z3_bool Z3_API Z3_algebraic_is_zero(Z3_context c, Z3_ast a) {
+ return Z3_algebraic_sign(c, a) == 0;
+ }
+
+ int Z3_API Z3_algebraic_sign(Z3_context c, Z3_ast a) {
+ Z3_TRY;
+ LOG_Z3_algebraic_sign(c, a);
+ RESET_ERROR_CODE();
+ CHECK_IS_ALGEBRAIC(a, 0);
+ if (is_rational(c, a)) {
+ rational v = get_rational(c, a);
+ if (v.is_pos()) return 1;
+ else if (v.is_neg()) return -1;
+ else return 0;
+ }
+ else {
+ algebraic_numbers::anum const & v = get_irrational(c, a);
+ if (am(c).is_pos(v)) return 1;
+ else if (am(c).is_neg(v)) return -1;
+ else return 0;
+ }
+ Z3_CATCH_RETURN(0);
+ }
+
+#define BIN_OP(RAT_OP, IRAT_OP) \
+ algebraic_numbers::manager & _am = am(c); \
+ ast * r = 0; \
+ if (is_rational(c, a)) { \
+ rational av = get_rational(c, a); \
+ if (is_rational(c, b)) { \
+ rational bv = get_rational(c, b); \
+ r = au(c).mk_numeral(av RAT_OP bv, false); \
+ } \
+ else { \
+ algebraic_numbers::anum const & bv = get_irrational(c, b); \
+ scoped_anum _av(_am); \
+ _am.set(_av, av.to_mpq()); \
+ scoped_anum _r(_am); \
+ _am.IRAT_OP(_av, bv, _r); \
+ r = au(c).mk_numeral(_r, false); \
+ } \
+ } \
+ else { \
+ algebraic_numbers::anum const & av = get_irrational(c, a); \
+ if (is_rational(c, b)) { \
+ rational bv = get_rational(c, b); \
+ scoped_anum _bv(_am); \
+ _am.set(_bv, bv.to_mpq()); \
+ scoped_anum _r(_am); \
+ _am.IRAT_OP(av, _bv, _r); \
+ r = au(c).mk_numeral(_r, false); \
+ } \
+ else { \
+ algebraic_numbers::anum const & bv = get_irrational(c, b); \
+ scoped_anum _r(_am); \
+ _am.IRAT_OP(av, bv, _r); \
+ r = au(c).mk_numeral(_r, false); \
+ } \
+ } \
+ mk_c(c)->save_ast_trail(r); \
+ RETURN_Z3(of_ast(r));
+
+
+ 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);
+ BIN_OP(+,add);
+ Z3_CATCH_RETURN(0);
+ }
+
+ 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);
+ BIN_OP(-,sub);
+ Z3_CATCH_RETURN(0);
+ }
+
+ 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);
+ BIN_OP(*,mul);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_algebraic_div(Z3_context c, Z3_ast a, Z3_ast b) {
+ Z3_TRY;
+ LOG_Z3_algebraic_div(c, a, b);
+ RESET_ERROR_CODE();
+ CHECK_IS_ALGEBRAIC_X(a, 0);
+ CHECK_IS_ALGEBRAIC_X(b, 0);
+ if ((is_rational(c, b) && get_rational(c, b).is_zero()) ||
+ (!is_rational(c, b) && am(c).is_zero(get_irrational(c, b)))) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ RETURN_Z3(0);
+ }
+ BIN_OP(/,div);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_algebraic_root(Z3_context c, Z3_ast a, unsigned k) {
+ Z3_TRY;
+ LOG_Z3_algebraic_root(c, a, k);
+ RESET_ERROR_CODE();
+ CHECK_IS_ALGEBRAIC_X(a, 0);
+ if (k % 2 == 0) {
+ if ((is_rational(c, a) && get_rational(c, a).is_neg()) ||
+ (!is_rational(c, a) && am(c).is_neg(get_irrational(c, a)))) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ RETURN_Z3(0);
+ }
+ }
+ 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());
+ _am.root(av, k, _r);
+ }
+ else {
+ algebraic_numbers::anum const & av = get_irrational(c, a);
+ _am.root(av, k, _r);
+ }
+ expr * r = au(c).mk_numeral(_r, false);
+ mk_c(c)->save_ast_trail(r);
+ RETURN_Z3(of_ast(r));
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_algebraic_power(Z3_context c, Z3_ast a, unsigned k) {
+ Z3_TRY;
+ LOG_Z3_algebraic_power(c, a, k);
+ RESET_ERROR_CODE();
+ CHECK_IS_ALGEBRAIC_X(a, 0);
+ 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());
+ _am.power(av, k, _r);
+ }
+ else {
+ algebraic_numbers::anum const & av = get_irrational(c, a);
+ _am.power(av, k, _r);
+ }
+ expr * r = au(c).mk_numeral(_r, false);
+ mk_c(c)->save_ast_trail(r);
+ RETURN_Z3(of_ast(r));
+ Z3_CATCH_RETURN(0);
+ }
+
+#define BIN_PRED(RAT_PRED, IRAT_PRED) \
+ algebraic_numbers::manager & _am = am(c); \
+ bool r; \
+ if (is_rational(c, a)) { \
+ rational av = get_rational(c, a); \
+ if (is_rational(c, b)) { \
+ rational bv = get_rational(c, b); \
+ r = av RAT_PRED bv; \
+ } \
+ else { \
+ algebraic_numbers::anum const & bv = get_irrational(c, b); \
+ scoped_anum _av(_am); \
+ _am.set(_av, av.to_mpq()); \
+ r = _am.IRAT_PRED(_av, bv); \
+ } \
+ } \
+ else { \
+ algebraic_numbers::anum const & av = get_irrational(c, a); \
+ if (is_rational(c, b)) { \
+ rational bv = get_rational(c, b); \
+ scoped_anum _bv(_am); \
+ _am.set(_bv, bv.to_mpq()); \
+ r = _am.IRAT_PRED(av, _bv); \
+ } \
+ else { \
+ algebraic_numbers::anum const & bv = get_irrational(c, b); \
+ r = _am.IRAT_PRED(av, bv); \
+ } \
+ } \
+ return r ? Z3_TRUE : Z3_FALSE;
+
+
+ Z3_bool Z3_API Z3_algebraic_lt(Z3_context c, Z3_ast a, Z3_ast b) {
+ Z3_TRY;
+ LOG_Z3_algebraic_lt(c, a, b);
+ RESET_ERROR_CODE();
+ CHECK_IS_ALGEBRAIC(a, 0);
+ CHECK_IS_ALGEBRAIC(b, 0);
+ BIN_PRED(<,lt);
+ Z3_CATCH_RETURN(Z3_FALSE);
+ }
+
+ Z3_bool Z3_API Z3_algebraic_gt(Z3_context c, Z3_ast a, Z3_ast b) {
+ return Z3_algebraic_lt(c, b, a);
+ }
+
+ Z3_bool Z3_API Z3_algebraic_le(Z3_context c, Z3_ast a, Z3_ast b) {
+ return !Z3_algebraic_lt(c, b, a);
+ }
+
+ Z3_bool Z3_API Z3_algebraic_ge(Z3_context c, Z3_ast a, Z3_ast b) {
+ return !Z3_algebraic_lt(c, a, b);
+ }
+
+ Z3_bool Z3_API Z3_algebraic_eq(Z3_context c, Z3_ast a, Z3_ast b) {
+ Z3_TRY;
+ LOG_Z3_algebraic_eq(c, a, b);
+ RESET_ERROR_CODE();
+ CHECK_IS_ALGEBRAIC(a, 0);
+ CHECK_IS_ALGEBRAIC(b, 0);
+ BIN_PRED(==,eq);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_bool Z3_API Z3_algebraic_neq(Z3_context c, Z3_ast a, Z3_ast b) {
+ return !Z3_algebraic_eq(c, a, b);
+ }
+
+ static bool to_anum_vector(Z3_context c, unsigned n, Z3_ast a[], scoped_anum_vector & as) {
+ algebraic_numbers::manager & _am = am(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());
+ as.push_back(tmp);
+ }
+ else if (is_irrational(c, a[i])) {
+ as.push_back(get_irrational(c, a[i]));
+ }
+ else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ class vector_var2anum : public polynomial::var2anum {
+ scoped_anum_vector const & m_as;
+ public:
+ vector_var2anum(scoped_anum_vector & as):m_as(as) {}
+ virtual ~vector_var2anum() {}
+ virtual algebraic_numbers::manager & m() const { return m_as.m(); }
+ virtual bool contains(polynomial::var x) const { return static_cast(x) < m_as.size(); }
+ virtual algebraic_numbers::anum const & operator()(polynomial::var x) const { return m_as.get(x); }
+ };
+
+ Z3_ast_vector Z3_API Z3_algebraic_roots(Z3_context c, Z3_ast p, unsigned n, Z3_ast a[]) {
+ Z3_TRY;
+ LOG_Z3_algebraic_roots(c, p, n, a);
+ RESET_ERROR_CODE();
+ polynomial::manager & pm = mk_c(c)->pm();
+ polynomial_ref _p(pm);
+ polynomial::scoped_numeral d(pm.m());
+ expr2polynomial converter(mk_c(c)->m(), pm, 0, true);
+ if (!converter.to_polynomial(to_expr(p), _p, d) ||
+ static_cast(max_var(_p)) >= n + 1) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ algebraic_numbers::manager & _am = am(c);
+ scoped_anum_vector as(_am);
+ if (!to_anum_vector(c, n, a, as)) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ scoped_anum_vector roots(_am);
+ {
+ cancel_eh eh(_am);
+ api::context::set_interruptable(*(mk_c(c)), eh);
+ scoped_timer timer(mk_c(c)->params().m_timeout, &eh);
+ vector_var2anum v2a(as);
+ _am.isolate_roots(_p, v2a, roots);
+ }
+ Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, mk_c(c)->m());
+ mk_c(c)->save_object(result);
+ for (unsigned i = 0; i < roots.size(); i++) {
+ result->m_ast_vector.push_back(au(c).mk_numeral(roots.get(i), false));
+ }
+ RETURN_Z3(of_ast_vector(result));
+ Z3_CATCH_RETURN(0);
+ }
+
+ int Z3_API Z3_algebraic_eval(Z3_context c, Z3_ast p, unsigned n, Z3_ast a[]) {
+ Z3_TRY;
+ LOG_Z3_algebraic_eval(c, p, n, a);
+ RESET_ERROR_CODE();
+ polynomial::manager & pm = mk_c(c)->pm();
+ polynomial_ref _p(pm);
+ polynomial::scoped_numeral d(pm.m());
+ expr2polynomial converter(mk_c(c)->m(), pm, 0, true);
+ if (!converter.to_polynomial(to_expr(p), _p, d) ||
+ static_cast(max_var(_p)) >= n) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ algebraic_numbers::manager & _am = am(c);
+ scoped_anum_vector as(_am);
+ if (!to_anum_vector(c, n, a, as)) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ {
+ cancel_eh eh(_am);
+ api::context::set_interruptable(*(mk_c(c)), eh);
+ scoped_timer timer(mk_c(c)->params().m_timeout, &eh);
+ vector_var2anum v2a(as);
+ int r = _am.eval_sign_at(_p, v2a);
+ if (r > 0) return 1;
+ else if (r < 0) return -1;
+ else return 0;
+ }
+ Z3_CATCH_RETURN(0);
+ }
+
+};
diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp
index c604927fd..404d9d9ac 100644
--- a/src/api/api_ast.cpp
+++ b/src/api/api_ast.cpp
@@ -324,7 +324,8 @@ extern "C" {
switch (_a->get_kind()) {
case AST_APP: {
expr * e = to_expr(_a);
- if (is_numeral_sort(c, of_sort(mk_c(c)->m().get_sort(e))) && mk_c(c)->m().is_value(e))
+ // Real algebraic numbers are not considered Z3_NUMERAL_AST
+ if (is_numeral_sort(c, of_sort(mk_c(c)->m().get_sort(e))) && mk_c(c)->m().is_unique_value(e))
return Z3_NUMERAL_AST;
return Z3_APP_AST;
}
diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp
index 69b7ea999..7dc8d1a12 100644
--- a/src/api/api_context.cpp
+++ b/src/api/api_context.cpp
@@ -82,13 +82,13 @@ namespace api {
context::context(context_params * p, bool user_ref_count):
m_params(p != 0 ? *p : context_params()),
m_user_ref_count(user_ref_count),
- m_manager(m_params.m_proof ? PGM_FINE : PGM_DISABLED, m_params.m_trace ? m_params.m_trace_file_name.c_str() : 0),
- m_plugins(m_manager),
- m_arith_util(m_manager),
- m_bv_util(m_manager),
- m_datalog_util(m_manager),
- m_last_result(m_manager),
- m_ast_trail(m_manager),
+ m_manager(m_params.mk_ast_manager()),
+ m_plugins(m()),
+ m_arith_util(m()),
+ m_bv_util(m()),
+ m_datalog_util(m()),
+ m_last_result(m()),
+ m_ast_trail(m()),
m_replay_stack() {
m_solver = 0;
@@ -102,22 +102,16 @@ namespace api {
m_smtlib_parser_has_decls = false;
z3_bound_num_procs();
- //
- // Configuration parameter settings.
- //
- if (m_params.m_debug_ref_count) {
- m_manager.debug_ref_count();
- }
m_error_handler = &default_error_handler;
- m_basic_fid = m_manager.get_basic_family_id();
- m_arith_fid = m_manager.get_family_id("arith");
- m_bv_fid = m_manager.get_family_id("bv");
- m_array_fid = m_manager.get_family_id("array");
- m_dt_fid = m_manager.get_family_id("datatype");
- m_datalog_fid = m_manager.get_family_id("datalog_relation");
- m_dt_plugin = static_cast(m_manager.get_plugin(m_dt_fid));
+ m_basic_fid = m().get_basic_family_id();
+ m_arith_fid = m().get_family_id("arith");
+ m_bv_fid = m().get_family_id("bv");
+ m_array_fid = m().get_family_id("array");
+ m_dt_fid = m().get_family_id("datatype");
+ m_datalog_fid = m().get_family_id("datalog_relation");
+ m_dt_plugin = static_cast(m().get_plugin(m_dt_fid));
if (!m_user_ref_count) {
m_replay_stack.push_back(0);
@@ -143,6 +137,7 @@ namespace api {
{
if (m_interruptable)
(*m_interruptable)();
+ m().set_cancel(true);
}
}
@@ -195,12 +190,12 @@ namespace api {
expr * context::mk_and(unsigned num_exprs, expr * const * exprs) {
switch(num_exprs) {
case 0:
- return m_manager.mk_true();
+ return m().mk_true();
case 1:
save_ast_trail(exprs[0]);
return exprs[0];
default: {
- expr * a = m_manager.mk_and(num_exprs, exprs);
+ expr * a = m().mk_and(num_exprs, exprs);
save_ast_trail(a);
return a;
} }
@@ -216,7 +211,7 @@ namespace api {
SASSERT(m_replay_stack.size() > num_scopes);
unsigned j = m_replay_stack.size() - num_scopes - 1;
if (!m_replay_stack[j]) {
- m_replay_stack[j] = alloc(ast_ref_vector, m_manager);
+ m_replay_stack[j] = alloc(ast_ref_vector, m());
}
m_replay_stack[j]->push_back(n);
}
@@ -324,7 +319,7 @@ namespace api {
smt::kernel & context::get_smt_kernel() {
if (!m_solver) {
m_fparams.updt_params(m_params);
- m_solver = alloc(smt::kernel, m_manager, m_fparams);
+ m_solver = alloc(smt::kernel, m(), m_fparams);
}
return *m_solver;
}
diff --git a/src/api/api_context.h b/src/api/api_context.h
index a126f0790..edb79b2d5 100644
--- a/src/api/api_context.h
+++ b/src/api/api_context.h
@@ -32,6 +32,7 @@ Revision History:
#include"event_handler.h"
#include"tactic_manager.h"
#include"context_params.h"
+#include"api_polynomial.h"
namespace smtlib {
class parser;
@@ -45,7 +46,7 @@ namespace api {
struct add_plugins { add_plugins(ast_manager & m); };
context_params m_params;
bool m_user_ref_count; //!< if true, the user is responsible for managing referenc counters.
- ast_manager m_manager;
+ scoped_ptr m_manager;
add_plugins m_plugins;
arith_util m_arith_util;
@@ -81,6 +82,8 @@ namespace api {
Z3_ast_print_mode m_print_mode;
event_handler * m_interruptable; // Reference to an object that can be interrupted by Z3_interrupt
+
+ pmanager m_pmanager;
public:
// Scoped obj for setting m_interruptable
class set_interruptable {
@@ -98,10 +101,10 @@ namespace api {
context(context_params * p, bool user_ref_count = false);
~context();
- ast_manager & m() { return m_manager; }
+ ast_manager & m() const { return *(m_manager.get()); }
context_params & params() { return m_params; }
- bool produce_proofs() const { return m_manager.proofs_enabled(); }
+ bool produce_proofs() const { return m().proofs_enabled(); }
bool produce_models() const { return m_params.m_model; }
bool produce_unsat_cores() const { return m_params.m_unsat_core; }
bool use_auto_config() const { return m_params.m_auto_config; }
@@ -167,6 +170,13 @@ namespace api {
void check_sorts(ast * n);
+ // ------------------------
+ //
+ // Polynomial manager & caches
+ //
+ // -----------------------
+ polynomial::manager & pm() { return m_pmanager.pm(); }
+
// ------------------------
//
// Solver interface for backward compatibility
diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp
index 69ca1fc81..8f6eb1125 100644
--- a/src/api/api_parsers.cpp
+++ b/src/api/api_parsers.cpp
@@ -252,42 +252,6 @@ extern "C" {
// ---------------
// Support for SMTLIB2
- class z3_context_solver : public solver_na2as {
- api::context & m_ctx;
- smt::kernel & ctx() const { return m_ctx.get_smt_kernel(); }
- public:
- virtual ~z3_context_solver() {}
- z3_context_solver(api::context& c) : m_ctx(c) {}
- virtual void init_core(ast_manager & m, symbol const & logic) {}
- virtual void collect_statistics(statistics & st) const {}
- virtual void reset_core() { ctx().reset(); }
- virtual void assert_expr(expr * t) { ctx().assert_expr(t); }
- virtual void push_core() { ctx().push(); }
- virtual void pop_core(unsigned n) { ctx().pop(n); }
- virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) {
- return ctx().check(num_assumptions, assumptions);
- }
- virtual void get_unsat_core(ptr_vector & r) {
- unsigned sz = ctx().get_unsat_core_size();
- for (unsigned i = 0; i < sz; i++)
- r.push_back(ctx().get_unsat_core_expr(i));
- }
- virtual void get_model(model_ref & m) { ctx().get_model(m); }
- virtual proof * get_proof() { return ctx().get_proof(); }
- virtual std::string reason_unknown() const { return ctx().last_failure_as_string(); }
- virtual void get_labels(svector & r) {
- buffer tmp;
- ctx().get_relevant_labels(0, tmp);
- r.append(tmp.size(), tmp.c_ptr());
- }
-
- // These are controlled by the main API
- virtual void set_cancel(bool f) { }
- void cancel() { set_cancel(true); }
- void reset_cancel() { set_cancel(false); }
- virtual void set_progress_callback(progress_callback * callback) {}
- };
-
Z3_ast parse_smtlib2_stream(bool exec, Z3_context c, std::istream& is,
unsigned num_sorts,
Z3_symbol const sort_names[],
@@ -298,9 +262,6 @@ extern "C" {
Z3_TRY;
cmd_context ctx(false, &(mk_c(c)->m()));
ctx.set_ignore_check(true);
- if (exec) {
- ctx.set_solver(alloc(z3_context_solver, *mk_c(c)));
- }
for (unsigned i = 0; i < num_decls; ++i) {
ctx.insert(to_symbol(decl_names[i]), to_func_decl(decls[i]));
}
@@ -353,39 +314,4 @@ extern "C" {
RETURN_Z3(r);
Z3_CATCH_RETURN(0);
}
-
- Z3_ast Z3_API Z3_exec_smtlib2_string(Z3_context c, Z3_string str,
- unsigned num_sorts,
- Z3_symbol sort_names[],
- Z3_sort sorts[],
- unsigned num_decls,
- Z3_symbol decl_names[],
- Z3_func_decl decls[]) {
- Z3_TRY;
- cmd_context ctx(false, &(mk_c(c)->m()));
- std::string s(str);
- std::istringstream is(s);
- // No logging for this one, since it private.
- return parse_smtlib2_stream(true, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls);
- Z3_CATCH_RETURN(0);
- }
-
- Z3_ast Z3_API Z3_exec_smtlib2_file(Z3_context c, Z3_string file_name,
- unsigned num_sorts,
- Z3_symbol sort_names[],
- Z3_sort sorts[],
- unsigned num_decls,
- Z3_symbol decl_names[],
- Z3_func_decl decls[]) {
- Z3_TRY;
- std::ifstream is(file_name);
- if (!is) {
- SET_ERROR_CODE(Z3_PARSER_ERROR);
- return 0;
- }
- // No logging for this one, since it private.
- return parse_smtlib2_stream(true, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls);
- Z3_CATCH_RETURN(0);
- }
-
};
diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp
new file mode 100644
index 000000000..3148f972b
--- /dev/null
+++ b/src/api/api_polynomial.cpp
@@ -0,0 +1,84 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ api_polynomial.cpp
+
+Abstract:
+
+ Polynomial manager and caches for the external API.
+
+Author:
+
+ Leonardo de Moura (leonardo) 2012-12-08
+
+Notes:
+
+--*/
+#include
+#include"z3.h"
+#include"api_log_macros.h"
+#include"api_context.h"
+#include"api_polynomial.h"
+#include"api_ast_vector.h"
+#include"expr2polynomial.h"
+#include"cancel_eh.h"
+#include"scoped_timer.h"
+#include"expr2var.h"
+
+namespace api {
+
+ pmanager::pmanager():
+ m_pm(m_nm) {
+ }
+
+ pmanager::~pmanager() {
+ }
+
+ void pmanager::set_cancel(bool f) {
+ m_pm.set_cancel(f);
+ }
+
+};
+
+extern "C" {
+
+ Z3_ast_vector Z3_API Z3_polynomial_subresultants(Z3_context c, Z3_ast p, Z3_ast q, Z3_ast x) {
+ Z3_TRY;
+ LOG_Z3_polynomial_subresultants(c, p, q, x);
+ RESET_ERROR_CODE();
+ polynomial::manager & pm = mk_c(c)->pm();
+ polynomial_ref _p(pm), _q(pm);
+ polynomial::scoped_numeral d(pm.m());
+ default_expr2polynomial converter(mk_c(c)->m(), pm);
+ if (!converter.to_polynomial(to_expr(p), _p, d) ||
+ !converter.to_polynomial(to_expr(q), _q, d)) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, mk_c(c)->m());
+ mk_c(c)->save_object(result);
+ if (converter.is_var(to_expr(x))) {
+ expr2var const & mapping = converter.get_mapping();
+ unsigned v_x = mapping.to_var(to_expr(x));
+ polynomial_ref_vector rs(pm);
+ polynomial_ref r(pm);
+ expr_ref _r(mk_c(c)->m());
+ {
+ cancel_eh eh(pm);
+ api::context::set_interruptable(*(mk_c(c)), eh);
+ scoped_timer timer(mk_c(c)->params().m_timeout, &eh);
+ pm.psc_chain(_p, _q, v_x, rs);
+ }
+ for (unsigned i = 0; i < rs.size(); i++) {
+ r = rs.get(i);
+ converter.to_expr(r, true, _r);
+ result->m_ast_vector.push_back(_r);
+ }
+ }
+ RETURN_Z3(of_ast_vector(result));
+ Z3_CATCH_RETURN(0);
+ }
+
+};
diff --git a/src/api/api_polynomial.h b/src/api/api_polynomial.h
new file mode 100644
index 000000000..27317a7dd
--- /dev/null
+++ b/src/api/api_polynomial.h
@@ -0,0 +1,39 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ api_polynomial.h
+
+Abstract:
+
+ Polynomial manager and caches for the external API.
+
+Author:
+
+ Leonardo de Moura (leonardo) 2012-12-08
+
+Notes:
+
+--*/
+#ifndef _API_POLYNOMIAL_H_
+#define _API_POLYNOMIAL_H_
+
+#include"polynomial.h"
+
+namespace api {
+
+ class pmanager {
+ unsynch_mpz_manager m_nm;
+ polynomial::manager m_pm;
+ // TODO: add support for caching expressions -> polynomial and back
+ public:
+ pmanager();
+ virtual ~pmanager();
+ polynomial::manager & pm() { return m_pm; }
+ void set_cancel(bool f);
+ };
+
+};
+
+#endif
diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp
index 67d083704..6bf184708 100644
--- a/src/api/api_solver.cpp
+++ b/src/api/api_solver.cpp
@@ -34,25 +34,15 @@ Revision History:
extern "C" {
static void init_solver_core(Z3_context c, Z3_solver _s) {
- ast_manager & m = mk_c(c)->m();
Z3_solver_ref * s = to_solver(_s);
- s->m_solver->set_produce_proofs(mk_c(c)->produce_proofs());
- s->m_solver->set_produce_unsat_cores(s->m_params.get_bool("unsat_core", mk_c(c)->produce_unsat_cores()));
- s->m_solver->set_produce_models(s->m_params.get_bool("model", mk_c(c)->produce_models()));
- if (!mk_c(c)->use_auto_config()) {
- params_ref p = s->m_params;
- p.set_bool("auto_config", false);
- s->m_solver->updt_params(p);
- }
- else {
- s->m_solver->updt_params(s->m_params);
- }
- s->m_solver->init(m, s->m_logic);
- s->m_initialized = true;
+ bool proofs_enabled, models_enabled, unsat_core_enabled;
+ params_ref p = s->m_params;
+ mk_c(c)->params().get_solver_params(mk_c(c)->m(), p, proofs_enabled, models_enabled, unsat_core_enabled);
+ s->m_solver = (*(s->m_solver_factory))(mk_c(c)->m(), p, proofs_enabled, models_enabled, unsat_core_enabled, s->m_logic);
}
static void init_solver(Z3_context c, Z3_solver s) {
- if (!to_solver(s)->m_initialized)
+ if (to_solver(s)->m_solver.get() == 0)
init_solver_core(c, s);
}
@@ -60,8 +50,7 @@ extern "C" {
Z3_TRY;
LOG_Z3_mk_simple_solver(c);
RESET_ERROR_CODE();
- Z3_solver_ref * s = alloc(Z3_solver_ref);
- s->m_solver = mk_smt_solver();
+ Z3_solver_ref * s = alloc(Z3_solver_ref, mk_smt_solver_factory());
mk_c(c)->save_object(s);
Z3_solver r = of_solver(s);
RETURN_Z3(r);
@@ -72,8 +61,7 @@ extern "C" {
Z3_TRY;
LOG_Z3_mk_solver(c);
RESET_ERROR_CODE();
- Z3_solver_ref * s = alloc(Z3_solver_ref);
- s->m_solver = mk_smt_strategic_solver();
+ Z3_solver_ref * s = alloc(Z3_solver_ref, mk_smt_strategic_solver_factory());
mk_c(c)->save_object(s);
Z3_solver r = of_solver(s);
RETURN_Z3(r);
@@ -84,8 +72,7 @@ extern "C" {
Z3_TRY;
LOG_Z3_mk_solver_for_logic(c, logic);
RESET_ERROR_CODE();
- Z3_solver_ref * s = alloc(Z3_solver_ref, to_symbol(logic));
- s->m_solver = mk_smt_strategic_solver(true /* force solver to use tactics even when auto_config is disabled */);
+ Z3_solver_ref * s = alloc(Z3_solver_ref, mk_smt_strategic_solver_factory(to_symbol(logic)));
mk_c(c)->save_object(s);
Z3_solver r = of_solver(s);
RETURN_Z3(r);
@@ -96,8 +83,7 @@ extern "C" {
Z3_TRY;
LOG_Z3_mk_solver_from_tactic(c, t);
RESET_ERROR_CODE();
- Z3_solver_ref * s = alloc(Z3_solver_ref);
- s->m_solver = alloc(tactic2solver, to_tactic_ref(t));
+ Z3_solver_ref * s = alloc(Z3_solver_ref, mk_tactic2solver_factory(to_tactic_ref(t)));
mk_c(c)->save_object(s);
Z3_solver r = of_solver(s);
RETURN_Z3(r);
@@ -110,7 +96,12 @@ extern "C" {
RESET_ERROR_CODE();
std::ostringstream buffer;
param_descrs descrs;
+ bool initialized = to_solver(s)->m_solver.get() != 0;
+ if (!initialized)
+ init_solver(c, s);
to_solver_ref(s)->collect_param_descrs(descrs);
+ if (!initialized)
+ to_solver(s)->m_solver = 0;
descrs.display(buffer);
return mk_c(c)->mk_external_string(buffer.str());
Z3_CATCH_RETURN("");
@@ -122,7 +113,12 @@ extern "C" {
RESET_ERROR_CODE();
Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref);
mk_c(c)->save_object(d);
+ bool initialized = to_solver(s)->m_solver.get() != 0;
+ if (!initialized)
+ init_solver(c, s);
to_solver_ref(s)->collect_param_descrs(d->m_descrs);
+ if (!initialized)
+ to_solver(s)->m_solver = 0;
Z3_param_descrs r = of_param_descrs(d);
RETURN_Z3(r);
Z3_CATCH_RETURN(0);
@@ -132,7 +128,7 @@ extern "C" {
Z3_TRY;
LOG_Z3_solver_set_params(c, s, p);
RESET_ERROR_CODE();
- if (to_solver(s)->m_initialized) {
+ if (to_solver(s)->m_solver) {
bool old_model = to_solver(s)->m_params.get_bool("model", true);
bool new_model = to_param_ref(p).get_bool("model", true);
if (old_model != new_model)
@@ -186,8 +182,7 @@ extern "C" {
Z3_TRY;
LOG_Z3_solver_reset(c, s);
RESET_ERROR_CODE();
- to_solver_ref(s)->reset();
- to_solver(s)->m_initialized = false;
+ to_solver(s)->m_solver = 0;
Z3_CATCH;
}
diff --git a/src/api/api_solver.h b/src/api/api_solver.h
index 1569ef0da..f11c9bfd8 100644
--- a/src/api/api_solver.h
+++ b/src/api/api_solver.h
@@ -22,17 +22,16 @@ Revision History:
#include"solver.h"
struct Z3_solver_ref : public api::object {
- solver * m_solver;
- params_ref m_params;
- bool m_initialized;
- symbol m_logic;
- Z3_solver_ref():m_solver(0), m_initialized(false), m_logic(symbol::null) {}
- Z3_solver_ref(symbol const & logic):m_solver(0), m_initialized(false), m_logic(logic) {}
- virtual ~Z3_solver_ref() { dealloc(m_solver); }
+ scoped_ptr m_solver_factory;
+ ref m_solver;
+ params_ref m_params;
+ symbol m_logic;
+ Z3_solver_ref(solver_factory * f):m_solver_factory(f), m_solver(0), m_logic(symbol::null) {}
+ virtual ~Z3_solver_ref() {}
};
inline Z3_solver_ref * to_solver(Z3_solver s) { return reinterpret_cast(s); }
inline Z3_solver of_solver(Z3_solver_ref * s) { return reinterpret_cast(s); }
-inline solver * to_solver_ref(Z3_solver s) { return to_solver(s)->m_solver; }
+inline solver * to_solver_ref(Z3_solver s) { return to_solver(s)->m_solver.get(); }
#endif
diff --git a/src/api/api_solver_old.cpp b/src/api/api_solver_old.cpp
index cd4b797e3..d43e103c2 100644
--- a/src/api/api_solver_old.cpp
+++ b/src/api/api_solver_old.cpp
@@ -24,6 +24,7 @@ Revision History:
#include"api_model.h"
#include"smt_implied_equalities.h"
#include"cancel_eh.h"
+#include"api_solver.h"
extern "C" {
@@ -113,14 +114,16 @@ extern "C" {
}
Z3_lbool Z3_API Z3_get_implied_equalities(Z3_context c,
+ Z3_solver s,
unsigned num_terms,
Z3_ast const terms[],
unsigned class_ids[]) {
Z3_TRY;
- LOG_Z3_get_implied_equalities(c, num_terms, terms, class_ids);
+ LOG_Z3_get_implied_equalities(c, s, num_terms, terms, class_ids);
+ ast_manager& m = mk_c(c)->m();
RESET_ERROR_CODE();
CHECK_SEARCHING(c);
- lbool result = smt::implied_equalities(mk_c(c)->get_smt_kernel(), num_terms, to_exprs(terms), class_ids);
+ lbool result = smt::implied_equalities(m, *to_solver_ref(s), num_terms, to_exprs(terms), class_ids);
return static_cast(result);
Z3_CATCH_RETURN(Z3_L_UNDEF);
}
diff --git a/src/api/java/README b/src/api/java/README
index 0591eec88..7afe098fb 100644
--- a/src/api/java/README
+++ b/src/api/java/README
@@ -1,4 +1,3 @@
Java bindings
-------------
-This is currently "working in progress".
\ No newline at end of file
diff --git a/src/api/python/z3.py b/src/api/python/z3.py
index e690a9bff..924ac0ea5 100644
--- a/src/api/python/z3.py
+++ b/src/api/python/z3.py
@@ -1126,6 +1126,27 @@ def Var(idx, s):
_z3_assert(is_sort(s), "Z3 sort expected")
return _to_expr_ref(Z3_mk_bound(s.ctx_ref(), idx, s.ast), s.ctx)
+def RealVar(idx, ctx=None):
+ """
+ Create a real free variable. Free variables are used to create quantified formulas.
+ They are also used to create polynomials.
+
+ >>> RealVar(0)
+ Var(0)
+ """
+ return Var(idx, RealSort(ctx))
+
+def RealVarVector(n, ctx=None):
+ """
+ Create a list of Real free variables.
+ The variables have ids: 0, 1, ..., n-1
+
+ >>> x0, x1, x2, x3 = RealVarVector(4)
+ >>> x2
+ Var(2)
+ """
+ return [ RealVar(i, ctx) for i in range(n) ]
+
#########################################
#
# Booleans
@@ -5787,8 +5808,15 @@ class Solver(Z3PPObject):
>>> s.assert_and_track(x < 0, p3)
>>> print s.check()
unsat
- >>> print s.unsat_core()
- [p3, p1]
+ >>> c = s.unsat_core()
+ >>> len(c)
+ 2
+ >>> Bool('p1') in c
+ True
+ >>> Bool('p2') in c
+ False
+ >>> p3 in c
+ True
"""
if isinstance(p, str):
p = Bool(p, self.ctx)
@@ -6985,9 +7013,9 @@ def solve(*args, **keywords):
configure it using the options in `keywords`, adds the constraints
in `args`, and invokes check.
- >>> a, b = Ints('a b')
- >>> solve(a + b == 3, Or(a == 0, a == 1), a != 0)
- [b = 2, a = 1]
+ >>> a = Int('a')
+ >>> solve(a > 0, a < 2)
+ [a = 1]
"""
s = Solver()
s.set(**keywords)
diff --git a/src/api/python/z3num.py b/src/api/python/z3num.py
new file mode 100644
index 000000000..581536e44
--- /dev/null
+++ b/src/api/python/z3num.py
@@ -0,0 +1,564 @@
+############################################
+# Copyright (c) 2012 Microsoft Corporation
+#
+# Z3 Python interface for Z3 numerals
+#
+# Author: Leonardo de Moura (leonardo)
+############################################
+from z3 import *
+from z3core import *
+from z3printer import *
+
+def _to_numeral(num, ctx=None):
+ if isinstance(num, Numeral):
+ return num
+ else:
+ return Numeral(num, ctx)
+
+class Numeral:
+ """
+ A Z3 numeral can be used to perform computations over arbitrary
+ precision integers, rationals and real algebraic numbers.
+ It also automatically converts python numeric values.
+
+ >>> Numeral(2)
+ 2
+ >>> Numeral("3/2") + 1
+ 5/2
+ >>> Numeral(Sqrt(2))
+ 1.4142135623?
+ >>> Numeral(Sqrt(2)) + 2
+ 3.4142135623?
+ >>> Numeral(Sqrt(2)) + Numeral(Sqrt(3))
+ 3.1462643699?
+
+ Z3 numerals can be used to perform computations with
+ values in a Z3 model.
+
+ >>> s = Solver()
+ >>> x = Real('x')
+ >>> s.add(x*x == 2)
+ >>> s.add(x > 0)
+ >>> s.check()
+ sat
+ >>> m = s.model()
+ >>> m[x]
+ 1.4142135623?
+ >>> m[x] + 1
+ 1.4142135623? + 1
+
+ The previous result is a Z3 expression.
+
+ >>> (m[x] + 1).sexpr()
+ '(+ (root-obj (+ (^ x 2) (- 2)) 2) 1.0)'
+
+ >>> Numeral(m[x]) + 1
+ 2.4142135623?
+ >>> Numeral(m[x]).is_pos()
+ True
+ >>> Numeral(m[x])**2
+ 2
+
+ We can also isolate the roots of polynomials.
+
+ >>> x0, x1, x2 = RealVarVector(3)
+ >>> r0 = isolate_roots(x0**5 - x0 - 1)
+ >>> r0
+ [1.1673039782?]
+
+ In the following example, we are isolating the roots
+ of a univariate polynomial (on x1) obtained after substituting
+ x0 -> r0[0]
+
+ >>> r1 = isolate_roots(x1**2 - x0 + 1, [ r0[0] ])
+ >>> r1
+ [-0.4090280898?, 0.4090280898?]
+
+ Similarly, in the next example we isolate the roots of
+ a univariate polynomial (on x2) obtained after substituting
+ x0 -> r0[0] and x1 -> r1[0]
+
+ >>> isolate_roots(x1*x2 + x0, [ r0[0], r1[0] ])
+ [2.8538479564?]
+
+ """
+ def __init__(self, num, ctx=None):
+ if isinstance(num, Ast):
+ self.ast = num
+ self.ctx = z3._get_ctx(ctx)
+ elif isinstance(num, RatNumRef) or isinstance(num, AlgebraicNumRef):
+ self.ast = num.ast
+ self.ctx = num.ctx
+ elif isinstance(num, ArithRef):
+ r = simplify(num)
+ self.ast = r.ast
+ self.ctx = r.ctx
+ else:
+ v = RealVal(num, ctx)
+ self.ast = v.ast
+ self.ctx = v.ctx
+ Z3_inc_ref(self.ctx_ref(), self.as_ast())
+ assert Z3_algebraic_is_value(self.ctx_ref(), self.ast)
+
+ def __del__(self):
+ Z3_dec_ref(self.ctx_ref(), self.as_ast())
+
+ def is_integer(self):
+ """ Return True if the numeral is integer.
+
+ >>> Numeral(2).is_integer()
+ True
+ >>> (Numeral(Sqrt(2)) * Numeral(Sqrt(2))).is_integer()
+ True
+ >>> Numeral(Sqrt(2)).is_integer()
+ False
+ >>> Numeral("2/3").is_integer()
+ False
+ """
+ return self.is_rational() and self.denominator() == 1
+
+ def is_rational(self):
+ """ Return True if the numeral is rational.
+
+ >>> Numeral(2).is_rational()
+ True
+ >>> Numeral("2/3").is_rational()
+ True
+ >>> Numeral(Sqrt(2)).is_rational()
+ False
+
+ """
+ return Z3_get_ast_kind(self.ctx_ref(), self.as_ast()) == Z3_NUMERAL_AST
+
+ def denominator(self):
+ """ Return the denominator if `self` is rational.
+
+ >>> Numeral("2/3").denominator()
+ 3
+ """
+ assert(self.is_rational())
+ return Numeral(Z3_get_denominator(self.ctx_ref(), self.as_ast()), self.ctx)
+
+ def numerator(self):
+ """ Return the numerator if `self` is rational.
+
+ >>> Numeral("2/3").numerator()
+ 2
+ """
+ assert(self.is_rational())
+ return Numeral(Z3_get_numerator(self.ctx_ref(), self.as_ast()), self.ctx)
+
+
+ def is_irrational(self):
+ """ Return True if the numeral is irrational.
+
+ >>> Numeral(2).is_irrational()
+ False
+ >>> Numeral("2/3").is_irrational()
+ False
+ >>> Numeral(Sqrt(2)).is_irrational()
+ True
+ """
+ return not self.is_rational()
+
+ def as_long(self):
+ """ Return a numeral (that is an integer) as a Python long.
+
+ >>> (Numeral(10)**20).as_long()
+ 100000000000000000000L
+ """
+ assert(self.is_integer())
+ return long(Z3_get_numeral_string(self.ctx_ref(), self.as_ast()))
+
+ def approx(self, precision=10):
+ """Return a numeral that approximates the numeral `self`.
+ The result `r` is such that |r - self| <= 1/10^precision
+
+ If `self` is rational, then the result is `self`.
+
+ >>> x = Numeral(2).root(2)
+ >>> x.approx(20)
+ 6838717160008073720548335/4835703278458516698824704
+ >>> x.approx(5)
+ 2965821/2097152
+ >>> Numeral(2).approx(10)
+ 2
+ """
+ return self.upper(precision)
+
+ def upper(self, precision=10):
+ """Return a upper bound that approximates the numeral `self`.
+ The result `r` is such that r - self <= 1/10^precision
+
+ If `self` is rational, then the result is `self`.
+
+ >>> x = Numeral(2).root(2)
+ >>> x.upper(20)
+ 6838717160008073720548335/4835703278458516698824704
+ >>> x.upper(5)
+ 2965821/2097152
+ >>> Numeral(2).upper(10)
+ 2
+ """
+ if self.is_rational():
+ return self
+ else:
+ return Numeral(Z3_get_algebraic_number_upper(self.ctx_ref(), self.as_ast(), precision), self.ctx)
+
+ def lower(self, precision=10):
+ """Return a lower bound that approximates the numeral `self`.
+ The result `r` is such that self - r <= 1/10^precision
+
+ If `self` is rational, then the result is `self`.
+
+ >>> x = Numeral(2).root(2)
+ >>> x.lower(20)
+ 1709679290002018430137083/1208925819614629174706176
+ >>> Numeral("2/3").lower(10)
+ 2/3
+ """
+ if self.is_rational():
+ return self
+ else:
+ return Numeral(Z3_get_algebraic_number_lower(self.ctx_ref(), self.as_ast(), precision), self.ctx)
+
+ def sign(self):
+ """ Return the sign of the numeral.
+
+ >>> Numeral(2).sign()
+ 1
+ >>> Numeral(-3).sign()
+ -1
+ >>> Numeral(0).sign()
+ 0
+ """
+ return Z3_algebraic_sign(self.ctx_ref(), self.ast)
+
+ def is_pos(self):
+ """ Return True if the numeral is positive.
+
+ >>> Numeral(2).is_pos()
+ True
+ >>> Numeral(-3).is_pos()
+ False
+ >>> Numeral(0).is_pos()
+ False
+ """
+ return Z3_algebraic_is_pos(self.ctx_ref(), self.ast)
+
+ def is_neg(self):
+ """ Return True if the numeral is negative.
+
+ >>> Numeral(2).is_neg()
+ False
+ >>> Numeral(-3).is_neg()
+ True
+ >>> Numeral(0).is_neg()
+ False
+ """
+ return Z3_algebraic_is_neg(self.ctx_ref(), self.ast)
+
+ def is_zero(self):
+ """ Return True if the numeral is zero.
+
+ >>> Numeral(2).is_zero()
+ False
+ >>> Numeral(-3).is_zero()
+ False
+ >>> Numeral(0).is_zero()
+ True
+ >>> sqrt2 = Numeral(2).root(2)
+ >>> sqrt2.is_zero()
+ False
+ >>> (sqrt2 - sqrt2).is_zero()
+ True
+ """
+ return Z3_algebraic_is_zero(self.ctx_ref(), self.ast)
+
+ def __add__(self, other):
+ """ Return the numeral `self + other`.
+
+ >>> Numeral(2) + 3
+ 5
+ >>> Numeral(2) + Numeral(4)
+ 6
+ >>> Numeral("2/3") + 1
+ 5/3
+ """
+ return Numeral(Z3_algebraic_add(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
+
+ def __radd__(self, other):
+ """ Return the numeral `other + self`.
+
+ >>> 3 + Numeral(2)
+ 5
+ """
+ return Numeral(Z3_algebraic_add(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
+
+ def __sub__(self, other):
+ """ Return the numeral `self - other`.
+
+ >>> Numeral(2) - 3
+ -1
+ """
+ return Numeral(Z3_algebraic_sub(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
+
+ def __rsub__(self, other):
+ """ Return the numeral `other - self`.
+
+ >>> 3 - Numeral(2)
+ 1
+ """
+ return Numeral(Z3_algebraic_sub(self.ctx_ref(), _to_numeral(other, self.ctx).ast, self.ast), self.ctx)
+
+ def __mul__(self, other):
+ """ Return the numeral `self * other`.
+ >>> Numeral(2) * 3
+ 6
+ """
+ return Numeral(Z3_algebraic_mul(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
+
+ def __rmul__(self, other):
+ """ Return the numeral `other * mul`.
+ >>> 3 * Numeral(2)
+ 6
+ """
+ return Numeral(Z3_algebraic_mul(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
+
+ def __div__(self, other):
+ """ Return the numeral `self / other`.
+ >>> Numeral(2) / 3
+ 2/3
+ >>> Numeral(2).root(2) / 3
+ 0.4714045207?
+ >>> Numeral(Sqrt(2)) / Numeral(Sqrt(3))
+ 0.8164965809?
+ """
+ return Numeral(Z3_algebraic_div(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
+
+ def __rdiv__(self, other):
+ """ Return the numeral `other / self`.
+ >>> 3 / Numeral(2)
+ 3/2
+ >>> 3 / Numeral(2).root(2)
+ 2.1213203435?
+ """
+ return Numeral(Z3_algebraic_div(self.ctx_ref(), _to_numeral(other, self.ctx).ast, self.ast), self.ctx)
+
+ def root(self, k):
+ """ Return the numeral `self^(1/k)`.
+
+ >>> sqrt2 = Numeral(2).root(2)
+ >>> sqrt2
+ 1.4142135623?
+ >>> sqrt2 * sqrt2
+ 2
+ >>> sqrt2 * 2 + 1
+ 3.8284271247?
+ >>> (sqrt2 * 2 + 1).sexpr()
+ '(root-obj (+ (^ x 2) (* (- 2) x) (- 7)) 2)'
+ """
+ return Numeral(Z3_algebraic_root(self.ctx_ref(), self.ast, k), self.ctx)
+
+ def power(self, k):
+ """ Return the numeral `self^k`.
+
+ >>> sqrt3 = Numeral(3).root(2)
+ >>> sqrt3
+ 1.7320508075?
+ >>> sqrt3.power(2)
+ 3
+ """
+ return Numeral(Z3_algebraic_power(self.ctx_ref(), self.ast, k), self.ctx)
+
+ def __pow__(self, k):
+ """ Return the numeral `self^k`.
+
+ >>> sqrt3 = Numeral(3).root(2)
+ >>> sqrt3
+ 1.7320508075?
+ >>> sqrt3**2
+ 3
+ """
+ return self.power(k)
+
+ def __lt__(self, other):
+ """ Return True if `self < other`.
+
+ >>> Numeral(Sqrt(2)) < 2
+ True
+ >>> Numeral(Sqrt(3)) < Numeral(Sqrt(2))
+ False
+ >>> Numeral(Sqrt(2)) < Numeral(Sqrt(2))
+ False
+ """
+ return Z3_algebraic_lt(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
+
+ def __rlt__(self, other):
+ """ Return True if `other < self`.
+
+ >>> 2 < Numeral(Sqrt(2))
+ False
+ """
+ return self > other
+
+ def __gt__(self, other):
+ """ Return True if `self > other`.
+
+ >>> Numeral(Sqrt(2)) > 2
+ False
+ >>> Numeral(Sqrt(3)) > Numeral(Sqrt(2))
+ True
+ >>> Numeral(Sqrt(2)) > Numeral(Sqrt(2))
+ False
+ """
+ return Z3_algebraic_gt(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
+
+ def __rgt__(self, other):
+ """ Return True if `other > self`.
+
+ >>> 2 > Numeral(Sqrt(2))
+ True
+ """
+ return self < other
+
+
+ def __le__(self, other):
+ """ Return True if `self <= other`.
+
+ >>> Numeral(Sqrt(2)) <= 2
+ True
+ >>> Numeral(Sqrt(3)) <= Numeral(Sqrt(2))
+ False
+ >>> Numeral(Sqrt(2)) <= Numeral(Sqrt(2))
+ True
+ """
+ return Z3_algebraic_le(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
+
+ def __rle__(self, other):
+ """ Return True if `other <= self`.
+
+ >>> 2 <= Numeral(Sqrt(2))
+ False
+ """
+ return self >= other
+
+ def __ge__(self, other):
+ """ Return True if `self >= other`.
+
+ >>> Numeral(Sqrt(2)) >= 2
+ False
+ >>> Numeral(Sqrt(3)) >= Numeral(Sqrt(2))
+ True
+ >>> Numeral(Sqrt(2)) >= Numeral(Sqrt(2))
+ True
+ """
+ return Z3_algebraic_ge(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
+
+ def __rge__(self, other):
+ """ Return True if `other >= self`.
+
+ >>> 2 >= Numeral(Sqrt(2))
+ True
+ """
+ return self <= other
+
+ def __eq__(self, other):
+ """ Return True if `self == other`.
+
+ >>> Numeral(Sqrt(2)) == 2
+ False
+ >>> Numeral(Sqrt(3)) == Numeral(Sqrt(2))
+ False
+ >>> Numeral(Sqrt(2)) == Numeral(Sqrt(2))
+ True
+ """
+ return Z3_algebraic_eq(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
+
+ def __ne__(self, other):
+ """ Return True if `self != other`.
+
+ >>> Numeral(Sqrt(2)) != 2
+ True
+ >>> Numeral(Sqrt(3)) != Numeral(Sqrt(2))
+ True
+ >>> Numeral(Sqrt(2)) != Numeral(Sqrt(2))
+ False
+ """
+ return Z3_algebraic_neq(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
+
+ def __str__(self):
+ if Z3_is_numeral_ast(self.ctx_ref(), self.ast):
+ return str(RatNumRef(self.ast, self.ctx))
+ else:
+ return str(AlgebraicNumRef(self.ast, self.ctx))
+
+ def __repr__(self):
+ return self.__str__()
+
+ def sexpr(self):
+ return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
+
+ def as_ast(self):
+ return self.ast
+
+ def ctx_ref(self):
+ return self.ctx.ref()
+
+def eval_sign_at(p, vs):
+ """
+ Evaluate the sign of the polynomial `p` at `vs`. `p` is a Z3
+ Expression containing arithmetic operators: +, -, *, ^k where k is
+ an integer; and free variables x that is_var(x) is True. Moreover,
+ all variables must be real.
+
+ The result is 1 if the polynomial is positive at the given point,
+ -1 if negative, and 0 if zero.
+
+ >>> x0, x1, x2 = RealVarVector(3)
+ >>> eval_sign_at(x0**2 + x1*x2 + 1, (Numeral(0), Numeral(1), Numeral(2)))
+ 1
+ >>> eval_sign_at(x0**2 - 2, [ Numeral(Sqrt(2)) ])
+ 0
+ >>> eval_sign_at((x0 + x1)*(x0 + x2), (Numeral(0), Numeral(Sqrt(2)), Numeral(Sqrt(3))))
+ 1
+ """
+ num = len(vs)
+ _vs = (Ast * num)()
+ for i in range(num):
+ _vs[i] = vs[i].ast
+ return Z3_algebraic_eval(p.ctx_ref(), p.as_ast(), num, _vs)
+
+def isolate_roots(p, vs=[]):
+ """
+ Given a multivariate polynomial p(x_0, ..., x_{n-1}, x_n), returns the
+ roots of the univariate polynomial p(vs[0], ..., vs[len(vs)-1], x_n).
+
+ Remarks:
+ * p is a Z3 expression that contains only arithmetic terms and free variables.
+ * forall i in [0, n) vs is a numeral.
+
+ The result is a list of numerals
+
+ >>> x0 = RealVar(0)
+ >>> isolate_roots(x0**5 - x0 - 1)
+ [1.1673039782?]
+ >>> x1 = RealVar(1)
+ >>> isolate_roots(x0**2 - x1**4 - 1, [ Numeral(Sqrt(3)) ])
+ [-1.1892071150?, 1.1892071150?]
+ >>> x2 = RealVar(2)
+ >>> isolate_roots(x2**2 + x0 - x1, [ Numeral(Sqrt(3)), Numeral(Sqrt(2)) ])
+ []
+ """
+ num = len(vs)
+ _vs = (Ast * num)()
+ for i in range(num):
+ _vs[i] = vs[i].ast
+ _roots = AstVector(Z3_algebraic_roots(p.ctx_ref(), p.as_ast(), num, _vs), p.ctx)
+ return [ Numeral(r) for r in _roots ]
+
+if __name__ == "__main__":
+ import doctest
+ if doctest.testmod().failed:
+ exit(1)
+
diff --git a/src/api/python/z3poly.py b/src/api/python/z3poly.py
new file mode 100644
index 000000000..0b8bf9457
--- /dev/null
+++ b/src/api/python/z3poly.py
@@ -0,0 +1,37 @@
+############################################
+# Copyright (c) 2012 Microsoft Corporation
+#
+# Z3 Python interface for Z3 polynomials
+#
+# Author: Leonardo de Moura (leonardo)
+############################################
+from z3 import *
+
+def subresultants(p, q, x):
+ """
+ Return the non-constant subresultants of 'p' and 'q' with respect to the "variable" 'x'.
+
+ 'p', 'q' and 'x' are Z3 expressions where 'p' and 'q' are arithmetic terms.
+ Note that, any subterm that cannot be viewed as a polynomial is assumed to be a variable.
+ Example: f(a) is a considered to be a variable b in the polynomial
+
+ f(a)*f(a) + 2*f(a) + 1
+
+ >>> x, y = Reals('x y')
+ >>> subresultants(2*x + y, 3*x - 2*y + 2, x)
+ [-7*y + 4]
+ >>> r = subresultants(3*y*x**2 + y**3 + 1, 2*x**3 + y + 3, x)
+ >>> r[0]
+ 4*y**9 + 12*y**6 + 27*y**5 + 162*y**4 + 255*y**3 + 4
+ >>> r[1]
+ -6*y**4 + -6*y
+ """
+ return AstVector(Z3_polynomial_subresultants(p.ctx_ref(), p.as_ast(), q.as_ast(), x.as_ast()), p.ctx)
+
+if __name__ == "__main__":
+ import doctest
+ if doctest.testmod().failed:
+ exit(1)
+
+
+
diff --git a/src/api/z3.h b/src/api/z3.h
index 8df894f40..c3e38e3f1 100644
--- a/src/api/z3.h
+++ b/src/api/z3.h
@@ -24,6 +24,8 @@ Notes:
#include
#include"z3_macros.h"
#include"z3_api.h"
+#include"z3_algebraic.h"
+#include"z3_polynomial.h"
#undef __in
#undef __out
diff --git a/src/api/z3_algebraic.h b/src/api/z3_algebraic.h
new file mode 100644
index 000000000..eef791170
--- /dev/null
+++ b/src/api/z3_algebraic.h
@@ -0,0 +1,226 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ z3_algebraic.h
+
+Abstract:
+
+ Additional APIs for handling Z3 algebraic numbers encoded as
+ Z3_ASTs
+
+Author:
+
+ Leonardo de Moura (leonardo) 2012-12-07
+
+Notes:
+
+--*/
+
+#ifndef _Z3_ALGEBRAIC_H_
+#define _Z3_ALGEBRAIC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+ /**
+ \brief Return Z3_TRUE if \c can be used as value in the Z3 real algebraic
+ number package.
+
+ def_API('Z3_algebraic_is_value', BOOL, (_in(CONTEXT), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_algebraic_is_value(__in Z3_context c, __in Z3_ast a);
+
+ /**
+ \brief Return the Z3_TRUE if \c a is positive, and Z3_FALSE otherwise.
+
+ \pre Z3_algebraic_is_value(c, a)
+
+ def_API('Z3_algebraic_is_pos', BOOL, (_in(CONTEXT), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_algebraic_is_pos(__in Z3_context c, __in Z3_ast a);
+
+ /**
+ \brief Return the Z3_TRUE if \c a is negative, and Z3_FALSE otherwise.
+
+ \pre Z3_algebraic_is_value(c, a)
+
+ def_API('Z3_algebraic_is_neg', BOOL, (_in(CONTEXT), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_algebraic_is_neg(__in Z3_context c, __in Z3_ast a);
+
+ /**
+ \brief Return the Z3_TRUE if \c a is zero, and Z3_FALSE otherwise.
+
+ \pre Z3_algebraic_is_value(c, a)
+
+ def_API('Z3_algebraic_is_zero', BOOL, (_in(CONTEXT), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_algebraic_is_zero(__in Z3_context c, __in Z3_ast a);
+
+ /**
+ \brief Return 1 if \c a is positive, 0 if \c a is zero, and -1 if \c a is negative.
+
+ \pre Z3_algebraic_is_value(c, a)
+
+ def_API('Z3_algebraic_sign', INT, (_in(CONTEXT), _in(AST)))
+ */
+ int Z3_API Z3_algebraic_sign(__in Z3_context c, __in Z3_ast a);
+
+ /**
+ \brief Return the value a + b.
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre Z3_algebraic_is_value(c, b)
+ \post Z3_algebraic_is_value(c, result)
+
+ def_API('Z3_algebraic_add', AST, (_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_algebraic_add(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
+
+ /**
+ \brief Return the value a - b.
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre Z3_algebraic_is_value(c, b)
+ \post Z3_algebraic_is_value(c, result)
+
+ def_API('Z3_algebraic_sub', AST, (_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_algebraic_sub(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
+
+ /**
+ \brief Return the value a * b.
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre Z3_algebraic_is_value(c, b)
+ \post Z3_algebraic_is_value(c, result)
+
+ def_API('Z3_algebraic_mul', AST, (_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_algebraic_mul(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
+
+ /**
+ \brief Return the value a / b.
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre Z3_algebraic_is_value(c, b)
+ \pre !Z3_algebraic_is_zero(c, b)
+ \post Z3_algebraic_is_value(c, result)
+
+ def_API('Z3_algebraic_div', AST, (_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_algebraic_div(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
+
+ /**
+ \brief Return the a^(1/k)
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre k is even => !Z3_algebraic_is_neg(c, a)
+ \post Z3_algebraic_is_value(c, result)
+
+ def_API('Z3_algebraic_root', AST, (_in(CONTEXT), _in(AST), _in(UINT)))
+ */
+ Z3_ast Z3_API Z3_algebraic_root(__in Z3_context c, __in Z3_ast a, __in unsigned k);
+
+ /**
+ \brief Return the a^k
+
+ \pre Z3_algebraic_is_value(c, a)
+ \post Z3_algebraic_is_value(c, result)
+
+ def_API('Z3_algebraic_power', AST, (_in(CONTEXT), _in(AST), _in(UINT)))
+ */
+ Z3_ast Z3_API Z3_algebraic_power(__in Z3_context c, __in Z3_ast a, __in unsigned k);
+
+ /**
+ \brief Return Z3_TRUE if a < b, and Z3_FALSE otherwise.
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre Z3_algebraic_is_value(c, b)
+
+ def_API('Z3_algebraic_lt', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_algebraic_lt(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
+
+ /**
+ \brief Return Z3_TRUE if a > b, and Z3_FALSE otherwise.
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre Z3_algebraic_is_value(c, b)
+
+ def_API('Z3_algebraic_gt', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_algebraic_gt(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
+
+ /**
+ \brief Return Z3_TRUE if a <= b, and Z3_FALSE otherwise.
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre Z3_algebraic_is_value(c, b)
+
+ def_API('Z3_algebraic_le', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_algebraic_le(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
+
+ /**
+ \brief Return Z3_TRUE if a >= b, and Z3_FALSE otherwise.
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre Z3_algebraic_is_value(c, b)
+
+ def_API('Z3_algebraic_ge', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_algebraic_ge(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
+
+ /**
+ \brief Return Z3_TRUE if a == b, and Z3_FALSE otherwise.
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre Z3_algebraic_is_value(c, b)
+
+ def_API('Z3_algebraic_eq', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_algebraic_eq(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
+
+ /**
+ \brief Return Z3_TRUE if a != b, and Z3_FALSE otherwise.
+
+ \pre Z3_algebraic_is_value(c, a)
+ \pre Z3_algebraic_is_value(c, b)
+
+ def_API('Z3_algebraic_neq', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_algebraic_neq(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
+
+ /**
+ \brief Given a multivariate polynomial p(x_0, ..., x_{n-1}, x_n), returns the
+ roots of the univariate polynomial p(a[0], ..., a[n-1], x_n).
+
+ \pre p is a Z3 expression that contains only arithmetic terms and free variables.
+ \pre forall i in [0, n) Z3_algebraic_is_value(c, a[i])
+ \post forall r in result Z3_algebraic_is_value(c, result)
+
+ def_API('Z3_algebraic_roots', AST_VECTOR, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST)))
+ */
+ Z3_ast_vector Z3_API Z3_algebraic_roots(__in Z3_context c, __in Z3_ast p, __in unsigned n, __in Z3_ast a[]);
+
+ /**
+ \brief Given a multivariate polynomial p(x_0, ..., x_{n-1}), return the
+ sign of p(a[0], ..., a[n-1]).
+
+ \pre p is a Z3 expression that contains only arithmetic terms and free variables.
+ \pre forall i in [0, n) Z3_algebraic_is_value(c, a[i])
+
+ def_API('Z3_algebraic_eval', INT, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST)))
+ */
+ int Z3_API Z3_algebraic_eval(__in Z3_context c, __in Z3_ast p, __in unsigned n, __in Z3_ast a[]);
+
+
+#ifdef __cplusplus
+};
+#endif // __cplusplus
+
+#endif
diff --git a/src/api/z3_api.h b/src/api/z3_api.h
index 49d59e125..e12ce3591 100644
--- a/src/api/z3_api.h
+++ b/src/api/z3_api.h
@@ -7123,18 +7123,19 @@ END_MLAPI_EXCLUDE
This means that two terms map to the same class identifier if and only if
the current context implies that they are equal.
- A side-effect of the function is a satisfiability check.
+ A side-effect of the function is a satisfiability check on the assertions on the solver that is passed in.
The function return Z3_L_FALSE if the current assertions are not satisfiable.
\sa Z3_check_and_get_model
\sa Z3_check
- \deprecated Subsumed by Z3_solver API
+ \deprecated To be moved outside of API.
- def_API('Z3_get_implied_equalities', UINT, (_in(CONTEXT), _in(UINT), _in_array(1, AST), _out_array(1, UINT)))
+ def_API('Z3_get_implied_equalities', UINT, (_in(CONTEXT), _in(SOLVER), _in(UINT), _in_array(2, AST), _out_array(2, UINT)))
*/
Z3_lbool Z3_API Z3_get_implied_equalities(
__in Z3_context c,
+ __in Z3_solver s,
__in unsigned num_terms,
__in_ecount(num_terms) Z3_ast const terms[],
__out_ecount(num_terms) unsigned class_ids[]
diff --git a/src/api/z3_polynomial.h b/src/api/z3_polynomial.h
new file mode 100644
index 000000000..614e654f9
--- /dev/null
+++ b/src/api/z3_polynomial.h
@@ -0,0 +1,45 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ z3_polynomial.h
+
+Abstract:
+
+ Additional APIs for polynomials.
+
+Author:
+
+ Leonardo de Moura (leonardo) 2012-12-09
+
+Notes:
+
+--*/
+
+#ifndef _Z3_POLYNOMIAL_H_
+#define _Z3_POLYNOMIAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+ /**
+ \brief Return the nonzero subresultants of \c p and \c q with respect to the "variable" \c x.
+
+ \pre \c p, \c q and \c x are Z3 expressions where \c p and \c q are arithmetic terms.
+ Note that, any subterm that cannot be viewed as a polynomial is assumed to be a variable.
+ Example: f(a) is a considered to be a variable in the polynomial
+
+ f(a)*f(a) + 2*f(a) + 1
+
+ def_API('Z3_polynomial_subresultants', AST_VECTOR, (_in(CONTEXT), _in(AST), _in(AST), _in(AST)))
+ */
+ Z3_ast_vector Z3_API Z3_polynomial_subresultants(__in Z3_context c, __in Z3_ast p, __in Z3_ast q, __in Z3_ast x);
+
+
+#ifdef __cplusplus
+};
+#endif // __cplusplus
+
+#endif
diff --git a/src/api/z3_private.h b/src/api/z3_private.h
index 17075a6c6..91becd158 100644
--- a/src/api/z3_private.h
+++ b/src/api/z3_private.h
@@ -36,38 +36,6 @@ extern "C" {
Z3_bool Z3_API Z3_get_numeral_rational(__in Z3_context c, __in Z3_ast a, rational& r);
- /**
- \brief \mlh exec_smtlib2_string c str \endmlh
- Parse the given string using the SMT-LIB2 parser and execute its commands.
-
- It returns a formula comprising of the conjunction of assertions in the scope
- (up to push/pop) at the end of the string.
- The returned formula is also asserted to the logical context on return.
- */
- Z3_ast Z3_API Z3_exec_smtlib2_string(__in Z3_context c,
- __in Z3_string str,
- __in unsigned num_sorts,
- __in_ecount(num_sorts) Z3_symbol sort_names[],
- __in_ecount(num_sorts) Z3_sort sorts[],
- __in unsigned num_decls,
- __in_ecount(num_decls) Z3_symbol decl_names[],
- __in_ecount(num_decls) Z3_func_decl decls[]
- );
-
- /**
- \brief Similar to #Z3_exec_smtlib2_string, but reads the commands from a file.
- */
- Z3_ast Z3_API Z3_exec_smtlib2_file(__in Z3_context c,
- __in Z3_string file_name,
- __in unsigned num_sorts,
- __in_ecount(num_sorts) Z3_symbol sort_names[],
- __in_ecount(num_sorts) Z3_sort sorts[],
- __in unsigned num_decls,
- __in_ecount(num_decls) Z3_symbol decl_names[],
- __in_ecount(num_decls) Z3_func_decl decls[]
- );
-
-
#ifndef CAMLIDL
#ifdef __cplusplus
};
diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp
index 4aadafae2..a89cc18d0 100644
--- a/src/ast/arith_decl_plugin.cpp
+++ b/src/ast/arith_decl_plugin.cpp
@@ -38,13 +38,6 @@ struct arith_decl_plugin::algebraic_numbers_wrapper {
unsigned mk_id(algebraic_numbers::anum const & val) {
SASSERT(!m_amanager.is_rational(val));
- // TODO: avoid linear scan. Use hashtable based on the floor of val
- unsigned sz = m_nums.size();
- for (unsigned i = 0; i < sz; i++) {
- algebraic_numbers::anum const & other = m_nums.get(i);
- if (m_amanager.eq(val, other))
- return i;
- }
unsigned new_id = m_id_gen.mk();
m_nums.reserve(new_id+1);
m_amanager.set(m_nums[new_id], val);
@@ -71,13 +64,13 @@ struct arith_decl_plugin::algebraic_numbers_wrapper {
};
-arith_decl_plugin::algebraic_numbers_wrapper & arith_decl_plugin::aw() {
+arith_decl_plugin::algebraic_numbers_wrapper & arith_decl_plugin::aw() const {
if (m_aw == 0)
- m_aw = alloc(algebraic_numbers_wrapper);
+ const_cast(this)->m_aw = alloc(algebraic_numbers_wrapper);
return *m_aw;
}
-algebraic_numbers::manager & arith_decl_plugin::am() {
+algebraic_numbers::manager & arith_decl_plugin::am() const {
return aw().m_amanager;
}
@@ -509,16 +502,43 @@ void arith_decl_plugin::get_op_names(svector& op_names, symbol con
}
}
-bool arith_decl_plugin::is_value(app* e) const {
- return is_app_of(e, m_family_id, OP_NUM);
+bool arith_decl_plugin::is_value(app * e) const {
+ return
+ is_app_of(e, m_family_id, OP_NUM) ||
+ is_app_of(e, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) ||
+ is_app_of(e, m_family_id, OP_PI) ||
+ is_app_of(e, m_family_id, OP_E);
}
-bool arith_decl_plugin::are_distinct(app* a, app* b) const {
+bool arith_decl_plugin::is_unique_value(app * e) const {
+ return
+ is_app_of(e, m_family_id, OP_NUM) ||
+ is_app_of(e, m_family_id, OP_PI) ||
+ is_app_of(e, m_family_id, OP_E);
+}
+
+bool arith_decl_plugin::are_equal(app * a, app * b) const {
+ if (decl_plugin::are_equal(a, b)) {
+ return true;
+ }
+
+ if (is_app_of(a, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) && is_app_of(b, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM)) {
+ return am().eq(aw().to_anum(a->get_decl()), aw().to_anum(b->get_decl()));
+ }
+
+ return false;
+}
+
+bool arith_decl_plugin::are_distinct(app * a, app * b) const {
TRACE("are_distinct_bug", tout << mk_ismt2_pp(a, *m_manager) << "\n" << mk_ismt2_pp(b, *m_manager) << "\n";);
if (decl_plugin::are_distinct(a,b)) {
return true;
}
+ if (is_app_of(a, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) && is_app_of(b, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM)) {
+ return am().neq(aw().to_anum(a->get_decl()), aw().to_anum(b->get_decl()));
+ }
+
#define is_non_zero(e) is_app_of(e,m_family_id, OP_NUM) && !to_app(e)->get_decl()->get_parameter(0).get_rational().is_zero()
if (is_app_of(a, m_family_id, OP_ADD) &&
diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h
index 6a377c577..c39768d4c 100644
--- a/src/ast/arith_decl_plugin.h
+++ b/src/ast/arith_decl_plugin.h
@@ -141,8 +141,8 @@ public:
virtual ~arith_decl_plugin();
virtual void finalize();
- algebraic_numbers::manager & am();
- algebraic_numbers_wrapper & aw();
+ algebraic_numbers::manager & am() const;
+ algebraic_numbers_wrapper & aw() const;
virtual void del(parameter const & p);
virtual parameter translate(parameter const & p, decl_plugin & target);
@@ -159,9 +159,13 @@ public:
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range);
- virtual bool is_value(app* e) const;
+ virtual bool is_value(app * e) const;
- virtual bool are_distinct(app* a, app* b) const;
+ virtual bool is_unique_value(app * e) const;
+
+ virtual bool are_equal(app * a, app * b) const;
+
+ virtual bool are_distinct(app * a, app * b) const;
virtual void get_op_names(svector & op_names, symbol const & logic);
@@ -180,7 +184,7 @@ public:
virtual expr * get_some_value(sort * s);
- void set_cancel(bool f);
+ virtual void set_cancel(bool f);
};
class arith_util {
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index ae82dcadf..3fb422a2e 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -872,6 +872,10 @@ bool basic_decl_plugin::is_value(app* a) const {
return a->get_decl() == m_true_decl || a->get_decl() == m_false_decl;
}
+bool basic_decl_plugin::is_unique_value(app* a) const {
+ return is_value(a);
+}
+
void basic_decl_plugin::finalize() {
#define DEC_REF(FIELD) if (FIELD) { m_manager->dec_ref(FIELD); }
#define DEC_ARRAY_REF(FIELD) m_manager->dec_array_ref(FIELD.size(), FIELD.begin())
@@ -1151,6 +1155,10 @@ bool model_value_decl_plugin::is_value(app* n) const {
return is_app_of(n, m_family_id, OP_MODEL_VALUE);
}
+bool model_value_decl_plugin::is_unique_value(app* n) const {
+ return is_value(n);
+}
+
// -----------------------------------
//
// user_sort_plugin
@@ -1328,6 +1336,12 @@ ast_manager::~ast_manager() {
}
}
+void ast_manager::set_cancel(bool f) {
+ for (unsigned i = 0; i < m_plugins.size(); i++) {
+ m_plugins[i]->set_cancel(f);
+ }
+}
+
void ast_manager::compact_memory() {
m_alloc.consolidate();
unsigned capacity = m_ast_table.capacity();
@@ -1442,6 +1456,27 @@ bool ast_manager::is_value(expr* e) const {
return false;
}
+bool ast_manager::is_unique_value(expr* e) const {
+ decl_plugin const * p = 0;
+ if (is_app(e)) {
+ p = get_plugin(to_app(e)->get_family_id());
+ return p && p->is_unique_value(to_app(e));
+ }
+ return false;
+}
+
+bool ast_manager::are_equal(expr * a, expr * b) const {
+ if (is_app(a) && is_app(b)) {
+ app* ap = to_app(a), *bp = to_app(b);
+ decl_plugin const * p = get_plugin(ap->get_family_id());
+ if (!p) {
+ p = get_plugin(bp->get_family_id());
+ }
+ return p && p->are_equal(ap, bp);
+ }
+ return false;
+}
+
bool ast_manager::are_distinct(expr* a, expr* b) const {
if (is_app(a) && is_app(b)) {
app* ap = to_app(a), *bp = to_app(b);
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 2a0872721..e9da41377 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -921,6 +921,8 @@ public:
virtual ~decl_plugin() {}
virtual void finalize() {}
+ virtual void set_cancel(bool f) {}
+
virtual decl_plugin * mk_fresh() = 0;
family_id get_family_id() const { return m_family_id; }
@@ -933,9 +935,39 @@ public:
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const* parameters,
unsigned num_args, expr * const * args, sort * range);
- virtual bool is_value(app*) const { return false; }
+ /**
+ \brief Return true if the plugin can decide whether two
+ interpreted constants are equal or not.
+
+ For all a, b:
+ If is_value(a) and is_value(b)
+ Then,
+ are_equal(a, b) != are_distinct(a, b)
+
+ The may be much more expensive than checking a pointer.
- virtual bool are_distinct(app* a, app* b) const { return a != b && is_value(a) && is_value(b); }
+ We need this because some plugin values are too expensive too canonize.
+ */
+ virtual bool is_value(app * a) const { return false; }
+
+ /**
+ \brief Return true if \c a is a unique plugin value.
+ The following property should hold for unique theory values:
+
+ For all a, b:
+ If is_unique_value(a) and is_unique_value(b)
+ Then,
+ a == b (pointer equality)
+ IFF
+ the interpretations of these theory terms are equal.
+
+ \remark This is a stronger version of is_value.
+ */
+ virtual bool is_unique_value(app * a) const { return false; }
+
+ virtual bool are_equal(app * a, app * b) const { return a == b && is_unique_value(a) && is_unique_value(b); }
+
+ virtual bool are_distinct(app * a, app * b) const { return a != b && is_unique_value(a) && is_unique_value(b); }
virtual void get_op_names(svector & op_names, symbol const & logic = symbol()) {}
@@ -1080,6 +1112,8 @@ public:
virtual void get_sort_names(svector & sort_names, symbol const & logic);
virtual bool is_value(app* a) const;
+
+ virtual bool is_unique_value(app* a) const;
sort * mk_bool_sort() const { return m_bool_sort; }
sort * mk_proof_sort() const { return m_proof_sort; }
@@ -1116,7 +1150,6 @@ public:
virtual decl_plugin * mk_fresh() { return alloc(label_decl_plugin); }
-
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
/**
@@ -1198,6 +1231,8 @@ public:
unsigned arity, sort * const * domain, sort * range);
virtual bool is_value(app* n) const;
+
+ virtual bool is_unique_value(app* a) const;
};
// -----------------------------------
@@ -1367,6 +1402,9 @@ public:
ast_manager(ast_manager const & src, bool disable_proofs = false);
~ast_manager();
+ // propagate cancellation signal to decl_plugins
+ void set_cancel(bool f);
+
bool has_trace_stream() const { return m_trace_stream != 0; }
std::ostream & trace_stream() { SASSERT(has_trace_stream()); return *m_trace_stream; }
@@ -1442,9 +1480,13 @@ public:
*/
void set_next_expr_id(unsigned id);
- bool is_value(expr* e) const;
+ bool is_value(expr * e) const;
+
+ bool is_unique_value(expr * e) const;
- bool are_distinct(expr* a, expr* b) const;
+ bool are_equal(expr * a, expr * b) const;
+
+ bool are_distinct(expr * a, expr * b) const;
bool contains(ast * a) const { return m_ast_table.contains(a); }
diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h
index a98f39323..34f2baf6b 100644
--- a/src/ast/bv_decl_plugin.h
+++ b/src/ast/bv_decl_plugin.h
@@ -260,8 +260,10 @@ public:
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range);
- virtual bool is_value(app* e) const;
+ virtual bool is_value(app * e) const;
+ virtual bool is_unique_value(app * e) const { return is_value(e); }
+
virtual void get_op_names(svector & op_names, symbol const & logic);
virtual void get_sort_names(svector & sort_names, symbol const & logic);
diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h
index a8bd28d8e..96b678fb2 100644
--- a/src/ast/datatype_decl_plugin.h
+++ b/src/ast/datatype_decl_plugin.h
@@ -146,6 +146,9 @@ public:
virtual bool is_fully_interp(sort const * s) const;
virtual bool is_value(app* e) const;
+
+ virtual bool is_unique_value(app * e) const { return is_value(e); }
+
private:
bool is_value_visit(expr * arg, ptr_buffer & todo) const;
};
diff --git a/src/ast/dl_decl_plugin.h b/src/ast/dl_decl_plugin.h
index 32e3c6da9..559aff7bd 100644
--- a/src/ast/dl_decl_plugin.h
+++ b/src/ast/dl_decl_plugin.h
@@ -130,7 +130,8 @@ namespace datalog {
virtual void get_sort_names(svector & sort_names, symbol const & logic);
- virtual bool is_value(app* e) const { return is_app_of(e, m_family_id, OP_DL_CONSTANT); }
+ virtual bool is_value(app * e) const { return is_app_of(e, m_family_id, OP_DL_CONSTANT); }
+ virtual bool is_unique_value(app * e) const { return is_value(e); }
};
diff --git a/src/ast/expr2polynomial.cpp b/src/ast/expr2polynomial.cpp
index 72bd72aa7..fbabcb150 100644
--- a/src/ast/expr2polynomial.cpp
+++ b/src/ast/expr2polynomial.cpp
@@ -49,21 +49,24 @@ struct expr2polynomial::imp {
polynomial::polynomial_ref_vector m_presult_stack;
polynomial::scoped_numeral_vector m_dresult_stack;
+ bool m_use_var_idxs;
+
volatile bool m_cancel;
- imp(expr2polynomial & w, ast_manager & am, polynomial::manager & pm, expr2var * e2v):
+ imp(expr2polynomial & w, ast_manager & am, polynomial::manager & pm, expr2var * e2v, bool use_var_idxs):
m_wrapper(w),
m_am(am),
m_autil(am),
m_pm(pm),
- m_expr2var(e2v == 0 ? alloc(expr2var, am) : e2v),
- m_expr2var_owner(e2v == 0),
+ m_expr2var(e2v == 0 && !use_var_idxs ? alloc(expr2var, am) : e2v),
+ m_expr2var_owner(e2v == 0 && !use_var_idxs),
m_var2expr(am),
m_cached_domain(am),
m_cached_polynomials(pm),
m_cached_denominators(pm.m()),
m_presult_stack(pm),
m_dresult_stack(pm.m()),
+ m_use_var_idxs(use_var_idxs),
m_cancel(false) {
}
@@ -95,6 +98,14 @@ struct expr2polynomial::imp {
cooperate("expr2polynomial");
}
+ void throw_not_polynomial() {
+ throw default_exception("the given expression is not a polynomial");
+ }
+
+ void throw_no_int_var() {
+ throw default_exception("integer variables are not allowed in the given polynomial");
+ }
+
void push_frame(app * t) {
m_frame_stack.push_back(frame(t));
}
@@ -127,14 +138,26 @@ struct expr2polynomial::imp {
}
void store_var_poly(expr * t) {
- polynomial::var x = m_expr2var->to_var(t);
- if (x == UINT_MAX) {
- bool is_int = m_autil.is_int(t);
- x = m_wrapper.mk_var(is_int);
- m_expr2var->insert(t, x);
- if (x >= m_var2expr.size())
- m_var2expr.resize(x+1, 0);
- m_var2expr.set(x, t);
+ polynomial::var x;
+ if (m_use_var_idxs) {
+ SASSERT(::is_var(t));
+ if (m_autil.is_int(t))
+ throw_no_int_var();
+ unsigned idx = to_var(t)->get_idx();
+ while (idx >= m_pm.num_vars())
+ m_pm.mk_var();
+ x = static_cast(idx);
+ }
+ else {
+ x = m_expr2var->to_var(t);
+ if (x == UINT_MAX) {
+ bool is_int = m_autil.is_int(t);
+ x = m_wrapper.mk_var(is_int);
+ m_expr2var->insert(t, x);
+ if (x >= m_var2expr.size())
+ m_var2expr.resize(x+1, 0);
+ m_var2expr.set(x, t);
+ }
}
polynomial::numeral one(1);
store_result(t, pm().mk_polynomial(x), one);
@@ -160,7 +183,10 @@ struct expr2polynomial::imp {
rational k;
SASSERT(t->get_num_args() == 2);
if (!m_autil.is_numeral(t->get_arg(1), k) || !k.is_int() || !k.is_unsigned()) {
- store_var_poly(t);
+ if (m_use_var_idxs)
+ throw_not_polynomial();
+ else
+ store_var_poly(t);
return true;
}
push_frame(t);
@@ -168,6 +194,8 @@ struct expr2polynomial::imp {
}
default:
// can't handle operator
+ if (m_use_var_idxs)
+ throw_not_polynomial();
store_var_poly(t);
return true;
}
@@ -190,6 +218,8 @@ struct expr2polynomial::imp {
SASSERT(is_app(t));
if (!m_autil.is_arith_expr(t)) {
+ if (m_use_var_idxs)
+ throw_not_polynomial();
store_var_poly(t);
return true;
}
@@ -378,19 +408,25 @@ struct expr2polynomial::imp {
for (unsigned i = 0; i < sz; i++) {
margs.reset();
- polynomial::monomial * m = pm().get_monomial(p, i);
+ polynomial::monomial * _m = pm().get_monomial(p, i);
polynomial::numeral const & a = pm().coeff(p, i);
if (!nm().is_one(a)) {
margs.push_back(m_autil.mk_numeral(rational(a), is_int));
}
- unsigned msz = pm().size(m);
+ unsigned msz = pm().size(_m);
for (unsigned j = 0; j < msz; j++) {
- polynomial::var x = pm().get_var(m, j);
- expr * t = m_var2expr.get(x);
- if (m_wrapper.is_int(x) && !is_int) {
- t = m_autil.mk_to_real(t);
+ polynomial::var x = pm().get_var(_m, j);
+ expr * t;
+ if (m_use_var_idxs) {
+ t = m().mk_var(x, m_autil.mk_real());
}
- unsigned d = pm().degree(m, j);
+ else {
+ t = m_var2expr.get(x);
+ if (m_wrapper.is_int(x) && !is_int) {
+ t = m_autil.mk_to_real(t);
+ }
+ }
+ unsigned d = pm().degree(_m, j);
if (use_power && d > 1) {
margs.push_back(m_autil.mk_power(t, m_autil.mk_numeral(rational(d), is_int)));
}
@@ -426,8 +462,8 @@ struct expr2polynomial::imp {
}
};
-expr2polynomial::expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v) {
- m_imp = alloc(imp, *this, am, pm, e2v);
+expr2polynomial::expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v, bool use_var_idxs) {
+ m_imp = alloc(imp, *this, am, pm, e2v, use_var_idxs);
}
expr2polynomial::~expr2polynomial() {
@@ -451,10 +487,12 @@ void expr2polynomial::to_expr(polynomial::polynomial_ref const & p, bool use_pow
}
bool expr2polynomial::is_var(expr * t) const {
+ SASSERT(!m_imp->m_use_var_idxs);
return m_imp->m_expr2var->is_var(t);
}
expr2var const & expr2polynomial::get_mapping() const {
+ SASSERT(!m_imp->m_use_var_idxs);
return *(m_imp->m_expr2var);
}
diff --git a/src/ast/expr2polynomial.h b/src/ast/expr2polynomial.h
index fbeda019d..8934f3f24 100644
--- a/src/ast/expr2polynomial.h
+++ b/src/ast/expr2polynomial.h
@@ -29,7 +29,24 @@ class expr2polynomial {
struct imp;
imp * m_imp;
public:
- expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v);
+ expr2polynomial(ast_manager & am,
+ polynomial::manager & pm,
+ expr2var * e2v,
+ /*
+ If true, the expressions converted into
+ polynomials should only contain Z3 free variables.
+ A Z3 variable x, with idx i, is converted into
+ the variable i of the polynomial manager pm.
+
+ An exception is thrown if there is a mismatch between
+ the sorts x and the variable in the polynomial manager.
+
+ The argument e2v is ignored when use_var_idxs is true.
+
+ Moreover, only real variables are allowed.
+ */
+ bool use_var_idxs = false
+ );
virtual ~expr2polynomial();
ast_manager & m() const;
@@ -63,6 +80,8 @@ public:
/**
\brief Return the mapping from expressions to variables
+
+ \pre the object was created using use_var_idxs = false.
*/
expr2var const & get_mapping() const;
@@ -74,10 +93,10 @@ public:
/**
\brief Return true if the variable is associated with an expression of integer sort.
*/
- virtual bool is_int(polynomial::var x) const = 0;
+ virtual bool is_int(polynomial::var x) const { UNREACHABLE(); return false; }
protected:
- virtual polynomial::var mk_var(bool is_int) = 0;
+ virtual polynomial::var mk_var(bool is_int) { UNREACHABLE(); return polynomial::null_var; }
};
class default_expr2polynomial : public expr2polynomial {
diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h
index c4503349b..6f1ef5ec2 100644
--- a/src/ast/float_decl_plugin.h
+++ b/src/ast/float_decl_plugin.h
@@ -141,6 +141,7 @@ public:
virtual void get_op_names(svector & op_names, symbol const & logic);
virtual void get_sort_names(svector & sort_names, symbol const & logic);
virtual bool is_value(app* e) const;
+ virtual bool is_unique_value(app* e) const { return is_value(e); }
mpf_manager & fm() { return m_fm; }
func_decl * mk_value_decl(mpf const & v);
diff --git a/src/ast/pattern/pattern_inference_params_helper.pyg b/src/ast/pattern/pattern_inference_params_helper.pyg
index 5d64e8e52..52c6c653e 100644
--- a/src/ast/pattern/pattern_inference_params_helper.pyg
+++ b/src/ast/pattern/pattern_inference_params_helper.pyg
@@ -5,7 +5,7 @@ def_module_params(class_name='pattern_inference_params_helper',
params=(('max_multi_patterns', UINT, 0, 'when patterns are not provided, the prover uses a heuristic to infer them, this option sets the threshold on the number of extra multi-patterns that can be created; by default, the prover creates at most one multi-pattern when there is no unary pattern'),
('block_loop_patterns', BOOL, True, 'block looping patterns during pattern inference'),
('arith', UINT, 1, '0 - do not infer patterns with arithmetic terms, 1 - use patterns with arithmetic terms if there is no other pattern, 2 - always use patterns with arithmetic terms'),
- ('use_database', BOOL, True, 'use pattern database'),
+ ('use_database', BOOL, False, 'use pattern database'),
('arith_weight', UINT, 5, 'default weight for quantifiers where the only available pattern has nested arithmetic terms'),
('non_nested_arith_weight', UINT, 10, 'default weight for quantifiers where the only available pattern has non nested arithmetic terms'),
('pull_quantifiers', BOOL, True, 'pull nested quantifiers, if no pattern was found'),
diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp
index 4fcaf02fe..b5f18a461 100644
--- a/src/ast/rewriter/bool_rewriter.cpp
+++ b/src/ast/rewriter/bool_rewriter.cpp
@@ -732,7 +732,7 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args
return BR_DONE;
}
visited.mark(arg);
- if (!m().is_value(arg))
+ if (!m().is_unique_value(arg))
all_value = false;
}
if (all_value) {
diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp
index 07ee7698d..966544b78 100644
--- a/src/ast/rewriter/th_rewriter.cpp
+++ b/src/ast/rewriter/th_rewriter.cpp
@@ -200,7 +200,12 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
expr * mk_eq_value(expr * lhs, expr * value) {
SASSERT(m().is_value(value));
if (m().is_value(lhs)) {
- return lhs == value ? m().mk_true() : m().mk_false();
+ if (m().are_equal(lhs, value)) {
+ return m().mk_true();
+ }
+ else if (m().are_distinct(lhs, value)) {
+ return m().mk_false();
+ }
}
return m().mk_eq(lhs, value);
}
@@ -483,10 +488,13 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
f = to_app(t1)->get_decl();
return unify_core(to_app(t1), t2, new_t1, new_t2, c, first);
}
- else {
+ else if (is_arith_bv_app(t2)) {
f = to_app(t2)->get_decl();
return unify_core(to_app(t2), t1, new_t2, new_t1, c, first);
}
+ else {
+ return false;
+ }
}
// Apply transformations of the form
diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h
index c055694eb..1bb3f3581 100644
--- a/src/ast/seq_decl_plugin.h
+++ b/src/ast/seq_decl_plugin.h
@@ -112,7 +112,10 @@ public:
virtual void get_sort_names(svector & sort_names, symbol const & logic);
- virtual bool is_value(app* e) const;
+ virtual bool is_value(app * e) const;
+
+ virtual bool is_unique_value(app * e) const { return is_value(e); }
+
};
diff --git a/src/ast/simplifier/array_simplifier_plugin.cpp b/src/ast/simplifier/array_simplifier_plugin.cpp
index 75c3cdbce..bf9ca8ffe 100644
--- a/src/ast/simplifier/array_simplifier_plugin.cpp
+++ b/src/ast/simplifier/array_simplifier_plugin.cpp
@@ -293,7 +293,7 @@ bool array_simplifier_plugin::all_const_array(unsigned num_args, expr* const* ar
bool array_simplifier_plugin::all_values(unsigned num_args, expr* const* args) const {
for (unsigned i = 0; i < num_args; ++i) {
- if (!m_manager.is_value(args[i])) {
+ if (!m_manager.is_unique_value(args[i])) {
return false;
}
}
@@ -331,7 +331,7 @@ lbool array_simplifier_plugin::eq_default(expr* def, unsigned arity, unsigned nu
if (st[i][arity] == def) {
continue;
}
- if (m_manager.is_value(st[i][arity]) && m_manager.is_value(def)) {
+ if (m_manager.is_unique_value(st[i][arity]) && m_manager.is_unique_value(def)) {
return l_false;
}
return l_undef;
@@ -342,7 +342,7 @@ lbool array_simplifier_plugin::eq_default(expr* def, unsigned arity, unsigned nu
bool array_simplifier_plugin::insert_table(expr* def, unsigned arity, unsigned num_st, expr*const* const* st, arg_table& table) {
for (unsigned i = 0; i < num_st; ++i ) {
for (unsigned j = 0; j < arity; ++j) {
- if (!m_manager.is_value(st[i][j])) {
+ if (!m_manager.is_unique_value(st[i][j])) {
return false;
}
}
@@ -380,12 +380,12 @@ lbool array_simplifier_plugin::eq_stores(expr* def, unsigned arity, unsigned num
table2.erase(e1);
continue;
}
- if (m_manager.is_value(v1) && m_manager.is_value(v2)) {
+ if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(v2)) {
return l_false;
}
return l_undef;
}
- else if (m_manager.is_value(v1) && m_manager.is_value(def) && v1 != def) {
+ else if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(def) && v1 != def) {
return l_false;
}
}
@@ -394,7 +394,7 @@ lbool array_simplifier_plugin::eq_stores(expr* def, unsigned arity, unsigned num
for (; it != end; ++it) {
args_entry const & e = *it;
expr* v = e.m_args[arity];
- if (m_manager.is_value(v) && m_manager.is_value(def) && v != def) {
+ if (m_manager.is_unique_value(v) && m_manager.is_unique_value(def) && v != def) {
return l_false;
}
}
@@ -431,7 +431,7 @@ bool array_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & resul
return false;
}
}
- else if (m_manager.is_value(c1) && m_manager.is_value(c2)) {
+ else if (m_manager.is_unique_value(c1) && m_manager.is_unique_value(c2)) {
result = m_manager.mk_false();
return true;
}
@@ -464,7 +464,7 @@ array_simplifier_plugin::mk_select_const(expr* m, app* index, expr_ref& result)
//
// Unfold and cache the store while searching for value of index.
//
- while (is_store(a) && m_manager.is_value(to_app(a)->get_arg(1))) {
+ while (is_store(a) && m_manager.is_unique_value(to_app(a)->get_arg(1))) {
app* b = to_app(a);
app* c = to_app(b->get_arg(1));
@@ -728,7 +728,7 @@ void array_simplifier_plugin::mk_select(unsigned num_args, expr * const * args,
return;
}
- bool is_const_select = num_args == 2 && m_manager.is_value(args[1]);
+ bool is_const_select = num_args == 2 && m_manager.is_unique_value(args[1]);
app* const_index = is_const_select?to_app(args[1]):0;
unsigned num_const_stores = 0;
expr_ref tmp(m_manager);
@@ -766,7 +766,7 @@ void array_simplifier_plugin::mk_select(unsigned num_args, expr * const * args,
expr * else_branch = 0;
entry[0] = nested_array;
if (is_const_select) {
- if (m_manager.is_value(to_app(m)->get_arg(1))) {
+ if (m_manager.is_unique_value(to_app(m)->get_arg(1))) {
app* const_index2 = to_app(to_app(m)->get_arg(1));
//
// we found the value, all other stores are different.
diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp
index 0380e91ea..e86e56b69 100644
--- a/src/cmd_context/cmd_context.cpp
+++ b/src/cmd_context/cmd_context.cpp
@@ -37,6 +37,7 @@ Notes:
#include"well_sorted.h"
#include"model_evaluator.h"
#include"for_each_expr.h"
+#include"scoped_timer.h"
func_decls::func_decls(ast_manager & m, func_decl * f):
m_decls(TAG(func_decl*, f, 0)) {
@@ -581,8 +582,8 @@ void cmd_context::init_manager_core(bool new_manager) {
// it prevents clashes with builtin types.
insert(pm().mk_plist_decl());
}
- if (m_solver) {
- init_solver_options(m_solver.get());
+ if (m_solver_factory) {
+ mk_solver();
}
m_check_logic.set_logic(m(), m_logic);
}
@@ -591,14 +592,9 @@ void cmd_context::init_manager() {
SASSERT(m_manager == 0);
SASSERT(m_pmanager == 0);
m_check_sat_result = 0;
- m_manager = alloc(ast_manager,
- produce_proofs() ? PGM_FINE : PGM_DISABLED,
- m_params.m_trace ? m_params.m_trace_file_name.c_str() : 0);
+ m_manager = m_params.mk_ast_manager();
m_pmanager = alloc(pdecl_manager, *m_manager);
init_manager_core(true);
- // PARAM-TODO
- // if (params().m_smtlib2_compliant)
- // m_manager->enable_int_real_coercions(false);
}
void cmd_context::init_external_manager() {
@@ -1123,7 +1119,7 @@ void cmd_context::reset(bool finalize) {
reset_func_decls();
restore_assertions(0);
if (m_solver)
- m_solver->reset();
+ m_solver = 0;
m_pp_env = 0;
m_dt_eh = 0;
if (m_manager) {
@@ -1304,9 +1300,11 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions
if (m_solver) {
m_check_sat_result = m_solver.get(); // solver itself stores the result.
m_solver->set_progress_callback(this);
+ unsigned timeout = m_params.m_timeout;
scoped_watch sw(*this);
cancel_eh eh(*m_solver);
scoped_ctrl_c ctrlc(eh);
+ scoped_timer timer(timeout, &eh);
lbool r;
try {
r = m_solver->check_sat(num_assumptions, assumptions);
@@ -1443,23 +1441,18 @@ void cmd_context::validate_model() {
}
}
-void cmd_context::init_solver_options(solver * s) {
- m_solver->set_produce_unsat_cores(produce_unsat_cores());
- m_solver->set_produce_models(produce_models());
- m_solver->set_produce_proofs(produce_proofs());
- m_solver->init(m(), m_logic);
- if (!m_params.m_auto_config) {
- params_ref p;
- p.set_bool("auto_config", false);
- m_solver->updt_params(p);
- }
+void cmd_context::mk_solver() {
+ bool proofs_enabled, models_enabled, unsat_core_enabled;
+ params_ref p;
+ m_params.get_solver_params(m(), p, proofs_enabled, models_enabled, unsat_core_enabled);
+ m_solver = (*m_solver_factory)(m(), p, proofs_enabled, models_enabled, unsat_core_enabled, m_logic);
}
-void cmd_context::set_solver(solver * s) {
+void cmd_context::set_solver_factory(solver_factory * f) {
+ m_solver_factory = f;
m_check_sat_result = 0;
- m_solver = s;
- if (has_manager() && s != 0) {
- init_solver_options(s);
+ if (has_manager() && f != 0) {
+ mk_solver();
// assert formulas and create scopes in the new solver.
unsigned lim = 0;
svector::iterator it = m_scopes.begin();
diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h
index 2edc87ca6..63e5e7040 100644
--- a/src/cmd_context/cmd_context.h
+++ b/src/cmd_context/cmd_context.h
@@ -185,6 +185,7 @@ protected:
};
svector m_scopes;
+ scoped_ptr m_solver_factory;
ref m_solver;
ref m_check_sat_result;
@@ -243,7 +244,7 @@ protected:
void print_unsupported_msg() { regular_stream() << "unsupported" << std::endl; }
void print_unsupported_info(symbol const& s) { if (s != symbol::null) diagnostic_stream() << "; " << s << std::endl;}
- void init_solver_options(solver * s);
+ void mk_solver();
public:
cmd_context(bool main_ctx = true, ast_manager * m = 0, symbol const & l = symbol::null);
@@ -289,8 +290,7 @@ public:
pdecl_manager & pm() const { if (!m_pmanager) const_cast(this)->init_manager(); return *m_pmanager; }
sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast(this)->m_sexpr_manager = alloc(sexpr_manager); return *m_sexpr_manager; }
- void set_solver(solver * s);
- solver * get_solver() const { return m_solver.get(); }
+ void set_solver_factory(solver_factory * s);
void set_check_sat_result(check_sat_result * r) { m_check_sat_result = r; }
check_sat_result * get_check_sat_result() const { return m_check_sat_result.get(); }
check_sat_state cs_state() const;
diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp
index 495f73b75..2752967dd 100644
--- a/src/cmd_context/context_params.cpp
+++ b/src/cmd_context/context_params.cpp
@@ -20,6 +20,8 @@ Notes:
#include"context_params.h"
#include"gparams.h"
#include"params.h"
+#include"ast.h"
+#include"solver.h"
context_params::context_params() {
updt_params();
@@ -39,7 +41,7 @@ void context_params::set_bool(bool & opt, char const * param, char const * value
void context_params::set(char const * param, char const * value) {
std::string p = param;
- unsigned n = p.size();
+ unsigned n = static_cast(p.size());
for (unsigned i = 0; i < n; i++) {
if (p[i] >= 'A' && p[i] <= 'Z')
p[i] = p[i] - 'A' + 'a';
@@ -77,6 +79,9 @@ void context_params::set(char const * param, char const * value) {
else if (p == "debug_ref_count") {
set_bool(m_debug_ref_count, param, value);
}
+ else if (p == "smtlib2_compliant") {
+ set_bool(m_smtlib2_compliant, param, value);
+ }
else {
throw default_exception("unknown parameter '%s'", p.c_str());
}
@@ -97,6 +102,7 @@ void context_params::updt_params(params_ref const & p) {
m_trace_file_name = p.get_str("trace_file_name", "z3.log");
m_unsat_core = p.get_bool("unsat_core", false);
m_debug_ref_count = p.get_bool("debug_ref_count", false);
+ m_smtlib2_compliant = p.get_bool("smtlib2_compliant", false);
}
void context_params::collect_param_descrs(param_descrs & d) {
@@ -111,4 +117,36 @@ void context_params::collect_param_descrs(param_descrs & d) {
d.insert("trace_file_name", CPK_STRING, "trace out file name (see option 'trace')", "z3.log");
d.insert("unsat_core", CPK_BOOL, "unsat-core generation for solvers, this parameter can be overwritten when creating a solver, not every solver in Z3 supports unsat core generation", "false");
d.insert("debug_ref_count", CPK_BOOL, "debug support for AST reference counting", "false");
+ d.insert("smtlib2_compliant", CPK_BOOL, "enable/disable SMT-LIB 2.0 compliance", "false");
}
+
+params_ref context_params::merge_default_params(params_ref const & p) {
+ if (!m_auto_config && !p.contains("auto_config")) {
+ params_ref new_p = p;
+ new_p.set_bool("auto_config", false);
+ return new_p;
+ }
+ else {
+ return p;
+ }
+}
+
+void context_params::get_solver_params(ast_manager const & m, params_ref & p, bool & proofs_enabled, bool & models_enabled, bool & unsat_core_enabled) {
+ proofs_enabled = m.proofs_enabled() && p.get_bool("proof", m_proof);
+ models_enabled = p.get_bool("model", m_model);
+ unsat_core_enabled = p.get_bool("unsat_core", m_unsat_core);
+ p = merge_default_params(p);
+}
+
+ast_manager * context_params::mk_ast_manager() {
+ ast_manager * r = alloc(ast_manager,
+ m_proof ? PGM_FINE : PGM_DISABLED,
+ m_trace ? m_trace_file_name.c_str() : 0);
+ if (m_smtlib2_compliant)
+ r->enable_int_real_coercions(false);
+ if (m_debug_ref_count)
+ r->debug_ref_count();
+ return r;
+}
+
+
diff --git a/src/cmd_context/context_params.h b/src/cmd_context/context_params.h
index 6b42b5b50..526b4f517 100644
--- a/src/cmd_context/context_params.h
+++ b/src/cmd_context/context_params.h
@@ -21,6 +21,7 @@ Notes:
#define _CONTEXT_PARAMS_H_
#include"params.h"
+class ast_manager;
class context_params {
void set_bool(bool & opt, char const * param, char const * value);
@@ -35,6 +36,7 @@ public:
bool m_model;
bool m_model_validate;
bool m_unsat_core;
+ bool m_smtlib2_compliant; // it must be here because it enable/disable the use of coercions in the ast_manager.
unsigned m_timeout;
context_params();
@@ -45,6 +47,23 @@ public:
/*
REG_PARAMS('context_params::collect_param_descrs')
*/
+
+ /**
+ \brief Goodies for extracting parameters for creating a solver object.
+ */
+ void get_solver_params(ast_manager const & m, params_ref & p, bool & proofs_enabled, bool & models_enabled, bool & unsat_core_enabled);
+
+ /**
+ \brief Include in p parameters derived from this context_params.
+ These are parameters that are meaningful for tactics and solvers.
+ Example: auto_config
+ */
+ params_ref merge_default_params(params_ref const & p);
+
+ /**
+ \brief Create an AST manager using this configuration.
+ */
+ ast_manager * mk_ast_manager();
};
diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp
index ca87406c7..27014bca9 100644
--- a/src/cmd_context/tactic_cmds.cpp
+++ b/src/cmd_context/tactic_cmds.cpp
@@ -36,7 +36,7 @@ tactic_cmd::~tactic_cmd() {
dealloc(m_factory);
}
-tactic * tactic_cmd::mk(ast_manager & m) {
+tactic * tactic_cmd::mk(ast_manager & m) {
return (*m_factory)(m, params_ref());
}
@@ -185,7 +185,7 @@ public:
}
virtual void execute(cmd_context & ctx) {
- params_ref p = ps();
+ params_ref p = ctx.params().merge_default_params(ps());
tactic_ref tref = using_params(sexpr2tactic(ctx, m_tactic), p);
tref->set_logic(ctx.get_logic());
ast_manager & m = ctx.m();
@@ -295,7 +295,7 @@ public:
}
virtual void execute(cmd_context & ctx) {
- params_ref p = ps();
+ params_ref p = ctx.params().merge_default_params(ps());
tactic_ref tref = using_params(sexpr2tactic(ctx, m_tactic), p);
{
tactic & t = *(tref.get());
diff --git a/src/math/polynomial/algebraic_numbers.h b/src/math/polynomial/algebraic_numbers.h
index 4735a875b..a4669eae6 100644
--- a/src/math/polynomial/algebraic_numbers.h
+++ b/src/math/polynomial/algebraic_numbers.h
@@ -64,6 +64,8 @@ namespace algebraic_numbers {
static void collect_param_descrs(param_descrs & r) { get_param_descrs(r); }
void set_cancel(bool f);
+
+ void cancel() { set_cancel(true); }
void updt_params(params_ref const & p);
diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h
index 7cefe6f56..d17d2ac5a 100644
--- a/src/math/polynomial/polynomial.h
+++ b/src/math/polynomial/polynomial.h
@@ -219,6 +219,7 @@ namespace polynomial {
void set_zp(uint64 p);
void set_cancel(bool f);
+ void cancel() { set_cancel(true); }
/**
\brief Abstract event handler.
diff --git a/src/model/func_interp.cpp b/src/model/func_interp.cpp
index 678d95c86..ae4c657bd 100644
--- a/src/model/func_interp.cpp
+++ b/src/model/func_interp.cpp
@@ -49,10 +49,10 @@ void func_entry::set_result(ast_manager & m, expr * r) {
m_result = r;
}
-bool func_entry::eq_args(unsigned arity, expr * const * args) const {
+bool func_entry::eq_args(ast_manager & m, unsigned arity, expr * const * args) const {
unsigned i = 0;
for (; i < arity; i++) {
- if (m_args[i] != args[i])
+ if (!m.are_equal(m_args[i], args[i]))
return false;
}
return true;
@@ -131,7 +131,7 @@ bool func_interp::is_constant() const {
}
/**
- \brief Return a func_entry e such that e.m_args[i] == args[i] for all i in [0, m_arity).
+ \brief Return a func_entry e such that m().are_equal(e.m_args[i], args[i]) for all i in [0, m_arity).
If such entry does not exist then return 0, and store set
args_are_values to true if for all entries e e.args_are_values() is true.
*/
@@ -140,7 +140,7 @@ func_entry * func_interp::get_entry(expr * const * args) const {
ptr_vector::const_iterator end = m_entries.end();
for (; it != end; ++it) {
func_entry * curr = *it;
- if (curr->eq_args(m_arity, args))
+ if (curr->eq_args(m(), m_arity, args))
return curr;
}
return 0;
diff --git a/src/model/func_interp.h b/src/model/func_interp.h
index b10fe0dad..fd21a6a7c 100644
--- a/src/model/func_interp.h
+++ b/src/model/func_interp.h
@@ -58,9 +58,9 @@ public:
expr * get_arg(unsigned idx) const { return m_args[idx]; }
expr * const * get_args() const { return m_args; }
/**
- \brief Return true if m_args[i] == args[i] for all i in [0, arity)
+ \brief Return true if m.are_equal(m_args[i], args[i]) for all i in [0, arity)
*/
- bool eq_args(unsigned arity, expr * const * args) const;
+ bool eq_args(ast_manager & m, unsigned arity, expr * const * args) const;
};
class func_interp {
diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp
index 27161320e..b5ffa808a 100644
--- a/src/muz_qe/dl_bmc_engine.cpp
+++ b/src/muz_qe/dl_bmc_engine.cpp
@@ -29,30 +29,1382 @@ Revision History:
#include "model_smt2_pp.h"
#include "ast_smt_pp.h"
#include "well_sorted.h"
+#include "rewriter_def.h"
namespace datalog {
+
+ // ---------------------------------------------------------------------------
+ // Basic linear BMC based on indexed variables using quantified bit-vector domains.
+
+ class bmc::qlinear {
+ bmc& b;
+ ast_manager& m;
+ bv_util m_bv;
+ unsigned m_bit_width;
+ public:
+ qlinear(bmc& b): b(b), m(b.m), m_bv(m), m_bit_width(1) {}
+
+
+ lbool check() {
+ setup();
+ m_bit_width = 4;
+ lbool res = l_false;
+ while (res == l_false) {
+ b.m_solver.push();
+ IF_VERBOSE(1, verbose_stream() << "bit_width: " << m_bit_width << "\n";);
+ compile();
+ b.checkpoint();
+ func_decl_ref q = mk_q_func_decl(b.m_query_pred);
+ expr* T = m.mk_const(symbol("T"), mk_index_sort());
+ expr_ref fml(m.mk_app(q, T), m);
+ b.assert_expr(fml);
+ res = b.m_solver.check();
+
+ if (res == l_true) {
+ res = get_model();
+ }
+ b.m_solver.pop(1);
+ ++m_bit_width;
+ }
+ return res;
+ }
+ private:
+
+ sort_ref mk_index_sort() {
+ return sort_ref(m_bv.mk_sort(m_bit_width), m);
+ }
+
+ var_ref mk_index_var() {
+ return var_ref(m.mk_var(0, mk_index_sort()), m);
+ }
+
+ void compile() {
+ sort_ref index_sort = mk_index_sort();
+ var_ref var = mk_index_var();
+ sort* index_sorts[1] = { index_sort };
+ symbol tick("T");
+ rule_set::decl2rules::iterator it = b.m_rules.begin_grouped_rules();
+ rule_set::decl2rules::iterator end = b.m_rules.end_grouped_rules();
+ for (; it != end; ++it) {
+ func_decl* p = it->m_key;
+ rule_vector const& rls = *it->m_value;
+ // Assert: forall level . p(T) => body of rule i + equalities for head of rule i
+ func_decl_ref pr = mk_q_func_decl(p);
+ expr_ref pred = expr_ref(m.mk_app(pr, var.get()), m);
+ expr_ref_vector rules(m), sub(m), conjs(m);
+ expr_ref trm(m), rule_body(m), rule_i(m);
+ for (unsigned i = 0; i < rls.size(); ++i) {
+ sub.reset();
+ conjs.reset();
+ rule& r = *rls[i];
+ rule_i = m.mk_app(mk_q_rule(p, i), var.get());
+ rules.push_back(rule_i);
+
+ mk_qrule_vars(r, i, sub);
+
+ // apply substitution to body.
+ var_subst vs(m, false);
+ for (unsigned k = 0; k < p->get_arity(); ++k) {
+ vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), trm);
+ conjs.push_back(m.mk_eq(trm, mk_q_arg(p, k, true)));
+ }
+ for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
+ func_decl* q = r.get_decl(j);
+ for (unsigned k = 0; k < q->get_arity(); ++k) {
+ vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), trm);
+ conjs.push_back(m.mk_eq(trm, mk_q_arg(q, k, false)));
+ }
+ func_decl_ref qr = mk_q_func_decl(q);
+ conjs.push_back(m.mk_app(qr, m_bv.mk_bv_sub(var, mk_q_one())));
+ }
+ for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
+ vs(r.get_tail(j), sub.size(), sub.c_ptr(), trm);
+ conjs.push_back(trm);
+ }
+ if (r.get_uninterpreted_tail_size() > 0) {
+ conjs.push_back(m_bv.mk_ule(mk_q_one(), var));
+ }
+ bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), rule_body);
+ trm = m.mk_implies(rule_i, rule_body);
+ trm = m.mk_forall(1, index_sorts, &tick, trm, 1);
+ b.assert_expr(trm);
+ }
+ bool_rewriter(m).mk_or(rules.size(), rules.c_ptr(), trm);
+ trm = m.mk_implies(pred, trm);
+ trm = m.mk_forall(1, index_sorts, &tick, trm, 1);
+ SASSERT(is_well_sorted(m, trm));
+ b.assert_expr(trm);
+ }
+ }
+
+ void setup() {
+ b.m_fparams.m_relevancy_lvl = 2;
+ b.m_fparams.m_model = true;
+ b.m_fparams.m_model_compact = true;
+ b.m_fparams.m_mbqi = true;
+ }
+
+ void mk_qrule_vars(datalog::rule const& r, unsigned rule_id, expr_ref_vector& sub) {
+ ptr_vector sorts;
+ r.get_vars(sorts);
+ // populate substitution of bound variables.
+ sub.reset();
+ sub.resize(sorts.size());
+
+ for (unsigned k = 0; k < r.get_decl()->get_arity(); ++k) {
+ expr* arg = r.get_head()->get_arg(k);
+ if (is_var(arg)) {
+ unsigned idx = to_var(arg)->get_idx();
+ if (!sub[idx].get()) {
+ sub[idx] = mk_q_arg(r.get_decl(), k, true);
+ }
+ }
+ }
+ for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
+ func_decl* q = r.get_decl(j);
+ for (unsigned k = 0; k < q->get_arity(); ++k) {
+ expr* arg = r.get_tail(j)->get_arg(k);
+ if (is_var(arg)) {
+ unsigned idx = to_var(arg)->get_idx();
+ if (!sub[idx].get()) {
+ sub[idx] = mk_q_arg(q, k, false);
+ }
+ }
+ }
+ }
+ for (unsigned j = 0, idx = 0; j < sorts.size(); ++j) {
+ if (sorts[j] && !sub[j].get()) {
+ sub[j] = mk_q_var(r.get_decl(), sorts[j], rule_id, idx++);
+ }
+ }
+ }
+
+ expr_ref mk_q_var(func_decl* pred, sort* s, unsigned rule_id, unsigned idx) {
+ std::stringstream _name;
+ _name << pred->get_name() << "#" << rule_id << "_" << idx;
+ symbol nm(_name.str().c_str());
+ var_ref var = mk_index_var();
+ return expr_ref(m.mk_app(m.mk_func_decl(nm, mk_index_sort(), s), var), m);
+ }
+
+ expr_ref mk_q_arg(func_decl* pred, unsigned idx, bool is_current) {
+ SASSERT(idx < pred->get_arity());
+ std::stringstream _name;
+ _name << pred->get_name() << "#" << idx;
+ symbol nm(_name.str().c_str());
+ expr_ref var(mk_index_var(), m);
+ if (!is_current) {
+ var = m_bv.mk_bv_sub(var, mk_q_one());
+ }
+ return expr_ref(m.mk_app(m.mk_func_decl(nm, mk_index_sort(), pred->get_domain(idx)), var), m);
+ }
+
+ expr_ref mk_q_one() {
+ return mk_q_num(1);
+ }
+
+ expr_ref mk_q_num(unsigned i) {
+ return expr_ref(m_bv.mk_numeral(i, m_bit_width), m);
+ }
+
+ func_decl_ref mk_q_func_decl(func_decl* f) {
+ std::stringstream _name;
+ _name << f->get_name() << "#";
+ symbol nm(_name.str().c_str());
+ return func_decl_ref(m.mk_func_decl(nm, mk_index_sort(), f->get_range()), m);
+ }
+
+ func_decl_ref mk_q_rule(func_decl* f, unsigned rule_id) {
+ std::stringstream _name;
+ _name << f->get_name() << "#" << rule_id;
+ symbol nm(_name.str().c_str());
+ return func_decl_ref(m.mk_func_decl(nm, mk_index_sort(), m.mk_bool_sort()), m);
+ }
+
+
+ expr_ref eval_q(model_ref& model, func_decl* f, unsigned i) {
+ func_decl_ref fn = mk_q_func_decl(f);
+ expr_ref t(m), result(m);
+ t = m.mk_app(mk_q_func_decl(f).get(), mk_q_num(i));
+ model->eval(t, result);
+ return result;
+ }
+
+ expr_ref eval_q(model_ref& model, expr* t, unsigned i) {
+ expr_ref tmp(m), result(m), num(m);
+ var_subst vs(m, false);
+ num = mk_q_num(i);
+ expr* nums[1] = { num };
+ vs(t, 1, nums, tmp);
+ model->eval(tmp, result);
+ return result;
+ }
+
+ lbool get_model() {
+ rule_manager& rm = b.m_ctx.get_rule_manager();
+ func_decl_ref q = mk_q_func_decl(b.m_query_pred);
+ expr_ref T(m), rule_i(m), vl(m);
+ model_ref md;
+ proof_ref pr(m);
+ rule_unifier unifier(b.m_ctx);
+ rational num;
+ unsigned level, bv_size;
+
+ b.m_solver.get_model(md);
+ func_decl* pred = b.m_query_pred;
+ dl_decl_util util(m);
+ T = m.mk_const(symbol("T"), mk_index_sort());
+ md->eval(T, vl);
+ VERIFY (m_bv.is_numeral(vl, num, bv_size));
+ SASSERT(num.is_unsigned());
+ level = num.get_unsigned();
+ SASSERT(m.is_true(eval_q(md, b.m_query_pred, level)));
+ TRACE("bmc", model_smt2_pp(tout, m, *md, 0););
+
+ rule_ref r0(rm), r1(rm), r2(rm);
+ while (true) {
+ TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";);
+ expr_ref_vector sub(m);
+ rule_vector const& rls = b.m_rules.get_predicate_rules(pred);
+ rule* r = 0;
+ unsigned i = 0;
+ for (; i < rls.size(); ++i) {
+ rule_i = m.mk_app(mk_q_rule(pred, i), mk_q_num(level).get());
+ TRACE("bmc", rls[i]->display(b.m_ctx, tout << "Checking rule " << mk_pp(rule_i, m) << " "););
+ if (m.is_true(eval_q(md, rule_i, level))) {
+ r = rls[i];
+ break;
+ }
+ }
+ SASSERT(r);
+ mk_qrule_vars(*r, i, sub);
+ // we have rule, we have variable names of rule.
+
+ // extract values for the variables in the rule.
+ for (unsigned j = 0; j < sub.size(); ++j) {
+ expr_ref vl = eval_q(md, sub[j].get(), i);
+ if (vl) {
+ // vl can be 0 if the interpretation does not assign a value to it.
+ sub[j] = vl;
+ }
+ else {
+ sub[j] = m.mk_var(j, m.get_sort(sub[j].get()));
+ }
+ }
+ svector > positions;
+ vector substs;
+ expr_ref fml(m), concl(m);
+
+ r->to_formula(fml);
+ r2 = r;
+ rm.substitute(r2, sub.size(), sub.c_ptr());
+ if (r0) {
+ VERIFY(unifier.unify_rules(*r0.get(), 0, *r2.get()));
+ expr_ref_vector sub1 = unifier.get_rule_subst(*r0.get(), true);
+ expr_ref_vector sub2 = unifier.get_rule_subst(*r2.get(), false);
+ apply_subst(sub, sub2);
+ unifier.apply(*r0.get(), 0, *r2.get(), r1);
+ r1->to_formula(concl);
+ scoped_coarse_proof _sp(m);
+
+ proof* p = m.mk_asserted(fml);
+ proof* premises[2] = { pr, p };
+
+ positions.push_back(std::make_pair(0, 1));
+
+ substs.push_back(sub1);
+ substs.push_back(sub);
+ pr = m.mk_hyper_resolve(2, premises, concl, positions, substs);
+ r0 = r1;
+ }
+ else {
+ r2->to_formula(concl);
+ scoped_coarse_proof _sp(m);
+ proof* p = m.mk_asserted(fml);
+ if (sub.empty()) {
+ pr = p;
+ }
+ else {
+ substs.push_back(sub);
+ pr = m.mk_hyper_resolve(1, &p, concl, positions, substs);
+ }
+ r0 = r2;
+ }
+
+ if (level == 0) {
+ SASSERT(r->get_uninterpreted_tail_size() == 0);
+ break;
+ }
+ --level;
+ SASSERT(r->get_uninterpreted_tail_size() == 1);
+ pred = r->get_decl(0);
+ }
+ scoped_coarse_proof _sp(m);
+ apply(m, b.m_pc.get(), pr);
+ b.m_answer = pr;
+ return l_true;
+ }
+ };
+
+
+ // --------------------------------------------------------------------------
+ // Basic non-linear BMC based on compiling into quantifiers.
+
+ class bmc::nonlinear {
+ bmc& b;
+ ast_manager& m;
+
+ public:
+
+ nonlinear(bmc& b): b(b), m(b.m) {}
+
+ lbool check() {
+ setup();
+ for (unsigned i = 0; ; ++i) {
+ IF_VERBOSE(1, verbose_stream() << "level: " << i << "\n";);
+ b.checkpoint();
+ expr_ref_vector fmls(m);
+ compile(b.m_rules, fmls, i);
+ assert_fmls(fmls);
+ lbool res = check(i);
+ if (res == l_undef) {
+ return res;
+ }
+ if (res == l_true) {
+ get_model(i);
+ return res;
+ }
+ }
+ }
+
+ expr_ref compile_query(func_decl* query_pred, unsigned level) {
+ expr_ref_vector vars(m);
+ func_decl_ref level_p = mk_level_predicate(query_pred, level);
+ for (unsigned i = 0; i < level_p->get_arity(); ++i) {
+ std::stringstream _name;
+ _name << query_pred->get_name() << "#" << level << "_" << i;
+ symbol nm(_name.str().c_str());
+ vars.push_back(m.mk_const(nm, level_p->get_domain(i)));
+ }
+ return expr_ref(m.mk_app(level_p, vars.size(), vars.c_ptr()), m);
+ }
+
+ void compile(rule_set const& rules, expr_ref_vector& result, unsigned level) {
+ bool_rewriter br(m);
+ rule_set::decl2rules::iterator it = rules.begin_grouped_rules();
+ rule_set::decl2rules::iterator end = rules.end_grouped_rules();
+ for (; it != end; ++it) {
+ func_decl* p = it->m_key;
+ rule_vector const& rls = *it->m_value;
+
+ // Assert: p_level(vars) => r1_level(vars) \/ r2_level(vars) \/ r3_level(vars) \/ ...
+ // Assert: r_i_level(vars) => exists aux_vars . body of rule i for level
+
+ func_decl_ref level_pred = mk_level_predicate(p, level);
+ expr_ref_vector rules(m);
+ expr_ref body(m), head(m);
+ for (unsigned i = 0; i < rls.size(); ++i) {
+ rule& r = *rls[i];
+ func_decl_ref rule_i = mk_level_rule(p, i, level);
+ rules.push_back(apply_vars(rule_i));
+
+ ptr_vector rule_vars;
+ expr_ref_vector args(m), conjs(m);
+
+ r.get_vars(rule_vars);
+ obj_hashtable used_vars;
+ unsigned num_vars = 0;
+ for (unsigned i = 0; i < r.get_decl()->get_arity(); ++i) {
+ expr* arg = r.get_head()->get_arg(i);
+ if (is_var(arg) && !used_vars.contains(arg)) {
+ used_vars.insert(arg);
+ args.push_back(arg);
+ rule_vars[to_var(arg)->get_idx()] = 0;
+ }
+ else {
+ sort* srt = m.get_sort(arg);
+ args.push_back(m.mk_var(rule_vars.size()+num_vars, srt));
+ conjs.push_back(m.mk_eq(args.back(), arg));
+ ++num_vars;
+ }
+ }
+ head = m.mk_app(rule_i, args.size(), args.c_ptr());
+ for (unsigned i = 0; i < r.get_tail_size(); ++i) {
+ conjs.push_back(r.get_tail(i));
+ }
+ br.mk_and(conjs.size(), conjs.c_ptr(), body);
+
+ replace_by_level_predicates(level, body);
+ body = skolemize_vars(r, args, rule_vars, body);
+ body = m.mk_implies(head, body);
+ body = bind_vars(body, head);
+ result.push_back(body);
+ }
+ br.mk_or(rules.size(), rules.c_ptr(), body);
+ head = apply_vars(level_pred);
+ body = m.mk_implies(head, body);
+ body = bind_vars(body, head);
+ result.push_back(body);
+ }
+ }
+
+ private:
+
+ void assert_fmls(expr_ref_vector const& fmls) {
+ for (unsigned i = 0; i < fmls.size(); ++i) {
+ b.assert_expr(fmls[i]);
+ }
+ }
+
+ void setup() {
+ b.m_fparams.m_model = true;
+ b.m_fparams.m_model_compact = true;
+ b.m_fparams.m_mbqi = true;
+ b.m_fparams.m_relevancy_lvl = 2;
+ }
+
+ lbool check(unsigned level) {
+ expr_ref p = compile_query(b.m_query_pred, level);
+ expr_ref q(m), q_at_level(m);
+ q = m.mk_fresh_const("q",m.mk_bool_sort());
+ q_at_level = m.mk_implies(q, p);
+ b.assert_expr(q_at_level);
+ expr* qr = q.get();
+ return b.m_solver.check(1, &qr);
+ }
+
+ proof_ref get_proof(model_ref& md, func_decl* pred, app* prop, unsigned level) {
+ TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";);
+
+ expr_ref prop_r(m), prop_v(m), fml(m), prop_body(m), tmp(m), body(m);
+ expr_ref_vector args(m);
+ proof_ref_vector prs(m);
+ proof_ref pr(m);
+
+ // find the rule that was triggered by evaluating the arguments to prop.
+ rule_vector const& rls = b.m_rules.get_predicate_rules(pred);
+ rule* r = 0;
+ for (unsigned i = 0; i < rls.size(); ++i) {
+ func_decl_ref rule_i = mk_level_rule(pred, i, level);
+ TRACE("bmc", rls[i]->display(b.m_ctx, tout << "Checking rule " << mk_pp(rule_i, m) << " "););
+ prop_r = m.mk_app(rule_i, prop->get_num_args(), prop->get_args());
+ md->eval(prop_r, prop_v);
+ if (m.is_true(prop_v)) {
+ r = rls[i];
+ break;
+ }
+ }
+ SASSERT(r);
+ r->to_formula(fml);
+ IF_VERBOSE(1, verbose_stream() << mk_pp(fml, m) << "\n";);
+ prs.push_back(m.mk_asserted(fml));
+ unsigned sz = r->get_uninterpreted_tail_size();
+
+ ptr_vector rule_vars;
+ r->get_vars(rule_vars);
+ args.append(prop->get_num_args(), prop->get_args());
+ expr_ref_vector sub = mk_skolem_binding(*r, rule_vars, args);
+ if (sub.empty() && sz == 0) {
+ pr = prs[0].get();
+ return pr;
+ }
+ for (unsigned j = 0; j < sub.size(); ++j) {
+ md->eval(sub[j].get(), tmp);
+ sub[j] = tmp;
+ }
+
+ svector > positions;
+ vector substs;
+ var_subst vs(m, false);
+
+ substs.push_back(sub);
+ for (unsigned j = 0; j < sz; ++j) {
+ func_decl* head_j = r->get_decl(j);
+ app* body_j = r->get_tail(j);
+ vs(body_j, sub.size(), sub.c_ptr(), prop_body);
+ prs.push_back(get_proof(md, head_j, to_app(prop_body), level-1));
+ positions.push_back(std::make_pair(j+1,0));
+ substs.push_back(expr_ref_vector(m));
+ }
+ pr = m.mk_hyper_resolve(sz+1, prs.c_ptr(), prop, positions, substs);
+ return pr;
+ }
+
+ void get_model(unsigned level) {
+ scoped_coarse_proof _sp(m);
+ expr_ref level_query = compile_query(b.m_query_pred, level);
+ model_ref md;
+ b.m_solver.get_model(md);
+ IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0););
+ proof_ref pr = get_proof(md, b.m_query_pred, to_app(level_query), level);
+ apply(m, b.m_pc.get(), pr);
+ b.m_answer = pr;
+ }
+
+ func_decl_ref mk_level_predicate(func_decl* p, unsigned level) {
+ std::stringstream _name;
+ _name << p->get_name() << "#" << level;
+ symbol nm(_name.str().c_str());
+ return func_decl_ref(m.mk_func_decl(nm, p->get_arity(), p->get_domain(), m.mk_bool_sort()), m);
+ }
+
+ func_decl_ref mk_level_rule(func_decl* p, unsigned rule_idx, unsigned level) {
+ std::stringstream _name;
+ _name << "rule:" << p->get_name() << "#" << level << "_" << rule_idx;
+ symbol nm(_name.str().c_str());
+ return func_decl_ref(m.mk_func_decl(nm, p->get_arity(), p->get_domain(), m.mk_bool_sort()), m);
+ }
+
+ expr_ref apply_vars(func_decl* p) {
+ expr_ref_vector vars(m);
+ for (unsigned i = 0; i < p->get_arity(); ++i) {
+ vars.push_back(m.mk_var(i, p->get_domain(i)));
+ }
+ return expr_ref(m.mk_app(p, vars.size(), vars.c_ptr()), m);
+ }
+
+ // remove variables from dst that are in src.
+ void subtract_vars(ptr_vector& dst, ptr_vector const& src) {
+ for (unsigned i = 0; i < dst.size(); ++i) {
+ if (i >= src.size()) {
+ break;
+ }
+ if (src[i]) {
+ dst[i] = 0;
+ }
+ }
+ }
+
+ expr_ref_vector mk_skolem_binding(rule& r, ptr_vector const& vars, expr_ref_vector const& args) {
+ expr_ref_vector binding(m);
+ ptr_vector arg_sorts;
+ for (unsigned i = 0; i < args.size(); ++i) {
+ arg_sorts.push_back(m.get_sort(args[i]));
+ }
+ for (unsigned i = 0; i < vars.size(); ++i) {
+ if (vars[i]) {
+ func_decl_ref f = mk_body_func(r, arg_sorts, i, vars[i]);
+ binding.push_back(m.mk_app(f, args.size(), args.c_ptr()));
+ }
+ else {
+ binding.push_back(0);
+ }
+ }
+ return binding;
+ }
+
+ expr_ref skolemize_vars(rule& r, expr_ref_vector const& args, ptr_vector const& vars, expr* e) {
+ expr_ref result(m);
+ expr_ref_vector binding = mk_skolem_binding(r, vars, args);
+ var_subst vs(m, false);
+ vs(e, binding.size(), binding.c_ptr(), result);
+ return result;
+ }
+
+ func_decl_ref mk_body_func(rule& r, ptr_vector const& args, unsigned index, sort* s) {
+ std::stringstream _name;
+ _name << r.get_decl()->get_name() << "@" << index;
+ symbol name(_name.str().c_str());
+ func_decl* f = m.mk_func_decl(name, args.size(), args.c_ptr(), s);
+ return func_decl_ref(f, m);
+ }
+
+ expr_ref bind_vars(expr* e, expr* pat) {
+ ptr_vector vars, sorts;
+ svector names;
+ expr_ref_vector binding(m), patterns(m);
+ expr_ref tmp(m), head(m);
+ get_free_vars(e, vars);
+ for (unsigned i = 0; i < vars.size(); ++i) {
+ if (vars[i]) {
+ binding.push_back(m.mk_var(sorts.size(), vars[i]));
+ sorts.push_back(vars[i]);
+ names.push_back(symbol(i));
+ }
+ else {
+ binding.push_back(0);
+ }
+ }
+ sorts.reverse();
+ if (sorts.empty()) {
+ return expr_ref(e, m);
+ }
+ var_subst vs(m, false);
+ vs(e, binding.size(), binding.c_ptr(), tmp);
+ vs(pat, binding.size(), binding.c_ptr(), head);
+ patterns.push_back(m.mk_pattern(to_app(head)));
+ symbol qid, skid;
+ return expr_ref(m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp, 1, qid, skid, 1, patterns.c_ptr()), m);
+ }
+
+ public:
+ class level_replacer {
+ nonlinear& n;
+ unsigned m_level;
+ bool is_predicate(func_decl* f) {
+ return n.b.m_ctx.is_predicate(f);
+ }
+ public:
+ level_replacer(nonlinear& n, unsigned level): n(n), m_level(level) {}
+
+ br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) {
+ if (is_predicate(f)) {
+ if (m_level > 0) {
+ result = n.m.mk_app(n.mk_level_predicate(f, m_level-1), num_args, args);
+ }
+ else {
+ result = n.m.mk_false();
+ }
+ return BR_DONE;
+ }
+ return BR_FAILED;
+ }
+
+ bool reduce_quantifier(quantifier* old_q, expr* new_body, expr_ref& result) {
+ if (is_ground(new_body)) {
+ result = new_body;
+ }
+ else {
+ expr * const * no_pats = &new_body;
+ result = n.m.update_quantifier(old_q, 0, 0, 1, no_pats, new_body);
+ }
+ return true;
+ }
+ };
+
+ struct level_replacer_cfg : public default_rewriter_cfg {
+ level_replacer m_r;
+
+ level_replacer_cfg(nonlinear& nl, unsigned level):
+ m_r(nl, level) {}
+
+ bool rewrite_patterns() const { return false; }
+ br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
+ return m_r.mk_app_core(f, num, args, result);
+ }
+ bool reduce_quantifier(quantifier * old_q,
+ expr * new_body,
+ expr * const * new_patterns,
+ expr * const * new_no_patterns,
+ expr_ref & result,
+ proof_ref & result_pr) {
+ return m_r.reduce_quantifier(old_q, new_body, result);
+ }
+
+ };
+
+ class level_replacer_star : public rewriter_tpl {
+ level_replacer_cfg m_cfg;
+ public:
+ level_replacer_star(nonlinear& nl, unsigned level):
+ rewriter_tpl(nl.m, false, m_cfg),
+ m_cfg(nl, level)
+ {}
+ };
+
+ private:
+
+ void replace_by_level_predicates(unsigned level, expr_ref& fml) {
+ level_replacer_star rep(*this, level);
+ expr_ref tmp(m);
+ rep(fml, tmp);
+ fml = tmp;
+ }
+
+
+ };
+
+ // --------------------------------------------------------------------------
+ // Basic non-linear BMC based on compiling into data-types (it is inefficient)
+
+ class bmc::nonlinear_dt {
+ bmc& b;
+ ast_manager& m;
+ ast_ref_vector m_pinned;
+ sort_ref m_path_sort;
+ obj_map m_pred2sort;
+ obj_map m_sort2pred;
+
+
+ public:
+ nonlinear_dt(bmc& b): b(b), m(b.m), m_pinned(m), m_path_sort(m) {}
+
+ lbool check() {
+ setup();
+ declare_datatypes();
+ compile();
+ return check_query();
+ }
+
+ private:
+ void setup() {
+ m_pred2sort.reset();
+ m_pinned.reset();
+ m_sort2pred.reset();
+ b.m_fparams.m_relevancy_lvl = 0;
+ b.m_fparams.m_model = true;
+ b.m_fparams.m_model_compact = true;
+ b.m_fparams.m_mbqi = false;
+ b.m_fparams.m_relevancy_lvl = 2;
+ }
+
+ func_decl_ref mk_predicate(func_decl* pred) {
+ std::stringstream _name;
+ _name << pred->get_name() << "#";
+ symbol nm(_name.str().c_str());
+ sort* pred_trace_sort = m_pred2sort.find(pred);
+ return func_decl_ref(m.mk_func_decl(nm, pred_trace_sort, m_path_sort, m.mk_bool_sort()), m);
+ }
+
+ func_decl_ref mk_rule(func_decl* p, unsigned rule_idx) {
+ std::stringstream _name;
+ _name << "rule:" << p->get_name() << "#" << rule_idx;
+ symbol nm(_name.str().c_str());
+ sort* pred_trace_sort = m_pred2sort.find(p);
+ return func_decl_ref(m.mk_func_decl(nm, pred_trace_sort, m_path_sort, m.mk_bool_sort()), m);
+ }
+
+ expr_ref mk_var(func_decl* pred, sort*s, unsigned idx, expr* path_arg, expr* trace_arg) {
+ std::stringstream _name;
+ _name << pred->get_name() << "#V_" << idx;
+ symbol nm(_name.str().c_str());
+ func_decl_ref fn(m);
+ fn = m.mk_func_decl(nm, m_pred2sort.find(pred), m_path_sort, s);
+ return expr_ref(m.mk_app(fn, trace_arg, path_arg), m);
+ }
+
+ expr_ref mk_arg(func_decl* pred, unsigned idx, expr* path_arg, expr* trace_arg) {
+ SASSERT(idx < pred->get_arity());
+ std::stringstream _name;
+ _name << pred->get_name() << "#X_" << idx;
+ symbol nm(_name.str().c_str());
+ func_decl_ref fn(m);
+ fn = m.mk_func_decl(nm, m_pred2sort.find(pred), m_path_sort, pred->get_domain(idx));
+ return expr_ref(m.mk_app(fn, trace_arg, path_arg), m);
+ }
+
+ void mk_subst(datalog::rule& r, expr* path, app* trace, expr_ref_vector& sub) {
+ datatype_util dtu(m);
+ ptr_vector sorts;
+ func_decl* p = r.get_decl();
+ ptr_vector const& succs = *dtu.get_datatype_constructors(m.get_sort(path));
+ // populate substitution of bound variables.
+ r.get_vars(sorts);
+ sub.reset();
+ sub.resize(sorts.size());
+ for (unsigned k = 0; k < r.get_decl()->get_arity(); ++k) {
+ expr* arg = r.get_head()->get_arg(k);
+ if (is_var(arg)) {
+ unsigned idx = to_var(arg)->get_idx();
+ if (!sub[idx].get()) {
+ sub[idx] = mk_arg(p, k, path, trace);
+ }
+ }
+ }
+ for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
+ func_decl* q = r.get_decl(j);
+ expr_ref path_arg(m);
+ if (j == 0) {
+ path_arg = path;
+ }
+ else {
+ path_arg = m.mk_app(succs[j], path);
+ }
+ for (unsigned k = 0; k < q->get_arity(); ++k) {
+ expr* arg = r.get_tail(j)->get_arg(k);
+ if (is_var(arg)) {
+ unsigned idx = to_var(arg)->get_idx();
+ if (!sub[idx].get()) {
+ sub[idx] = mk_arg(q, k, path_arg, trace->get_arg(j));
+ }
+ }
+ }
+ }
+ for (unsigned j = 0, idx = 0; j < sorts.size(); ++j) {
+ if (sorts[j] && !sub[j].get()) {
+ sub[j] = mk_var(r.get_decl(), sorts[j], idx++, path, trace);
+ }
+ }
+ }
+
+ /**
+ \brief compile Horn rule into co-Horn implication.
+ forall args . R(path_var, rule_i(trace_vars)) => Body[X(path_var, rule_i(trace_vars)), Y(S_j(path_var), trace_vars_j)]
+ */
+ void compile() {
+ datatype_util dtu(m);
+
+ rule_set::decl2rules::iterator it = b.m_rules.begin_grouped_rules();
+ rule_set::decl2rules::iterator end = b.m_rules.end_grouped_rules();
+ for (; it != end; ++it) {
+ func_decl* p = it->m_key;
+ rule_vector const& rls = *it->m_value;
+
+ // Assert: p_level => r1_level \/ r2_level \/ r3_level \/ ...
+ // where: r_i_level = body of rule i for level + equalities for head of rule i
+
+ expr_ref rule_body(m), tmp(m), pred(m), trace_arg(m), fml(m);
+ var_ref path_var(m), trace_var(m);
+ expr_ref_vector rules(m), sub(m), conjs(m), vars(m), patterns(m);
+ sort* pred_sort = m_pred2sort.find(p);
+ path_var = m.mk_var(0, m_path_sort);
+ trace_var = m.mk_var(1, pred_sort);
+ // sort* sorts[2] = { pred_sort, m_path_sort };
+ ptr_vector const& cnstrs = *dtu.get_datatype_constructors(pred_sort);
+ ptr_vector const& succs = *dtu.get_datatype_constructors(m_path_sort);
+ SASSERT(cnstrs.size() == rls.size());
+ pred = m.mk_app(mk_predicate(p), trace_var.get(), path_var.get());
+ for (unsigned i = 0; i < rls.size(); ++i) {
+ sub.reset();
+ conjs.reset();
+ vars.reset();
+ rule& r = *rls[i];
+ func_decl_ref rule_pred_i = mk_rule(p, i);
+
+ // Create cnstr_rule_i(Vars)
+ func_decl* cnstr = cnstrs[i];
+ rules.push_back(m.mk_app(rule_pred_i, trace_var.get(), path_var.get()));
+ unsigned arity = cnstr->get_arity();
+ for (unsigned j = 0; j < arity; ++j) {
+ vars.push_back(m.mk_var(arity-j,cnstr->get_domain(j)));
+ }
+ trace_arg = m.mk_app(cnstr, vars.size(), vars.c_ptr());
+
+ mk_subst(r, path_var, to_app(trace_arg), sub);
+
+ // apply substitution to body.
+ var_subst vs(m, false);
+ for (unsigned k = 0; k < p->get_arity(); ++k) {
+ vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), tmp);
+ expr_ref arg = mk_arg(p, k, path_var, trace_arg);
+ conjs.push_back(m.mk_eq(tmp, arg));
+ }
+ for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
+ expr_ref path_arg(m);
+ if (j == 0) {
+ path_arg = path_var.get();
+ }
+ else {
+ path_arg = m.mk_app(succs[j], path_var.get());
+ }
+ func_decl* q = r.get_decl(j);
+ for (unsigned k = 0; k < q->get_arity(); ++k) {
+ vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), tmp);
+ expr_ref arg = mk_arg(q, k, path_arg, vars[j].get());
+ conjs.push_back(m.mk_eq(tmp, arg));
+ }
+ func_decl_ref q_pred = mk_predicate(q);
+ conjs.push_back(m.mk_app(q_pred, vars[j].get(), path_arg));
+ }
+ for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
+ vs(r.get_tail(j), sub.size(), sub.c_ptr(), tmp);
+ conjs.push_back(tmp);
+ }
+ bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), rule_body);
+ ptr_vector q_sorts;
+ vector names;
+ for (unsigned i = 0; i < vars.size(); ++i) {
+ q_sorts.push_back(m.get_sort(vars[i].get()));
+ names.push_back(symbol(i+1));
+ }
+ vars.push_back(path_var);
+ q_sorts.push_back(m.get_sort(path_var));
+ names.push_back(symbol("path"));
+ SASSERT(names.size() == q_sorts.size());
+ SASSERT(vars.size() == names.size());
+ symbol qid = r.name(), skid;
+ tmp = m.mk_app(mk_predicate(p), trace_arg.get(), path_var.get());
+ patterns.reset();
+ patterns.push_back(m.mk_pattern(to_app(tmp)));
+ fml = m.mk_implies(tmp, rule_body);
+ fml = m.mk_forall(vars.size(), q_sorts.c_ptr(), names.c_ptr(), fml, 1, qid, skid, 1, patterns.c_ptr());
+ b.assert_expr(fml);
+ }
+ }
+ }
+
+ void declare_datatypes() {
+ rule_set::decl2rules::iterator it = b.m_rules.begin_grouped_rules();
+ rule_set::decl2rules::iterator end = b.m_rules.end_grouped_rules();
+ datatype_util dtu(m);
+ ptr_vector dts;
+
+ obj_map pred_idx;
+ for (unsigned i = 0; it != end; ++it, ++i) {
+ pred_idx.insert(it->m_key, i);
+ }
+
+ it = b.m_rules.begin_grouped_rules();
+ for (; it != end; ++it) {
+ rule_vector const& rls = *it->m_value;
+ func_decl* pred = it->m_key;
+ ptr_vector cnstrs;
+ for (unsigned i = 0; i < rls.size(); ++i) {
+ rule* r = rls[i];
+ ptr_vector accs;
+ for (unsigned j = 0; j < r->get_uninterpreted_tail_size(); ++j) {
+ func_decl* q = r->get_decl(j);
+ unsigned idx = pred_idx.find(q);
+ std::stringstream _name;
+ _name << pred->get_name() << "_" << q->get_name() << j;
+ symbol name(_name.str().c_str());
+ type_ref tr(idx);
+ accs.push_back(mk_accessor_decl(name, tr));
+ }
+ std::stringstream _name;
+ _name << pred->get_name() << "_" << i;
+ symbol name(_name.str().c_str());
+ _name << "?";
+ symbol is_name(_name.str().c_str());
+ cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr()));
+ }
+ dts.push_back(mk_datatype_decl(pred->get_name(), cnstrs.size(), cnstrs.c_ptr()));
+ }
+
+
+ sort_ref_vector new_sorts(m);
+ family_id dfid = m.get_family_id("datatype");
+ datatype_decl_plugin* dtp = static_cast(m.get_plugin(dfid));
+ VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), new_sorts));
+
+ it = b.m_rules.begin_grouped_rules();
+ for (unsigned i = 0; it != end; ++it, ++i) {
+ m_pred2sort.insert(it->m_key, new_sorts[i].get());
+ m_sort2pred.insert(new_sorts[i].get(), it->m_key);
+ m_pinned.push_back(new_sorts[i].get());
+ }
+ if (new_sorts.size() > 0) {
+ TRACE("bmc", dtu.display_datatype(new_sorts[0].get(), tout););
+ }
+ del_datatype_decls(dts.size(), dts.c_ptr());
+
+ // declare path data-type.
+ {
+ new_sorts.reset();
+ dts.reset();
+ ptr_vector cnstrs;
+ unsigned max_arity = 0;
+ rule_set::iterator it = b.m_rules.begin();
+ rule_set::iterator end = b.m_rules.end();
+ for (; it != end; ++it) {
+ rule* r = *it;
+ unsigned sz = r->get_uninterpreted_tail_size();
+ max_arity = std::max(sz, max_arity);
+ }
+ cnstrs.push_back(mk_constructor_decl(symbol("Z#"), symbol("Z#?"), 0, 0));
+
+ for (unsigned i = 0; i + 1 < max_arity; ++i) {
+ std::stringstream _name;
+ _name << "succ#" << i;
+ symbol name(_name.str().c_str());
+ _name << "?";
+ symbol is_name(_name.str().c_str());
+ std::stringstream _name2;
+ _name2 << "get_succ#" << i;
+ symbol acc_name(_name2.str().c_str());
+ ptr_vector accs;
+ type_ref tr(0);
+ accs.push_back(mk_accessor_decl(name, tr));
+ cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr()));
+ }
+ dts.push_back(mk_datatype_decl(symbol("Path"), cnstrs.size(), cnstrs.c_ptr()));
+ VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), new_sorts));
+ m_path_sort = new_sorts[0].get();
+ }
+ }
+
+ proof_ref get_proof(model_ref& md, app* trace, app* path) {
+ datatype_util dtu(m);
+ sort* trace_sort = m.get_sort(trace);
+ func_decl* p = m_sort2pred.find(trace_sort);
+ datalog::rule_vector const& rules = b.m_rules.get_predicate_rules(p);
+ ptr_vector const& cnstrs = *dtu.get_datatype_constructors(trace_sort);
+ ptr_vector const& succs = *dtu.get_datatype_constructors(m_path_sort);
+ for (unsigned i = 0; i < cnstrs.size(); ++i) {
+ if (trace->get_decl() == cnstrs[i]) {
+ svector > positions;
+ scoped_coarse_proof _sc(m);
+ proof_ref_vector prs(m);
+ expr_ref_vector sub(m);
+ vector substs;
+ proof_ref pr(m);
+ expr_ref fml(m), head(m), tmp(m);
+ app_ref path1(m);
+
+ var_subst vs(m, false);
+ mk_subst(*rules[i], path, trace, sub);
+ rules[i]->to_formula(fml);
+ prs.push_back(m.mk_asserted(fml));
+ unsigned sz = trace->get_num_args();
+ if (sub.empty() && sz == 0) {
+ pr = prs[0].get();
+ return pr;
+ }
+ for (unsigned j = 0; j < sub.size(); ++j) {
+ md->eval(sub[j].get(), tmp);
+ sub[j] = tmp;
+ }
+ rule_ref rl(b.m_ctx.get_rule_manager());
+ rl = rules[i];
+ b.m_ctx.get_rule_manager().substitute(rl, sub.size(), sub.c_ptr());
+
+ substs.push_back(sub);
+
+ for (unsigned j = 0; j < sz; ++j) {
+ if (j == 0) {
+ path1 = path;
+ }
+ else {
+ path1 = m.mk_app(succs[j], path);
+ }
+
+ prs.push_back(get_proof(md, to_app(trace->get_arg(j)), path1));
+ positions.push_back(std::make_pair(j+1,0));
+ substs.push_back(expr_ref_vector(m));
+ }
+ head = rl->get_head();
+ pr = m.mk_hyper_resolve(sz+1, prs.c_ptr(), head, positions, substs);
+ return pr;
+ }
+ }
+ UNREACHABLE();
+ return proof_ref(0, m);
+ }
+
+ // instantiation of algebraic data-types takes care of the rest.
+ lbool check_query() {
+ sort* trace_sort = m_pred2sort.find(b.m_query_pred);
+ func_decl_ref q = mk_predicate(b.m_query_pred);
+ expr_ref trace(m), path(m), fml(m);
+ trace = m.mk_const(symbol("trace"), trace_sort);
+ path = m.mk_const(symbol("path"), m_path_sort);
+ fml = m.mk_app(q, trace.get(), path.get());
+ b.assert_expr(fml);
+ while (true) {
+ lbool is_sat = b.m_solver.check();
+ model_ref md;
+ if (is_sat == l_false) {
+ return is_sat;
+ }
+ b.m_solver.get_model(md);
+ mk_answer(md, trace, path);
+ return l_true;
+ }
+ }
+
+ bool check_model(model_ref& md, expr* trace) {
+ expr_ref trace_val(m), eq(m);
+ md->eval(trace, trace_val);
+ eq = m.mk_eq(trace, trace_val);
+ b.m_solver.push();
+ b.m_solver.assert_expr(eq);
+ lbool is_sat = b.m_solver.check();
+ if (is_sat != l_false) {
+ b.m_solver.get_model(md);
+ }
+ b.m_solver.pop(1);
+ if (is_sat == l_false) {
+ IF_VERBOSE(1, verbose_stream() << "infeasible trace " << mk_pp(trace_val, m) << "\n";);
+ eq = m.mk_not(eq);
+ b.assert_expr(eq);
+ }
+ return is_sat != l_false;
+ }
+
+ void mk_answer(model_ref& md, expr_ref& trace, expr_ref& path) {
+ proof_ref pr(m);
+ IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0););
+ md->eval(trace, trace);
+ md->eval(path, path);
+ IF_VERBOSE(2, verbose_stream() << mk_pp(trace, m) << "\n";
+ for (unsigned i = 0; i < b.m_solver.size(); ++i) {
+ verbose_stream() << mk_pp(b.m_solver.get_formulas()[i], m) << "\n";
+ });
+ b.m_answer = get_proof(md, to_app(trace), to_app(path));
+ }
+
+ };
+
+ // --------------------------------------------------------------------------
+ // Basic linear BMC based on incrementally unfolding the transition relation.
+
+ class bmc::linear {
+ bmc& b;
+ ast_manager& m;
+
+ public:
+ linear(bmc& b): b(b), m(b.m) {}
+
+ lbool check() {
+ setup();
+ for (unsigned i = 0; ; ++i) {
+ IF_VERBOSE(1, verbose_stream() << "level: " << i << "\n";);
+ b.checkpoint();
+ compile(i);
+ lbool res = check(i);
+ if (res == l_undef) {
+ return res;
+ }
+ if (res == l_true) {
+ get_model(i);
+ return res;
+ }
+ }
+ }
+
+ private:
+
+ void get_model(unsigned level) {
+ rule_manager& rm = b.m_ctx.get_rule_manager();
+ expr_ref level_query = mk_level_predicate(b.m_query_pred, level);
+ model_ref md;
+ proof_ref pr(m);
+ rule_unifier unifier(b.m_ctx);
+ b.m_solver.get_model(md);
+ func_decl* pred = b.m_query_pred;
+ SASSERT(m.is_true(md->get_const_interp(to_app(level_query)->get_decl())));
+
+ TRACE("bmc", model_smt2_pp(tout, m, *md, 0););
+
+ rule_ref r0(rm), r1(rm), r2(rm);
+ while (true) {
+ TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";);
+ expr_ref_vector sub(m);
+ rule_vector const& rls = b.m_rules.get_predicate_rules(pred);
+ rule* r = 0;
+ unsigned i = 0;
+ for (; i < rls.size(); ++i) {
+ expr_ref rule_i = mk_level_rule(pred, i, level);
+ TRACE("bmc", rls[i]->display(b.m_ctx, tout << "Checking rule " << mk_pp(rule_i, m) << " "););
+ if (m.is_true(md->get_const_interp(to_app(rule_i)->get_decl()))) {
+ r = rls[i];
+ break;
+ }
+ }
+ SASSERT(r);
+ mk_rule_vars(*r, level, i, sub);
+ // we have rule, we have variable names of rule.
+
+ // extract values for the variables in the rule.
+ for (unsigned j = 0; j < sub.size(); ++j) {
+ expr* vl = md->get_const_interp(to_app(sub[j].get())->get_decl());
+ if (vl) {
+ // vl can be 0 if the interpretation does not assign a value to it.
+ sub[j] = vl;
+ }
+ else {
+ sub[j] = m.mk_var(j, m.get_sort(sub[j].get()));
+ }
+ }
+ svector > positions;
+ vector substs;
+ expr_ref fml(m), concl(m);
+
+ r->to_formula(fml);
+ r2 = r;
+ rm.substitute(r2, sub.size(), sub.c_ptr());
+ if (r0) {
+ VERIFY(unifier.unify_rules(*r0.get(), 0, *r2.get()));
+ expr_ref_vector sub1 = unifier.get_rule_subst(*r0.get(), true);
+ expr_ref_vector sub2 = unifier.get_rule_subst(*r2.get(), false);
+ apply_subst(sub, sub2);
+ unifier.apply(*r0.get(), 0, *r2.get(), r1);
+ r1->to_formula(concl);
+ scoped_coarse_proof _sp(m);
+
+ proof* p = m.mk_asserted(fml);
+ proof* premises[2] = { pr, p };
+
+ positions.push_back(std::make_pair(0, 1));
+
+ substs.push_back(sub1);
+ substs.push_back(sub);
+ pr = m.mk_hyper_resolve(2, premises, concl, positions, substs);
+ r0 = r1;
+ }
+ else {
+ r2->to_formula(concl);
+ scoped_coarse_proof _sp(m);
+ proof* p = m.mk_asserted(fml);
+ if (sub.empty()) {
+ pr = p;
+ }
+ else {
+ substs.push_back(sub);
+ pr = m.mk_hyper_resolve(1, &p, concl, positions, substs);
+ }
+ r0 = r2;
+ }
+
+ if (level == 0) {
+ SASSERT(r->get_uninterpreted_tail_size() == 0);
+ break;
+ }
+ --level;
+ SASSERT(r->get_uninterpreted_tail_size() == 1);
+ pred = r->get_decl(0);
+ }
+ scoped_coarse_proof _sp(m);
+ apply(m, b.m_pc.get(), pr);
+ b.m_answer = pr;
+ }
+
+
+ void setup() {
+ b.m_fparams.m_relevancy_lvl = 0;
+ b.m_fparams.m_model = true;
+ b.m_fparams.m_model_compact = true;
+ b.m_fparams.m_mbqi = false;
+ // m_fparams.m_auto_config = false;
+ }
+
+
+ lbool check(unsigned level) {
+ expr_ref level_query = mk_level_predicate(b.m_query_pred, level);
+ expr* q = level_query.get();
+ return b.m_solver.check(1, &q);
+ }
+
+ expr_ref mk_level_predicate(func_decl* p, unsigned level) {
+ return mk_level_predicate(p->get_name(), level);
+ }
+
+ expr_ref mk_level_predicate(symbol const& name, unsigned level) {
+ std::stringstream _name;
+ _name << name << "#" << level;
+ symbol nm(_name.str().c_str());
+ return expr_ref(m.mk_const(nm, m.mk_bool_sort()), m);
+ }
+
+ expr_ref mk_level_arg(func_decl* pred, unsigned idx, unsigned level) {
+ SASSERT(idx < pred->get_arity());
+ std::stringstream _name;
+ _name << pred->get_name() << "#" << level << "_" << idx;
+ symbol nm(_name.str().c_str());
+ return expr_ref(m.mk_const(nm, pred->get_domain(idx)), m);
+ }
+
+ expr_ref mk_level_var(func_decl* pred, sort* s, unsigned rule_id, unsigned idx, unsigned level) {
+ std::stringstream _name;
+ _name << pred->get_name() << "#" << level << "_" << rule_id << "_" << idx;
+ symbol nm(_name.str().c_str());
+ return expr_ref(m.mk_const(nm, s), m);
+ }
+
+ expr_ref mk_level_rule(func_decl* p, unsigned rule_idx, unsigned level) {
+ std::stringstream _name;
+ _name << "rule:" << p->get_name() << "#" << level << "_" << rule_idx;
+ symbol nm(_name.str().c_str());
+ return expr_ref(m.mk_const(nm, m.mk_bool_sort()), m);
+ }
+
+ void mk_rule_vars(rule& r, unsigned level, unsigned rule_id, expr_ref_vector& sub) {
+ ptr_vector sorts;
+ r.get_vars(sorts);
+ // populate substitution of bound variables.
+ sub.reset();
+ sub.resize(sorts.size());
+
+ for (unsigned k = 0; k < r.get_decl()->get_arity(); ++k) {
+ expr* arg = r.get_head()->get_arg(k);
+ if (is_var(arg)) {
+ unsigned idx = to_var(arg)->get_idx();
+ if (!sub[idx].get()) {
+ sub[idx] = mk_level_arg(r.get_decl(), k, level);
+ }
+ }
+ }
+ for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
+ SASSERT(level > 0);
+ func_decl* q = r.get_decl(j);
+ for (unsigned k = 0; k < q->get_arity(); ++k) {
+ expr* arg = r.get_tail(j)->get_arg(k);
+ if (is_var(arg)) {
+ unsigned idx = to_var(arg)->get_idx();
+ if (!sub[idx].get()) {
+ sub[idx] = mk_level_arg(q, k, level-1);
+ }
+ }
+ }
+ }
+ for (unsigned j = 0, idx = 0; j < sorts.size(); ++j) {
+ if (sorts[j] && !sub[j].get()) {
+ sub[j] = mk_level_var(r.get_decl(), sorts[j], rule_id, idx++, level);
+ }
+ }
+ }
+
+ void compile(unsigned level) {
+ rule_set::decl2rules::iterator it = b.m_rules.begin_grouped_rules();
+ rule_set::decl2rules::iterator end = b.m_rules.end_grouped_rules();
+ for (; it != end; ++it) {
+ func_decl* p = it->m_key;
+ rule_vector const& rls = *it->m_value;
+
+ // Assert: p_level => r1_level \/ r2_level \/ r3_level \/ ...
+ // Assert: r_i_level => body of rule i for level + equalities for head of rule i
+
+ expr_ref level_pred = mk_level_predicate(p, level);
+ expr_ref_vector rules(m), sub(m), conjs(m);
+ expr_ref rule_body(m), tmp(m);
+ for (unsigned i = 0; i < rls.size(); ++i) {
+ sub.reset();
+ conjs.reset();
+ rule& r = *rls[i];
+ expr_ref rule_i = mk_level_rule(p, i, level);
+ rules.push_back(rule_i);
+ if (level == 0 && r.get_uninterpreted_tail_size() > 0) {
+ tmp = m.mk_not(rule_i);
+ b.assert_expr(tmp);
+ continue;
+ }
+
+ mk_rule_vars(r, level, i, sub);
+
+ // apply substitution to body.
+ var_subst vs(m, false);
+ for (unsigned k = 0; k < p->get_arity(); ++k) {
+ vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), tmp);
+ conjs.push_back(m.mk_eq(tmp, mk_level_arg(p, k, level)));
+ }
+ for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
+ SASSERT(level > 0);
+ func_decl* q = r.get_decl(j);
+ for (unsigned k = 0; k < q->get_arity(); ++k) {
+ vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), tmp);
+ conjs.push_back(m.mk_eq(tmp, mk_level_arg(q, k, level-1)));
+ }
+ conjs.push_back(mk_level_predicate(q, level-1));
+ }
+ for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
+ vs(r.get_tail(j), sub.size(), sub.c_ptr(), tmp);
+ conjs.push_back(tmp);
+ }
+ bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), rule_body);
+ rule_body = m.mk_implies(rule_i, rule_body);
+ b.assert_expr(rule_body);
+ }
+ bool_rewriter(m).mk_or(rules.size(), rules.c_ptr(), tmp);
+ tmp = m.mk_implies(level_pred, tmp);
+ b.assert_expr(tmp);
+ }
+ }
+ };
+
bmc::bmc(context& ctx):
m_ctx(ctx),
m(ctx.get_manager()),
m_solver(m, m_fparams),
- m_pinned(m),
m_rules(ctx),
m_query_pred(m),
m_answer(m),
- m_cancel(false),
- m_path_sort(m),
- m_bv(m) {
- }
+ m_cancel(false) {
+ }
bmc::~bmc() {}
lbool bmc::query(expr* query) {
m_solver.reset();
- m_pinned.reset();
- m_pred2sort.reset();
- m_sort2pred.reset();
- m_pred2newpred.reset();
- m_pred2args.reset();
m_answer = 0;
m_ctx.ensure_opened();
@@ -93,984 +1445,39 @@ namespace datalog {
if (is_linear()) {
if (m_ctx.get_engine() == QBMC_ENGINE) {
- return check_qlinear();
+ qlinear ql(*this);
+ return ql.check();
+ }
+ else {
+ linear lin(*this);
+ return lin.check();
}
- return check_linear();
}
else {
IF_VERBOSE(0, verbose_stream() << "WARNING: non-linear BMC is highly inefficient\n";);
- return check_nonlinear();
+ nonlinear nl(*this);
+ return nl.check();
}
}
+ void bmc::assert_expr(expr* e) {
+ TRACE("bmc", tout << mk_pp(e, m) << "\n";);
+ m_solver.assert_expr(e);
+ }
+
bool bmc::is_linear() const {
unsigned sz = m_rules.get_num_rules();
for (unsigned i = 0; i < sz; ++i) {
if (m_rules.get_rule(i)->get_uninterpreted_tail_size() > 1) {
return false;
}
+ if (m_rules.get_rule(i)->has_quantifiers()) {
+ return false;
+ }
}
return true;
}
- // --------------------------------------------------------------------------
- // Basic linear BMC based on incrementally unfolding the transition relation.
-
- void bmc::get_model_linear(unsigned level) {
- rule_manager& rm = m_ctx.get_rule_manager();
- expr_ref level_query = mk_level_predicate(m_query_pred, level);
- model_ref md;
- proof_ref pr(m);
- rule_unifier unifier(m_ctx);
- m_solver.get_model(md);
- func_decl* pred = m_query_pred;
- SASSERT(m.is_true(md->get_const_interp(to_app(level_query)->get_decl())));
- dl_decl_util util(m);
-
- TRACE("bmc", model_smt2_pp(tout, m, *md, 0););
-
- rule_ref r0(rm), r1(rm), r2(rm);
- while (true) {
- TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";);
- expr_ref_vector sub(m);
- rule_vector const& rls = m_rules.get_predicate_rules(pred);
- rule* r = 0;
- unsigned i = 0;
- for (; i < rls.size(); ++i) {
- expr_ref rule_i = mk_level_rule(pred, i, level);
- TRACE("bmc", rls[i]->display(m_ctx, tout << "Checking rule " << mk_pp(rule_i, m) << " "););
- if (m.is_true(md->get_const_interp(to_app(rule_i)->get_decl()))) {
- r = rls[i];
- break;
- }
- }
- SASSERT(r);
- mk_rule_vars(*r, level, i, sub);
- // we have rule, we have variable names of rule.
-
- // extract values for the variables in the rule.
- for (unsigned j = 0; j < sub.size(); ++j) {
- expr* vl = md->get_const_interp(to_app(sub[j].get())->get_decl());
- if (vl) {
- // vl can be 0 if the interpretation does not assign a value to it.
- sub[j] = vl;
- }
- else {
- sub[j] = m.mk_var(j, m.get_sort(sub[j].get()));
- }
- }
- svector > positions;
- vector substs;
- expr_ref fml(m), concl(m);
-
- r->to_formula(fml);
- r2 = r;
- rm.substitute(r2, sub.size(), sub.c_ptr());
- if (r0) {
- VERIFY(unifier.unify_rules(*r0.get(), 0, *r2.get()));
- expr_ref_vector sub1 = unifier.get_rule_subst(*r0.get(), true);
- expr_ref_vector sub2 = unifier.get_rule_subst(*r2.get(), false);
- apply_subst(sub, sub2);
- unifier.apply(*r0.get(), 0, *r2.get(), r1);
- r1->to_formula(concl);
- scoped_coarse_proof _sp(m);
-
- proof* p = m.mk_asserted(fml);
- proof* premises[2] = { pr, p };
-
- positions.push_back(std::make_pair(0, 1));
-
- substs.push_back(sub1);
- substs.push_back(sub);
- pr = m.mk_hyper_resolve(2, premises, concl, positions, substs);
- r0 = r1;
- }
- else {
- r2->to_formula(concl);
- scoped_coarse_proof _sp(m);
- proof* p = m.mk_asserted(fml);
- if (sub.empty()) {
- pr = p;
- }
- else {
- substs.push_back(sub);
- pr = m.mk_hyper_resolve(1, &p, concl, positions, substs);
- }
- r0 = r2;
- }
-
- if (level == 0) {
- SASSERT(r->get_uninterpreted_tail_size() == 0);
- break;
- }
- --level;
- SASSERT(r->get_uninterpreted_tail_size() == 1);
- pred = r->get_decl(0);
- }
- scoped_coarse_proof _sp(m);
- apply(m, m_pc.get(), pr);
- m_answer = pr;
- }
-
-
- void bmc::setup_linear() {
- m_fparams.m_relevancy_lvl = 0;
- m_fparams.m_model = true;
- m_fparams.m_model_compact = true;
- m_fparams.m_mbqi = false;
- // m_fparams.m_auto_config = false;
- }
-
- lbool bmc::check_linear() {
- setup_linear();
- for (unsigned i = 0; ; ++i) {
- IF_VERBOSE(1, verbose_stream() << "level: " << i << "\n";);
- checkpoint();
- compile_linear(i);
- lbool res = check_linear(i);
- if (res == l_undef) {
- return res;
- }
- if (res == l_true) {
- get_model_linear(i);
- return res;
- }
- }
- }
-
- lbool bmc::check_linear(unsigned level) {
- expr_ref level_query = mk_level_predicate(m_query_pred, level);
- expr* q = level_query.get();
- return m_solver.check(1, &q);
- }
-
- void bmc::assert_expr(expr* e) {
- TRACE("bmc", tout << mk_pp(e, m) << "\n";);
- m_solver.assert_expr(e);
- }
-
- expr_ref bmc::mk_level_predicate(func_decl* p, unsigned level) {
- return mk_level_predicate(p->get_name(), level);
- }
-
- expr_ref bmc::mk_level_predicate(symbol const& name, unsigned level) {
- std::stringstream _name;
- _name << name << "#" << level;
- symbol nm(_name.str().c_str());
- return expr_ref(m.mk_const(nm, m.mk_bool_sort()), m);
- }
-
- expr_ref bmc::mk_level_arg(func_decl* pred, unsigned idx, unsigned level) {
- SASSERT(idx < pred->get_arity());
- std::stringstream _name;
- _name << pred->get_name() << "#" << level << "_" << idx;
- symbol nm(_name.str().c_str());
- return expr_ref(m.mk_const(nm, pred->get_domain(idx)), m);
- }
-
- expr_ref bmc::mk_level_var(func_decl* pred, sort* s, unsigned rule_id, unsigned idx, unsigned level) {
- std::stringstream _name;
- _name << pred->get_name() << "#" << level << "_" << rule_id << "_" << idx;
- symbol nm(_name.str().c_str());
- return expr_ref(m.mk_const(nm, s), m);
- }
-
- expr_ref bmc::mk_level_rule(func_decl* p, unsigned rule_idx, unsigned level) {
- std::stringstream _name;
- _name << "rule:" << p->get_name() << "#" << level << "_" << rule_idx;
- symbol nm(_name.str().c_str());
- return expr_ref(m.mk_const(nm, m.mk_bool_sort()), m);
- }
-
- void bmc::mk_rule_vars(rule& r, unsigned level, unsigned rule_id, expr_ref_vector& sub) {
- sort_ref_vector sorts(m);
- r.get_vars(sorts);
- // populate substitution of bound variables.
- sub.reset();
- sub.resize(sorts.size());
-
- for (unsigned k = 0; k < r.get_decl()->get_arity(); ++k) {
- expr* arg = r.get_head()->get_arg(k);
- if (is_var(arg)) {
- unsigned idx = to_var(arg)->get_idx();
- if (!sub[idx].get()) {
- sub[idx] = mk_level_arg(r.get_decl(), k, level);
- }
- }
- }
- for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
- SASSERT(level > 0);
- func_decl* q = r.get_decl(j);
- for (unsigned k = 0; k < q->get_arity(); ++k) {
- expr* arg = r.get_tail(j)->get_arg(k);
- if (is_var(arg)) {
- unsigned idx = to_var(arg)->get_idx();
- if (!sub[idx].get()) {
- sub[idx] = mk_level_arg(q, k, level-1);
- }
- }
- }
- }
- for (unsigned j = 0, idx = 0; j < sorts.size(); ++j) {
- if (sorts[j].get() && !sub[j].get()) {
- sub[j] = mk_level_var(r.get_decl(), sorts[j].get(), rule_id, idx++, level);
- }
- }
- }
-
- void bmc::compile_linear(unsigned level) {
- rule_set::decl2rules::iterator it = m_rules.begin_grouped_rules();
- rule_set::decl2rules::iterator end = m_rules.end_grouped_rules();
- for (; it != end; ++it) {
- func_decl* p = it->m_key;
- rule_vector const& rls = *it->m_value;
-
- // Assert: p_level => r1_level \/ r2_level \/ r3_level \/ ...
- // Assert: r_i_level => body of rule i for level + equalities for head of rule i
-
- expr_ref level_pred = mk_level_predicate(p, level);
- expr_ref_vector rules(m), sub(m), conjs(m);
- expr_ref rule_body(m), tmp(m);
- for (unsigned i = 0; i < rls.size(); ++i) {
- sub.reset();
- conjs.reset();
- rule& r = *rls[i];
- expr_ref rule_i = mk_level_rule(p, i, level);
- rules.push_back(rule_i);
- if (level == 0 && r.get_uninterpreted_tail_size() > 0) {
- tmp = m.mk_not(rule_i);
- assert_expr(tmp);
- continue;
- }
-
- mk_rule_vars(r, level, i, sub);
-
- // apply substitution to body.
- var_subst vs(m, false);
- for (unsigned k = 0; k < p->get_arity(); ++k) {
- vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), tmp);
- conjs.push_back(m.mk_eq(tmp, mk_level_arg(p, k, level)));
- }
- for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
- SASSERT(level > 0);
- func_decl* q = r.get_decl(j);
- for (unsigned k = 0; k < q->get_arity(); ++k) {
- vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), tmp);
- conjs.push_back(m.mk_eq(tmp, mk_level_arg(q, k, level-1)));
- }
- conjs.push_back(mk_level_predicate(q, level-1));
- }
- for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
- vs(r.get_tail(j), sub.size(), sub.c_ptr(), tmp);
- conjs.push_back(tmp);
- }
- bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), rule_body);
- rule_body = m.mk_implies(rule_i, rule_body);
- assert_expr(rule_body);
- }
- bool_rewriter(m).mk_or(rules.size(), rules.c_ptr(), tmp);
- tmp = m.mk_implies(level_pred, tmp);
- assert_expr(tmp);
- }
- }
-
- // ---------------------------------------------------------------------------
- // Basic linear BMC based on indexed variables using quantified bit-vector domains.
-
- lbool bmc::check_qlinear() {
- setup_qlinear();
- m_bit_width = 4;
- lbool res = l_false;
- while (res == l_false) {
- m_solver.push();
- IF_VERBOSE(1, verbose_stream() << "bit_width: " << m_bit_width << "\n";);
- compile_qlinear();
- checkpoint();
- func_decl_ref q = mk_q_func_decl(m_query_pred);
- expr* T = m.mk_const(symbol("T"), mk_index_sort());
- expr_ref fml(m.mk_app(q, T), m);
- assert_expr(fml);
- res = m_solver.check();
-
- if (res == l_true) {
- res = get_model_qlinear();
- }
- m_solver.pop(1);
- ++m_bit_width;
- }
- return res;
- }
-
- sort_ref bmc::mk_index_sort() {
- return sort_ref(m_bv.mk_sort(m_bit_width), m);
- }
-
- var_ref bmc::mk_index_var() {
- return var_ref(m.mk_var(0, mk_index_sort()), m);
- }
-
- void bmc::compile_qlinear() {
- sort_ref index_sort = mk_index_sort();
- var_ref var = mk_index_var();
- sort* index_sorts[1] = { index_sort };
- symbol tick("T");
- rule_set::decl2rules::iterator it = m_rules.begin_grouped_rules();
- rule_set::decl2rules::iterator end = m_rules.end_grouped_rules();
- for (; it != end; ++it) {
- func_decl* p = it->m_key;
- rule_vector const& rls = *it->m_value;
- // Assert: forall level . p(T) => body of rule i + equalities for head of rule i
- func_decl_ref pr = mk_q_func_decl(p);
- expr_ref pred = expr_ref(m.mk_app(pr, var.get()), m);
- expr_ref_vector rules(m), sub(m), conjs(m);
- expr_ref trm(m), rule_body(m), rule_i(m);
- for (unsigned i = 0; i < rls.size(); ++i) {
- sub.reset();
- conjs.reset();
- rule& r = *rls[i];
- rule_i = m.mk_app(mk_q_rule(p, i), var.get());
- rules.push_back(rule_i);
-
- mk_qrule_vars(r, i, sub);
-
- // apply substitution to body.
- var_subst vs(m, false);
- for (unsigned k = 0; k < p->get_arity(); ++k) {
- vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), trm);
- conjs.push_back(m.mk_eq(trm, mk_q_arg(p, k, true)));
- }
- for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
- func_decl* q = r.get_decl(j);
- for (unsigned k = 0; k < q->get_arity(); ++k) {
- vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), trm);
- conjs.push_back(m.mk_eq(trm, mk_q_arg(q, k, false)));
- }
- func_decl_ref qr = mk_q_func_decl(q);
- conjs.push_back(m.mk_app(qr, m_bv.mk_bv_sub(var, mk_q_one())));
- }
- for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
- vs(r.get_tail(j), sub.size(), sub.c_ptr(), trm);
- conjs.push_back(trm);
- }
- if (r.get_uninterpreted_tail_size() > 0) {
- conjs.push_back(m_bv.mk_ule(mk_q_one(), var));
- }
- bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), rule_body);
- trm = m.mk_implies(rule_i, rule_body);
- trm = m.mk_forall(1, index_sorts, &tick, trm, 1);
- assert_expr(trm);
- }
- bool_rewriter(m).mk_or(rules.size(), rules.c_ptr(), trm);
- trm = m.mk_implies(pred, trm);
- trm = m.mk_forall(1, index_sorts, &tick, trm, 1);
- SASSERT(is_well_sorted(m, trm));
- assert_expr(trm);
- }
- }
-
- void bmc::setup_qlinear() {
- m_fparams.m_relevancy_lvl = 2;
- m_fparams.m_model = true;
- m_fparams.m_model_compact = true;
- m_fparams.m_mbqi = true;
- }
-
- void bmc::mk_qrule_vars(datalog::rule const& r, unsigned rule_id, expr_ref_vector& sub) {
- sort_ref_vector sorts(m);
- r.get_vars(sorts);
- // populate substitution of bound variables.
- sub.reset();
- sub.resize(sorts.size());
-
- for (unsigned k = 0; k < r.get_decl()->get_arity(); ++k) {
- expr* arg = r.get_head()->get_arg(k);
- if (is_var(arg)) {
- unsigned idx = to_var(arg)->get_idx();
- if (!sub[idx].get()) {
- sub[idx] = mk_q_arg(r.get_decl(), k, true);
- }
- }
- }
- for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
- func_decl* q = r.get_decl(j);
- for (unsigned k = 0; k < q->get_arity(); ++k) {
- expr* arg = r.get_tail(j)->get_arg(k);
- if (is_var(arg)) {
- unsigned idx = to_var(arg)->get_idx();
- if (!sub[idx].get()) {
- sub[idx] = mk_q_arg(q, k, false);
- }
- }
- }
- }
- for (unsigned j = 0, idx = 0; j < sorts.size(); ++j) {
- if (sorts[j].get() && !sub[j].get()) {
- sub[j] = mk_q_var(r.get_decl(), sorts[j].get(), rule_id, idx++);
- }
- }
- }
-
- expr_ref bmc::mk_q_var(func_decl* pred, sort* s, unsigned rule_id, unsigned idx) {
- std::stringstream _name;
- _name << pred->get_name() << "#" << rule_id << "_" << idx;
- symbol nm(_name.str().c_str());
- var_ref var = mk_index_var();
- return expr_ref(m.mk_app(m.mk_func_decl(nm, mk_index_sort(), s), var), m);
- }
-
- expr_ref bmc::mk_q_arg(func_decl* pred, unsigned idx, bool is_current) {
- SASSERT(idx < pred->get_arity());
- std::stringstream _name;
- _name << pred->get_name() << "#" << idx;
- symbol nm(_name.str().c_str());
- expr_ref var(mk_index_var(), m);
- if (!is_current) {
- var = m_bv.mk_bv_sub(var, mk_q_one());
- }
- return expr_ref(m.mk_app(m.mk_func_decl(nm, mk_index_sort(), pred->get_domain(idx)), var), m);
- }
-
- expr_ref bmc::mk_q_one() {
- return mk_q_num(1);
- }
-
- expr_ref bmc::mk_q_num(unsigned i) {
- return expr_ref(m_bv.mk_numeral(i, m_bit_width), m);
- }
-
- func_decl_ref bmc::mk_q_func_decl(func_decl* f) {
- std::stringstream _name;
- _name << f->get_name() << "#";
- symbol nm(_name.str().c_str());
- return func_decl_ref(m.mk_func_decl(nm, mk_index_sort(), f->get_range()), m);
- }
-
- func_decl_ref bmc::mk_q_rule(func_decl* f, unsigned rule_id) {
- std::stringstream _name;
- _name << f->get_name() << "#" << rule_id;
- symbol nm(_name.str().c_str());
- return func_decl_ref(m.mk_func_decl(nm, mk_index_sort(), m.mk_bool_sort()), m);
- }
-
-
- expr_ref bmc::eval_q(model_ref& model, func_decl* f, unsigned i) {
- func_decl_ref fn = mk_q_func_decl(f);
- expr_ref t(m), result(m);
- t = m.mk_app(mk_q_func_decl(f).get(), mk_q_num(i));
- model->eval(t, result);
- return result;
- }
-
- expr_ref bmc::eval_q(model_ref& model, expr* t, unsigned i) {
- expr_ref tmp(m), result(m), num(m);
- var_subst vs(m, false);
- num = mk_q_num(i);
- expr* nums[1] = { num };
- vs(t, 1, nums, tmp);
- model->eval(tmp, result);
- return result;
- }
-
- lbool bmc::get_model_qlinear() {
- rule_manager& rm = m_ctx.get_rule_manager();
- func_decl_ref q = mk_q_func_decl(m_query_pred);
- expr_ref T(m), rule_i(m), vl(m);
- model_ref md;
- proof_ref pr(m);
- rule_unifier unifier(m_ctx);
- rational num;
- unsigned level, bv_size;
-
- m_solver.get_model(md);
- func_decl* pred = m_query_pred;
- dl_decl_util util(m);
- T = m.mk_const(symbol("T"), mk_index_sort());
- md->eval(T, vl);
- VERIFY (m_bv.is_numeral(vl, num, bv_size));
- SASSERT(num.is_unsigned());
- level = num.get_unsigned();
- SASSERT(m.is_true(eval_q(md, m_query_pred, level)));
- TRACE("bmc", model_smt2_pp(tout, m, *md, 0););
-
- rule_ref r0(rm), r1(rm), r2(rm);
- while (true) {
- TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";);
- expr_ref_vector sub(m);
- rule_vector const& rls = m_rules.get_predicate_rules(pred);
- rule* r = 0;
- unsigned i = 0;
- for (; i < rls.size(); ++i) {
- rule_i = m.mk_app(mk_q_rule(pred, i), mk_q_num(level).get());
- TRACE("bmc", rls[i]->display(m_ctx, tout << "Checking rule " << mk_pp(rule_i, m) << " "););
- if (m.is_true(eval_q(md, rule_i, level))) {
- r = rls[i];
- break;
- }
- }
- SASSERT(r);
- mk_qrule_vars(*r, i, sub);
- // we have rule, we have variable names of rule.
-
- // extract values for the variables in the rule.
- for (unsigned j = 0; j < sub.size(); ++j) {
- expr_ref vl = eval_q(md, sub[j].get(), i);
- if (vl) {
- // vl can be 0 if the interpretation does not assign a value to it.
- sub[j] = vl;
- }
- else {
- sub[j] = m.mk_var(j, m.get_sort(sub[j].get()));
- }
- }
- svector > positions;
- vector substs;
- expr_ref fml(m), concl(m);
-
- r->to_formula(fml);
- r2 = r;
- rm.substitute(r2, sub.size(), sub.c_ptr());
- if (r0) {
- VERIFY(unifier.unify_rules(*r0.get(), 0, *r2.get()));
- expr_ref_vector sub1 = unifier.get_rule_subst(*r0.get(), true);
- expr_ref_vector sub2 = unifier.get_rule_subst(*r2.get(), false);
- apply_subst(sub, sub2);
- unifier.apply(*r0.get(), 0, *r2.get(), r1);
- r1->to_formula(concl);
- scoped_coarse_proof _sp(m);
-
- proof* p = m.mk_asserted(fml);
- proof* premises[2] = { pr, p };
-
- positions.push_back(std::make_pair(0, 1));
-
- substs.push_back(sub1);
- substs.push_back(sub);
- pr = m.mk_hyper_resolve(2, premises, concl, positions, substs);
- r0 = r1;
- }
- else {
- r2->to_formula(concl);
- scoped_coarse_proof _sp(m);
- proof* p = m.mk_asserted(fml);
- if (sub.empty()) {
- pr = p;
- }
- else {
- substs.push_back(sub);
- pr = m.mk_hyper_resolve(1, &p, concl, positions, substs);
- }
- r0 = r2;
- }
-
- if (level == 0) {
- SASSERT(r->get_uninterpreted_tail_size() == 0);
- break;
- }
- --level;
- SASSERT(r->get_uninterpreted_tail_size() == 1);
- pred = r->get_decl(0);
- }
- scoped_coarse_proof _sp(m);
- apply(m, m_pc.get(), pr);
- m_answer = pr;
- return l_true;
- }
-
- // --------------------------------------------------------------------------
- // Basic non-linear BMC based on compiling into data-types (it is inefficient)
-
-
- lbool bmc::check_nonlinear() {
- setup_nonlinear();
- declare_datatypes();
- compile_nonlinear();
- return check_query();
- }
-
- void bmc::setup_nonlinear() {
- setup_linear();
- m_fparams.m_relevancy_lvl = 2;
- }
-
- func_decl_ref bmc::mk_predicate(func_decl* pred) {
- std::stringstream _name;
- _name << pred->get_name() << "#";
- symbol nm(_name.str().c_str());
- sort* pred_trace_sort = m_pred2sort.find(pred);
- return func_decl_ref(m.mk_func_decl(nm, pred_trace_sort, m_path_sort, m.mk_bool_sort()), m);
- }
-
- func_decl_ref bmc::mk_rule(func_decl* p, unsigned rule_idx) {
- std::stringstream _name;
- _name << "rule:" << p->get_name() << "#" << rule_idx;
- symbol nm(_name.str().c_str());
- sort* pred_trace_sort = m_pred2sort.find(p);
- return func_decl_ref(m.mk_func_decl(nm, pred_trace_sort, m_path_sort, m.mk_bool_sort()), m);
- }
-
- expr_ref bmc::mk_var_nonlinear(func_decl* pred, sort*s, unsigned idx, expr* path_arg, expr* trace_arg) {
- std::stringstream _name;
- _name << pred->get_name() << "#V_" << idx;
- symbol nm(_name.str().c_str());
- func_decl_ref fn(m);
- fn = m.mk_func_decl(nm, m_pred2sort.find(pred), m_path_sort, s);
- return expr_ref(m.mk_app(fn, trace_arg, path_arg), m);
- }
-
- expr_ref bmc::mk_arg_nonlinear(func_decl* pred, unsigned idx, expr* path_arg, expr* trace_arg) {
- SASSERT(idx < pred->get_arity());
- std::stringstream _name;
- _name << pred->get_name() << "#X_" << idx;
- symbol nm(_name.str().c_str());
- func_decl_ref fn(m);
- fn = m.mk_func_decl(nm, m_pred2sort.find(pred), m_path_sort, pred->get_domain(idx));
- return expr_ref(m.mk_app(fn, trace_arg, path_arg), m);
- }
-
- void bmc::mk_subst(datalog::rule& r, expr* path, app* trace, expr_ref_vector& sub) {
- datatype_util dtu(m);
- sort_ref_vector sorts(m);
- func_decl* p = r.get_decl();
- ptr_vector const& succs = *dtu.get_datatype_constructors(m.get_sort(path));
- // populate substitution of bound variables.
- r.get_vars(sorts);
- sub.reset();
- sub.resize(sorts.size());
- for (unsigned k = 0; k < r.get_decl()->get_arity(); ++k) {
- expr* arg = r.get_head()->get_arg(k);
- if (is_var(arg)) {
- unsigned idx = to_var(arg)->get_idx();
- if (!sub[idx].get()) {
- sub[idx] = mk_arg_nonlinear(p, k, path, trace);
- }
- }
- }
- for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
- func_decl* q = r.get_decl(j);
- expr_ref path_arg(m);
- if (j == 0) {
- path_arg = path;
- }
- else {
- path_arg = m.mk_app(succs[j], path);
- }
- for (unsigned k = 0; k < q->get_arity(); ++k) {
- expr* arg = r.get_tail(j)->get_arg(k);
- if (is_var(arg)) {
- unsigned idx = to_var(arg)->get_idx();
- if (!sub[idx].get()) {
- sub[idx] = mk_arg_nonlinear(q, k, path_arg, trace->get_arg(j));
- }
- }
- }
- }
- for (unsigned j = 0, idx = 0; j < sorts.size(); ++j) {
- if (sorts[j].get() && !sub[j].get()) {
- sub[j] = mk_var_nonlinear(r.get_decl(), sorts[j].get(), idx++, path, trace);
- }
- }
- }
-
- /**
- \brief compile Horn rule into co-Horn implication.
- forall args . R(path_var, rule_i(trace_vars)) => Body[X(path_var, rule_i(trace_vars)), Y(S_j(path_var), trace_vars_j)]
- */
- void bmc::compile_nonlinear() {
- datatype_util dtu(m);
-
- rule_set::decl2rules::iterator it = m_rules.begin_grouped_rules();
- rule_set::decl2rules::iterator end = m_rules.end_grouped_rules();
- for (; it != end; ++it) {
- func_decl* p = it->m_key;
- rule_vector const& rls = *it->m_value;
-
- // Assert: p_level => r1_level \/ r2_level \/ r3_level \/ ...
- // where: r_i_level = body of rule i for level + equalities for head of rule i
-
- expr_ref rule_body(m), tmp(m), pred(m), trace_arg(m), fml(m);
- var_ref path_var(m), trace_var(m);
- expr_ref_vector rules(m), sub(m), conjs(m), vars(m), patterns(m);
- sort* pred_sort = m_pred2sort.find(p);
- path_var = m.mk_var(0, m_path_sort);
- trace_var = m.mk_var(1, pred_sort);
- // sort* sorts[2] = { pred_sort, m_path_sort };
- ptr_vector const& cnstrs = *dtu.get_datatype_constructors(pred_sort);
- ptr_vector const& succs = *dtu.get_datatype_constructors(m_path_sort);
- SASSERT(cnstrs.size() == rls.size());
- pred = m.mk_app(mk_predicate(p), trace_var.get(), path_var.get());
- for (unsigned i = 0; i < rls.size(); ++i) {
- sub.reset();
- conjs.reset();
- vars.reset();
- rule& r = *rls[i];
- func_decl_ref rule_pred_i = mk_rule(p, i);
-
- // Create cnstr_rule_i(Vars)
- func_decl* cnstr = cnstrs[i];
- rules.push_back(m.mk_app(rule_pred_i, trace_var.get(), path_var.get()));
- unsigned arity = cnstr->get_arity();
- for (unsigned j = 0; j < arity; ++j) {
- vars.push_back(m.mk_var(arity-j,cnstr->get_domain(j)));
- }
- trace_arg = m.mk_app(cnstr, vars.size(), vars.c_ptr());
-
- mk_subst(r, path_var, to_app(trace_arg), sub);
-
- // apply substitution to body.
- var_subst vs(m, false);
- for (unsigned k = 0; k < p->get_arity(); ++k) {
- vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), tmp);
- expr_ref arg = mk_arg_nonlinear(p, k, path_var, trace_arg);
- conjs.push_back(m.mk_eq(tmp, arg));
- }
- for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
- expr_ref path_arg(m);
- if (j == 0) {
- path_arg = path_var.get();
- }
- else {
- path_arg = m.mk_app(succs[j], path_var.get());
- }
- func_decl* q = r.get_decl(j);
- for (unsigned k = 0; k < q->get_arity(); ++k) {
- vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), tmp);
- expr_ref arg = mk_arg_nonlinear(q, k, path_arg, vars[j].get());
- conjs.push_back(m.mk_eq(tmp, arg));
- }
- func_decl_ref q_pred = mk_predicate(q);
- conjs.push_back(m.mk_app(q_pred, vars[j].get(), path_arg));
- }
- for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
- vs(r.get_tail(j), sub.size(), sub.c_ptr(), tmp);
- conjs.push_back(tmp);
- }
- bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), rule_body);
- ptr_vector q_sorts;
- vector names;
- for (unsigned i = 0; i < vars.size(); ++i) {
- q_sorts.push_back(m.get_sort(vars[i].get()));
- names.push_back(symbol(i+1));
- }
- vars.push_back(path_var);
- q_sorts.push_back(m.get_sort(path_var));
- names.push_back(symbol("path"));
- SASSERT(names.size() == q_sorts.size());
- SASSERT(vars.size() == names.size());
- symbol qid = r.name(), skid;
- tmp = m.mk_app(mk_predicate(p), trace_arg.get(), path_var.get());
- patterns.reset();
- patterns.push_back(m.mk_pattern(to_app(tmp)));
- fml = m.mk_implies(tmp, rule_body);
- fml = m.mk_forall(vars.size(), q_sorts.c_ptr(), names.c_ptr(), fml, 1, qid, skid, 1, patterns.c_ptr());
- assert_expr(fml);
-
- }
- }
- }
-
- void bmc::declare_datatypes() {
- rule_set::decl2rules::iterator it = m_rules.begin_grouped_rules();
- rule_set::decl2rules::iterator end = m_rules.end_grouped_rules();
- datatype_util dtu(m);
- ptr_vector dts;
-
- obj_map pred_idx;
- for (unsigned i = 0; it != end; ++it, ++i) {
- pred_idx.insert(it->m_key, i);
- }
-
- it = m_rules.begin_grouped_rules();
- for (; it != end; ++it) {
- rule_vector const& rls = *it->m_value;
- func_decl* pred = it->m_key;
- ptr_vector cnstrs;
- for (unsigned i = 0; i < rls.size(); ++i) {
- rule* r = rls[i];
- ptr_vector accs;
- for (unsigned j = 0; j < r->get_uninterpreted_tail_size(); ++j) {
- func_decl* q = r->get_decl(j);
- unsigned idx = pred_idx.find(q);
- std::stringstream _name;
- _name << pred->get_name() << "_" << q->get_name() << j;
- symbol name(_name.str().c_str());
- type_ref tr(idx);
- accs.push_back(mk_accessor_decl(name, tr));
- }
- std::stringstream _name;
- _name << pred->get_name() << "_" << i;
- symbol name(_name.str().c_str());
- _name << "?";
- symbol is_name(_name.str().c_str());
- cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr()));
- }
- dts.push_back(mk_datatype_decl(pred->get_name(), cnstrs.size(), cnstrs.c_ptr()));
- }
-
-
- sort_ref_vector new_sorts(m);
- family_id dfid = m.get_family_id("datatype");
- datatype_decl_plugin* dtp = static_cast(m.get_plugin(dfid));
- VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), new_sorts));
-
- it = m_rules.begin_grouped_rules();
- for (unsigned i = 0; it != end; ++it, ++i) {
- m_pred2sort.insert(it->m_key, new_sorts[i].get());
- m_sort2pred.insert(new_sorts[i].get(), it->m_key);
- m_pinned.push_back(new_sorts[i].get());
- }
- if (new_sorts.size() > 0) {
- TRACE("bmc", dtu.display_datatype(new_sorts[0].get(), tout););
- }
- del_datatype_decls(dts.size(), dts.c_ptr());
-
- // declare path data-type.
- {
- new_sorts.reset();
- dts.reset();
- ptr_vector cnstrs;
- unsigned max_arity = 0;
- rule_set::iterator it = m_rules.begin();
- rule_set::iterator end = m_rules.end();
- for (; it != end; ++it) {
- rule* r = *it;
- unsigned sz = r->get_uninterpreted_tail_size();
- max_arity = std::max(sz, max_arity);
- }
- cnstrs.push_back(mk_constructor_decl(symbol("Z#"), symbol("Z#?"), 0, 0));
-
- for (unsigned i = 0; i + 1 < max_arity; ++i) {
- std::stringstream _name;
- _name << "succ#" << i;
- symbol name(_name.str().c_str());
- _name << "?";
- symbol is_name(_name.str().c_str());
- std::stringstream _name2;
- _name2 << "get_succ#" << i;
- symbol acc_name(_name2.str().c_str());
- ptr_vector accs;
- type_ref tr(0);
- accs.push_back(mk_accessor_decl(name, tr));
- cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr()));
- }
- dts.push_back(mk_datatype_decl(symbol("Path"), cnstrs.size(), cnstrs.c_ptr()));
- VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), new_sorts));
- m_path_sort = new_sorts[0].get();
- }
- }
-
- proof_ref bmc::get_proof(model_ref& md, app* trace, app* path) {
- datatype_util dtu(m);
- sort* trace_sort = m.get_sort(trace);
- func_decl* p = m_sort2pred.find(trace_sort);
- datalog::rule_vector const& rules = m_rules.get_predicate_rules(p);
- ptr_vector const& cnstrs = *dtu.get_datatype_constructors(trace_sort);
- ptr_vector const& succs = *dtu.get_datatype_constructors(m_path_sort);
- // bool found = false;
- for (unsigned i = 0; i < cnstrs.size(); ++i) {
- if (trace->get_decl() == cnstrs[i]) {
- // found = true;
- svector > positions;
- scoped_coarse_proof _sc(m);
- proof_ref_vector prs(m);
- expr_ref_vector sub(m);
- vector substs;
- proof_ref pr(m);
- expr_ref fml(m), head(m), tmp(m);
- app_ref path1(m);
-
- var_subst vs(m, false);
- mk_subst(*rules[i], path, trace, sub);
- rules[i]->to_formula(fml);
- prs.push_back(m.mk_asserted(fml));
- unsigned sz = trace->get_num_args();
- if (sub.empty() && sz == 0) {
- pr = prs[0].get();
- return pr;
- }
- for (unsigned j = 0; j < sub.size(); ++j) {
- md->eval(sub[j].get(), tmp);
- sub[j] = tmp;
- }
- rule_ref rl(m_ctx.get_rule_manager());
- rl = rules[i];
- m_ctx.get_rule_manager().substitute(rl, sub.size(), sub.c_ptr());
-
- substs.push_back(sub);
-
- for (unsigned j = 0; j < sz; ++j) {
- if (j == 0) {
- path1 = path;
- }
- else {
- path1 = m.mk_app(succs[j], path);
- }
-
- prs.push_back(get_proof(md, to_app(trace->get_arg(j)), path1));
- positions.push_back(std::make_pair(j+1,0));
- substs.push_back(expr_ref_vector(m));
- }
- head = rl->get_head();
- pr = m.mk_hyper_resolve(sz+1, prs.c_ptr(), head, positions, substs);
- return pr;
- }
- }
- UNREACHABLE();
- return proof_ref(0, m);
- }
-
- // instantiation of algebraic data-types takes care of the rest.
- lbool bmc::check_query() {
- sort* trace_sort = m_pred2sort.find(m_query_pred);
- func_decl_ref q = mk_predicate(m_query_pred);
- expr_ref trace(m), path(m), fml(m);
- trace = m.mk_const(symbol("trace"), trace_sort);
- path = m.mk_const(symbol("path"), m_path_sort);
- fml = m.mk_app(q, trace.get(), path.get());
- assert_expr(fml);
- while (true) {
- lbool is_sat = m_solver.check();
- model_ref md;
- if (is_sat == l_false) {
- return is_sat;
- }
- m_solver.get_model(md);
- mk_answer_nonlinear(md, trace, path);
- return l_true;
- }
- }
-
- bool bmc::check_model_nonlinear(model_ref& md, expr* trace) {
- expr_ref trace_val(m), eq(m);
- md->eval(trace, trace_val);
- eq = m.mk_eq(trace, trace_val);
- m_solver.push();
- m_solver.assert_expr(eq);
- lbool is_sat = m_solver.check();
- if (is_sat != l_false) {
- m_solver.get_model(md);
- }
- m_solver.pop(1);
- if (is_sat == l_false) {
- IF_VERBOSE(1, verbose_stream() << "infeasible trace " << mk_pp(trace_val, m) << "\n";);
- eq = m.mk_not(eq);
- m_solver.assert_expr(eq);
- }
- return is_sat != l_false;
- }
-
- void bmc::mk_answer_nonlinear(model_ref& md, expr_ref& trace, expr_ref& path) {
- proof_ref pr(m);
- IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0););
- md->eval(trace, trace);
- md->eval(path, path);
- IF_VERBOSE(2, verbose_stream() << mk_pp(trace, m) << "\n";
- for (unsigned i = 0; i < m_solver.size(); ++i) {
- verbose_stream() << mk_pp(m_solver.get_formulas()[i], m) << "\n";
- });
- m_answer = get_proof(md, to_app(trace), to_app(path));
- }
-
-
void bmc::checkpoint() {
if (m_cancel) {
throw default_exception("bmc canceled");
@@ -1103,4 +1510,16 @@ namespace datalog {
return m_answer;
}
+ void bmc::compile(rule_set const& rules, expr_ref_vector& fmls, unsigned level) {
+ nonlinear nl(*this);
+ nl.compile(rules, fmls, level);
+ }
+
+ expr_ref bmc::compile_query(func_decl* query_pred, unsigned level) {
+ nonlinear nl(*this);
+ return nl.compile_query(query_pred, level);
+ }
+
};
+
+template class rewriter_tpl;
diff --git a/src/muz_qe/dl_bmc_engine.h b/src/muz_qe/dl_bmc_engine.h
index 5b6e433cd..06901a160 100644
--- a/src/muz_qe/dl_bmc_engine.h
+++ b/src/muz_qe/dl_bmc_engine.h
@@ -35,83 +35,23 @@ namespace datalog {
ast_manager& m;
smt_params m_fparams;
smt::kernel m_solver;
- obj_map m_pred2sort;
- obj_map m_sort2pred;
- obj_map m_pred2newpred;
- obj_map > m_pred2args;
- ast_ref_vector m_pinned;
rule_set m_rules;
func_decl_ref m_query_pred;
expr_ref m_answer;
volatile bool m_cancel;
proof_converter_ref m_pc;
- sort_ref m_path_sort;
- bv_util m_bv;
- unsigned m_bit_width;
-
- lbool check_query();
-
- proof_ref get_proof(model_ref& md, app* trace, app* path);
void checkpoint();
- void declare_datatypes();
-
- void compile_nonlinear();
-
- void mk_rule_vars_nonlinear(rule& r, unsigned rule_id, expr* trace_arg, expr* path_arg, expr_ref_vector& sub);
-
- expr_ref mk_var_nonlinear(func_decl* pred, sort* s, unsigned idx, expr* path_arg, expr* trace_arg);
-
- expr_ref mk_arg_nonlinear(func_decl* pred, unsigned idx, expr* path_arg, expr* trace_arg);
-
- void mk_subst(rule& r, expr* path, app* trace, expr_ref_vector& sub);
+ class nonlinear_dt;
+ class nonlinear;
+ class qlinear;
+ class linear;
bool is_linear() const;
-
- lbool check_nonlinear();
- void setup_nonlinear();
- bool check_model_nonlinear(model_ref& md, expr* trace);
- void mk_answer_nonlinear(model_ref& md, expr_ref& trace, expr_ref& path);
- func_decl_ref mk_predicate(func_decl* p);
-
- func_decl_ref mk_rule(func_decl* p, unsigned rule_idx);
-
- // linear check
- lbool check_linear();
- lbool check_linear(unsigned level);
- void compile_linear();
- void compile_linear(unsigned level);
- void compile_linear(rule& r, unsigned level);
- expr_ref mk_level_predicate(symbol const& name, unsigned level);
- expr_ref mk_level_predicate(func_decl* p, unsigned level);
- expr_ref mk_level_arg(func_decl* pred, unsigned idx, unsigned level);
- expr_ref mk_level_rule(func_decl* p, unsigned rule_idx, unsigned level);
- expr_ref mk_level_var(func_decl* pred, sort* s, unsigned rule_id, unsigned idx, unsigned level);
- void get_model_linear(unsigned level);
- void setup_linear();
-
void assert_expr(expr* e);
- void mk_rule_vars(rule& r, unsigned level, unsigned rule_id, expr_ref_vector& sub);
-
- // quantified linear check
- void compile_qlinear();
- void setup_qlinear();
- lbool check_qlinear();
- lbool get_model_qlinear();
- sort_ref mk_index_sort();
- var_ref mk_index_var();
- void mk_qrule_vars(datalog::rule const& r, unsigned i, expr_ref_vector& sub);
- expr_ref mk_q_var(func_decl* pred, sort* s, unsigned rule_id, unsigned idx);
- expr_ref mk_q_arg(func_decl* pred, unsigned idx, bool is_current);
- expr_ref mk_q_one();
- expr_ref mk_q_num(unsigned i);
- expr_ref eval_q(model_ref& model, expr* t, unsigned i);
- expr_ref eval_q(model_ref& model, func_decl* f, unsigned i);
- func_decl_ref mk_q_rule(func_decl* f, unsigned rule_id);
- func_decl_ref mk_q_func_decl(func_decl* f);
public:
bmc(context& ctx);
@@ -131,6 +71,10 @@ namespace datalog {
void reset_statistics();
expr_ref get_answer();
+
+ // direct access to (new) non-linear compiler.
+ void compile(rule_set const& rules, expr_ref_vector& fmls, unsigned level);
+ expr_ref compile_query(func_decl* query_pred, unsigned level);
};
};
diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp
index 7a46228ce..5581732c8 100644
--- a/src/muz_qe/dl_context.cpp
+++ b/src/muz_qe/dl_context.cpp
@@ -715,6 +715,8 @@ namespace datalog {
check_positive_predicates(r);
break;
case BMC_ENGINE:
+ check_positive_predicates(r);
+ break;
case QBMC_ENGINE:
check_existential_tail(r);
check_positive_predicates(r);
diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp
index a5259ba8a..880f196a2 100644
--- a/src/muz_qe/dl_mk_array_blast.cpp
+++ b/src/muz_qe/dl_mk_array_blast.cpp
@@ -18,7 +18,8 @@ Revision History:
--*/
#include "dl_mk_array_blast.h"
-#include "expr_replacer.h"
+#include "expr_safe_replace.h"
+
namespace datalog {
@@ -54,9 +55,10 @@ namespace datalog {
unsigned tsz = r.get_tail_size();
expr_ref_vector conjs(m), new_conjs(m);
expr_ref tmp(m);
- expr_substitution sub(m);
+ expr_safe_replace sub(m);
uint_set lhs_vars, rhs_vars;
bool change = false;
+ bool inserted = false;
for (unsigned i = 0; i < utsz; ++i) {
new_conjs.push_back(r.get_tail(i));
@@ -81,6 +83,7 @@ namespace datalog {
}
else {
sub.insert(x, y);
+ inserted = true;
}
}
else {
@@ -89,7 +92,7 @@ namespace datalog {
new_conjs.push_back(tmp);
}
}
- if (sub.empty() && !change) {
+ if (!inserted && !change) {
rules.add_rule(&r);
return false;
}
@@ -99,11 +102,9 @@ namespace datalog {
r.to_formula(fml1);
body = m.mk_and(new_conjs.size(), new_conjs.c_ptr());
head = r.get_head();
- scoped_ptr replace = mk_default_expr_replacer(m);
- replace->set_substitution(&sub);
- (*replace)(body);
+ sub(body);
m_rewriter(body);
- (*replace)(head);
+ sub(head);
m_rewriter(head);
fml2 = m.mk_implies(body, head);
rm.mk_rule(fml2, new_rules, r.name());
diff --git a/src/muz_qe/dl_mk_coalesce.cpp b/src/muz_qe/dl_mk_coalesce.cpp
index 251988a84..222881bc4 100644
--- a/src/muz_qe/dl_mk_coalesce.cpp
+++ b/src/muz_qe/dl_mk_coalesce.cpp
@@ -60,7 +60,7 @@ namespace datalog {
obj_map indices;
bool_rewriter bwr(m);
rule_ref r(const_cast(&rl), rm);
- sort_ref_vector sorts(m);
+ ptr_vector sorts;
expr_ref_vector revsub(m), conjs(m);
rl.get_vars(sorts);
revsub.resize(sorts.size());
@@ -72,8 +72,8 @@ namespace datalog {
if (is_var(e)) {
unsigned v = to_var(e)->get_idx();
SASSERT(v < valid.size());
- if (sorts[v].get()) {
- SASSERT(s == sorts[v].get());
+ if (sorts[v]) {
+ SASSERT(s == sorts[v]);
if (valid[v]) {
revsub[v] = w;
valid[v] = false;
@@ -92,8 +92,8 @@ namespace datalog {
}
}
for (unsigned i = 0; i < sorts.size(); ++i) {
- if (valid[i] && sorts[i].get() && !revsub[i].get()) {
- revsub[i] = m.mk_var(m_idx++, sorts[i].get());
+ if (valid[i] && sorts[i] && !revsub[i].get()) {
+ revsub[i] = m.mk_var(m_idx++, sorts[i]);
}
}
var_subst vs(m, false);
@@ -112,7 +112,7 @@ namespace datalog {
app_ref pred(m), head(m);
expr_ref fml1(m), fml2(m), fml(m);
app_ref_vector tail(m);
- sort_ref_vector sorts1(m), sorts2(m);
+ ptr_vector sorts1, sorts2;
expr_ref_vector conjs1(m), conjs(m);
rule_ref res(rm);
bool_rewriter bwr(m);
diff --git a/src/muz_qe/dl_mk_extract_quantifiers2.cpp b/src/muz_qe/dl_mk_extract_quantifiers2.cpp
new file mode 100644
index 000000000..97976a6be
--- /dev/null
+++ b/src/muz_qe/dl_mk_extract_quantifiers2.cpp
@@ -0,0 +1,366 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ dl_mk_extract_quantifiers2.cpp
+
+Abstract:
+
+ Remove universal quantifiers over interpreted predicates in the body.
+
+Author:
+
+ Nikolaj Bjorner (nbjorner) 2012-11-21
+
+Revision History:
+
+--*/
+
+#include"dl_mk_extract_quantifiers2.h"
+#include"ast_pp.h"
+#include"dl_bmc_engine.h"
+#include"smt_quantifier.h"
+#include"smt_context.h"
+
+namespace datalog {
+
+
+ mk_extract_quantifiers2::mk_extract_quantifiers2(context & ctx) :
+ rule_transformer::plugin(101, false),
+ m_ctx(ctx),
+ m(ctx.get_manager()),
+ rm(ctx.get_rule_manager()),
+ m_query_pred(m),
+ m_quantifiers(m),
+ m_refs(m)
+ {}
+
+ mk_extract_quantifiers2::~mk_extract_quantifiers2() {
+ reset();
+ }
+
+ void mk_extract_quantifiers2::set_query(func_decl* q) {
+ m_query_pred = q;
+ }
+
+ bool mk_extract_quantifiers2::matches_signature(func_decl* head, expr_ref_vector const& binding) {
+ unsigned sz = head->get_arity();
+ if (sz != binding.size()) {
+ return false;
+ }
+ for (unsigned i = 0; i < sz; ++i) {
+ if (head->get_domain(i) != m.get_sort(binding[sz-i-1])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool mk_extract_quantifiers2::matches_quantifier(quantifier* q, expr_ref_vector const& binding) {
+ unsigned sz = q->get_num_decls();
+ if (sz != binding.size()) {
+ return false;
+ }
+ for (unsigned i = 0; i < sz; ++i) {
+ if (q->get_decl_sort(i) != m.get_sort(binding[sz-i-1])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool mk_extract_quantifiers2::mk_abstract_expr(expr_ref& term) {
+ if (!is_app(term)) {
+ return false;
+ }
+ expr* r;
+ if (m_map.find(term, r)) {
+ term = r;
+ return true;
+ }
+ if (to_app(term)->get_family_id() == null_family_id) {
+ return false;
+ }
+ expr_ref_vector args(m);
+ expr_ref tmp(m);
+ for (unsigned i = 0; i < to_app(term)->get_num_args(); ++i) {
+ tmp = to_app(term)->get_arg(i);
+ if (!mk_abstract_expr(tmp)) {
+ return false;
+ }
+ args.push_back(tmp);
+ }
+ tmp = m.mk_app(to_app(term)->get_decl(), args.size(), args.c_ptr());
+ m_refs.push_back(tmp);
+ m_map.insert(term, tmp);
+ term = tmp;
+ return true;
+ }
+
+ bool mk_extract_quantifiers2::mk_abstract_binding(expr_ref_vector const& binding, expr_ref_vector& result) {
+ for (unsigned i = 0; i < binding.size(); ++i) {
+ expr_ref tmp(m);
+ tmp = binding[i];
+ if (!mk_abstract_expr(tmp)) {
+ return false;
+ }
+ result.push_back(tmp);
+ }
+ return true;
+ }
+
+ void mk_extract_quantifiers2::mk_abstraction_map(rule& r, expr_ref_vector const& binding) {
+ m_map.reset();
+ unsigned sz = binding.size();
+ SASSERT(sz == r.get_decl()->get_arity());
+ for (unsigned i = 0; i < sz; ++i) {
+ m_map.insert(binding[sz-i-1], r.get_head()->get_arg(i));
+ SASSERT(m.get_sort(binding[sz-i-1]) == m.get_sort(r.get_head()->get_arg(i)));
+ }
+ // todo: also make bindings for variables in rule body.
+ }
+
+ void mk_extract_quantifiers2::match_bindings(unsigned i, unsigned j, unsigned k) {
+ expr_ref_vector resb(m);
+ rule* r = m_qrules[i];
+ quantifier* q = m_quantifiers[i].get();
+ expr_ref_vector const& ruleb = m_rule_bindings[i][j];
+ expr_ref_vector const& quantb = m_quantifier_bindings[i][k];
+ mk_abstraction_map(*r, ruleb);
+ if (!mk_abstract_binding(quantb, resb)) {
+ return;
+ }
+ expr_ref inst(m), tmp(m);
+ var_shifter shift(m);
+
+ for (unsigned l = 0; l < resb.size(); ++l) {
+ tmp = resb[l].get();
+ shift(tmp, q->get_num_decls(), tmp);
+ resb[l] = tmp;
+ }
+
+ instantiate(m, q, resb.c_ptr(), inst);
+ if (!m_seen.contains(r)) {
+ m_seen.insert(r, alloc(obj_hashtable));
+ }
+ obj_hashtable& seen = *m_seen.find(r);
+ if (seen.contains(inst)) {
+ return;
+ }
+ seen.insert(inst);
+ m_refs.push_back(inst);
+ if (!m_quantifier_instantiations.contains(r, q)) {
+ m_quantifier_instantiations.insert(r, q, alloc(expr_ref_vector, m));
+ }
+ expr_ref_vector* vec = 0;
+ VERIFY(m_quantifier_instantiations.find(r, q, vec));
+ vec->push_back(inst);
+ TRACE("dl", tout << "matched: " << mk_pp(q, m) << "\n" << mk_pp(inst, m) << "\n";);
+ }
+
+ app_ref mk_extract_quantifiers2::ensure_app(expr* e) {
+ if (is_app(e)) {
+ return app_ref(to_app(e), m);
+ }
+ else {
+ return app_ref(m.mk_eq(e, m.mk_true()), m);
+ }
+ }
+
+ void mk_extract_quantifiers2::extract(rule& r, rule_set& new_rules) {
+ unsigned utsz = r.get_uninterpreted_tail_size();
+ unsigned tsz = r.get_tail_size();
+ bool has_quantifier = false;
+ expr_ref_vector conjs(m);
+ for (unsigned i = utsz; i < tsz; ++i) {
+ conjs.push_back(r.get_tail(i));
+ }
+ datalog::flatten_and(conjs);
+ for (unsigned j = 0; j < conjs.size(); ++j) {
+ expr* e = conjs[j].get();
+ quantifier* q;
+ if (rule_manager::is_forall(m, e, q)) {
+ m_quantifiers.push_back(q);
+ m_qrules.push_back(&r);
+ m_rule_bindings.push_back(vector());
+ m_quantifier_bindings.push_back(vector());
+ has_quantifier = true;
+ }
+ }
+ if (!has_quantifier) {
+ new_rules.add_rule(&r);
+ }
+ }
+
+ void mk_extract_quantifiers2::apply(rule& r, rule_set& new_rules) {
+ expr_ref_vector tail(m), conjs(m);
+ expr_ref fml(m);
+ unsigned utsz = r.get_uninterpreted_tail_size();
+ unsigned tsz = r.get_tail_size();
+ for (unsigned i = 0; i < utsz; ++i) {
+ SASSERT(!r.is_neg_tail(i));
+ tail.push_back(r.get_tail(i));
+ }
+ bool has_quantifier = false;
+ for (unsigned i = utsz; i < tsz; ++i) {
+ conjs.push_back(r.get_tail(i));
+ }
+ datalog::flatten_and(conjs);
+ for (unsigned j = 0; j < conjs.size(); ++j) {
+ expr* e = conjs[j].get();
+ quantifier* q;
+ if (rule_manager::is_forall(m, e, q)) {
+ expr_ref_vector* ls;
+ if (m_quantifier_instantiations.find(&r,q,ls)) {
+ tail.append(*ls);
+ }
+ has_quantifier = true;
+ }
+ else {
+ tail.push_back(e);
+ }
+ }
+ if (has_quantifier) {
+ fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), r.get_head());
+ rule_ref_vector rules(rm);
+ rm.mk_rule(fml, rules, r.name());
+ for (unsigned i = 0; i < rules.size(); ++i) {
+ new_rules.add_rule(rules[i].get());
+ }
+ }
+ }
+
+#if 0
+ class mk_extract_quantifiers2::instance_plugin : public smt::quantifier_instance_plugin {
+ mk_extract_quantifiers2& ex;
+ ast_manager& m;
+ expr_ref_vector m_refs;
+ obj_hashtable m_bindings;
+ public:
+ instance_plugin(mk_extract_quantifiers2& ex): ex(ex), m(ex.m), m_refs(m) {}
+
+ virtual void operator()(quantifier* q, unsigned num_bindings, smt::enode*const* bindings) {
+ expr_ref_vector binding(m);
+ ptr_vector sorts;
+ for (unsigned i = 0; i < num_bindings; ++i) {
+ binding.push_back(bindings[i]->get_owner());
+ sorts.push_back(m.get_sort(binding[i].get()));
+ }
+ func_decl* f = m.mk_func_decl(symbol("T"), sorts.size(), sorts.c_ptr(), m.mk_bool_sort());
+ expr_ref tup(m);
+ tup = m.mk_app(f, binding.size(), binding.c_ptr());
+ if (!m_bindings.contains(tup)) {
+ m_bindings.insert(tup);
+ m_refs.push_back(tup);
+ ex.m_bindings.push_back(binding);
+ TRACE("dl", tout << "insert\n" << mk_pp(q, m) << "\n" << mk_pp(tup, m) << "\n";);
+ }
+ }
+ };
+
+#endif
+
+ void mk_extract_quantifiers2::reset() {
+ {
+ obj_pair_map::iterator
+ it = m_quantifier_instantiations.begin(),
+ end = m_quantifier_instantiations.end();
+ for (; it != end; ++it) {
+ dealloc(it->get_value());
+ }
+ }
+ {
+ obj_map*>::iterator
+ it = m_seen.begin(),
+ end = m_seen.end();
+ for (; it != end; ++it) {
+ dealloc(it->m_value);
+ }
+ }
+ m_quantifier_instantiations.reset();
+ m_seen.reset();
+ m_has_quantifiers = false;
+ m_quantifiers.reset();
+ m_qrules.reset();
+ m_bindings.reset();
+ m_rule_bindings.reset();
+ m_quantifier_bindings.reset();
+ m_refs.reset();
+ }
+
+ rule_set * mk_extract_quantifiers2::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
+ reset();
+ rule_set::iterator it = source.begin(), end = source.end();
+ for (; !m_has_quantifiers && it != end; ++it) {
+ m_has_quantifiers = (*it)->has_quantifiers();
+ }
+ if (!m_has_quantifiers) {
+ return 0;
+ }
+
+ rule_set* rules = alloc(rule_set, m_ctx);
+ it = source.begin();
+ for (; it != end; ++it) {
+ extract(**it, *rules);
+ }
+
+ bmc bmc(m_ctx);
+ expr_ref_vector fmls(m);
+ bmc.compile(source, fmls, 0); // TBD: use cancel_eh to terminate without base-case.
+ bmc.compile(source, fmls, 1);
+ bmc.compile(source, fmls, 2);
+// bmc.compile(source, fmls, 3);
+ expr_ref query = bmc.compile_query(m_query_pred, 2);
+ fmls.push_back(query);
+ smt_params fparams;
+ fparams.m_relevancy_lvl = 0;
+ fparams.m_model = true;
+ fparams.m_model_compact = true;
+ fparams.m_mbqi = true;
+ smt::kernel solver(m, fparams);
+ TRACE("dl",
+ for (unsigned i = 0; i < fmls.size(); ++i) {
+ tout << mk_pp(fmls[i].get(), m) << "\n";
+ });
+
+ for (unsigned i = 0; i < fmls.size(); ++i) {
+ solver.assert_expr(fmls[i].get());
+ }
+#if 0
+ smt::context& ctx = solver.get_context();
+ smt::quantifier_manager* qm = ctx.get_quantifier_manager();
+ qm->get_plugin()->set_instance_plugin(alloc(instance_plugin, *this));
+#endif
+ lbool res = solver.check();
+
+ for (unsigned i = 0; i < m_bindings.size(); ++i) {
+ expr_ref_vector& binding = m_bindings[i];
+ for (unsigned j = 0; j < m_qrules.size(); ++j) {
+ rule* r = m_qrules[j];
+ if (matches_signature(r->get_decl(), binding)) {
+ m_rule_bindings[j].push_back(binding);
+ }
+ else if (matches_quantifier(m_quantifiers[j].get(), binding)) {
+ m_quantifier_bindings[j].push_back(binding);
+ }
+ }
+ }
+ for (unsigned i = 0; i < m_qrules.size(); ++i) {
+ for (unsigned j = 0; j < m_rule_bindings[i].size(); ++j) {
+ for (unsigned k = 0; k < m_quantifier_bindings[i].size(); ++k) {
+ match_bindings(i, j, k);
+ }
+ }
+ }
+ it = source.begin();
+ for (; it != end; ++it) {
+ apply(**it, *rules);
+ }
+
+ return rules;
+ }
+
+};
+
+
diff --git a/src/muz_qe/dl_mk_extract_quantifiers2.h b/src/muz_qe/dl_mk_extract_quantifiers2.h
new file mode 100644
index 000000000..30c15b313
--- /dev/null
+++ b/src/muz_qe/dl_mk_extract_quantifiers2.h
@@ -0,0 +1,91 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ dl_mk_extract_quantifiers2.h
+
+Abstract:
+
+ Replace universal quantifiers over interpreted predicates in the body
+ by instantiations mined using bounded model checking search.
+
+Author:
+
+ Nikolaj Bjorner (nbjorner) 2012-11-21
+
+Revision History:
+
+--*/
+#ifndef _DL_MK_EXTRACT_QUANTIFIERS2_H_
+#define _DL_MK_EXTRACT_QUANTIFIERS2_H_
+
+#include"dl_context.h"
+#include"dl_rule_set.h"
+#include"dl_rule_transformer.h"
+#include"obj_pair_hashtable.h"
+
+namespace datalog {
+
+ /**
+ \brief Extract universal quantifiers from rules.
+ */
+ class mk_extract_quantifiers2 : public rule_transformer::plugin {
+ context& m_ctx;
+ ast_manager& m;
+ rule_manager& rm;
+ func_decl_ref m_query_pred;
+ quantifier_ref_vector m_quantifiers;
+ ptr_vector m_qrules;
+ vectorm_bindings;
+ vector > m_rule_bindings;
+ vector > m_quantifier_bindings;
+ obj_pair_map m_quantifier_instantiations;
+ obj_map*> m_seen;
+
+ bool m_has_quantifiers;
+ obj_map m_map;
+ expr_ref_vector m_refs;
+
+ class instance_plugin;
+
+ void reset();
+
+ void extract(rule& r, rule_set& new_rules);
+
+ void apply(rule& r, rule_set& new_rules);
+
+ app_ref ensure_app(expr* e);
+
+ bool matches_signature(func_decl* head, expr_ref_vector const& binding);
+
+ bool matches_quantifier(quantifier* q, expr_ref_vector const& binding);
+
+ void match_bindings(unsigned i, unsigned j, unsigned k);
+
+ bool mk_abstract_expr(expr_ref& term);
+
+ bool mk_abstract_binding(expr_ref_vector const& binding, expr_ref_vector& result);
+
+ void mk_abstraction_map(rule& r, expr_ref_vector const& binding);
+
+ public:
+ /**
+ \brief Create rule transformer that extracts universal quantifiers (over recursive predicates).
+ */
+ mk_extract_quantifiers2(context & ctx);
+
+ virtual ~mk_extract_quantifiers2();
+
+ void set_query(func_decl* q);
+
+ rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
+
+ bool has_quantifiers() { return m_has_quantifiers; }
+
+ };
+
+};
+
+#endif /* _DL_MK_EXTRACT_QUANTIFIERS2_H_ */
+
diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp
index fa532ee6c..24ddd9ba5 100644
--- a/src/muz_qe/dl_mk_rule_inliner.cpp
+++ b/src/muz_qe/dl_mk_rule_inliner.cpp
@@ -136,14 +136,14 @@ namespace datalog {
expr_ref_vector rule_unifier::get_rule_subst(const rule& r, bool is_tgt) {
SASSERT(m_ready);
expr_ref_vector result(m);
- sort_ref_vector sorts(m);
+ ptr_vector sorts;
expr_ref v(m), w(m);
r.get_vars(sorts);
for (unsigned i = 0; i < sorts.size(); ++i) {
- if (!sorts[i].get()) {
+ if (!sorts[i]) {
sorts[i] = m.mk_bool_sort();
}
- v = m.mk_var(i, sorts[i].get());
+ v = m.mk_var(i, sorts[i]);
m_subst.apply(2, m_deltas, expr_offset(v, is_tgt?0:1), w);
result.push_back(w);
}
diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp
index dedd37a78..bd7131fea 100644
--- a/src/muz_qe/dl_rule.cpp
+++ b/src/muz_qe/dl_rule.cpp
@@ -41,6 +41,7 @@ Revision History:
#include"expr_replacer.h"
#include"bool_rewriter.h"
#include"qe_lite.h"
+#include"expr_safe_replace.h"
namespace datalog {
@@ -130,17 +131,15 @@ namespace datalog {
return index;
}
// replace vars by de-bruijn indices
- expr_substitution sub(m);
+ expr_safe_replace rep(m);
for (unsigned i = 0; i < vars.size(); ++i) {
app* v = vars[i].get();
if (names) {
names->push_back(v->get_decl()->get_name());
}
- sub.insert(v, m.mk_var(index++,m.get_sort(v)));
+ rep.insert(v, m.mk_var(index++,m.get_sort(v)));
}
- scoped_ptr rep = mk_default_expr_replacer(m);
- rep->set_substitution(&sub);
- (*rep)(fml);
+ rep(fml);
return index;
}
@@ -936,7 +935,7 @@ namespace datalog {
}
}
- void rule::get_vars(sort_ref_vector& sorts) const {
+ void rule::get_vars(ptr_vector& sorts) const {
sorts.reset();
used_vars used;
get_used_vars(used);
diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h
index 79a46052c..a9e360344 100644
--- a/src/muz_qe/dl_rule.h
+++ b/src/muz_qe/dl_rule.h
@@ -244,7 +244,7 @@ namespace datalog {
void norm_vars(rule_manager & rm);
- void get_vars(sort_ref_vector& sorts) const;
+ void get_vars(ptr_vector& sorts) const;
void to_formula(expr_ref& result) const;
diff --git a/src/muz_qe/pdr_quantifiers.cpp b/src/muz_qe/pdr_quantifiers.cpp
index 2816a58d4..9233f6314 100644
--- a/src/muz_qe/pdr_quantifiers.cpp
+++ b/src/muz_qe/pdr_quantifiers.cpp
@@ -440,7 +440,7 @@ namespace pdr {
unsigned ut_size = r.get_uninterpreted_tail_size();
unsigned t_size = r.get_tail_size();
var_subst vs(m, false);
- sort_ref_vector vars(m);
+ ptr_vector vars;
uint_set empty_index_set;
qe_lite qe(m);
diff --git a/src/muz_qe/pdr_util.cpp b/src/muz_qe/pdr_util.cpp
index fd08b1aad..1ea705e6e 100644
--- a/src/muz_qe/pdr_util.cpp
+++ b/src/muz_qe/pdr_util.cpp
@@ -1129,7 +1129,11 @@ namespace pdr {
if (a.is_numeral(lhs) || a.is_numeral(rhs)) {
return test_ineq(e);
}
- return test_term(lhs) && test_term(rhs);
+ return
+ test_term(lhs) &&
+ test_term(rhs) &&
+ !a.is_mul(lhs) &&
+ !a.is_mul(rhs);
}
bool test_term(expr* e) const {
diff --git a/src/muz_qe/proof_utils.cpp b/src/muz_qe/proof_utils.cpp
index 75c9cbb15..1e837b578 100644
--- a/src/muz_qe/proof_utils.cpp
+++ b/src/muz_qe/proof_utils.cpp
@@ -312,9 +312,10 @@ public:
};
void proof_utils::reduce_hypotheses(proof_ref& pr) {
- class reduce_hypotheses reduce(pr.get_manager());
+ ast_manager& m = pr.get_manager();
+ class reduce_hypotheses reduce(m);
reduce(pr);
- SASSERT(is_closed(pr.get_manager(), pr));
+ CTRACE("proof_utils", !is_closed(m, pr), tout << mk_pp(pr, m) << "\n";);
}
class proof_is_closed {
diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp
index 8880a9ba5..df4a55475 100644
--- a/src/muz_qe/qe_lite.cpp
+++ b/src/muz_qe/qe_lite.cpp
@@ -35,7 +35,7 @@ Revision History:
#include "dl_util.h"
#include "for_each_expr.h"
#include "expr_safe_replace.h"
-
+#include "cooperate.h"
class is_variable_proc {
public:
@@ -91,6 +91,7 @@ namespace eq {
expr_ref_vector m_subst_map;
expr_ref_buffer m_new_args;
th_rewriter m_rewriter;
+ volatile bool m_cancel;
void der_sort_vars(ptr_vector & vars, ptr_vector & definitions, unsigned_vector & order) {
order.reset();
@@ -530,6 +531,7 @@ namespace eq {
// Find all definitions
for (unsigned i = 0; i < num_args; i++) {
+ checkpoint();
if (is_var_def(is_exists, args[i], v, t)) {
unsigned idx = v->get_idx();
if(m_map.get(idx, 0) == 0) {
@@ -569,8 +571,14 @@ namespace eq {
return false;
}
+ void checkpoint() {
+ cooperate("der");
+ if (m_cancel)
+ throw tactic_exception(TACTIC_CANCELED_MSG);
+ }
+
public:
- der(ast_manager & m): m(m), a(m), m_is_variable(0), m_subst(m), m_new_exprs(m), m_subst_map(m), m_new_args(m), m_rewriter(m) {}
+ der(ast_manager & m): m(m), a(m), m_is_variable(0), m_subst(m), m_new_exprs(m), m_subst_map(m), m_new_args(m), m_rewriter(m), m_cancel(false) {}
void set_is_variable_proc(is_variable_proc& proc) { m_is_variable = &proc;}
@@ -588,6 +596,7 @@ namespace eq {
r = q;
// Keep applying reduce_quantifier1 until r doesn't change anymore
do {
+ checkpoint();
proof_ref curr_pr(m);
q = to_quantifier(r);
reduce_quantifier1(q, r, curr_pr);
@@ -605,6 +614,12 @@ namespace eq {
}
ast_manager& get_manager() const { return m; }
+
+ void set_cancel(bool f) {
+ m_rewriter.set_cancel(f);
+ m_cancel = f;
+ }
+
};
}; // namespace eq
@@ -618,6 +633,7 @@ namespace ar {
is_variable_proc* m_is_variable;
ptr_vector m_todo;
expr_mark m_visited;
+ volatile bool m_cancel;
bool is_variable(expr * e) const {
return (*m_is_variable)(e);
@@ -723,13 +739,19 @@ namespace ar {
return false;
}
+ void checkpoint() {
+ cooperate("der");
+ if (m_cancel)
+ throw tactic_exception(TACTIC_CANCELED_MSG);
+ }
public:
- der(ast_manager& m): m(m), a(m), m_is_variable(0) {}
+ der(ast_manager& m): m(m), a(m), m_is_variable(0), m_cancel(false) {}
void operator()(expr_ref_vector& fmls) {
for (unsigned i = 0; i < fmls.size(); ++i) {
+ checkpoint();
solve_select(fmls, i, fmls[i].get());
solve_neq_select(fmls, i, fmls[i].get());
}
@@ -738,6 +760,10 @@ namespace ar {
void operator()(expr* e) {}
void set_is_variable_proc(is_variable_proc& proc) { m_is_variable = &proc;}
+
+ void set_cancel(bool f) {
+ m_cancel = f;
+ }
};
}; // namespace ar
@@ -866,7 +892,6 @@ namespace fm {
unsigned m_fm_cutoff2;
unsigned m_fm_extra;
bool m_fm_occ;
- unsigned long long m_max_memory;
unsigned m_counter;
bool m_inconsistent;
expr_dependency_ref m_inconsistent_core;
@@ -1243,7 +1268,7 @@ namespace fm {
//
// ---------------------------
- fm(ast_manager & _m, params_ref const & p):
+ fm(ast_manager & _m):
m(_m),
m_allocator("fm-elim"),
m_util(m),
@@ -1251,7 +1276,6 @@ namespace fm {
m_var2expr(m),
m_new_fmls(m),
m_inconsistent_core(m) {
- updt_params(p);
m_cancel = false;
}
@@ -1259,14 +1283,13 @@ namespace fm {
reset_constraints();
}
- void updt_params(params_ref const & p) {
- m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
- m_fm_real_only = p.get_bool("fm_real_only", true);
- m_fm_limit = p.get_uint("fm_limit", 5000000);
- m_fm_cutoff1 = p.get_uint("fm_cutoff1", 8);
- m_fm_cutoff2 = p.get_uint("fm_cutoff2", 256);
- m_fm_extra = p.get_uint("fm_extra", 0);
- m_fm_occ = p.get_bool("fm_occ", false);
+ void updt_params() {
+ m_fm_real_only = true;
+ m_fm_limit = 5000000;
+ m_fm_cutoff1 = 8;
+ m_fm_cutoff2 = 256;
+ m_fm_extra = 0;
+ m_fm_occ = false;
}
void set_cancel(bool f) {
@@ -2010,11 +2033,9 @@ namespace fm {
}
void checkpoint() {
- // cooperate("fm");
+ cooperate("fm");
if (m_cancel)
throw tactic_exception(TACTIC_CANCELED_MSG);
- if (memory::get_allocation_size() > m_max_memory)
- throw tactic_exception(TACTIC_MAX_MEMORY_MSG);
}
public:
@@ -2083,11 +2104,56 @@ namespace fm {
} // namespace fm
class qe_lite::impl {
+public:
+ struct elim_cfg : public default_rewriter_cfg {
+ impl& m_imp;
+ ast_manager& m;
+ public:
+ elim_cfg(impl& i): m_imp(i), m(i.m) {}
+
+ bool reduce_quantifier(quantifier * q,
+ expr * new_body,
+ expr * const * new_patterns,
+ expr * const * new_no_patterns,
+ expr_ref & result,
+ proof_ref & result_pr) {
+ result = new_body;
+ if (is_forall(q)) {
+ result = m.mk_not(result);
+ }
+ uint_set indices;
+ for (unsigned i = 0; i < q->get_num_decls(); ++i) {
+ indices.insert(i);
+ }
+ m_imp(indices, true, result);
+ if (is_forall(q)) {
+ result = m.mk_not(result);
+ }
+ result = m.update_quantifier(
+ q,
+ q->get_num_patterns(), new_patterns,
+ q->get_num_no_patterns(), new_no_patterns, result);
+ m_imp.m_rewriter(result);
+ return true;
+ }
+ };
+
+ class elim_star : public rewriter_tpl {
+ elim_cfg m_cfg;
+ public:
+ elim_star(impl& i):
+ rewriter_tpl(i.m, false, m_cfg),
+ m_cfg(i)
+ {}
+ };
+
+private:
ast_manager& m;
- params_ref m_params;
eq::der m_der;
fm::fm m_fm;
ar::der m_array_der;
+ elim_star m_elim_star;
+ th_rewriter m_rewriter;
bool has_unique_non_ground(expr_ref_vector const& fmls, unsigned& index) {
index = fmls.size();
@@ -2106,7 +2172,13 @@ class qe_lite::impl {
}
public:
- impl(ast_manager& m): m(m), m_der(m), m_fm(m, m_params), m_array_der(m) {}
+ impl(ast_manager& m):
+ m(m),
+ m_der(m),
+ m_fm(m),
+ m_array_der(m),
+ m_elim_star(*this),
+ m_rewriter(m) {}
void operator()(app_ref_vector& vars, expr_ref& fml) {
if (vars.empty()) {
@@ -2145,14 +2217,12 @@ public:
else {
fml = tmp;
}
- }
+ }
void operator()(expr_ref& fml, proof_ref& pr) {
- // TODO apply der everywhere as a rewriting rule.
- // TODO add cancel method.
- if (is_quantifier(fml)) {
- m_der(to_quantifier(fml), fml, pr);
- }
+ expr_ref tmp(m);
+ m_elim_star(fml, tmp, pr);
+ fml = tmp;
}
void operator()(uint_set const& index_set, bool index_of_bound, expr_ref& fml) {
@@ -2195,6 +2265,14 @@ public:
TRACE("qe_lite", for (unsigned i = 0; i < fmls.size(); ++i) tout << mk_pp(fmls[i].get(), m) << "\n";);
}
+ void set_cancel(bool f) {
+ m_der.set_cancel(f);
+ m_array_der.set_cancel(f);
+ m_fm.set_cancel(f);
+ m_elim_star.set_cancel(f);
+ m_rewriter.set_cancel(f);
+ }
+
};
qe_lite::qe_lite(ast_manager& m) {
@@ -2209,6 +2287,10 @@ void qe_lite::operator()(app_ref_vector& vars, expr_ref& fml) {
(*m_impl)(vars, fml);
}
+void qe_lite::set_cancel(bool f) {
+ m_impl->set_cancel(f);
+}
+
void qe_lite::operator()(expr_ref& fml, proof_ref& pr) {
(*m_impl)(fml, pr);
}
@@ -2220,3 +2302,130 @@ void qe_lite::operator()(uint_set const& index_set, bool index_of_bound, expr_re
void qe_lite::operator()(uint_set const& index_set, bool index_of_bound, expr_ref_vector& fmls) {
(*m_impl)(index_set, index_of_bound, fmls);
}
+
+class qe_lite_tactic : public tactic {
+
+ struct imp {
+ ast_manager& m;
+ qe_lite m_qe;
+ volatile bool m_cancel;
+
+ imp(ast_manager& m, params_ref const& p):
+ m(m),
+ m_qe(m),
+ m_cancel(false)
+ {}
+
+ void set_cancel(bool f) {
+ m_cancel = f;
+ m_qe.set_cancel(f);
+ }
+
+ void checkpoint() {
+ if (m_cancel)
+ throw tactic_exception(TACTIC_CANCELED_MSG);
+ cooperate("qe-lite");
+ }
+
+ void operator()(goal_ref const & g,
+ goal_ref_buffer & result,
+ model_converter_ref & mc,
+ proof_converter_ref & pc,
+ expr_dependency_ref & core) {
+ SASSERT(g->is_well_sorted());
+ mc = 0; pc = 0; core = 0;
+ tactic_report report("qe-lite", *g);
+ proof_ref new_pr(m);
+ expr_ref new_f(m);
+ bool produce_proofs = g->proofs_enabled();
+
+ unsigned sz = g->size();
+ for (unsigned i = 0; i < sz; i++) {
+ checkpoint();
+ if (g->inconsistent())
+ break;
+ expr * f = g->form(i);
+ if (!has_quantifiers(f))
+ continue;
+ new_f = f;
+ m_qe(new_f, new_pr);
+ if (produce_proofs) {
+ new_pr = m.mk_modus_ponens(g->pr(i), new_pr);
+ }
+ g->update(i, new_f, new_pr, g->dep(i));
+ }
+ g->inc_depth();
+ result.push_back(g.get());
+ TRACE("qe", g->display(tout););
+ SASSERT(g->is_well_sorted());
+ }
+
+ };
+
+ params_ref m_params;
+ imp * m_imp;
+
+public:
+ qe_lite_tactic(ast_manager & m, params_ref const & p):
+ m_params(p) {
+ m_imp = alloc(imp, m, p);
+ }
+
+ virtual tactic * translate(ast_manager & m) {
+ return alloc(qe_lite_tactic, m, m_params);
+ }
+
+ virtual ~qe_lite_tactic() {
+ dealloc(m_imp);
+ }
+
+ virtual void updt_params(params_ref const & p) {
+ m_params = p;
+ // m_imp->updt_params(p);
+ }
+
+
+ virtual void collect_param_descrs(param_descrs & r) {
+ // m_imp->collect_param_descrs(r);
+ }
+
+ virtual void operator()(goal_ref const & in,
+ goal_ref_buffer & result,
+ model_converter_ref & mc,
+ proof_converter_ref & pc,
+ expr_dependency_ref & core) {
+ (*m_imp)(in, result, mc, pc, core);
+ }
+
+
+ virtual void collect_statistics(statistics & st) const {
+ // m_imp->collect_statistics(st);
+ }
+
+ virtual void reset_statistics() {
+ // m_imp->reset_statistics();
+ }
+
+
+ virtual void cleanup() {
+ ast_manager & m = m_imp->m;
+ imp * d = m_imp;
+ #pragma omp critical (tactic_cancel)
+ {
+ m_imp = 0;
+ }
+ dealloc(d);
+ d = alloc(imp, m, m_params);
+ #pragma omp critical (tactic_cancel)
+ {
+ m_imp = d;
+ }
+ }
+
+};
+
+tactic * mk_qe_lite_tactic(ast_manager & m, params_ref const & p) {
+ return alloc(qe_lite_tactic, m, p);
+}
+
+template class rewriter_tpl;
diff --git a/src/muz_qe/qe_lite.h b/src/muz_qe/qe_lite.h
index 3ffbf8fad..7d9239fa7 100644
--- a/src/muz_qe/qe_lite.h
+++ b/src/muz_qe/qe_lite.h
@@ -23,6 +23,9 @@ Revision History:
#include "ast.h"
#include "uint_set.h"
+#include "params.h"
+
+class tactic;
class qe_lite {
class impl;
@@ -56,6 +59,13 @@ public:
\brief full rewriting based light-weight quantifier elimination round.
*/
void operator()(expr_ref& fml, proof_ref& pr);
+
+ void set_cancel(bool f);
};
+tactic * mk_qe_lite_tactic(ast_manager & m, params_ref const & p = params_ref());
+/*
+ ADD_TACTIC("qe-light", "apply light-weight quantifier elimination.", "mk_qe_lite_tactic(m, p)")
+*/
+
#endif
diff --git a/src/parsers/smt/smtlib_solver.cpp b/src/parsers/smt/smtlib_solver.cpp
index ef28216bf..7c8572ad8 100644
--- a/src/parsers/smt/smtlib_solver.cpp
+++ b/src/parsers/smt/smtlib_solver.cpp
@@ -86,7 +86,7 @@ namespace smtlib {
benchmark.add_formula(m_ast_manager.mk_true());
}
m_ctx = alloc(cmd_context, true, &m_ast_manager, benchmark.get_logic());
- m_ctx->set_solver(mk_smt_strategic_solver(false));
+ m_ctx->set_solver_factory(mk_smt_strategic_solver_factory());
theory::expr_iterator fit = benchmark.begin_formulas();
theory::expr_iterator fend = benchmark.end_formulas();
for (; fit != fend; ++fit)
diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp
index ee93dca2f..c99c362bd 100644
--- a/src/parsers/smt2/smt2parser.cpp
+++ b/src/parsers/smt2/smt2parser.cpp
@@ -2365,7 +2365,7 @@ namespace smt2 {
parser(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & p):
m_ctx(ctx),
m_params(p),
- m_scanner(ctx, is, interactive, p),
+ m_scanner(ctx, is, interactive),
m_curr(scanner::NULL_TOKEN),
m_curr_cmd(0),
m_num_bindings(0),
diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp
index e2b2030ac..0f6101a93 100644
--- a/src/parsers/smt2/smt2scanner.cpp
+++ b/src/parsers/smt2/smt2scanner.cpp
@@ -242,7 +242,7 @@ namespace smt2 {
}
}
- scanner::scanner(cmd_context & ctx, std::istream& stream, bool interactive, params_ref const & _p):
+ scanner::scanner(cmd_context & ctx, std::istream& stream, bool interactive):
m_ctx(ctx),
m_interactive(interactive),
m_spos(0),
@@ -254,9 +254,8 @@ namespace smt2 {
m_bend(0),
m_stream(stream),
m_cache_input(false) {
-
- parser_params p(_p);
- m_smtlib2_compliant = p.smt2_compliant();
+
+ m_smtlib2_compliant = ctx.params().m_smtlib2_compliant;
for (int i = 0; i < 256; ++i) {
m_normalized[i] = (char) i;
diff --git a/src/parsers/smt2/smt2scanner.h b/src/parsers/smt2/smt2scanner.h
index c63a09ff1..7b74c752f 100644
--- a/src/parsers/smt2/smt2scanner.h
+++ b/src/parsers/smt2/smt2scanner.h
@@ -76,7 +76,7 @@ namespace smt2 {
EOF_TOKEN
};
- scanner(cmd_context & ctx, std::istream& stream, bool interactive = false, params_ref const & p = params_ref());
+ scanner(cmd_context & ctx, std::istream& stream, bool interactive = false);
~scanner() {}
diff --git a/src/parsers/util/parser_params.pyg b/src/parsers/util/parser_params.pyg
index fa8f17a00..3f7495f43 100644
--- a/src/parsers/util/parser_params.pyg
+++ b/src/parsers/util/parser_params.pyg
@@ -3,4 +3,4 @@ def_module_params('parser',
params=(('ignore_user_patterns', BOOL, False, 'ignore patterns provided by the user'),
('ignore_bad_patterns', BOOL, True, 'ignore malformed patterns'),
('error_for_visual_studio', BOOL, False, 'display error messages in Visual Studio format'),
- ('smt2_compliant', BOOL, False, 'enable/disable SMT-LIB 2.0 compliance')))
+ ))
diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp
index 1551329c6..ef0b4ad6b 100644
--- a/src/shell/smtlib_frontend.cpp
+++ b/src/shell/smtlib_frontend.cpp
@@ -30,9 +30,6 @@ Revision History:
#include"subpaving_cmds.h"
#include"smt_strategic_solver.h"
-#include"tactic2solver.h"
-#include"qfnra_nlsat_tactic.h"
-
extern bool g_display_statistics;
extern void display_config();
static clock_t g_start_time;
@@ -98,8 +95,7 @@ unsigned read_smtlib2_commands(char const * file_name) {
signal(SIGINT, on_ctrl_c);
cmd_context ctx;
- solver * s = mk_smt_strategic_solver(false);
- ctx.set_solver(s);
+ ctx.set_solver_factory(mk_smt_strategic_solver_factory());
install_dl_cmds(ctx);
install_dbg_cmds(ctx);
diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp
index 24b8e2e7c..c9d6ead88 100644
--- a/src/smt/mam.cpp
+++ b/src/smt/mam.cpp
@@ -142,6 +142,14 @@ namespace smt {
}
};
+ struct initn : public instruction {
+ // We need that because starting at Z3 3.0, some associative
+ // operators (e.g., + and *) are represented using n-ary
+ // applications.
+ // We do not need the extra field for INIT1, ..., INIT6.
+ unsigned m_num_args;
+ };
+
struct compare : public instruction {
unsigned m_reg1;
unsigned m_reg2;
@@ -608,7 +616,18 @@ namespace smt {
instruction * mk_init(unsigned n) {
SASSERT(n >= 1);
opcode op = n <= 6 ? static_cast(INIT1 + n - 1) : INITN;
- return mk_instr(op, sizeof(instruction));
+ if (op == INITN) {
+ // We store the actual number of arguments for INITN.
+ // Starting at Z3 3.0, some associative operators
+ // (e.g., + and *) are represented using n-ary
+ // applications.
+ initn * r = mk_instr(op, sizeof(initn));
+ r->m_num_args = n;
+ return r;
+ }
+ else {
+ return mk_instr(op, sizeof(instruction));
+ }
}
public:
@@ -2345,6 +2364,8 @@ namespace smt {
case INITN:
m_app = m_registers[0];
m_num_args = m_app->get_num_args();
+ if (m_num_args != static_cast(m_pc)->m_num_args)
+ goto backtrack;
for (unsigned i = 0; i < m_num_args; i++)
m_registers[i+1] = m_app->get_arg(i);
m_pc = m_pc->m_next;
@@ -3982,3 +4003,8 @@ namespace smt {
}
};
+#ifdef Z3DEBUG
+void pp(smt::code_tree * c) {
+ c->display(std::cout);
+}
+#endif
diff --git a/src/smt/params/preprocessor_params.cpp b/src/smt/params/preprocessor_params.cpp
index 375fef787..4799b8b9f 100644
--- a/src/smt/params/preprocessor_params.cpp
+++ b/src/smt/params/preprocessor_params.cpp
@@ -21,7 +21,8 @@ Revision History:
void preprocessor_params::updt_local_params(params_ref const & _p) {
smt_params_helper p(_p);
- m_macro_finder = p.macro_finder();
+ m_macro_finder = p.macro_finder();
+ m_pull_nested_quantifiers = p.pull_nested_quantifiers();
}
void preprocessor_params::updt_params(params_ref const & p) {
diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp
index f74798499..e62a3de21 100644
--- a/src/smt/params/smt_params.cpp
+++ b/src/smt/params/smt_params.cpp
@@ -32,6 +32,7 @@ void smt_params::updt_local_params(params_ref const & _p) {
m_delay_units = p.delay_units();
m_delay_units_threshold = p.delay_units_threshold();
m_preprocess = _p.get_bool("preprocess", true); // hidden parameter
+ m_soft_timeout = p.soft_timeout();
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))
@@ -48,7 +49,6 @@ 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_soft_timeout = p.m_timeout;
m_model = p.m_model;
m_model_validate = p.m_model_validate;
}
diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg
index ee583ff85..43dd1b586 100644
--- a/src/smt/params/smt_params_helper.pyg
+++ b/src/smt/params/smt_params_helper.pyg
@@ -7,12 +7,14 @@ def_module_params(module_name='smt',
('relevancy', UINT, 2, 'relevancy propagation heuristic: 0 - disabled, 1 - relevancy is tracked by only affects quantifier instantiation, 2 - relevancy is tracked, and an atom is only asserted if it is relevant'),
('macro_finder', BOOL, False, 'try to find universally quantified formulas that can be viewed as macros'),
('ematching', BOOL, True, 'E-Matching based quantifier instantiation'),
- ('phase_selection', UINT, 4, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences'),
+ ('phase_selection', UINT, 3, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences'),
('restart_strategy', UINT, 1, '0 - geometric, 1 - inner-outer-geometric, 2 - luby, 3 - fixed, 4 - arithmetic'),
('restart_factor', DOUBLE, 1.1, 'when using geometric (or inner-outer-geometric) progression of restarts, it specifies the constant used to multiply the currect restart threshold'),
('case_split', UINT, 1, '0 - case split based on variable activity, 1 - similar to 0, but delay case splits created during the search, 2 - similar to 0, but cache the relevancy, 3 - case split based on relevancy (structural splitting), 4 - case split on relevancy and activity, 5 - case split on relevancy and current goal'),
('delay_units', BOOL, False, 'if true then z3 will not restart when a unit clause is learned'),
('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ingored if delay_units is false'),
+ ('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'),
+ ('soft_timeout', UINT, 0, 'soft timeout (0 means no timeout)'),
('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'),
('mbqi.max_cexs_incr', UINT, 0, 'increment for MBQI_MAX_CEXS, the increment is performed after each round of MBQI'),
diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp
index 34742e3a0..92110bc1a 100644
--- a/src/smt/proto_model/proto_model.cpp
+++ b/src/smt/proto_model/proto_model.cpp
@@ -155,7 +155,7 @@ bool eval(func_interp & fi, simplifier & s, expr * const * args, expr_ref & resu
basic_simplifier_plugin * bs = static_cast(s.get_plugin(fi.m().get_basic_family_id()));
for (unsigned k = 0; k < fi.num_entries(); k++) {
func_entry const * curr = fi.get_entry(k);
- SASSERT(!curr->eq_args(fi.get_arity(), args));
+ SASSERT(!curr->eq_args(fi.m(), fi.get_arity(), args));
if (!actuals_are_values || !curr->args_are_values()) {
expr_ref_buffer eqs(fi.m());
unsigned i = fi.get_arity();
diff --git a/src/smt/smt_implied_equalities.cpp b/src/smt/smt_implied_equalities.cpp
index c6f28d4b2..70229ccab 100644
--- a/src/smt/smt_implied_equalities.cpp
+++ b/src/smt/smt_implied_equalities.cpp
@@ -21,23 +21,21 @@ Revision History:
#include "smt_implied_equalities.h"
#include "union_find.h"
-#include "cmd_context.h"
-#include "parametric_cmd.h"
#include "ast_pp.h"
-#include "arith_decl_plugin.h"
-#include "datatype_decl_plugin.h"
#include "array_decl_plugin.h"
#include "uint_set.h"
-#include "model_v2_pp.h"
#include "smt_value_sort.h"
-
+#include "model_smt2_pp.h"
+#include "stopwatch.h"
+#include "model.h"
+#include "solver.h"
namespace smt {
class get_implied_equalities_impl {
ast_manager& m;
- smt::kernel& m_solver;
+ solver& m_solver;
union_find_default_ctx m_df;
union_find m_uf;
array_util m_array_util;
@@ -98,7 +96,7 @@ namespace smt {
++m_stats_calls;
m_solver.push();
m_solver.assert_expr(m.mk_not(m.mk_eq(s, t)));
- bool is_eq = l_false == m_solver.check();
+ bool is_eq = l_false == m_solver.check_sat(0,0);
m_solver.pop(1);
TRACE("get_implied_equalities", tout << mk_pp(t, m) << " = " << mk_pp(s, m) << " " << (is_eq?"eq":"unrelated") << "\n";);
if (is_eq) {
@@ -125,7 +123,7 @@ namespace smt {
m_stats_timer.start();
m_solver.push();
m_solver.assert_expr(m.mk_not(m.mk_eq(s, t)));
- bool is_eq = l_false == m_solver.check();
+ bool is_eq = l_false == m_solver.check_sat(0,0);
m_solver.pop(1);
m_stats_timer.stop();
TRACE("get_implied_equalities", tout << mk_pp(t, m) << " = " << mk_pp(s, m) << " " << (is_eq?"eq":"unrelated") << "\n";);
@@ -168,7 +166,7 @@ namespace smt {
terms[i].term = m.mk_app(m_array_util.get_family_id(), OP_SELECT, 0, 0, args.size(), args.c_ptr());
}
assert_relevant(terms);
- lbool is_sat = m_solver.check();
+ lbool is_sat = m_solver.check_sat(0,0);
model_ref model1;
m_solver.get_model(model1);
SASSERT(model1.get());
@@ -218,7 +216,7 @@ namespace smt {
expr* s = terms[vec[j]].term;
m_solver.push();
m_solver.assert_expr(m.mk_not(m.mk_eq(t, s)));
- lbool is_sat = m_solver.check();
+ lbool is_sat = m_solver.check_sat(0,0);
m_solver.pop(1);
TRACE("get_implied_equalities", tout << mk_pp(t, m) << " = " << mk_pp(s, m) << " " << is_sat << "\n";);
if (is_sat == l_false) {
@@ -237,7 +235,7 @@ namespace smt {
if (!non_values.empty()) {
- TRACE("get_implied_equalities", model_v2_pp(tout, *model, true););
+ TRACE("get_implied_equalities", model_smt2_pp(tout, m, *model, 0););
get_implied_equalities_filter_basic(non_values, terms);
//get_implied_equalities_basic(terms);
}
@@ -321,7 +319,7 @@ namespace smt {
public:
- get_implied_equalities_impl(smt::kernel& s) : m(s.m()), m_solver(s), m_uf(m_df), m_array_util(m), m_stats_calls(0) {}
+ get_implied_equalities_impl(ast_manager& m, solver& s) : m(m), m_solver(s), m_uf(m_df), m_array_util(m), m_stats_calls(0) {}
lbool operator()(unsigned num_terms, expr* const* terms, unsigned* class_ids) {
params_ref p;
@@ -338,7 +336,7 @@ namespace smt {
m_solver.push();
assert_relevant(num_terms, terms);
- lbool is_sat = m_solver.check();
+ lbool is_sat = m_solver.check_sat(0,0);
if (is_sat != l_false) {
model_ref model;
@@ -374,8 +372,8 @@ namespace smt {
stopwatch get_implied_equalities_impl::s_timer;
stopwatch get_implied_equalities_impl::s_stats_val_eq_timer;
- lbool implied_equalities(smt::kernel& solver, unsigned num_terms, expr* const* terms, unsigned* class_ids) {
- get_implied_equalities_impl gi(solver);
+ lbool implied_equalities(ast_manager& m, solver& solver, unsigned num_terms, expr* const* terms, unsigned* class_ids) {
+ get_implied_equalities_impl gi(m, solver);
return gi(num_terms, terms, class_ids);
}
};
@@ -552,7 +550,7 @@ namespace smt {
m_solver.assert_expr(m.mk_implies(eq_lit, eq));
}
m_solver.assert_expr(m.mk_not(m.mk_and(eqs.size(), eqs.c_ptr())));
- lbool is_sat = m_solver.check();
+ lbool is_sat = m_solver.check_sat(0,0);
switch(is_sat) {
case l_false:
for (unsigned i = 0; i + 1 < terms.size(); ++i) {
diff --git a/src/smt/smt_implied_equalities.h b/src/smt/smt_implied_equalities.h
index 6fc002ff1..ec9b4bd21 100644
--- a/src/smt/smt_implied_equalities.h
+++ b/src/smt/smt_implied_equalities.h
@@ -23,13 +23,16 @@ Revision History:
#ifndef __SMT_IMPLIED_EQUALITIES_H__
#define __SMT_IMPLIED_EQUALITIES_H__
-#include"smt_kernel.h"
+#include"smt_solver.h"
+#include"lbool.h"
+#include"ast.h"
namespace smt {
lbool implied_equalities(
- kernel & solver,
+ ast_manager & m,
+ solver & solver,
unsigned num_terms, expr* const* terms,
unsigned* class_ids);
diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp
index 556222c33..b3f16a3ce 100644
--- a/src/smt/smt_internalizer.cpp
+++ b/src/smt/smt_internalizer.cpp
@@ -907,7 +907,7 @@ namespace smt {
}
enode * e = enode::mk(m_manager, m_region, m_app2enode, n, generation, suppress_args, merge_tf, m_scope_lvl, cgc_enabled, true);
TRACE("mk_enode_detail", tout << "e.get_num_args() = " << e->get_num_args() << "\n";);
- if (n->get_num_args() == 0 && m_manager.is_value(n))
+ if (n->get_num_args() == 0 && m_manager.is_unique_value(n))
e->mark_as_interpreted();
TRACE("mk_var_bug", tout << "mk_enode: " << id << "\n";);
TRACE("generation", tout << "mk_enode: " << id << " " << generation << "\n";);
diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp
index e8c1c6698..1fbb58847 100644
--- a/src/smt/smt_solver.cpp
+++ b/src/smt/smt_solver.cpp
@@ -25,166 +25,114 @@ namespace smt {
class solver : public solver_na2as {
smt_params m_params;
- smt::kernel * m_context;
+ smt::kernel m_context;
progress_callback * m_callback;
+ symbol m_logic;
public:
- solver():m_context(0), m_callback(0) {}
-
+ solver(ast_manager & m, params_ref const & p, symbol const & l):
+ solver_na2as(m),
+ m_params(p),
+ m_context(m, m_params) {
+ m_logic = l;
+ if (m_logic != symbol::null)
+ m_context.set_logic(m_logic);
+ }
+
virtual ~solver() {
- if (m_context != 0)
- dealloc(m_context);
}
virtual void updt_params(params_ref const & p) {
m_params.updt_params(p);
- if (m_context == 0)
- return;
- m_context->updt_params(p);
+ m_context.updt_params(p);
}
virtual void collect_param_descrs(param_descrs & r) {
- if (m_context == 0) {
- ast_manager m;
- reg_decl_plugins(m);
- smt::kernel s(m, m_params);
- s.collect_param_descrs(r);
- }
- else {
- m_context->collect_param_descrs(r);
- }
- }
-
- virtual void init_core(ast_manager & m, symbol const & logic) {
- reset();
- // We can throw exceptions when creating a smt::kernel object
- // So, we should create the smt::kernel outside of the criticial section
- // block. OMP does not allow exceptions to cross critical section boundaries.
- smt::kernel * new_kernel = alloc(smt::kernel, m, m_params);
- #pragma omp critical (solver)
- {
- m_context = new_kernel;
- if (m_callback)
- m_context->set_progress_callback(m_callback);
- }
- if (logic != symbol::null)
- m_context->set_logic(logic);
+ m_context.collect_param_descrs(r);
}
virtual void collect_statistics(statistics & st) const {
- if (m_context == 0) {
- return;
- }
- else {
- m_context->collect_statistics(st);
- }
- }
-
- virtual void reset_core() {
- if (m_context != 0) {
- #pragma omp critical (solver)
- {
- dealloc(m_context);
- m_context = 0;
- }
- }
- }
-
- // An exception may be thrown when creating a smt::kernel.
- // So, there is no guarantee that m_context != 0 when
- // using smt_solver from the SMT 2.0 command line frontend.
- void check_context() const {
- if (m_context == 0)
- throw default_exception("Z3 failed to create solver, check previous error messages");
+ m_context.collect_statistics(st);
}
virtual void assert_expr(expr * t) {
- check_context();
- m_context->assert_expr(t);
+ m_context.assert_expr(t);
}
virtual void push_core() {
- check_context();
- m_context->push();
+ m_context.push();
}
virtual void pop_core(unsigned n) {
- check_context();
- m_context->pop(n);
+ m_context.pop(n);
}
virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) {
- check_context();
TRACE("solver_na2as", tout << "smt_solver::check_sat_core: " << num_assumptions << "\n";);
- return m_context->check(num_assumptions, assumptions);
+ return m_context.check(num_assumptions, assumptions);
}
virtual void get_unsat_core(ptr_vector & r) {
- check_context();
- unsigned sz = m_context->get_unsat_core_size();
+ unsigned sz = m_context.get_unsat_core_size();
for (unsigned i = 0; i < sz; i++)
- r.push_back(m_context->get_unsat_core_expr(i));
+ r.push_back(m_context.get_unsat_core_expr(i));
}
virtual void get_model(model_ref & m) {
- check_context();
- m_context->get_model(m);
+ m_context.get_model(m);
}
virtual proof * get_proof() {
- check_context();
- return m_context->get_proof();
+ return m_context.get_proof();
}
virtual std::string reason_unknown() const {
- check_context();
- return m_context->last_failure_as_string();
+ return m_context.last_failure_as_string();
}
virtual void get_labels(svector & r) {
- check_context();
buffer tmp;
- m_context->get_relevant_labels(0, tmp);
+ m_context.get_relevant_labels(0, tmp);
r.append(tmp.size(), tmp.c_ptr());
}
virtual void set_cancel(bool f) {
-#pragma omp critical (solver)
- {
- if (m_context)
- m_context->set_cancel(f);
- }
+ m_context.set_cancel(f);
}
virtual void set_progress_callback(progress_callback * callback) {
m_callback = callback;
- if (m_context)
- m_context->set_progress_callback(callback);
+ m_context.set_progress_callback(callback);
}
virtual unsigned get_num_assertions() const {
- if (m_context)
- return m_context->size();
- else
- return 0;
+ return m_context.size();
}
virtual expr * get_assertion(unsigned idx) const {
- SASSERT(m_context);
SASSERT(idx < get_num_assertions());
- return m_context->get_formulas()[idx];
+ return m_context.get_formulas()[idx];
}
virtual void display(std::ostream & out) const {
- if (m_context)
- m_context->display(out);
- else
- out << "(solver)";
+ m_context.display(out);
}
};
};
-solver * mk_smt_solver() {
- return alloc(smt::solver);
+solver * mk_smt_solver(ast_manager & m, params_ref const & p, symbol const & logic) {
+ return alloc(smt::solver, m, p, logic);
}
+
+class smt_solver_factory : public solver_factory {
+public:
+ virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) {
+ return mk_smt_solver(m, p, logic);
+ }
+};
+
+solver_factory * mk_smt_solver_factory() {
+ return alloc(smt_solver_factory);
+}
+
diff --git a/src/smt/smt_solver.h b/src/smt/smt_solver.h
index e9af9aafa..81c9a1319 100644
--- a/src/smt/smt_solver.h
+++ b/src/smt/smt_solver.h
@@ -21,8 +21,13 @@ Notes:
#ifndef _SMT_SOLVER_H_
#define _SMT_SOLVER_H_
-class solver;
+#include"ast.h"
+#include"params.h"
-solver * mk_smt_solver();
+class solver;
+class solver_factory;
+
+solver * mk_smt_solver(ast_manager & m, params_ref const & p, symbol const & logic);
+solver_factory * mk_smt_solver_factory();
#endif
diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp
index 2c7d58b1a..95b150a8c 100644
--- a/src/smt/tactic/smt_tactic.cpp
+++ b/src/smt/tactic/smt_tactic.cpp
@@ -139,6 +139,7 @@ public:
ast_manager & m = in->m();
TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " "
<< " PREPROCESS: " << fparams().m_preprocess << "\n";
+ tout << "RELEVANCY: " << fparams().m_relevancy_lvl << "\n";
tout << "fail-if-inconclusive: " << m_fail_if_inconclusive << "\n";
tout << "params_ref: " << m_params_ref << "\n";);
TRACE("smt_tactic_detail", in->display(tout););
diff --git a/src/smt/user_plugin/user_decl_plugin.h b/src/smt/user_plugin/user_decl_plugin.h
index dc2fd55a1..9e6bd70c4 100644
--- a/src/smt/user_plugin/user_decl_plugin.h
+++ b/src/smt/user_plugin/user_decl_plugin.h
@@ -49,6 +49,8 @@ public:
virtual bool is_value(app*) const;
+ virtual bool is_unique_value(app * a) const { return is_value(a); }
+
bool is_value(func_decl *) const;
virtual void get_op_names(svector & op_names, symbol const & logic);
diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp
new file mode 100644
index 000000000..cd4191e76
--- /dev/null
+++ b/src/solver/combined_solver.cpp
@@ -0,0 +1,289 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ combined_solver.cpp
+
+Abstract:
+
+ Implements the solver API by combining two solvers.
+
+ This is a replacement for the strategic_solver class.
+
+Author:
+
+ Leonardo (leonardo) 2012-12-11
+
+Notes:
+
+--*/
+#include"solver.h"
+#include"scoped_timer.h"
+#include"combined_solver_params.hpp"
+#define PS_VB_LVL 15
+
+/**
+ \brief Implementation of the solver API that combines two given solvers.
+
+ The combined solver has two modes:
+ - non-incremental
+ - incremental
+ In non-incremental mode, the first solver is used.
+ In incremental mode, the second one is used.
+
+ A timeout for the second solver can be specified.
+ If the timeout is reached, then the first solver is executed.
+
+ The object switches to incremental when:
+ - push is used
+ - assertions are peformed after a check_sat
+ - parameter ignore_solver1==false
+*/
+class combined_solver : public solver {
+public:
+ // Behavior when the incremental solver returns unknown.
+ enum inc_unknown_behavior {
+ IUB_RETURN_UNDEF, // just return unknown
+ IUB_USE_TACTIC_IF_QF, // invoke tactic if problem is quantifier free
+ IUB_USE_TACTIC // invoke tactic
+ };
+
+private:
+ bool m_inc_mode;
+ bool m_check_sat_executed;
+ bool m_use_solver1_results;
+ ref m_solver1;
+ ref m_solver2;
+
+ bool m_ignore_solver1;
+ inc_unknown_behavior m_inc_unknown_behavior;
+ unsigned m_inc_timeout;
+
+ void switch_inc_mode() {
+ m_inc_mode = true;
+ }
+
+ struct aux_timeout_eh : public event_handler {
+ solver * m_solver;
+ volatile bool m_canceled;
+ aux_timeout_eh(solver * s):m_solver(s), m_canceled(false) {}
+ virtual void operator()() {
+ m_solver->cancel();
+ m_canceled = true;
+ }
+ };
+
+ void updt_local_params(params_ref const & _p) {
+ combined_solver_params p(_p);
+ m_inc_timeout = p.solver2_timeout();
+ m_ignore_solver1 = p.ignore_solver1();
+ m_inc_unknown_behavior = static_cast(p.solver2_unknown());
+ }
+
+ bool has_quantifiers() const {
+ unsigned sz = get_num_assertions();
+ for (unsigned i = 0; i < sz; i++) {
+ if (::has_quantifiers(get_assertion(i)))
+ return true;
+ }
+ return false;
+ }
+
+ bool use_solver1_when_undef() const {
+ switch (m_inc_unknown_behavior) {
+ case IUB_RETURN_UNDEF: return false;
+ case IUB_USE_TACTIC_IF_QF: return !has_quantifiers();
+ case IUB_USE_TACTIC: return true;
+ default:
+ UNREACHABLE();
+ return false;
+ }
+ }
+
+public:
+ combined_solver(solver * s1, solver * s2, params_ref const & p) {
+ m_solver1 = s1;
+ m_solver2 = s2;
+ updt_local_params(p);
+ m_inc_mode = false;
+ m_check_sat_executed = false;
+ m_use_solver1_results = true;
+ }
+
+ virtual void updt_params(params_ref const & p) {
+ m_solver1->updt_params(p);
+ m_solver2->updt_params(p);
+ updt_local_params(p);
+ }
+
+ virtual void collect_param_descrs(param_descrs & r) {
+ m_solver1->collect_param_descrs(r);
+ m_solver2->collect_param_descrs(r);
+ combined_solver_params::collect_param_descrs(r);
+ }
+
+ virtual void set_produce_models(bool f) {
+ m_solver1->set_produce_models(f);
+ m_solver2->set_produce_models(f);
+ }
+
+ virtual void assert_expr(expr * t) {
+ if (m_check_sat_executed)
+ switch_inc_mode();
+ m_solver1->assert_expr(t);
+ m_solver2->assert_expr(t);
+ }
+
+ virtual void assert_expr(expr * t, expr * a) {
+ if (m_check_sat_executed)
+ switch_inc_mode();
+ m_solver1->assert_expr(t, a);
+ m_solver2->assert_expr(t, a);
+ }
+
+ virtual void push() {
+ switch_inc_mode();
+ m_solver1->push();
+ m_solver2->push();
+ }
+
+ virtual void pop(unsigned n) {
+ switch_inc_mode();
+ m_solver1->pop(n);
+ m_solver2->pop(n);
+ }
+
+ virtual unsigned get_scope_level() const {
+ return m_solver1->get_scope_level();
+ }
+
+ virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) {
+ m_check_sat_executed = true;
+
+ if (num_assumptions > 0 || // assumptions were provided
+ m_ignore_solver1) {
+ // must use incremental solver
+ switch_inc_mode();
+ m_use_solver1_results = false;
+ return m_solver2->check_sat(num_assumptions, assumptions);
+ }
+
+ if (m_inc_mode) {
+ if (m_inc_timeout == UINT_MAX) {
+ IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"using solver 2 (without a timeout)\")\n";);
+ lbool r = m_solver2->check_sat(0, 0);
+ if (r != l_undef || !use_solver1_when_undef()) {
+ m_use_solver1_results = false;
+ return r;
+ }
+ }
+ else {
+ IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"using solver 2 (with timeout)\")\n";);
+ aux_timeout_eh eh(m_solver2.get());
+ lbool r;
+ {
+ scoped_timer timer(m_inc_timeout, &eh);
+ r = m_solver2->check_sat(0, 0);
+ }
+ if ((r != l_undef || !use_solver1_when_undef()) && !eh.m_canceled) {
+ m_use_solver1_results = false;
+ return r;
+ }
+ }
+ IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"solver 2 failed, trying solver1\")\n";);
+ }
+
+ IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"using solver 1\")\n";);
+ m_use_solver1_results = true;
+ return m_solver1->check_sat(0, 0);
+ }
+
+ virtual void set_cancel(bool f) {
+ m_solver1->set_cancel(f);
+ m_solver2->set_cancel(f);
+ }
+
+ virtual void set_progress_callback(progress_callback * callback) {
+ m_solver1->set_progress_callback(callback);
+ m_solver2->set_progress_callback(callback);
+ }
+
+ virtual unsigned get_num_assertions() const {
+ return m_solver1->get_num_assertions();
+ }
+
+ virtual expr * get_assertion(unsigned idx) const {
+ return m_solver1->get_assertion(idx);
+ }
+
+ virtual void display(std::ostream & out) const {
+ m_solver1->display(out);
+ }
+
+ virtual void collect_statistics(statistics & st) const {
+ if (m_use_solver1_results)
+ m_solver1->collect_statistics(st);
+ else
+ m_solver2->collect_statistics(st);
+ }
+
+ virtual void get_unsat_core(ptr_vector & r) {
+ if (m_use_solver1_results)
+ m_solver1->get_unsat_core(r);
+ else
+ m_solver2->get_unsat_core(r);
+ }
+
+ virtual void get_model(model_ref & m) {
+ if (m_use_solver1_results)
+ m_solver1->get_model(m);
+ else
+ m_solver2->get_model(m);
+ }
+
+ virtual proof * get_proof() {
+ if (m_use_solver1_results)
+ return m_solver1->get_proof();
+ else
+ return m_solver2->get_proof();
+ }
+
+ virtual std::string reason_unknown() const {
+ if (m_use_solver1_results)
+ return m_solver1->reason_unknown();
+ else
+ return m_solver2->reason_unknown();
+ }
+
+ virtual void get_labels(svector & r) {
+ if (m_use_solver1_results)
+ return m_solver1->get_labels(r);
+ else
+ return m_solver2->get_labels(r);
+ }
+
+};
+
+
+solver * mk_combined_solver(solver * s1, solver * s2, params_ref const & p) {
+ return alloc(combined_solver, s1, s2, p);
+}
+
+class combined_solver_factory : public solver_factory {
+ scoped_ptr m_f1;
+ scoped_ptr m_f2;
+public:
+ combined_solver_factory(solver_factory * f1, solver_factory * f2):m_f1(f1), m_f2(f2) {}
+ virtual ~combined_solver_factory() {}
+
+ virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) {
+ return mk_combined_solver((*m_f1)(m, p, proofs_enabled, models_enabled, unsat_core_enabled, logic),
+ (*m_f2)(m, p, proofs_enabled, models_enabled, unsat_core_enabled, logic),
+ p);
+ }
+};
+
+solver_factory * mk_combined_solver_factory(solver_factory * f1, solver_factory * f2) {
+ return alloc(combined_solver_factory, f1, f2);
+}
diff --git a/src/solver/combined_solver.h b/src/solver/combined_solver.h
new file mode 100644
index 000000000..2ccace7f0
--- /dev/null
+++ b/src/solver/combined_solver.h
@@ -0,0 +1,32 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ combined_solver.cpp
+
+Abstract:
+
+ Implements the solver API by combining two solvers.
+
+ This is a replacement for the strategic_solver class.
+
+Author:
+
+ Leonardo (leonardo) 2012-12-11
+
+Notes:
+
+--*/
+#ifndef _COMBINED_SOLVER_H_
+#define _COMBINED_SOLVER_H_
+
+#include"params.h"
+
+class solver;
+class solver_factory;
+
+solver * mk_combined_solver(solver * s1, solver * s2, params_ref const & p);
+solver_factory * mk_combined_solver_factory(solver_factory * f1, solver_factory * f2);
+
+#endif
diff --git a/src/solver/combined_solver_params.pyg b/src/solver/combined_solver_params.pyg
new file mode 100644
index 000000000..7e1635c16
--- /dev/null
+++ b/src/solver/combined_solver_params.pyg
@@ -0,0 +1,9 @@
+def_module_params('combined_solver',
+ description='combines two solvers: non-incremental (solver1) and incremental (solver2)',
+ export=True,
+ params=(('solver2_timeout', UINT, UINT_MAX, "fallback to solver 1 after timeout even when in incremental model"),
+ ('ignore_solver1', BOOL, False, "if true, solver 2 is always used"),
+ ('solver2_unknown', UINT, 1, "what should be done when solver 2 returns unknown: 0 - just return unknown, 1 - execute solver 1 if quantifier free problem, 2 - execute solver 1")
+ ))
+
+
diff --git a/src/solver/solver.h b/src/solver/solver.h
index 5cd3da52b..e047bace1 100644
--- a/src/solver/solver.h
+++ b/src/solver/solver.h
@@ -23,6 +23,14 @@ Notes:
#include"progress_callback.h"
#include"params.h"
+class solver;
+
+class solver_factory {
+public:
+ virtual ~solver_factory() {}
+ virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) = 0;
+};
+
/**
\brief Abstract interface for making solvers available in the Z3
API and front-ends such as SMT 2.0 and (legacy) SMT 1.0.
@@ -34,7 +42,6 @@ Notes:
- statistics
- results based on check_sat_result API
- interruption (set_cancel)
- - resets
*/
class solver : public check_sat_result {
public:
@@ -50,12 +57,6 @@ public:
*/
virtual void collect_param_descrs(param_descrs & r) {}
- /**
- \brief Enable/Disable proof production for this solver object.
-
- It is invoked before init(m, logic).
- */
- virtual void set_produce_proofs(bool f) {}
/**
\brief Enable/Disable model generation for this solver object.
@@ -63,23 +64,7 @@ public:
The user may optionally invoke it after init(m, logic).
*/
virtual void set_produce_models(bool f) {}
- /**
- \brief Enable/Disable unsat core generation for this solver object.
-
- It is invoked before init(m, logic).
- */
- virtual void set_produce_unsat_cores(bool f) {}
- /**
- \brief Initialize the solver object with the given ast_manager and logic.
- */
- virtual void init(ast_manager & m, symbol const & logic) = 0;
-
- /**
- \brief Reset the solver internal state. All assertions should be removed.
- */
- virtual void reset() = 0;
-
/**
\brief Add a new formula to the assertion stack.
*/
diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp
index e71a9873b..9889b5872 100644
--- a/src/solver/solver_na2as.cpp
+++ b/src/solver/solver_na2as.cpp
@@ -22,8 +22,8 @@ Notes:
#include"solver_na2as.h"
#include"ast_smt2_pp.h"
-solver_na2as::solver_na2as() {
- m_manager = 0;
+solver_na2as::solver_na2as(ast_manager & m):
+ m_manager(m) {
}
solver_na2as::~solver_na2as() {
@@ -35,23 +35,16 @@ void solver_na2as::assert_expr(expr * t, expr * a) {
assert_expr(t);
}
else {
- SASSERT(m_manager != 0);
SASSERT(is_uninterp_const(a));
- SASSERT(m_manager->is_bool(a));
- TRACE("solver_na2as", tout << "asserting\n" << mk_ismt2_pp(t, *m_manager) << "\n" << mk_ismt2_pp(a, *m_manager) << "\n";);
- m_manager->inc_ref(a);
+ SASSERT(m_manager.is_bool(a));
+ TRACE("solver_na2as", tout << "asserting\n" << mk_ismt2_pp(t, m_manager) << "\n" << mk_ismt2_pp(a, m_manager) << "\n";);
+ m_manager.inc_ref(a);
m_assumptions.push_back(a);
- expr_ref new_t(*m_manager);
- new_t = m_manager->mk_implies(a, t);
+ expr_ref new_t(m_manager);
+ new_t = m_manager.mk_implies(a, t);
assert_expr(new_t);
}
}
-
-void solver_na2as::init(ast_manager & m, symbol const & logic) {
- SASSERT(m_assumptions.empty());
- m_manager = &m;
- init_core(m, logic);
-}
struct append_assumptions {
ptr_vector & m_assumptions;
@@ -89,9 +82,9 @@ void solver_na2as::pop(unsigned n) {
}
void solver_na2as::restore_assumptions(unsigned old_sz) {
- SASSERT(old_sz == 0 || m_manager != 0);
+ SASSERT(old_sz == 0);
for (unsigned i = old_sz; i < m_assumptions.size(); i++) {
- m_manager->dec_ref(m_assumptions[i]);
+ m_manager.dec_ref(m_assumptions[i]);
}
m_assumptions.shrink(old_sz);
}
@@ -100,7 +93,3 @@ unsigned solver_na2as::get_scope_level() const {
return m_scopes.size();
}
-void solver_na2as::reset() {
- reset_core();
- restore_assumptions(0);
-}
diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h
index eb12479fc..15750344a 100644
--- a/src/solver/solver_na2as.h
+++ b/src/solver/solver_na2as.h
@@ -25,30 +25,26 @@ Notes:
#include"solver.h"
class solver_na2as : public solver {
- ast_manager * m_manager;
+ ast_manager & m_manager;
ptr_vector m_assumptions;
unsigned_vector m_scopes;
void restore_assumptions(unsigned old_sz);
public:
- solver_na2as();
+ solver_na2as(ast_manager & m);
virtual ~solver_na2as();
virtual void assert_expr(expr * t, expr * a);
virtual void assert_expr(expr * t) = 0;
// Subclasses of solver_na2as should redefine the following *_core methods instead of these ones.
- virtual void init(ast_manager & m, symbol const & logic);
virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions);
virtual void push();
virtual void pop(unsigned n);
virtual unsigned get_scope_level() const;
- virtual void reset();
protected:
- virtual void init_core(ast_manager & m, symbol const & logic) = 0;
virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0;
virtual void push_core() = 0;
virtual void pop_core(unsigned n) = 0;
- virtual void reset_core() = 0;
};
diff --git a/src/solver/strategic_solver.cpp b/src/solver/strategic_solver.cpp
deleted file mode 100644
index 40d77066e..000000000
--- a/src/solver/strategic_solver.cpp
+++ /dev/null
@@ -1,533 +0,0 @@
-/*++
-Copyright (c) 2011 Microsoft Corporation
-
-Module Name:
-
- strategic_solver.h
-
-Abstract:
-
- Strategies -> Solver
-
-Author:
-
- Leonardo (leonardo) 2011-05-19
-
-Notes:
-
---*/
-#include"strategic_solver.h"
-#include"scoped_timer.h"
-#include"ast_smt2_pp.h"
-
-// minimum verbosity level for portfolio verbose messages
-#define PS_VB_LVL 15
-
-
-strategic_solver::ctx::ctx(ast_manager & m):
- m_assertions(m),
- m_assertion_names(m) {
- }
-
-strategic_solver::strategic_solver():
- m_manager(0),
- m_force_tactic(false),
- m_inc_mode(false),
- m_check_sat_executed(false),
- m_inc_solver(0),
- m_inc_solver_timeout(UINT_MAX),
- m_inc_unknown_behavior(IUB_USE_TACTIC_IF_QF),
- m_default_fct(0),
- m_curr_tactic(0),
- m_proof(0),
- m_core(0),
- m_callback(0) {
- m_use_inc_solver_results = false;
- DEBUG_CODE(m_num_scopes = 0;);
- m_produce_proofs = false;
- m_produce_models = false;
- m_produce_unsat_cores = false;
- m_auto_config = true;
-}
-
-strategic_solver::~strategic_solver() {
- SASSERT(!m_curr_tactic);
- dictionary::iterator it = m_logic2fct.begin();
- dictionary::iterator end = m_logic2fct.end();
- for (; it != end; ++it) {
- dealloc(it->m_value);
- }
- if (m_proof)
- m().dec_ref(m_proof);
- if (m_core)
- m().dec_ref(m_core);
-}
-
-bool strategic_solver::has_quantifiers() const {
- unsigned sz = get_num_assertions();
- for (unsigned i = 0; i < sz; i++) {
- if (::has_quantifiers(get_assertion(i)))
- return true;
- }
- return false;
-}
-
-/**
- \brief Return true if a tactic should be used when the incremental solver returns unknown.
-*/
-bool strategic_solver::use_tactic_when_undef() const {
- switch (m_inc_unknown_behavior) {
- case IUB_RETURN_UNDEF: return false;
- case IUB_USE_TACTIC_IF_QF: return !has_quantifiers();
- case IUB_USE_TACTIC: return true;
- default:
- UNREACHABLE();
- return false;
- }
-}
-
-void strategic_solver::set_inc_solver(solver * s) {
- SASSERT(m_inc_solver == 0);
- SASSERT(m_num_scopes == 0);
- m_inc_solver = s;
- if (m_callback)
- m_inc_solver->set_progress_callback(m_callback);
-}
-
-void strategic_solver::updt_params(params_ref const & p) {
- if (m_inc_solver)
- m_inc_solver->updt_params(p);
- m_params = p;
- m_auto_config = p.get_bool("auto_config", true);
-}
-
-void strategic_solver::collect_param_descrs(param_descrs & r) {
- if (m_inc_solver)
- m_inc_solver->collect_param_descrs(r);
-}
-
-/**
- \brief Set a timeout for each check_sat query that is processed by the inc_solver.
- timeout == UINT_MAX means infinite
- After the timeout a strategy is used.
-*/
-void strategic_solver::set_inc_solver_timeout(unsigned timeout) {
- m_inc_solver_timeout = timeout;
-}
-
-/**
- \brief Set the default tactic factory.
- It is used if there is no tactic for a given logic.
-*/
-void strategic_solver::set_default_tactic(tactic_factory * fct) {
- m_default_fct = fct;
-}
-
-/**
- \brief Set a tactic factory for a given logic.
-*/
-void strategic_solver::set_tactic_for(symbol const & logic, tactic_factory * fct) {
- tactic_factory * old_fct;
- if (m_logic2fct.find(logic, old_fct)) {
- dealloc(old_fct);
- }
- m_logic2fct.insert(logic, fct);
-}
-
-void strategic_solver::init(ast_manager & m, symbol const & logic) {
- m_manager = &m;
- m_logic = logic;
- if (m_inc_mode) {
- SASSERT(m_inc_solver);
- m_inc_solver->init(m, logic);
- }
- m_ctx = alloc(ctx, m);
- TRACE("strategic_solver", tout << "strategic_solver was initialized.\n";);
-}
-
-unsigned strategic_solver::get_num_assertions() const {
- if (m_ctx == 0)
- return 0;
- return m_ctx->m_assertions.size();
-}
-
-expr * strategic_solver::get_assertion(unsigned idx) const {
- SASSERT(m_ctx);
- return m_ctx->m_assertions.get(idx);
-}
-
-expr * strategic_solver::get_assertion_name(unsigned idx) const {
- SASSERT(m_ctx);
- SASSERT(m_produce_unsat_cores);
- return m_ctx->m_assertion_names.get(idx);
-}
-
-void strategic_solver::set_produce_proofs(bool f) {
- m_produce_proofs = f;
- // do not need to propagate to inc_solver since flag cannot be changed after initialization
-}
-
-void strategic_solver::set_produce_models(bool f) {
- m_produce_models = f;
- if (m_inc_solver)
- m_inc_solver->set_produce_models(f);
-}
-
-void strategic_solver::set_produce_unsat_cores(bool f) {
- m_produce_unsat_cores = f;
- // do not need to propagate to inc_solver since flag cannot be changed after initialization
-}
-
-// delayed inc solver initialization
-void strategic_solver::init_inc_solver() {
- if (m_inc_mode)
- return; // solver was already initialized
- if (!m_inc_solver)
- return; // inc solver was not installed
- m_inc_mode = true;
- m_inc_solver->set_produce_proofs(m_produce_proofs);
- m_inc_solver->set_produce_models(m_produce_models);
- m_inc_solver->set_produce_unsat_cores(m_produce_unsat_cores);
- m_inc_solver->init(m(), m_logic);
- unsigned sz = get_num_assertions();
- if (m_produce_unsat_cores) {
- SASSERT(m_ctx->m_assertions.size() == m_ctx->m_assertion_names.size());
- for (unsigned i = 0; i < sz; i++) {
- m_inc_solver->assert_expr(get_assertion(i), get_assertion_name(i));
- }
- }
- else {
- for (unsigned i = 0; i < sz; i++) {
- m_inc_solver->assert_expr(get_assertion(i));
- }
- }
-}
-
-void strategic_solver::collect_statistics(statistics & st) const {
- if (m_use_inc_solver_results) {
- SASSERT(m_inc_solver);
- m_inc_solver->collect_statistics(st);
- }
- else {
- if (m_curr_tactic)
- m_curr_tactic->collect_statistics(st); // m_curr_tactic is still being executed.
- else
- st.copy(m_stats);
- }
-}
-
-void strategic_solver::reset() {
- m_ctx = 0;
- m_logic = symbol::null;
- m_inc_mode = false;
- m_check_sat_executed = false;
- if (m_inc_solver)
- m_inc_solver->reset();
- SASSERT(!m_curr_tactic);
- m_use_inc_solver_results = false;
- reset_results();
-}
-
-void strategic_solver::reset_results() {
- m_use_inc_solver_results = false;
- m_model = 0;
- if (m_proof) {
- m().dec_ref(m_proof);
- m_proof = 0;
- }
- if (m_core) {
- m().dec_ref(m_core);
- m_core = 0;
- }
- m_reason_unknown.clear();
- m_stats.reset();
-}
-
-void strategic_solver::assert_expr(expr * t) {
- if (m_check_sat_executed && !m_inc_mode) {
- // a check sat was already executed --> switch to incremental mode
- init_inc_solver();
- SASSERT(m_inc_solver == 0 || m_inc_mode);
- }
- if (m_inc_mode) {
- SASSERT(m_inc_solver);
- m_inc_solver->assert_expr(t);
- }
- SASSERT(m_ctx);
- m_ctx->m_assertions.push_back(t);
- if (m_produce_unsat_cores)
- m_ctx->m_assertion_names.push_back(0);
-}
-
-void strategic_solver::assert_expr(expr * t, expr * a) {
- if (m_check_sat_executed && !m_inc_mode) {
- // a check sat was already executed --> switch to incremental mode
- init_inc_solver();
- SASSERT(m_inc_solver == 0 || m_inc_mode);
- }
- if (m_inc_mode) {
- SASSERT(m_inc_solver);
- m_inc_solver->assert_expr(t, a);
- }
- SASSERT(m_ctx);
- m_ctx->m_assertions.push_back(t);
- if (m_produce_unsat_cores)
- m_ctx->m_assertion_names.push_back(a);
-}
-
-void strategic_solver::push() {
- DEBUG_CODE(m_num_scopes++;);
- init_inc_solver();
- if (m_inc_solver)
- m_inc_solver->push();
- m_ctx->m_scopes.push_back(m_ctx->m_assertions.size());
-}
-
-void strategic_solver::pop(unsigned n) {
- DEBUG_CODE({
- SASSERT(n <= m_num_scopes);
- m_num_scopes -= n;
- });
- init_inc_solver();
- if (m_inc_solver)
- m_inc_solver->pop(n);
-
- SASSERT(m_ctx);
- unsigned new_lvl = m_ctx->m_scopes.size() - n;
- unsigned old_sz = m_ctx->m_scopes[new_lvl];
- m_ctx->m_assertions.shrink(old_sz);
- if (m_produce_unsat_cores)
- m_ctx->m_assertion_names.shrink(old_sz);
- m_ctx->m_scopes.shrink(new_lvl);
-}
-
-unsigned strategic_solver::get_scope_level() const {
- if (m_ctx == 0)
- return 0;
- return m_ctx->m_scopes.size();
-}
-
-struct aux_timeout_eh : public event_handler {
- solver * m_solver;
- volatile bool m_canceled;
- aux_timeout_eh(solver * s):m_solver(s), m_canceled(false) {}
- virtual void operator()() {
- m_solver->cancel();
- m_canceled = true;
- }
-};
-
-struct strategic_solver::mk_tactic {
- strategic_solver * m_solver;
-
- mk_tactic(strategic_solver * s, tactic_factory * f, params_ref const & p):m_solver(s) {
- ast_manager & m = s->m();
- tactic * tct = (*f)(m, p);
- tct->set_logic(s->m_logic);
- if (s->m_callback)
- tct->set_progress_callback(s->m_callback);
- #pragma omp critical (strategic_solver)
- {
- s->m_curr_tactic = tct;
- }
- }
-
- ~mk_tactic() {
- #pragma omp critical (strategic_solver)
- {
- m_solver->m_curr_tactic = 0;
- }
- }
-};
-
-tactic_factory * strategic_solver::get_tactic_factory() const {
- tactic_factory * f = 0;
- if (m_logic2fct.find(m_logic, f))
- return f;
- return m_default_fct.get();
-}
-
-lbool strategic_solver::check_sat_with_assumptions(unsigned num_assumptions, expr * const * assumptions) {
- if (!m_inc_solver) {
- IF_VERBOSE(PS_VB_LVL, verbose_stream() << "incremental solver was not installed, returning unknown...\n";);
- m_use_inc_solver_results = false;
- m_reason_unknown = "incomplete";
- return l_undef;
- }
- init_inc_solver();
- m_use_inc_solver_results = true;
- TRACE("strategic_solver", tout << "invoking inc_solver with " << num_assumptions << " assumptions\n";);
- return m_inc_solver->check_sat(num_assumptions, assumptions);
-}
-
-lbool strategic_solver::check_sat(unsigned num_assumptions, expr * const * assumptions) {
- TRACE("strategic_solver", tout << "assumptions at strategic_solver:\n";
- for (unsigned i = 0; i < num_assumptions; i++) {
- tout << mk_ismt2_pp(assumptions[i], m()) << "\n";
- }
- tout << "m_produce_unsat_cores: " << m_produce_unsat_cores << ", m_inc_mode: " << m_inc_mode << "\n";);
- reset_results();
- m_check_sat_executed = true;
- if (num_assumptions > 0 || // assumptions were provided
- (!m_auto_config && !m_force_tactic) // auto config and force_tactic are turned off
- ) {
- // must use incremental solver
- return check_sat_with_assumptions(num_assumptions, assumptions);
- }
-
- tactic_factory * factory = get_tactic_factory();
- if (factory == 0)
- init_inc_solver(); // try to switch to incremental solver
-
- if (m_inc_mode) {
- SASSERT(m_inc_solver);
- unsigned timeout = m_inc_solver_timeout;
- if (factory == 0)
- timeout = UINT_MAX; // there is no tactic available
- if (timeout == UINT_MAX) {
- IF_VERBOSE(PS_VB_LVL, verbose_stream() << "using incremental solver (without a timeout).\n";);
- m_use_inc_solver_results = true;
- lbool r = m_inc_solver->check_sat(0, 0);
- if (r != l_undef || factory == 0 || !use_tactic_when_undef()) {
- m_use_inc_solver_results = true;
- return r;
- }
- }
- else {
- IF_VERBOSE(PS_VB_LVL, verbose_stream() << "using incremental solver (with timeout).\n";);
- SASSERT(factory != 0);
- aux_timeout_eh eh(m_inc_solver.get());
- lbool r;
- {
- scoped_timer timer(m_inc_solver_timeout, &eh);
- r = m_inc_solver->check_sat(0, 0);
- }
- if ((r != l_undef || !use_tactic_when_undef()) && !eh.m_canceled) {
- m_use_inc_solver_results = true;
- return r;
- }
- }
- IF_VERBOSE(PS_VB_LVL, verbose_stream() << "incremental solver failed, trying tactic.\n";);
- }
-
- m_use_inc_solver_results = false;
-
- if (factory == 0) {
- IF_VERBOSE(PS_VB_LVL, verbose_stream() << "there is no tactic available for the current logic.\n";);
- m_reason_unknown = "incomplete";
- return l_undef;
- }
-
- goal_ref g = alloc(goal, m(), m_produce_proofs, m_produce_models, m_produce_unsat_cores);
- unsigned sz = get_num_assertions();
- if (m_produce_unsat_cores) {
- SASSERT(m_ctx->m_assertions.size() == m_ctx->m_assertion_names.size());
- for (unsigned i = 0; i < sz; i++)
- g->assert_expr(get_assertion(i), get_assertion_name(i));
- }
- else {
- for (unsigned i = 0; i < sz; i++)
- g->assert_expr(get_assertion(i));
- }
- expr_dependency_ref core(m());
-
- TRACE("strategic_solver", tout << "using goal...\n"; g->display_with_dependencies(tout););
-
- mk_tactic tct_maker(this, factory, m_params);
- SASSERT(m_curr_tactic);
-
- proof_ref pr(m());
- lbool r = ::check_sat(*(m_curr_tactic.get()), g, m_model, pr, core, m_reason_unknown);
- m_curr_tactic->collect_statistics(m_stats);
- if (pr) {
- m_proof = pr;
- m().inc_ref(m_proof);
- }
- if (core) {
- m_core = core;
- m().inc_ref(m_core);
- }
- return r;
-}
-
-void strategic_solver::set_cancel(bool f) {
- if (m_inc_solver)
- m_inc_solver->set_cancel(f);
- #pragma omp critical (strategic_solver)
- {
- if (m_curr_tactic)
- m_curr_tactic->set_cancel(f);
- }
-}
-
-void strategic_solver::get_unsat_core(ptr_vector & r) {
- TRACE("strategic_solver", tout << "get_unsat_core, m_use_inc_solver_results: " << m_use_inc_solver_results << "\n";);
- if (m_use_inc_solver_results) {
- SASSERT(m_inc_solver);
- m_inc_solver->get_unsat_core(r);
- }
- else {
- m().linearize(m_core, r);
- }
-}
-
-void strategic_solver::get_model(model_ref & m) {
- if (m_use_inc_solver_results) {
- SASSERT(m_inc_solver);
- m_inc_solver->get_model(m);
- }
- else {
- m = m_model;
- }
-}
-
-proof * strategic_solver::get_proof() {
- if (m_use_inc_solver_results) {
- SASSERT(m_inc_solver);
- return m_inc_solver->get_proof();
- }
- else {
- return m_proof;
- }
-}
-
-std::string strategic_solver::reason_unknown() const {
- if (m_use_inc_solver_results) {
- SASSERT(m_inc_solver);
- return m_inc_solver->reason_unknown();
- }
- return m_reason_unknown;
-}
-
-void strategic_solver::get_labels(svector & r) {
- if (m_use_inc_solver_results) {
- SASSERT(m_inc_solver);
- m_inc_solver->get_labels(r);
- }
-}
-
-void strategic_solver::set_progress_callback(progress_callback * callback) {
- m_callback = callback;
- if (m_inc_solver)
- m_inc_solver->set_progress_callback(callback);
-}
-
-void strategic_solver::display(std::ostream & out) const {
- if (m_manager) {
- unsigned num = get_num_assertions();
- out << "(solver";
- for (unsigned i = 0; i < num; i++) {
- out << "\n " << mk_ismt2_pp(get_assertion(i), m(), 2);
- }
- out << ")";
- }
- else {
- out << "(solver)";
- }
-}
-
-
-
-
-
-
diff --git a/src/solver/strategic_solver.h b/src/solver/strategic_solver.h
deleted file mode 100644
index 1883a88cd..000000000
--- a/src/solver/strategic_solver.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*++
-Copyright (c) 2011 Microsoft Corporation
-
-Module Name:
-
- strategic_solver.h
-
-Abstract:
-
- Strategies -> Solver
-
-Author:
-
- Leonardo (leonardo) 2011-05-19
-
-Notes:
-
---*/
-#ifndef _STRATEGIC_SOLVER_H_
-#define _STRATEGIC_SOLVER_H_
-
-#include"solver.h"
-#include"tactic.h"
-
-class progress_callback;
-
-/**
- \brief Implementation of the solver API that supports:
- - a different tactic for each logic
- - a general purpose tactic
- - a default incremental solver
-
- The strategic solver has two modes:
- - non-incremental
- - incremental
- In non-incremental mode, tactics are used.
- In incremental model, the incremental (general purpose) solver is used.
-
- A timeout for the incremental solver can be specified.
- If the timeout is reached, then the strategic_solver tries to solve the problem using tactics.
-
- The strategic_solver switches to incremental when:
- - push is used
- - assertions are peformed after a check_sat
- It goes back to non_incremental mode when:
- - reset is invoked.
-*/
-class strategic_solver : public solver {
-public:
- // Behavior when the incremental solver returns unknown.
- enum inc_unknown_behavior {
- IUB_RETURN_UNDEF, // just return unknown
- IUB_USE_TACTIC_IF_QF, // invoke tactic if problem is quantifier free
- IUB_USE_TACTIC // invoke tactic
- };
-
-private:
- ast_manager * m_manager;
- params_ref m_params;
- symbol m_logic;
- bool m_force_tactic; // use tactics even when auto_config = false
- bool m_inc_mode;
- bool m_check_sat_executed;
- scoped_ptr m_inc_solver;
- unsigned m_inc_solver_timeout;
- inc_unknown_behavior m_inc_unknown_behavior;
- scoped_ptr m_default_fct;
- dictionary m_logic2fct;
-
- ref m_curr_tactic;
-
- bool m_use_inc_solver_results;
- model_ref m_model;
- proof * m_proof;
- expr_dependency * m_core;
- std::string m_reason_unknown;
- statistics m_stats;
-
- struct ctx {
- expr_ref_vector m_assertions;
- expr_ref_vector m_assertion_names;
- unsigned_vector m_scopes;
- ctx(ast_manager & m);
- };
- scoped_ptr m_ctx;
-
-#ifdef Z3DEBUG
- unsigned m_num_scopes;
-#endif
-
- bool m_produce_proofs;
- bool m_produce_models;
- bool m_produce_unsat_cores;
-
- bool m_auto_config;
-
- progress_callback * m_callback;
-
- void reset_results();
- void init_inc_solver();
- tactic_factory * get_tactic_factory() const;
- lbool check_sat_with_assumptions(unsigned num_assumptions, expr * const * assumptions);
-
- struct mk_tactic;
-
- bool has_quantifiers() const;
- bool use_tactic_when_undef() const;
-
-public:
- strategic_solver();
- ~strategic_solver();
-
- ast_manager & m() const { SASSERT(m_manager); return *m_manager; }
-
- void set_inc_solver(solver * s);
- void set_inc_solver_timeout(unsigned timeout);
- void set_default_tactic(tactic_factory * fct);
- void set_tactic_for(symbol const & logic, tactic_factory * fct);
- void set_inc_unknown_behavior(inc_unknown_behavior b) { m_inc_unknown_behavior = b; }
- void force_tactic(bool f) { m_force_tactic = f; }
-
- virtual void updt_params(params_ref const & p);
- virtual void collect_param_descrs(param_descrs & r);
-
- virtual void set_produce_proofs(bool f);
- virtual void set_produce_models(bool f);
- virtual void set_produce_unsat_cores(bool f);
-
- unsigned get_num_assertions() const;
- expr * get_assertion(unsigned idx) const;
- expr * get_assertion_name(unsigned idx) const;
-
- virtual void display(std::ostream & out) const;
-
- virtual void init(ast_manager & m, symbol const & logic);
- virtual void collect_statistics(statistics & st) const;
- virtual void reset();
- virtual void assert_expr(expr * t);
- virtual void assert_expr(expr * t, expr * a);
- virtual void push();
- virtual void pop(unsigned n);
- virtual unsigned get_scope_level() const;
- virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions);
- virtual void get_unsat_core(ptr_vector & r);
- virtual void get_model(model_ref & m);
- virtual proof * get_proof();
- virtual std::string reason_unknown() const;
- virtual void get_labels(svector & r);
- virtual void set_cancel(bool f);
- virtual void set_progress_callback(progress_callback * callback);
-};
-
-#endif
diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp
index e630f9c78..1268fbcea 100644
--- a/src/solver/tactic2solver.cpp
+++ b/src/solver/tactic2solver.cpp
@@ -19,96 +19,115 @@ Author:
Notes:
--*/
-#include"tactic2solver.h"
+#include"solver_na2as.h"
+#include"tactic.h"
#include"ast_smt2_pp.h"
-tactic2solver_core::ctx::ctx(ast_manager & m, symbol const & logic):
- m_logic(logic),
+/**
+ \brief Simulates the incremental solver interface using a tactic.
+
+ Every query will be solved from scratch. So, this is not a good
+ option for applications trying to solve many easy queries that a
+ similar to each other.
+*/
+class tactic2solver : public solver_na2as {
+ expr_ref_vector m_assertions;
+ unsigned_vector m_scopes;
+ ref m_result;
+ tactic_ref m_tactic;
+ symbol m_logic;
+ params_ref m_params;
+ bool m_produce_models;
+ bool m_produce_proofs;
+ bool m_produce_unsat_cores;
+public:
+ tactic2solver(ast_manager & m, tactic * t, params_ref const & p, bool produce_proofs, bool produce_models, bool produce_unsat_cores, symbol const & logic);
+ virtual ~tactic2solver();
+
+ virtual void updt_params(params_ref const & p);
+ virtual void collect_param_descrs(param_descrs & r);
+
+ virtual void set_produce_models(bool f) { m_produce_models = f; }
+
+ virtual void assert_expr(expr * t);
+
+ virtual void push_core();
+ virtual void pop_core(unsigned n);
+ virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions);
+
+ virtual void set_cancel(bool f);
+
+ virtual void collect_statistics(statistics & st) const;
+ virtual void get_unsat_core(ptr_vector & r);
+ virtual void get_model(model_ref & m);
+ virtual proof * get_proof();
+ virtual std::string reason_unknown() const;
+ virtual void get_labels(svector & r) {}
+
+ virtual void set_progress_callback(progress_callback * callback) {}
+
+ virtual unsigned get_num_assertions() const;
+ virtual expr * get_assertion(unsigned idx) const;
+
+ virtual void display(std::ostream & out) const;
+};
+
+tactic2solver::tactic2solver(ast_manager & m, tactic * t, params_ref const & p, bool produce_proofs, bool produce_models, bool produce_unsat_cores, symbol const & logic):
+ solver_na2as(m),
m_assertions(m) {
+
+ m_tactic = t;
+ m_logic = logic;
+ m_params = p;
+
+ m_produce_models = produce_models;
+ m_produce_proofs = produce_proofs;
+ m_produce_unsat_cores = produce_unsat_cores;
}
-tactic2solver_core::~tactic2solver_core() {
+tactic2solver::~tactic2solver() {
}
-void tactic2solver_core::init_core(ast_manager & m, symbol const & logic) {
- m_ctx = alloc(ctx, m, logic);
-}
-
-void tactic2solver_core::updt_params(params_ref const & p) {
+void tactic2solver::updt_params(params_ref const & p) {
m_params = p;
}
-void tactic2solver_core::collect_param_descrs(param_descrs & r) {
- if (m_ctx) {
- if (!m_ctx->m_tactic) {
- #pragma omp critical (tactic2solver_core)
- {
- m_ctx->m_tactic = get_tactic(m_ctx->m(), m_params);
- }
-
- if (m_ctx->m_tactic) {
- m_ctx->m_tactic->collect_param_descrs(r);
- }
-
- #pragma omp critical (tactic2solver_core)
- {
- m_ctx->m_tactic = 0;
- }
- }
- else {
- m_ctx->m_tactic->collect_param_descrs(r);
- }
- }
+void tactic2solver::collect_param_descrs(param_descrs & r) {
+ if (m_tactic.get())
+ m_tactic->collect_param_descrs(r);
}
-void tactic2solver_core::reset_core() {
- SASSERT(m_ctx);
- m_ctx->m_assertions.reset();
- m_ctx->m_scopes.reset();
- m_ctx->m_result = 0;
+void tactic2solver::assert_expr(expr * t) {
+ m_assertions.push_back(t);
+ m_result = 0;
}
-void tactic2solver_core::assert_expr(expr * t) {
- SASSERT(m_ctx);
- m_ctx->m_assertions.push_back(t);
- m_ctx->m_result = 0;
+void tactic2solver::push_core() {
+ m_scopes.push_back(m_assertions.size());
+ m_result = 0;
}
-void tactic2solver_core::push_core() {
- SASSERT(m_ctx);
- m_ctx->m_scopes.push_back(m_ctx->m_assertions.size());
- m_ctx->m_result = 0;
+void tactic2solver::pop_core(unsigned n) {
+ unsigned new_lvl = m_scopes.size() - n;
+ unsigned old_sz = m_scopes[new_lvl];
+ m_assertions.shrink(old_sz);
+ m_scopes.shrink(new_lvl);
+ m_result = 0;
}
-void tactic2solver_core::pop_core(unsigned n) {
- SASSERT(m_ctx);
- unsigned new_lvl = m_ctx->m_scopes.size() - n;
- unsigned old_sz = m_ctx->m_scopes[new_lvl];
- m_ctx->m_assertions.shrink(old_sz);
- m_ctx->m_scopes.shrink(new_lvl);
- m_ctx->m_result = 0;
-}
-
-lbool tactic2solver_core::check_sat_core(unsigned num_assumptions, expr * const * assumptions) {
- SASSERT(m_ctx);
- ast_manager & m = m_ctx->m();
- params_ref p = m_params;
- #pragma omp critical (tactic2solver_core)
- {
- m_ctx->m_tactic = get_tactic(m, p);
- if (m_ctx->m_tactic) {
- m_ctx->m_result = alloc(simple_check_sat_result, m);
- }
- }
- if (!m_ctx->m_tactic)
- return l_undef;
- tactic & t = *(m_ctx->m_tactic);
- simple_check_sat_result & result = *(m_ctx->m_result);
+lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) {
+ if (m_tactic.get() == 0)
+ return l_false;
+ ast_manager & m = m_assertions.m();
+ m_result = alloc(simple_check_sat_result, m);
+ m_tactic->cleanup();
+ m_tactic->updt_params(m_params);
+ m_tactic->set_logic(m_logic);
goal_ref g = alloc(goal, m, m_produce_proofs, m_produce_models, m_produce_unsat_cores);
- t.set_logic(m_ctx->m_logic);
- unsigned sz = m_ctx->m_assertions.size();
+
+ unsigned sz = m_assertions.size();
for (unsigned i = 0; i < sz; i++) {
- g->assert_expr(m_ctx->m_assertions.get(i));
+ g->assert_expr(m_assertions.get(i));
}
for (unsigned i = 0; i < num_assumptions; i++) {
g->assert_expr(assumptions[i], m.mk_asserted(assumptions[i]), m.mk_leaf(assumptions[i]));
@@ -119,17 +138,17 @@ lbool tactic2solver_core::check_sat_core(unsigned num_assumptions, expr * const
expr_dependency_ref core(m);
std::string reason_unknown = "unknown";
try {
- switch (::check_sat(t, g, md, pr, core, reason_unknown)) {
+ switch (::check_sat(*m_tactic, g, md, pr, core, reason_unknown)) {
case l_true:
- result.set_status(l_true);
+ m_result->set_status(l_true);
break;
case l_false:
- result.set_status(l_false);
+ m_result->set_status(l_false);
break;
default:
- result.set_status(l_undef);
+ m_result->set_status(l_undef);
if (reason_unknown != "")
- result.m_unknown = reason_unknown;
+ m_result->m_unknown = reason_unknown;
break;
}
}
@@ -137,112 +156,115 @@ lbool tactic2solver_core::check_sat_core(unsigned num_assumptions, expr * const
throw ex;
}
catch (z3_exception & ex) {
- TRACE("tactic2solver_core", tout << "exception: " << ex.msg() << "\n";);
- result.set_status(l_undef);
- result.m_unknown = ex.msg();
+ TRACE("tactic2solver", tout << "exception: " << ex.msg() << "\n";);
+ m_result->set_status(l_undef);
+ m_result->m_unknown = ex.msg();
}
- t.collect_statistics(result.m_stats);
- result.m_model = md;
- result.m_proof = pr;
+ m_tactic->collect_statistics(m_result->m_stats);
+ m_result->m_model = md;
+ m_result->m_proof = pr;
if (m_produce_unsat_cores) {
ptr_vector core_elems;
m.linearize(core, core_elems);
- result.m_core.append(core_elems.size(), core_elems.c_ptr());
+ m_result->m_core.append(core_elems.size(), core_elems.c_ptr());
}
-
- #pragma omp critical (tactic2solver_core)
- {
- m_ctx->m_tactic = 0;
- }
- return result.status();
+ m_tactic->cleanup();
+ return m_result->status();
}
-void tactic2solver_core::set_cancel(bool f) {
- #pragma omp critical (tactic2solver_core)
- {
- if (m_ctx && m_ctx->m_tactic)
- m_ctx->m_tactic->set_cancel(f);
- }
+void tactic2solver::set_cancel(bool f) {
+ if (m_tactic.get())
+ m_tactic->set_cancel(f);
}
-void tactic2solver_core::collect_statistics(statistics & st) const {
- if (m_ctx->m_result.get())
- m_ctx->m_result->collect_statistics(st);
+void tactic2solver::collect_statistics(statistics & st) const {
+ if (m_result.get())
+ m_result->collect_statistics(st);
}
-void tactic2solver_core::get_unsat_core(ptr_vector & r) {
- if (m_ctx->m_result.get())
- m_ctx->m_result->get_unsat_core(r);
+void tactic2solver::get_unsat_core(ptr_vector & r) {
+ if (m_result.get())
+ m_result->get_unsat_core(r);
}
-void tactic2solver_core::get_model(model_ref & m) {
- if (m_ctx->m_result.get())
- m_ctx->m_result->get_model(m);
+void tactic2solver::get_model(model_ref & m) {
+ if (m_result.get())
+ m_result->get_model(m);
}
-proof * tactic2solver_core::get_proof() {
- if (m_ctx->m_result.get())
- return m_ctx->m_result->get_proof();
+proof * tactic2solver::get_proof() {
+ if (m_result.get())
+ return m_result->get_proof();
else
return 0;
}
-std::string tactic2solver_core::reason_unknown() const {
- if (m_ctx->m_result.get())
- return m_ctx->m_result->reason_unknown();
+std::string tactic2solver::reason_unknown() const {
+ if (m_result.get())
+ return m_result->reason_unknown();
else
return std::string("unknown");
}
-unsigned tactic2solver_core::get_num_assertions() const {
- if (m_ctx)
- return m_ctx->m_assertions.size();
- else
- return 0;
+unsigned tactic2solver::get_num_assertions() const {
+ return m_assertions.size();
}
-expr * tactic2solver_core::get_assertion(unsigned idx) const {
- SASSERT(m_ctx);
- return m_ctx->m_assertions.get(idx);
+expr * tactic2solver::get_assertion(unsigned idx) const {
+ return m_assertions.get(idx);
}
-void tactic2solver_core::display(std::ostream & out) const {
- if (m_ctx) {
- ast_manager & m = m_ctx->m_assertions.m();
- unsigned num = m_ctx->m_assertions.size();
- out << "(solver";
- for (unsigned i = 0; i < num; i++) {
- out << "\n " << mk_ismt2_pp(m_ctx->m_assertions.get(i), m, 2);
- }
- out << ")";
+void tactic2solver::display(std::ostream & out) const {
+ ast_manager & m = m_assertions.m();
+ unsigned num = m_assertions.size();
+ out << "(solver";
+ for (unsigned i = 0; i < num; i++) {
+ out << "\n " << mk_ismt2_pp(m_assertions.get(i), m, 2);
}
- else {
- out << "(solver)";
+ out << ")";
+}
+
+solver * mk_tactic2solver(ast_manager & m,
+ tactic * t,
+ params_ref const & p,
+ bool produce_proofs,
+ bool produce_models,
+ bool produce_unsat_cores,
+ symbol const & logic) {
+ return alloc(tactic2solver, m, t, p, produce_proofs, produce_models, produce_unsat_cores, logic);
+}
+
+class tactic2solver_factory : public solver_factory {
+ ref m_tactic;
+public:
+ tactic2solver_factory(tactic * t):m_tactic(t) {
}
+
+ virtual ~tactic2solver_factory() {}
+
+ virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) {
+ return mk_tactic2solver(m, m_tactic.get(), p, proofs_enabled, models_enabled, unsat_core_enabled, logic);
+ }
+};
+
+class tactic_factory2solver_factory : public solver_factory {
+ scoped_ptr m_factory;
+public:
+ tactic_factory2solver_factory(tactic_factory * f):m_factory(f) {
+ }
+
+ virtual ~tactic_factory2solver_factory() {}
+
+ virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) {
+ tactic * t = (*m_factory)(m, p);
+ return mk_tactic2solver(m, t, p, proofs_enabled, models_enabled, unsat_core_enabled, logic);
+ }
+};
+
+solver_factory * mk_tactic2solver_factory(tactic * t) {
+ return alloc(tactic2solver_factory, t);
}
-tactic2solver::tactic2solver(tactic * t):
- m_tactic(t) {
-}
-
-tactic2solver::~tactic2solver() {
-}
-
-tactic * tactic2solver::get_tactic(ast_manager & m, params_ref const & p) {
- m_tactic->cleanup();
- m_tactic->updt_params(p);
- return m_tactic.get();
-}
-
-tactic_factory2solver::~tactic_factory2solver() {
-}
-
-void tactic_factory2solver::set_tactic(tactic_factory * f) {
- m_tactic_factory = f;
-}
-
-tactic * tactic_factory2solver::get_tactic(ast_manager & m, params_ref const & p) {
- if (m_tactic_factory == 0)
- return 0;
- return (*m_tactic_factory)(m, p);
+solver_factory * mk_tactic_factory2solver_factory(tactic_factory * f) {
+ return alloc(tactic_factory2solver_factory, f);
}
diff --git a/src/solver/tactic2solver.h b/src/solver/tactic2solver.h
index 0a057b04b..f20b1c4dd 100644
--- a/src/solver/tactic2solver.h
+++ b/src/solver/tactic2solver.h
@@ -22,88 +22,22 @@ Notes:
#ifndef _TACTIC2SOLVER_H_
#define _TACTIC2SOLVER_H_
-#include"solver_na2as.h"
-#include"tactic.h"
+#include"params.h"
+class ast_manager;
+class tactic;
+class tactic_factory;
+class solver;
+class solver_factory;
-/**
- \brief Simulates the incremental solver interface using a tactic.
-
- Every query will be solved from scratch. So, this is not a good
- option for applications trying to solve many easy queries that a
- similar to each other.
-*/
-class tactic2solver_core : public solver_na2as {
- struct ctx {
- symbol m_logic;
- expr_ref_vector m_assertions;
- unsigned_vector m_scopes;
- ref m_result;
- tactic_ref m_tactic;
- ctx(ast_manager & m, symbol const & logic);
- ast_manager & m() const { return m_assertions.m(); }
- };
- scoped_ptr m_ctx;
- params_ref m_params;
- bool m_produce_models;
- bool m_produce_proofs;
- bool m_produce_unsat_cores;
-public:
- tactic2solver_core():m_ctx(0), m_produce_models(false), m_produce_proofs(false), m_produce_unsat_cores(false) {}
- virtual ~tactic2solver_core();
-
- virtual tactic * get_tactic(ast_manager & m, params_ref const & p) = 0;
-
- virtual void updt_params(params_ref const & p);
- virtual void collect_param_descrs(param_descrs & r);
-
- virtual void set_produce_proofs(bool f) { m_produce_proofs = f; }
- virtual void set_produce_models(bool f) { m_produce_models = f; }
- virtual void set_produce_unsat_cores(bool f) { m_produce_unsat_cores = f; }
-
- virtual void assert_expr(expr * t);
-
- virtual void init_core(ast_manager & m, symbol const & logic);
- virtual void reset_core();
- virtual void push_core();
- virtual void pop_core(unsigned n);
- virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions);
-
- virtual void set_cancel(bool f);
-
- virtual void collect_statistics(statistics & st) const;
- virtual void get_unsat_core(ptr_vector & r);
- virtual void get_model(model_ref & m);
- virtual proof * get_proof();
- virtual std::string reason_unknown() const;
- virtual void get_labels(svector & r) {}
-
- virtual void set_progress_callback(progress_callback * callback) {}
-
- virtual unsigned get_num_assertions() const;
- virtual expr * get_assertion(unsigned idx) const;
-
- virtual void display(std::ostream & out) const;
-};
-
-class tactic2solver : public tactic2solver_core {
- tactic_ref m_tactic;
-public:
- tactic2solver(tactic * t);
- virtual ~tactic2solver();
- virtual tactic * get_tactic(ast_manager & m, params_ref const & p);
-};
-
-
-class tactic_factory2solver : public tactic2solver_core {
- scoped_ptr m_tactic_factory;
-public:
- virtual ~tactic_factory2solver();
- /**
- \brief Set tactic that will be used to process the satisfiability queries.
- */
- void set_tactic(tactic_factory * f);
- virtual tactic * get_tactic(ast_manager & m, params_ref const & p);
-};
+solver * mk_tactic2solver(ast_manager & m,
+ tactic * t = 0,
+ params_ref const & p = params_ref(),
+ bool produce_proofs = false,
+ bool produce_models = true,
+ bool produce_unsat_cores = false,
+ symbol const & logic = symbol::null);
+solver_factory * mk_tactic2solver_factory(tactic * t);
+solver_factory * mk_tactic_factory2solver_factory(tactic_factory * f);
#endif
diff --git a/src/tactic/core/cofactor_elim_term_ite.cpp b/src/tactic/core/cofactor_elim_term_ite.cpp
index 78d532357..d81b4fa13 100644
--- a/src/tactic/core/cofactor_elim_term_ite.cpp
+++ b/src/tactic/core/cofactor_elim_term_ite.cpp
@@ -355,12 +355,12 @@ struct cofactor_elim_term_ite::imp {
expr * lhs;
expr * rhs;
if (m.is_eq(t, lhs, rhs)) {
- if (m.is_value(lhs)) {
+ if (m.is_unique_value(lhs)) {
m_term = rhs;
m_value = to_app(lhs);
TRACE("set_cofactor_atom", tout << "term:\n" << mk_ismt2_pp(m_term, m) << "\nvalue: " << mk_ismt2_pp(m_value, m) << "\n";);
}
- else if (m.is_value(rhs)) {
+ else if (m.is_unique_value(rhs)) {
m_term = lhs;
m_value = to_app(rhs);
TRACE("set_cofactor_atom", tout << "term:\n" << mk_ismt2_pp(m_term, m) << "\nvalue: " << mk_ismt2_pp(m_value, m) << "\n";);
diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp
index 686c5128d..59ed2dcd3 100644
--- a/src/tactic/core/reduce_args_tactic.cpp
+++ b/src/tactic/core/reduce_args_tactic.cpp
@@ -128,7 +128,7 @@ struct reduce_args_tactic::imp {
unsigned j = n->get_num_args();
while (j > 0) {
--j;
- if (m_manager.is_value(n->get_arg(j)))
+ if (m_manager.is_unique_value(n->get_arg(j)))
return;
}
m_non_cadidates.insert(d);
@@ -185,13 +185,13 @@ struct reduce_args_tactic::imp {
it->m_value.reserve(j);
while (j > 0) {
--j;
- it->m_value.set(j, m_manager.is_value(n->get_arg(j)));
+ it->m_value.set(j, m_manager.is_unique_value(n->get_arg(j)));
}
} else {
SASSERT(j == it->m_value.size());
while (j > 0) {
--j;
- it->m_value.set(j, it->m_value.get(j) && m_manager.is_value(n->get_arg(j)));
+ it->m_value.set(j, it->m_value.get(j) && m_manager.is_unique_value(n->get_arg(j)));
}
}
}
diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp
index 7a274a830..4813cbe1a 100644
--- a/src/tactic/portfolio/smt_strategic_solver.cpp
+++ b/src/tactic/portfolio/smt_strategic_solver.cpp
@@ -18,7 +18,8 @@ Notes:
--*/
#include"cmd_context.h"
-#include"strategic_solver.h"
+#include"combined_solver.h"
+#include"tactic2solver.h"
#include"qfbv_tactic.h"
#include"qflia_tactic.h"
#include"qfnia_tactic.h"
@@ -36,57 +37,76 @@ Notes:
#include"horn_tactic.h"
#include"smt_solver.h"
-MK_SIMPLE_TACTIC_FACTORY(qfuf_fct, mk_qfuf_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(qfidl_fct, mk_qfidl_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(qfauflia_fct, mk_qfauflia_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(auflia_fct, mk_auflia_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(auflira_fct, mk_auflira_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(aufnira_fct, mk_aufnira_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(ufnia_fct, mk_ufnia_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(uflra_fct, mk_uflra_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(lra_fct, mk_lra_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(qfbv_fct, mk_qfbv_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(default_fct, mk_default_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(qfaufbv_fct, mk_qfaufbv_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(qflra_fct, mk_qflra_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(qflia_fct, mk_qflia_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(qfufbv_fct, mk_qfufbv_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(qfnia_fct, mk_qfnia_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(qfnra_fct, mk_qfnra_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(qffpa_fct, mk_qffpa_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(ufbv_fct, mk_ufbv_tactic(m, p));
-MK_SIMPLE_TACTIC_FACTORY(horn_fct, mk_horn_tactic(m, p));
-
-static void init(strategic_solver * s) {
- s->set_default_tactic(alloc(default_fct));
- s->set_tactic_for(symbol("QF_UF"), alloc(qfuf_fct));
- s->set_tactic_for(symbol("QF_BV"), alloc(qfbv_fct));
- s->set_tactic_for(symbol("QF_IDL"), alloc(qfidl_fct));
- s->set_tactic_for(symbol("QF_LIA"), alloc(qflia_fct));
- s->set_tactic_for(symbol("QF_LRA"), alloc(qflra_fct));
- s->set_tactic_for(symbol("QF_NIA"), alloc(qfnia_fct));
- s->set_tactic_for(symbol("QF_NRA"), alloc(qfnra_fct));
- s->set_tactic_for(symbol("QF_AUFLIA"), alloc(qfauflia_fct));
- s->set_tactic_for(symbol("QF_AUFBV"), alloc(qfaufbv_fct));
- s->set_tactic_for(symbol("QF_ABV"), alloc(qfaufbv_fct));
- s->set_tactic_for(symbol("QF_UFBV"), alloc(qfufbv_fct));
- s->set_tactic_for(symbol("AUFLIA"), alloc(auflia_fct));
- s->set_tactic_for(symbol("AUFLIRA"), alloc(auflira_fct));
- s->set_tactic_for(symbol("AUFNIRA"), alloc(aufnira_fct));
- s->set_tactic_for(symbol("UFNIA"), alloc(ufnia_fct));
- s->set_tactic_for(symbol("UFLRA"), alloc(uflra_fct));
- s->set_tactic_for(symbol("LRA"), alloc(lra_fct));
- s->set_tactic_for(symbol("UFBV"), alloc(ufbv_fct));
- s->set_tactic_for(symbol("BV"), alloc(ufbv_fct));
- s->set_tactic_for(symbol("QF_FPA"), alloc(qffpa_fct));
- s->set_tactic_for(symbol("QF_FPABV"), alloc(qffpa_fct));
- s->set_tactic_for(symbol("HORN"), alloc(horn_fct));
+tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const & logic) {
+ if (logic=="QF_UF")
+ return mk_qfufbv_tactic(m, p);
+ else if (logic=="QF_BV")
+ return mk_qfbv_tactic(m, p);
+ else if (logic=="QF_IDL")
+ return mk_qfidl_tactic(m, p);
+ else if (logic=="QF_LIA")
+ return mk_qflia_tactic(m, p);
+ else if (logic=="QF_LRA")
+ return mk_qflra_tactic(m, p);
+ else if (logic=="QF_NIA")
+ return mk_qfnia_tactic(m, p);
+ else if (logic=="QF_NRA")
+ return mk_qfnra_tactic(m, p);
+ else if (logic=="QF_AUFLIA")
+ return mk_qfauflia_tactic(m, p);
+ else if (logic=="QF_AUFBV")
+ return mk_qfaufbv_tactic(m, p);
+ else if (logic=="QF_ABV")
+ return mk_qfaufbv_tactic(m, p);
+ else if (logic=="QF_UFBV")
+ return mk_qfufbv_tactic(m, p);
+ else if (logic=="AUFLIA")
+ return mk_auflia_tactic(m, p);
+ else if (logic=="AUFLIRA")
+ return mk_auflira_tactic(m, p);
+ else if (logic=="AUFNIRA")
+ return mk_aufnira_tactic(m, p);
+ else if (logic=="UFNIA")
+ return mk_ufnia_tactic(m, p);
+ else if (logic=="UFLRA")
+ return mk_uflra_tactic(m, p);
+ else if (logic=="LRA")
+ return mk_lra_tactic(m, p);
+ else if (logic=="UFBV")
+ return mk_ufbv_tactic(m, p);
+ else if (logic=="BV")
+ return mk_ufbv_tactic(m, p);
+ else if (logic=="QF_FPA")
+ return mk_qffpa_tactic(m, p);
+ else if (logic=="QF_FPABV")
+ return mk_qffpa_tactic(m, p);
+ else if (logic=="HORN")
+ return mk_horn_tactic(m, p);
+ else
+ return mk_default_tactic(m, p);
}
-solver * mk_smt_strategic_solver(bool force_tactic) {
- strategic_solver * s = alloc(strategic_solver);
- s->force_tactic(force_tactic);
- s->set_inc_solver(mk_smt_solver());
- init(s);
- return s;
+class smt_strategic_solver_factory : public solver_factory {
+ symbol m_logic;
+public:
+ smt_strategic_solver_factory(symbol const & logic):m_logic(logic) {}
+
+ virtual ~smt_strategic_solver_factory() {}
+
+ virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) {
+ symbol l;
+ if (m_logic != symbol::null)
+ l = m_logic;
+ else
+ l = logic;
+ tactic * t = mk_tactic_for_logic(m, p, l);
+ return mk_combined_solver(mk_tactic2solver(m, t, p, proofs_enabled, models_enabled, unsat_core_enabled, l),
+ mk_smt_solver(m, p, l),
+ p);
+ }
+};
+
+solver_factory * mk_smt_strategic_solver_factory(symbol const & logic) {
+ return alloc(smt_strategic_solver_factory, logic);
}
+
diff --git a/src/tactic/portfolio/smt_strategic_solver.h b/src/tactic/portfolio/smt_strategic_solver.h
index 060721e09..1d132532a 100644
--- a/src/tactic/portfolio/smt_strategic_solver.h
+++ b/src/tactic/portfolio/smt_strategic_solver.h
@@ -20,8 +20,8 @@ Notes:
#ifndef _SMT_STRATEGIC_SOLVER_H_
#define _SMT_STRATEGIC_SOLVER_H_
-class solver;
-// Create a strategic solver for the Z3 API
-solver * mk_smt_strategic_solver(bool force_tactic=false);
+class solver_factory;
+
+solver_factory * mk_smt_strategic_solver_factory(symbol const & logic = symbol::null);
#endif
diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp
index 0d61f0916..785a9d82e 100644
--- a/src/tactic/tactical.cpp
+++ b/src/tactic/tactical.cpp
@@ -559,10 +559,10 @@ public:
ts.push_back(m_ts.get(i)->translate(*new_m));
}
- unsigned finished_id = UINT_MAX;
- par_exception_kind ex_kind;
+ unsigned finished_id = UINT_MAX;
+ par_exception_kind ex_kind = DEFAULT_EX;
std::string ex_msg;
- unsigned error_code;
+ unsigned error_code = 0;
#pragma omp parallel for
for (int i = 0; i < static_cast(sz); i++) {
@@ -734,8 +734,8 @@ public:
bool found_solution = false;
bool failed = false;
- par_exception_kind ex_kind;
- unsigned error_code;
+ par_exception_kind ex_kind = DEFAULT_EX;
+ unsigned error_code = 0;
std::string ex_msg;
#pragma omp parallel for
@@ -1242,8 +1242,7 @@ public:
virtual void updt_params(params_ref const & p) {
TRACE("using_params",
tout << "before p: " << p << "\n";
- tout << "m_params: " << m_params << "\n";
- ;);
+ tout << "m_params: " << m_params << "\n";);
params_ref new_p = p;
new_p.append(m_params);
diff --git a/src/tactic/ufbv/ufbv_tactic.cpp b/src/tactic/ufbv/ufbv_tactic.cpp
index 80d403b67..9d16d7f9a 100644
--- a/src/tactic/ufbv/ufbv_tactic.cpp
+++ b/src/tactic/ufbv/ufbv_tactic.cpp
@@ -62,9 +62,8 @@ tactic * mk_ufbv_preprocessor_tactic(ast_manager & m, params_ref const & p) {
tactic * mk_ufbv_tactic(ast_manager & m, params_ref const & p) {
params_ref main_p(p);
main_p.set_bool("mbqi", true);
- main_p.set_uint("mbqi_max_iterations", -1);
+ main_p.set_uint("mbqi.max_iterations", UINT_MAX);
main_p.set_bool("elim_and", true);
- main_p.set_bool("solver", true);
tactic * t = and_then(repeat(mk_ufbv_preprocessor_tactic(m, main_p), 2),
mk_smt_tactic_using(false, main_p));
diff --git a/src/util/basic_interval.h b/src/util/basic_interval.h
index 2bf5a8f30..ef414149c 100644
--- a/src/util/basic_interval.h
+++ b/src/util/basic_interval.h
@@ -260,8 +260,8 @@ public:
\brief c <- a - b
*/
void sub(interval const & a, interval const & b, interval & c) {
- m().sub(a.m_lower, b.m_lower, c.m_lower);
- m().sub(a.m_upper, b.m_upper, c.m_upper);
+ m().sub(a.m_lower, b.m_upper, c.m_lower);
+ m().sub(a.m_upper, b.m_lower, c.m_upper);
}
private:
diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp
index b81531798..8b1fbe40e 100644
--- a/src/util/gparams.cpp
+++ b/src/util/gparams.cpp
@@ -52,6 +52,7 @@ char const * g_params_renames[] = {
"qi_cost", "smt.qi.cost",
"qi_eager_threshold", "smt.qi.eager_threshold",
"nl_arith", "smt.arith.nl",
+ "pull_nested_quantifiers", "smt.pull_nested_quantifiers",
"nnf_sk_hack", "nnf.sk_hack",
"model_v2", "model.v2",
"pi_non_nested_arith_weight", "pi.non_nested_arith_weight",
@@ -165,7 +166,7 @@ public:
if (*name == ':')
name++;
std::string tmp = name;
- unsigned n = tmp.size();
+ unsigned n = static_cast(tmp.size());
for (unsigned i = 0; i < n; i++) {
if (tmp[i] >= 'A' && tmp[i] <= 'Z')
tmp[i] = tmp[i] - 'A' + 'a';
diff --git a/src/util/params.cpp b/src/util/params.cpp
index f302f7721..0ee42868d 100644
--- a/src/util/params.cpp
+++ b/src/util/params.cpp
@@ -21,13 +21,15 @@ Notes:
#include"symbol.h"
#include"dictionary.h"
+params_ref params_ref::g_empty_params_ref;
+
std::string norm_param_name(char const * n) {
if (n == 0)
return "_";
if (*n == ':')
n++;
std::string r = n;
- unsigned sz = r.size();
+ unsigned sz = static_cast(r.size());
if (sz == 0)
return "_";
for (unsigned i = 0; i < sz; i++) {
@@ -133,7 +135,7 @@ struct param_descrs::imp {
if (smt2_style)
out << ':';
char const * s = it2->bare_str();
- unsigned n = strlen(s);
+ unsigned n = static_cast(strlen(s));
for (unsigned i = 0; i < n; i++) {
if (smt2_style && s[i] == '_')
out << '-';
diff --git a/src/util/params.h b/src/util/params.h
index 13850758c..15be825b0 100644
--- a/src/util/params.h
+++ b/src/util/params.h
@@ -31,6 +31,8 @@ class params;
class param_descrs;
class params_ref {
+ static params_ref g_empty_params_ref;
+
params * m_params;
void init();
void copy_core(params const * p);
@@ -38,7 +40,9 @@ public:
params_ref():m_params(0) {}
params_ref(params_ref const & p);
~params_ref();
-
+
+ static params_ref const & get_empty() { return g_empty_params_ref; }
+
params_ref & operator=(params_ref const & p);
// copy params from src
diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp
index 4b191505f..d475e5489 100644
--- a/src/util/scoped_timer.cpp
+++ b/src/util/scoped_timer.cpp
@@ -43,7 +43,7 @@ Revision History:
#define CLOCKID CLOCK_PROCESS_CPUTIME_ID
#else
// FreeBSD does not support CLOCK_PROCESS_CPUTIME_ID
- #define CLOCKID CLOCK_PROF
+ #define CLOCKID CLOCK_MONOTONIC
#endif
#define SIG SIGRTMIN
// ---------