3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 02:15:19 +00:00

Merge branch 'unstable' of https://git01.codeplex.com/z3 into unstable

This commit is contained in:
Nikolaj Bjorner 2012-12-11 20:49:49 -08:00
commit 89ddb5eac4
105 changed files with 4992 additions and 2748 deletions

5
README
View file

@ -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

View file

@ -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
=============

View file

@ -13,6 +13,7 @@
- \ref capi
- \ref cppapi
- <a class="el" href="class_microsoft_1_1_z3_1_1_context.html">.NET API</a>
- <a class="el" href="namespacecom_1_1microsoft_1_1z3.html">Java API</a>
- <a class="el" href="namespacez3py.html">Python API</a> (also available in <a class="el" href="z3.html">pydoc format</a>).
- Try Z3 online at <a href="http://rise4fun.com/z3py">RiSE4Fun</a> using <a href="http://rise4fun.com/z3py">Python</a> or <a href="http://rise4fun.com/z3">SMT 2.0</a>.
*/

View file

@ -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.

View file

@ -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',

View file

@ -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<gmp.h>\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<omp.h>\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 <dir>, --prefix=<dir> installation prefix (default: %s)." % PREFIX
print " -y <dir>, --pydir=<dir> installation prefix for Z3 python bindings (default: %s)." % PYTHON_PACKAGE_DIR
print " -b <sudir>, --build=<subdir> subdirectory where Z3 will be built (default: build)."
print " -d, --debug compile Z3 in debug mode."
print " -t, --trace enable tracing in release mode."
@ -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(' <ClCompile Include="%s/%s" />\n' % (dep.to_src_dir, cpp))
f.write(' <ClCompile Include="%s" />\n' % os.path.join(dep.to_src_dir, cpp))
f.write(' </ItemGroup>\n')
f.write(' <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\n')
f.write(' <ImportGroup Label="ExtensionTargets">\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__':

View file

@ -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")

View file

@ -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')

422
src/api/api_algebraic.cpp Normal file
View file

@ -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<iostream>
#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<unsigned>(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<unsigned>(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<algebraic_numbers::manager> 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<unsigned>(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<algebraic_numbers::manager> 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);
}
};

View file

@ -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;
}

View file

@ -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<datatype_decl_plugin*>(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<datatype_decl_plugin*>(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;
}

View file

@ -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<ast_manager> 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

View file

@ -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<expr> & 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<symbol> & r) {
buffer<symbol> 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);
}
};

View file

@ -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<iostream>
#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<polynomial::manager> 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);
}
};

39
src/api/api_polynomial.h Normal file
View file

@ -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

View file

@ -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;
}

View file

@ -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<solver_factory> m_solver_factory;
ref<solver> 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<Z3_solver_ref *>(s); }
inline Z3_solver of_solver(Z3_solver_ref * s) { return reinterpret_cast<Z3_solver>(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

View file

@ -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<Z3_lbool>(result);
Z3_CATCH_RETURN(Z3_L_UNDEF);
}

View file

@ -1,4 +1,3 @@
Java bindings
-------------
This is currently "working in progress".

View file

@ -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)

564
src/api/python/z3num.py Normal file
View file

@ -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)

37
src/api/python/z3poly.py Normal file
View file

@ -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)

View file

@ -24,6 +24,8 @@ Notes:
#include<stdio.h>
#include"z3_macros.h"
#include"z3_api.h"
#include"z3_algebraic.h"
#include"z3_polynomial.h"
#undef __in
#undef __out

226
src/api/z3_algebraic.h Normal file
View file

@ -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

View file

@ -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[]

45
src/api/z3_polynomial.h Normal file
View file

@ -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

View file

@ -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
};

View file

@ -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<arith_decl_plugin*>(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<builtin_name>& 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) &&

View file

@ -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<builtin_name> & 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 {

View file

@ -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);

View file

@ -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<builtin_name> & op_names, symbol const & logic = symbol()) {}
@ -1080,6 +1112,8 @@ public:
virtual void get_sort_names(svector<builtin_name> & 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); }

View file

@ -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<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);

View file

@ -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<app> & todo) const;
};

View file

@ -130,7 +130,8 @@ namespace datalog {
virtual void get_sort_names(svector<builtin_name> & 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); }
};

View file

@ -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<polynomial::var>(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);
}

View file

@ -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 {

View file

@ -141,6 +141,7 @@ public:
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & 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);

View file

@ -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'),

View file

@ -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) {

View file

@ -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

View file

@ -112,7 +112,10 @@ public:
virtual void get_sort_names(svector<builtin_name> & 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); }
};

View file

@ -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.

View file

@ -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<solver> 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<scope>::iterator it = m_scopes.begin();

View file

@ -185,6 +185,7 @@ protected:
};
svector<scope> m_scopes;
scoped_ptr<solver_factory> m_solver_factory;
ref<solver> m_solver;
ref<check_sat_result> 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<cmd_context*>(this)->init_manager(); return *m_pmanager; }
sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast<cmd_context*>(this)->m_sexpr_manager = alloc(sexpr_manager); return *m_sexpr_manager; }
void set_solver(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;

View file

@ -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<unsigned>(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;
}

View file

@ -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();
};

View file

@ -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());

View file

@ -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);

View file

@ -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.

View file

@ -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<func_entry>::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;

View file

@ -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 {

File diff suppressed because it is too large Load diff

View file

@ -35,83 +35,23 @@ namespace datalog {
ast_manager& m;
smt_params m_fparams;
smt::kernel m_solver;
obj_map<func_decl, sort*> m_pred2sort;
obj_map<sort, func_decl*> m_sort2pred;
obj_map<func_decl, func_decl*> m_pred2newpred;
obj_map<func_decl, ptr_vector<func_decl> > 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);
};
};

View file

@ -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);

View file

@ -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<expr_replacer> 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());

View file

@ -60,7 +60,7 @@ namespace datalog {
obj_map<expr, unsigned> indices;
bool_rewriter bwr(m);
rule_ref r(const_cast<rule*>(&rl), rm);
sort_ref_vector sorts(m);
ptr_vector<sort> 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<sort> sorts1, sorts2;
expr_ref_vector conjs1(m), conjs(m);
rule_ref res(rm);
bool_rewriter bwr(m);

View file

@ -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<expr>));
}
obj_hashtable<expr>& 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<expr_ref_vector>());
m_quantifier_bindings.push_back(vector<expr_ref_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<expr> 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<sort> 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<rule,quantifier, expr_ref_vector*>::iterator
it = m_quantifier_instantiations.begin(),
end = m_quantifier_instantiations.end();
for (; it != end; ++it) {
dealloc(it->get_value());
}
}
{
obj_map<rule,obj_hashtable<expr>*>::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;
}
};

View file

@ -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<rule> m_qrules;
vector<expr_ref_vector>m_bindings;
vector<vector<expr_ref_vector> > m_rule_bindings;
vector<vector<expr_ref_vector> > m_quantifier_bindings;
obj_pair_map<rule,quantifier, expr_ref_vector*> m_quantifier_instantiations;
obj_map<rule, obj_hashtable<expr>*> m_seen;
bool m_has_quantifiers;
obj_map<expr,expr*> 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_ */

View file

@ -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<sort> 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);
}

View file

@ -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<expr_replacer> 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<sort>& sorts) const {
sorts.reset();
used_vars used;
get_used_vars(used);

View file

@ -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<sort>& sorts) const;
void to_formula(expr_ref& result) const;

View file

@ -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<sort> vars;
uint_set empty_index_set;
qe_lite qe(m);

View file

@ -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 {

View file

@ -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 {

View file

@ -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<var> & vars, ptr_vector<expr> & 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<expr> 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> {
elim_cfg m_cfg;
public:
elim_star(impl& i):
rewriter_tpl<elim_cfg>(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<qe_lite::impl::elim_cfg>;

View file

@ -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

View file

@ -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)

View file

@ -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),

View file

@ -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;

View file

@ -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() {}

View file

@ -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')))
))

View file

@ -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);

View file

@ -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<opcode>(INIT1 + n - 1) : INITN;
return mk_instr<instruction>(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<initn>(op, sizeof(initn));
r->m_num_args = n;
return r;
}
else {
return mk_instr<instruction>(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<const initn *>(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

View file

@ -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) {

View file

@ -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;
}

View file

@ -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'),

View file

@ -155,7 +155,7 @@ bool eval(func_interp & fi, simplifier & s, expr * const * args, expr_ref & resu
basic_simplifier_plugin * bs = static_cast<basic_simplifier_plugin*>(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();

View file

@ -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<union_find_default_ctx> 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) {

View file

@ -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);

View file

@ -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";);

View file

@ -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<expr> & 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<symbol> & r) {
check_context();
buffer<symbol> 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);
}

View file

@ -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

View file

@ -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););

View file

@ -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<builtin_name> & op_names, symbol const & logic);

View file

@ -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<solver> m_solver1;
ref<solver> 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<inc_unknown_behavior>(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<expr> & 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<symbol> & 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<solver_factory> m_f1;
scoped_ptr<solver_factory> 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);
}

View file

@ -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

View file

@ -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")
))

View file

@ -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.
*/

View file

@ -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<expr> & 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);
}

View file

@ -25,30 +25,26 @@ Notes:
#include"solver.h"
class solver_na2as : public solver {
ast_manager * m_manager;
ast_manager & m_manager;
ptr_vector<expr> 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;
};

View file

@ -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<tactic_factory*>::iterator it = m_logic2fct.begin();
dictionary<tactic_factory*>::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<expr> & 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<symbol> & 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)";
}
}

View file

@ -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<solver> m_inc_solver;
unsigned m_inc_solver_timeout;
inc_unknown_behavior m_inc_unknown_behavior;
scoped_ptr<tactic_factory> m_default_fct;
dictionary<tactic_factory*> m_logic2fct;
ref<tactic> 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<ctx> 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<expr> & r);
virtual void get_model(model_ref & m);
virtual proof * get_proof();
virtual std::string reason_unknown() const;
virtual void get_labels(svector<symbol> & r);
virtual void set_cancel(bool f);
virtual void set_progress_callback(progress_callback * callback);
};
#endif

View file

@ -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<simple_check_sat_result> 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<expr> & r);
virtual void get_model(model_ref & m);
virtual proof * get_proof();
virtual std::string reason_unknown() const;
virtual void get_labels(svector<symbol> & 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<expr> 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<expr> & r) {
if (m_ctx->m_result.get())
m_ctx->m_result->get_unsat_core(r);
void tactic2solver::get_unsat_core(ptr_vector<expr> & 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<tactic> 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<tactic_factory> 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);
}

View file

@ -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<simple_check_sat_result> m_result;
tactic_ref m_tactic;
ctx(ast_manager & m, symbol const & logic);
ast_manager & m() const { return m_assertions.m(); }
};
scoped_ptr<ctx> 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<expr> & r);
virtual void get_model(model_ref & m);
virtual proof * get_proof();
virtual std::string reason_unknown() const;
virtual void get_labels(svector<symbol> & 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<tactic_factory> 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

View file

@ -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";);

View file

@ -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)));
}
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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<int>(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);

View file

@ -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));

Some files were not shown because too many files have changed in this diff Show more