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:
commit
89ddb5eac4
5
README
5
README
|
@ -20,9 +20,10 @@ Execute:
|
|||
It will install z3 executable at /usr/bin, libraries at /usr/lib, and include files at /usr/include.
|
||||
You can change the installation p
|
||||
|
||||
Use the following commands to install in a different prefix (e.g., /home/leo).
|
||||
Use the following commands to install in a different prefix (e.g., /home/leo), and the Z3 python
|
||||
bindings in a different python package directory.
|
||||
|
||||
python scripts/mk_make.py --prefix=/home/leo
|
||||
python scripts/mk_make.py --prefix=/home/leo --pydir=/home/leo/python
|
||||
cd build
|
||||
make
|
||||
sudo make install
|
||||
|
|
|
@ -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
|
||||
=============
|
||||
|
||||
|
|
|
@ -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>.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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__':
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
422
src/api/api_algebraic.cpp
Normal 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);
|
||||
}
|
||||
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
84
src/api/api_polynomial.cpp
Normal file
84
src/api/api_polynomial.cpp
Normal 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
39
src/api/api_polynomial.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
Java bindings
|
||||
-------------
|
||||
|
||||
This is currently "working in progress".
|
|
@ -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
564
src/api/python/z3num.py
Normal 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
37
src/api/python/z3poly.py
Normal 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)
|
||||
|
||||
|
||||
|
|
@ -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
226
src/api/z3_algebraic.h
Normal 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
|
|
@ -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
45
src/api/z3_polynomial.h
Normal 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
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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) &&
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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); }
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
366
src/muz_qe/dl_mk_extract_quantifiers2.cpp
Normal file
366
src/muz_qe/dl_mk_extract_quantifiers2.cpp
Normal 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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
91
src/muz_qe/dl_mk_extract_quantifiers2.h
Normal file
91
src/muz_qe/dl_mk_extract_quantifiers2.h
Normal 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_ */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {}
|
||||
|
||||
|
|
|
@ -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')))
|
||||
))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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";);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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););
|
||||
|
|
|
@ -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);
|
||||
|
|
289
src/solver/combined_solver.cpp
Normal file
289
src/solver/combined_solver.cpp
Normal 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);
|
||||
}
|
32
src/solver/combined_solver.h
Normal file
32
src/solver/combined_solver.h
Normal 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
|
9
src/solver/combined_solver_params.pyg
Normal file
9
src/solver/combined_solver_params.pyg
Normal 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")
|
||||
))
|
||||
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";);
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue