3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-15 21:38:44 +00:00
This commit is contained in:
Nikolaj Bjorner 2016-11-09 09:49:48 -08:00
commit 865c0c0109
13 changed files with 245 additions and 148 deletions

View file

@ -32,9 +32,9 @@ project(Z3 C CXX)
# Project version # Project version
################################################################################ ################################################################################
set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MAJOR 4)
set(Z3_VERSION_MINOR 4) set(Z3_VERSION_MINOR 5)
set(Z3_VERSION_PATCH 2) set(Z3_VERSION_PATCH 1)
set(Z3_VERSION_TWEAK 1) set(Z3_VERSION_TWEAK 0)
set(Z3_FULL_VERSION 0) set(Z3_FULL_VERSION 0)
set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}")
message(STATUS "Z3 version ${Z3_VERSION}") message(STATUS "Z3 version ${Z3_VERSION}")

View file

@ -1,4 +1,30 @@
# Copyright (c) Microsoft Corporation 2015 # Copyright (c) Microsoft Corporation 2015, 2016
# The Z3 Python API requires libz3.dll/.so/.dylib in the
# PATH/LD_LIBRARY_PATH/DYLD_LIBRARY_PATH
# environment variable and the PYTHON_PATH environment variable
# needs to point to the `python' directory that contains `z3/z3.py'
# (which is at bin/python in our binary releases).
# If you obtained example.py as part of our binary release zip files,
# which you unzipped into a directory called `MYZ3', then follow these
# instructions to run the example:
# Running this example on Windows:
# set PATH=%PATH%;MYZ3\bin
# set PYTHONPATH=MYZ3\bin\python
# python example.py
# Running this example on Linux:
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:MYZ3/bin
# export PYTHONPATH=MYZ3/bin/python
# python example.py
# Running this example on OSX:
# export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:MYZ3/bin
# export PYTHONPATH=MYZ3/bin/python
# python example.py
from z3 import * from z3 import *

View file

@ -9,7 +9,7 @@ from mk_util import *
# Z3 Project definition # Z3 Project definition
def init_project_def(): def init_project_def():
set_version(4, 4, 2, 1) set_version(4, 5, 1, 0)
add_lib('util', []) add_lib('util', [])
add_lib('polynomial', ['util'], 'math/polynomial') add_lib('polynomial', ['util'], 'math/polynomial')
add_lib('sat', ['util']) add_lib('sat', ['util'])
@ -94,6 +94,7 @@ def init_project_def():
add_ml_lib('ml', ['api_dll'], 'api/ml', lib_name='libz3ml') add_ml_lib('ml', ['api_dll'], 'api/ml', lib_name='libz3ml')
add_hlib('cpp', 'api/c++', includes2install=['z3++.h']) add_hlib('cpp', 'api/c++', includes2install=['z3++.h'])
set_z3py_dir('api/python') set_z3py_dir('api/python')
add_python(_libz3Component)
add_python_install(_libz3Component) add_python_install(_libz3Component)
# Examples # Examples
add_cpp_example('cpp_example', 'c++') add_cpp_example('cpp_example', 'c++')

View file

@ -26,6 +26,7 @@ DOTNET_ENABLED=True
DOTNET_KEY_FILE=None DOTNET_KEY_FILE=None
JAVA_ENABLED=True JAVA_ENABLED=True
GIT_HASH=False GIT_HASH=False
PYTHON_ENABLED=True
def set_verbose(flag): def set_verbose(flag):
global VERBOSE global VERBOSE
@ -55,6 +56,7 @@ def display_help():
print(" --nodotnet do not include .NET bindings in the binary distribution files.") print(" --nodotnet do not include .NET bindings in the binary distribution files.")
print(" --dotnet-key=<file> sign the .NET assembly with the private key in <file>.") print(" --dotnet-key=<file> sign the .NET assembly with the private key in <file>.")
print(" --nojava do not include Java bindings in the binary distribution files.") print(" --nojava do not include Java bindings in the binary distribution files.")
print(" --nopython do not include Python bindings in the binary distribution files.")
print(" --githash include git hash in the Zip file.") print(" --githash include git hash in the Zip file.")
exit(0) exit(0)
@ -69,7 +71,8 @@ def parse_options():
'nojava', 'nojava',
'nodotnet', 'nodotnet',
'dotnet-key=', 'dotnet-key=',
'githash' 'githash',
'nopython'
]) ])
for opt, arg in options: for opt, arg in options:
if opt in ('-b', '--build'): if opt in ('-b', '--build'):
@ -84,6 +87,8 @@ def parse_options():
FORCE_MK = True FORCE_MK = True
elif opt == '--nodotnet': elif opt == '--nodotnet':
DOTNET_ENABLED = False DOTNET_ENABLED = False
elif opt == '--nopython':
PYTHON_ENABLED = False
elif opt == '--dotnet-key': elif opt == '--dotnet-key':
DOTNET_KEY_FILE = arg DOTNET_KEY_FILE = arg
elif opt == '--nojava': elif opt == '--nojava':
@ -111,6 +116,8 @@ def mk_build_dir(path):
if GIT_HASH: if GIT_HASH:
opts.append('--githash=%s' % mk_util.git_hash()) opts.append('--githash=%s' % mk_util.git_hash())
opts.append('--git-describe') opts.append('--git-describe')
if PYTHON_ENABLED:
opts.append('--python')
if subprocess.call(opts) != 0: if subprocess.call(opts) != 0:
raise MKException("Failed to generate build directory at '%s'" % path) raise MKException("Failed to generate build directory at '%s'" % path)
@ -181,6 +188,7 @@ def mk_dist_dir():
mk_util.DOTNET_ENABLED = DOTNET_ENABLED mk_util.DOTNET_ENABLED = DOTNET_ENABLED
mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE
mk_util.JAVA_ENABLED = JAVA_ENABLED mk_util.JAVA_ENABLED = JAVA_ENABLED
mk_util.PYTHON_ENABLED = PYTHON_ENABLED
mk_unix_dist(build_path, dist_path) mk_unix_dist(build_path, dist_path)
if is_verbose(): if is_verbose():
print("Generated distribution folder at '%s'" % dist_path) print("Generated distribution folder at '%s'" % dist_path)

View file

@ -63,6 +63,7 @@ DOTNET_COMPONENT='dotnet'
JAVA_COMPONENT='java' JAVA_COMPONENT='java'
ML_COMPONENT='ml' ML_COMPONENT='ml'
CPP_COMPONENT='cpp' CPP_COMPONENT='cpp'
PYTHON_COMPONENT='python'
##################### #####################
IS_WINDOWS=False IS_WINDOWS=False
IS_LINUX=False IS_LINUX=False
@ -81,6 +82,7 @@ ONLY_MAKEFILES = False
Z3PY_SRC_DIR=None Z3PY_SRC_DIR=None
VS_PROJ = False VS_PROJ = False
TRACE = False TRACE = False
PYTHON_ENABLED=False
DOTNET_ENABLED=False DOTNET_ENABLED=False
DOTNET_KEY_FILE=getenv("Z3_DOTNET_KEY_FILE", None) DOTNET_KEY_FILE=getenv("Z3_DOTNET_KEY_FILE", None)
JAVA_ENABLED=False JAVA_ENABLED=False
@ -675,7 +677,7 @@ def display_help(exit_code):
# Parse configuration option for mk_make script # Parse configuration option for mk_make script
def parse_options(): def parse_options():
global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM
global DOTNET_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED global DOTNET_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED
global LINUX_X64, SLOW_OPTIMIZE, USE_OMP global LINUX_X64, SLOW_OPTIMIZE, USE_OMP
try: try:
options, remainder = getopt.gnu_getopt(sys.argv[1:], options, remainder = getopt.gnu_getopt(sys.argv[1:],
@ -748,6 +750,7 @@ def parse_options():
elif opt in ('', '--noomp'): elif opt in ('', '--noomp'):
USE_OMP = False USE_OMP = False
elif opt in ('--python'): elif opt in ('--python'):
PYTHON_ENABLED = True
PYTHON_INSTALL_ENABLED = True PYTHON_INSTALL_ENABLED = True
else: else:
print("ERROR: Invalid command line option '%s'" % opt) print("ERROR: Invalid command line option '%s'" % opt)
@ -844,6 +847,9 @@ def is_ml_enabled():
def is_dotnet_enabled(): def is_dotnet_enabled():
return DOTNET_ENABLED return DOTNET_ENABLED
def is_python_enabled():
return PYTHON_ENABLED
def is_python_install_enabled(): def is_python_install_enabled():
return PYTHON_INSTALL_ENABLED return PYTHON_INSTALL_ENABLED
@ -1382,6 +1388,32 @@ class DLLComponent(Component):
shutil.copy('%s.a' % os.path.join(build_path, self.dll_name), shutil.copy('%s.a' % os.path.join(build_path, self.dll_name),
'%s.a' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) '%s.a' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
class PythonComponent(Component):
def __init__(self, name, libz3Component):
assert isinstance(libz3Component, DLLComponent)
global PYTHON_ENABLED
Component.__init__(self, name, None, [])
self.libz3Component = libz3Component
def main_component(self):
return False
def mk_win_dist(self, build_path, dist_path):
if not is_python_enabled():
return
src = os.path.join(build_path, 'python', 'z3')
dst = os.path.join(dist_path, INSTALL_BIN_DIR, 'python', 'z3')
if os.path.exists(dst):
shutil.rmtree(dst)
shutil.copytree(src, dst)
def mk_unix_dist(self, build_path, dist_path):
self.mk_win_dist(build_path, dist_path)
def mk_makefile(self, out):
return
class PythonInstallComponent(Component): class PythonInstallComponent(Component):
def __init__(self, name, libz3Component): def __init__(self, name, libz3Component):
assert isinstance(libz3Component, DLLComponent) assert isinstance(libz3Component, DLLComponent)
@ -1484,6 +1516,7 @@ class PythonInstallComponent(Component):
os.path.join('python', 'z3', '*.pyc'), os.path.join('python', 'z3', '*.pyc'),
os.path.join(self.pythonPkgDir,'z3'), os.path.join(self.pythonPkgDir,'z3'),
in_prefix=self.in_prefix_install) in_prefix=self.in_prefix_install)
if PYTHON_PACKAGE_DIR != distutils.sysconfig.get_python_lib(): if PYTHON_PACKAGE_DIR != distutils.sysconfig.get_python_lib():
out.write('\t@echo Z3Py was installed at \'%s\', make sure this directory is in your PYTHONPATH environment variable.' % PYTHON_PACKAGE_DIR) out.write('\t@echo Z3Py was installed at \'%s\', make sure this directory is in your PYTHONPATH environment variable.' % PYTHON_PACKAGE_DIR)
@ -2173,6 +2206,15 @@ class PythonExampleComponent(ExampleComponent):
print("Copied Z3Py example '%s' to '%s'" % (py, os.path.join(BUILD_DIR, 'python'))) print("Copied Z3Py example '%s' to '%s'" % (py, os.path.join(BUILD_DIR, 'python')))
out.write('_ex_%s: \n\n' % self.name) out.write('_ex_%s: \n\n' % self.name)
def mk_win_dist(self, build_path, dist_path):
full = os.path.join(EXAMPLE_DIR, self.path)
py = 'example.py'
shutil.copyfile(os.path.join(full, py),
os.path.join(dist_path, INSTALL_BIN_DIR, 'python', py))
def mk_unix_dist(self, build_path, dist_path):
self.mk_win_dist(build_path, dist_path)
def reg_component(name, c): def reg_component(name, c):
global _Id, _Components, _ComponentNames, _Name2Component global _Id, _Components, _ComponentNames, _Name2Component
@ -2213,6 +2255,10 @@ def add_java_dll(name, deps=[], path=None, dll_name=None, package_name=None, man
c = JavaDLLComponent(name, dll_name, package_name, manifest_file, path, deps) c = JavaDLLComponent(name, dll_name, package_name, manifest_file, path, deps)
reg_component(name, c) reg_component(name, c)
def add_python(libz3Component):
name = 'python'
reg_component(name, PythonComponent(name, libz3Component))
def add_python_install(libz3Component): def add_python_install(libz3Component):
name = 'python_install' name = 'python_install'
reg_component(name, PythonInstallComponent(name, libz3Component)) reg_component(name, PythonInstallComponent(name, libz3Component))
@ -3230,11 +3276,6 @@ def mk_vs_proj_dll(name, components):
def mk_win_dist(build_path, dist_path): def mk_win_dist(build_path, dist_path):
for c in get_components(): for c in get_components():
c.mk_win_dist(build_path, dist_path) c.mk_win_dist(build_path, dist_path)
# Add Z3Py to bin directory
print("Adding to %s\n" % dist_path)
for pyc in filter(lambda f: f.endswith('.pyc') or f.endswith('.py'), os.listdir(build_path)):
shutil.copy(os.path.join(build_path, pyc),
os.path.join(dist_path, INSTALL_BIN_DIR, pyc))
def mk_unix_dist(build_path, dist_path): def mk_unix_dist(build_path, dist_path):
for c in get_components(): for c in get_components():

View file

@ -28,6 +28,7 @@ DOTNET_ENABLED=True
DOTNET_KEY_FILE=None DOTNET_KEY_FILE=None
JAVA_ENABLED=True JAVA_ENABLED=True
GIT_HASH=False GIT_HASH=False
PYTHON_ENABLED=True
def set_verbose(flag): def set_verbose(flag):
global VERBOSE global VERBOSE
@ -60,12 +61,13 @@ def display_help():
print(" --nodotnet do not include .NET bindings in the binary distribution files.") print(" --nodotnet do not include .NET bindings in the binary distribution files.")
print(" --dotnet-key=<file> sign the .NET assembly with the private key in <file>.") print(" --dotnet-key=<file> sign the .NET assembly with the private key in <file>.")
print(" --nojava do not include Java bindings in the binary distribution files.") print(" --nojava do not include Java bindings in the binary distribution files.")
print(" --nopython do not include Python bindings in the binary distribution files.")
print(" --githash include git hash in the Zip file.") print(" --githash include git hash in the Zip file.")
exit(0) exit(0)
# Parse configuration option for mk_make script # Parse configuration option for mk_make script
def parse_options(): def parse_options():
global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED
path = BUILD_DIR path = BUILD_DIR
options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=',
'help', 'help',
@ -74,7 +76,8 @@ def parse_options():
'nojava', 'nojava',
'nodotnet', 'nodotnet',
'dotnet-key=', 'dotnet-key=',
'githash' 'githash',
'nopython'
]) ])
for opt, arg in options: for opt, arg in options:
if opt in ('-b', '--build'): if opt in ('-b', '--build'):
@ -89,6 +92,8 @@ def parse_options():
FORCE_MK = True FORCE_MK = True
elif opt == '--nodotnet': elif opt == '--nodotnet':
DOTNET_ENABLED = False DOTNET_ENABLED = False
elif opt == '--nopython':
PYTHON_ENABLED = False
elif opt == '--dotnet-key': elif opt == '--dotnet-key':
DOTNET_KEY_FILE = arg DOTNET_KEY_FILE = arg
elif opt == '--nojava': elif opt == '--nojava':
@ -118,6 +123,8 @@ def mk_build_dir(path, x64):
if GIT_HASH: if GIT_HASH:
opts.append('--githash=%s' % mk_util.git_hash()) opts.append('--githash=%s' % mk_util.git_hash())
opts.append('--git-describe') opts.append('--git-describe')
if PYTHON_ENABLED:
opts.append('--python')
if subprocess.call(opts) != 0: if subprocess.call(opts) != 0:
raise MKException("Failed to generate build directory at '%s'" % path) raise MKException("Failed to generate build directory at '%s'" % path)
@ -192,6 +199,7 @@ def mk_dist_dir_core(x64):
mk_util.DOTNET_ENABLED = DOTNET_ENABLED mk_util.DOTNET_ENABLED = DOTNET_ENABLED
mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE
mk_util.JAVA_ENABLED = JAVA_ENABLED mk_util.JAVA_ENABLED = JAVA_ENABLED
mk_util.PYTHON_ENABLED = PYTHON_ENABLED
mk_win_dist(build_path, dist_path) mk_win_dist(build_path, dist_path)
if is_verbose(): if is_verbose():
print("Generated %s distribution folder at '%s'" % (platform, dist_path)) print("Generated %s distribution folder at '%s'" % (platform, dist_path))

View file

@ -189,7 +189,7 @@ extern "C" {
Z3_CATCH_RETURN(0); Z3_CATCH_RETURN(0);
} }
Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, unsigned __int64 size) { Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, __uint64 size) {
Z3_TRY; Z3_TRY;
LOG_Z3_mk_finite_domain_sort(c, name, size); LOG_Z3_mk_finite_domain_sort(c, name, size);
RESET_ERROR_CODE(); RESET_ERROR_CODE();
@ -199,7 +199,7 @@ extern "C" {
Z3_CATCH_RETURN(0); Z3_CATCH_RETURN(0);
} }
Z3_bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, unsigned __int64 * out) { Z3_bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, __uint64 * out) {
Z3_TRY; Z3_TRY;
if (out) { if (out) {
*out = 0; *out = 0;

View file

@ -4,6 +4,7 @@ import shutil
import platform import platform
import subprocess import subprocess
import multiprocessing import multiprocessing
import re
from setuptools import setup from setuptools import setup
from distutils.errors import LibError from distutils.errors import LibError
from distutils.command.build import build as _build from distutils.command.build import build as _build
@ -43,6 +44,16 @@ def _clean_bins():
shutil.rmtree(BINS_DIR, ignore_errors=True) shutil.rmtree(BINS_DIR, ignore_errors=True)
shutil.rmtree(HEADERS_DIR, ignore_errors=True) shutil.rmtree(HEADERS_DIR, ignore_errors=True)
def _z3_version():
fn = os.path.join(SRC_DIR, 'scripts', 'mk_project.py')
if os.path.exists(fn):
with open(fn) as f:
for line in f:
n = re.match(".*set_version\((.*), (.*), (.*), (.*)\).*", line)
if not n is None:
return n.group(1) + '.' + n.group(2) + '.' + n.group(3) + '.' + n.group(4)
return "?.?.?.?"
def _configure_z3(): def _configure_z3():
# bail out early if we don't need to do this - it forces a rebuild every time otherwise # bail out early if we don't need to do this - it forces a rebuild every time otherwise
if os.path.exists(BUILD_DIR): if os.path.exists(BUILD_DIR):
@ -139,7 +150,7 @@ class sdist(_sdist):
setup( setup(
name='z3-solver', name='z3-solver',
version='4.4.2.1', version=_z3_version(),
description='an efficient SMT solver library', description='an efficient SMT solver library',
long_description='Z3 is a theorem prover from Microsoft Research with support for bitvectors, booleans, arrays, floating point numbers, strings, and other data types.\n\nFor documentation, please read http://z3prover.github.io/api/html/z3.html\n\nIn the event of technical difficulties related to configuration, compiliation, or installation, please submit issues to https://github.com/angr/angr-z3', long_description='Z3 is a theorem prover from Microsoft Research with support for bitvectors, booleans, arrays, floating point numbers, strings, and other data types.\n\nFor documentation, please read http://z3prover.github.io/api/html/z3.html\n\nIn the event of technical difficulties related to configuration, compiliation, or installation, please submit issues to https://github.com/angr/angr-z3',
author="The Z3 Theorem Prover Project", author="The Z3 Theorem Prover Project",

View file

@ -1807,7 +1807,7 @@ extern "C" {
def_API('Z3_mk_finite_domain_sort', SORT, (_in(CONTEXT), _in(SYMBOL), _in(UINT64))) def_API('Z3_mk_finite_domain_sort', SORT, (_in(CONTEXT), _in(SYMBOL), _in(UINT64)))
*/ */
Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, unsigned __int64 size); Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, __uint64 size);
/** /**
\brief Create an array type. \brief Create an array type.
@ -3143,14 +3143,14 @@ extern "C" {
/** /**
\brief Create a numeral of a int, bit-vector, or finite-domain sort. \brief Create a numeral of a int, bit-vector, or finite-domain sort.
This function can be use to create numerals that fit in a machine unsigned __int64 integer. This function can be use to create numerals that fit in a machine __uint64 integer.
It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string.
\sa Z3_mk_numeral \sa Z3_mk_numeral
def_API('Z3_mk_unsigned_int64', AST, (_in(CONTEXT), _in(UINT64), _in(SORT))) def_API('Z3_mk_unsigned_int64', AST, (_in(CONTEXT), _in(UINT64), _in(SORT)))
*/ */
Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, unsigned __int64 v, Z3_sort ty); Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, __uint64 v, Z3_sort ty);
/*@}*/ /*@}*/
@ -3722,7 +3722,7 @@ extern "C" {
def_API('Z3_get_finite_domain_sort_size', BOOL, (_in(CONTEXT), _in(SORT), _out(UINT64))) def_API('Z3_get_finite_domain_sort_size', BOOL, (_in(CONTEXT), _in(SORT), _out(UINT64)))
*/ */
Z3_bool_opt Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, unsigned __int64* r); Z3_bool_opt Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, __uint64* r);
/** /**
\brief Return the domain of the given array sort. \brief Return the domain of the given array sort.
@ -4288,7 +4288,7 @@ extern "C" {
/** /**
\brief Similar to #Z3_get_numeral_string, but only succeeds if \brief Similar to #Z3_get_numeral_string, but only succeeds if
the value can fit in a machine unsigned __int64 int. Return Z3_TRUE if the call succeeded. the value can fit in a machine __uint64 int. Return Z3_TRUE if the call succeeded.
\pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST \pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST
@ -4296,7 +4296,7 @@ extern "C" {
def_API('Z3_get_numeral_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64))) def_API('Z3_get_numeral_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64)))
*/ */
Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, unsigned __int64* u); Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, __uint64* u);
/** /**
\brief Similar to #Z3_get_numeral_string, but only succeeds if \brief Similar to #Z3_get_numeral_string, but only succeeds if

View file

@ -34,7 +34,7 @@ macro_util::macro_util(ast_manager & m, simplifier & s):
m_simplifier(s), m_simplifier(s),
m_arith_simp(0), m_arith_simp(0),
m_bv_simp(0), m_bv_simp(0),
m_basic_simp(0), m_basic_simp(0),
m_forbidden_set(0), m_forbidden_set(0),
m_curr_clause(0) { m_curr_clause(0) {
} }
@ -64,23 +64,23 @@ basic_simplifier_plugin * macro_util::get_basic_simp() const {
} }
bool macro_util::is_bv(expr * n) const { bool macro_util::is_bv(expr * n) const {
return get_bv_simp()->is_bv(n); return get_bv_simp()->is_bv(n);
} }
bool macro_util::is_bv_sort(sort * s) const { bool macro_util::is_bv_sort(sort * s) const {
return get_bv_simp()->is_bv_sort(s); return get_bv_simp()->is_bv_sort(s);
} }
bool macro_util::is_add(expr * n) const { bool macro_util::is_add(expr * n) const {
return get_arith_simp()->is_add(n) || get_bv_simp()->is_add(n); return get_arith_simp()->is_add(n) || get_bv_simp()->is_add(n);
} }
bool macro_util::is_times_minus_one(expr * n, expr * & arg) const { bool macro_util::is_times_minus_one(expr * n, expr * & arg) const {
return get_arith_simp()->is_times_minus_one(n, arg) || get_bv_simp()->is_times_minus_one(n, arg); return get_arith_simp()->is_times_minus_one(n, arg) || get_bv_simp()->is_times_minus_one(n, arg);
} }
bool macro_util::is_le(expr * n) const { bool macro_util::is_le(expr * n) const {
return get_arith_simp()->is_le(n) || get_bv_simp()->is_le(n); return get_arith_simp()->is_le(n) || get_bv_simp()->is_le(n);
} }
bool macro_util::is_le_ge(expr * n) const { bool macro_util::is_le_ge(expr * n) const {
@ -130,7 +130,7 @@ void macro_util::mk_add(unsigned num_args, expr * const * args, sort * s, expr_r
/** /**
\brief Return true if \c n is an application of the form \brief Return true if \c n is an application of the form
(f x_{k_1}, ..., x_{k_n}) (f x_{k_1}, ..., x_{k_n})
where f is uninterpreted where f is uninterpreted
@ -147,7 +147,7 @@ bool macro_util::is_macro_head(expr * n, unsigned num_decls) const {
var2pos.resize(num_decls, -1); var2pos.resize(num_decls, -1);
for (unsigned i = 0; i < num_decls; i++) { for (unsigned i = 0; i < num_decls; i++) {
expr * c = to_app(n)->get_arg(i); expr * c = to_app(n)->get_arg(i);
if (!is_var(c)) if (!is_var(c))
return false; return false;
unsigned idx = to_var(c)->get_idx(); unsigned idx = to_var(c)->get_idx();
if (idx >= num_decls || var2pos[idx] != -1) if (idx >= num_decls || var2pos[idx] != -1)
@ -161,12 +161,12 @@ bool macro_util::is_macro_head(expr * n, unsigned num_decls) const {
/** /**
\brief Return true if n is of the form \brief Return true if n is of the form
(= (f x_{k_1}, ..., x_{k_n}) t) OR (= (f x_{k_1}, ..., x_{k_n}) t) OR
(iff (f x_{k_1}, ..., x_{k_n}) t) (iff (f x_{k_1}, ..., x_{k_n}) t)
where where
is_macro_head((f x_{k_1}, ..., x_{k_n})) returns true AND is_macro_head((f x_{k_1}, ..., x_{k_n})) returns true AND
t does not contain f AND t does not contain f AND
f is not in forbidden_set f is not in forbidden_set
@ -180,7 +180,8 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & he
if (m_manager.is_eq(n) || m_manager.is_iff(n)) { if (m_manager.is_eq(n) || m_manager.is_iff(n)) {
expr * lhs = to_app(n)->get_arg(0); expr * lhs = to_app(n)->get_arg(0);
expr * rhs = to_app(n)->get_arg(1); expr * rhs = to_app(n)->get_arg(1);
if (is_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && !occurs(to_app(lhs)->get_decl(), rhs)) { if (is_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) &&
!occurs(to_app(lhs)->get_decl(), rhs)) {
head = to_app(lhs); head = to_app(lhs);
def = rhs; def = rhs;
return true; return true;
@ -192,12 +193,12 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & he
/** /**
\brief Return true if n is of the form \brief Return true if n is of the form
(= t (f x_{k_1}, ..., x_{k_n})) OR (= t (f x_{k_1}, ..., x_{k_n})) OR
(iff t (f x_{k_1}, ..., x_{k_n})) (iff t (f x_{k_1}, ..., x_{k_n}))
where where
is_macro_head((f x_{k_1}, ..., x_{k_n})) returns true AND is_macro_head((f x_{k_1}, ..., x_{k_n})) returns true AND
t does not contain f AND t does not contain f AND
f is not in forbidden_set f is not in forbidden_set
@ -211,7 +212,8 @@ bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app_ref & h
if (m_manager.is_eq(n) || m_manager.is_iff(n)) { if (m_manager.is_eq(n) || m_manager.is_iff(n)) {
expr * lhs = to_app(n)->get_arg(0); expr * lhs = to_app(n)->get_arg(0);
expr * rhs = to_app(n)->get_arg(1); expr * rhs = to_app(n)->get_arg(1);
if (is_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) && !occurs(to_app(rhs)->get_decl(), lhs)) { if (is_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) &&
!occurs(to_app(rhs)->get_decl(), lhs)) {
head = to_app(rhs); head = to_app(rhs);
def = lhs; def = lhs;
return true; return true;
@ -254,7 +256,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex
if (!as->is_numeral(rhs)) if (!as->is_numeral(rhs))
return false; return false;
inv = false; inv = false;
ptr_buffer<expr> args; ptr_buffer<expr> args;
expr * h = 0; expr * h = 0;
@ -271,15 +273,15 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex
for (unsigned i = 0; i < lhs_num_args; i++) { for (unsigned i = 0; i < lhs_num_args; i++) {
expr * arg = lhs_args[i]; expr * arg = lhs_args[i];
expr * neg_arg; expr * neg_arg;
if (h == 0 && if (h == 0 &&
is_macro_head(arg, num_decls) && is_macro_head(arg, num_decls) &&
!is_forbidden(to_app(arg)->get_decl()) && !is_forbidden(to_app(arg)->get_decl()) &&
!poly_contains_head(lhs, to_app(arg)->get_decl(), arg)) { !poly_contains_head(lhs, to_app(arg)->get_decl(), arg)) {
h = arg; h = arg;
} }
else if (h == 0 && as->is_times_minus_one(arg, neg_arg) && else if (h == 0 && as->is_times_minus_one(arg, neg_arg) &&
is_macro_head(neg_arg, num_decls) && is_macro_head(neg_arg, num_decls) &&
!is_forbidden(to_app(neg_arg)->get_decl()) && !is_forbidden(to_app(neg_arg)->get_decl()) &&
!poly_contains_head(lhs, to_app(neg_arg)->get_decl(), arg)) { !poly_contains_head(lhs, to_app(neg_arg)->get_decl(), arg)) {
h = neg_arg; h = neg_arg;
inv = true; inv = true;
@ -304,7 +306,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex
\brief Auxiliary function for is_pseudo_predicate_macro. It detects the pattern (= (f X) t) \brief Auxiliary function for is_pseudo_predicate_macro. It detects the pattern (= (f X) t)
*/ */
bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t) { bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t) {
if (!m_manager.is_eq(n)) if (!m_manager.is_eq(n))
return false; return false;
expr * lhs = to_app(n)->get_arg(0); expr * lhs = to_app(n)->get_arg(0);
expr * rhs = to_app(n)->get_arg(1); expr * rhs = to_app(n)->get_arg(1);
@ -331,7 +333,7 @@ bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, ap
/** /**
\brief Returns true if n if of the form (forall (X) (iff (= (f X) t) def[X])) \brief Returns true if n if of the form (forall (X) (iff (= (f X) t) def[X]))
where t is a ground term, (f X) is the head. where t is a ground term, (f X) is the head.
*/ */
bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def) { bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall()) if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
@ -343,14 +345,14 @@ bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t
return false; return false;
expr * lhs = to_app(body)->get_arg(0); expr * lhs = to_app(body)->get_arg(0);
expr * rhs = to_app(body)->get_arg(1); expr * rhs = to_app(body)->get_arg(1);
if (is_pseudo_head(lhs, num_decls, head, t) && if (is_pseudo_head(lhs, num_decls, head, t) &&
!is_forbidden(head->get_decl()) && !is_forbidden(head->get_decl()) &&
!occurs(head->get_decl(), rhs)) { !occurs(head->get_decl(), rhs)) {
def = rhs; def = rhs;
return true; return true;
} }
if (is_pseudo_head(rhs, num_decls, head, t) && if (is_pseudo_head(rhs, num_decls, head, t) &&
!is_forbidden(head->get_decl()) && !is_forbidden(head->get_decl()) &&
!occurs(head->get_decl(), lhs)) { !occurs(head->get_decl(), lhs)) {
def = lhs; def = lhs;
return true; return true;
@ -361,7 +363,7 @@ bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t
/** /**
\brief A quasi-macro head is of the form f[X_1, ..., X_n], \brief A quasi-macro head is of the form f[X_1, ..., X_n],
where n == num_decls, f[X_1, ..., X_n] is a term starting with symbol f, f is uninterpreted, where n == num_decls, f[X_1, ..., X_n] is a term starting with symbol f, f is uninterpreted,
contains all universally quantified variables as arguments. contains all universally quantified variables as arguments.
Note that, some arguments of f[X_1, ..., X_n] may not be variables. Note that, some arguments of f[X_1, ..., X_n] may not be variables.
Examples of quasi-macros: Examples of quasi-macros:
@ -477,16 +479,16 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const {
else else
var_mapping.setx(max_var_idx - i, v); var_mapping.setx(max_var_idx - i, v);
} }
for (unsigned i = num_args; i <= max_var_idx; i++) for (unsigned i = num_args; i <= max_var_idx; i++)
// CMW: Won't be used, but dictates a larger binding size, // CMW: Won't be used, but dictates a larger binding size,
// so that the indexes between here and in the rewriter match. // so that the indexes between here and in the rewriter match.
// It's possible that we don't see the true max idx of all vars here. // It's possible that we don't see the true max idx of all vars here.
var_mapping.setx(max_var_idx - i, 0); var_mapping.setx(max_var_idx - i, 0);
if (changed) { if (changed) {
// REMARK: t may have nested quantifiers... So, I must use the std order for variable substitution. // REMARK: t may have nested quantifiers... So, I must use the std order for variable substitution.
var_subst subst(m_manager, true); var_subst subst(m_manager, true);
TRACE("macro_util_bug", TRACE("macro_util_bug",
tout << "head: " << mk_pp(head, m_manager) << "\n"; tout << "head: " << mk_pp(head, m_manager) << "\n";
tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitution:\n"; tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitution:\n";
@ -503,8 +505,8 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const {
// ----------------------------- // -----------------------------
// //
// "Hint" support // "Hint" support
// See comment at is_hint_atom // See comment at is_hint_atom
// for a definition of what a hint is. // for a definition of what a hint is.
// //
// ----------------------------- // -----------------------------
@ -516,7 +518,7 @@ bool is_hint_head(expr * n, ptr_buffer<var> & vars) {
return false; return false;
unsigned num_args = to_app(n)->get_num_args(); unsigned num_args = to_app(n)->get_num_args();
for (unsigned i = 0; i < num_args; i++) { for (unsigned i = 0; i < num_args; i++) {
expr * arg = to_app(n)->get_arg(i); expr * arg = to_app(n)->get_arg(i);
if (is_var(arg)) if (is_var(arg))
vars.push_back(to_var(arg)); vars.push_back(to_var(arg));
} }
@ -552,7 +554,7 @@ bool vars_of_is_subset(expr * n, ptr_buffer<var> const & vars) {
} }
} }
else { else {
SASSERT(is_quantifier(curr)); SASSERT(is_quantifier(curr));
return false; // do no support nested quantifier... being conservative. return false; // do no support nested quantifier... being conservative.
} }
} }
@ -560,7 +562,7 @@ bool vars_of_is_subset(expr * n, ptr_buffer<var> const & vars) {
} }
/** /**
\brief (= lhs rhs) is a hint atom if \brief (= lhs rhs) is a hint atom if
lhs is of the form (f t_1 ... t_n) lhs is of the form (f t_1 ... t_n)
and all variables occurring in rhs are direct arguments of lhs. and all variables occurring in rhs are direct arguments of lhs.
*/ */
@ -598,7 +600,7 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref
/** /**
\brief Return true if n can be viewed as a polynomial "hint" based on head. \brief Return true if n can be viewed as a polynomial "hint" based on head.
That is, n (but the monomial exception) only uses the variables in head, and does not use That is, n (but the monomial exception) only uses the variables in head, and does not use
head->get_decl(). head->get_decl().
is_hint_head(head, vars) must also return true is_hint_head(head, vars) must also return true
*/ */
bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) {
@ -630,7 +632,7 @@ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) {
} }
TRACE("macro_util_hint", tout << "succeeded\n";); TRACE("macro_util_hint", tout << "succeeded\n";);
return true; return true;
} }
// ----------------------------- // -----------------------------
@ -681,7 +683,7 @@ void macro_util::insert_macro(app * head, expr * def, expr * cond, bool ineq, bo
r.insert(head->get_decl(), norm_def.get(), norm_cond.get(), ineq, satisfy_atom, hint); r.insert(head->get_decl(), norm_def.get(), norm_cond.get(), ineq, satisfy_atom, hint);
} }
void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom,
bool hint, macro_candidates & r) { bool hint, macro_candidates & r) {
if (!is_macro_head(head, head->get_num_args())) { if (!is_macro_head(head, head->get_num_args())) {
app_ref new_head(m_manager); app_ref new_head(m_manager);
@ -783,8 +785,8 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a
if (!is_app(arg)) if (!is_app(arg))
continue; continue;
func_decl * f = to_app(arg)->get_decl(); func_decl * f = to_app(arg)->get_decl();
bool _is_arith_macro = bool _is_arith_macro =
is_quasi_macro_head(arg, num_decls) && is_quasi_macro_head(arg, num_decls) &&
!is_forbidden(f) && !is_forbidden(f) &&
!poly_contains_head(lhs, f, arg) && !poly_contains_head(lhs, f, arg) &&
@ -805,14 +807,14 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a
} }
else if (is_times_minus_one(arg, neg_arg) && is_app(neg_arg)) { else if (is_times_minus_one(arg, neg_arg) && is_app(neg_arg)) {
f = to_app(neg_arg)->get_decl(); f = to_app(neg_arg)->get_decl();
bool _is_arith_macro = bool _is_arith_macro =
is_quasi_macro_head(neg_arg, num_decls) && is_quasi_macro_head(neg_arg, num_decls) &&
!is_forbidden(f) && !is_forbidden(f) &&
!poly_contains_head(lhs, f, arg) && !poly_contains_head(lhs, f, arg) &&
!occurs(f, rhs) && !occurs(f, rhs) &&
!rest_contains_decl(f, atom); !rest_contains_decl(f, atom);
bool _is_poly_hint = !_is_arith_macro && is_poly_hint(lhs, to_app(neg_arg), arg); bool _is_poly_hint = !_is_arith_macro && is_poly_hint(lhs, to_app(neg_arg), arg);
if (_is_arith_macro || _is_poly_hint) { if (_is_arith_macro || _is_poly_hint) {
collect_poly_args(lhs, arg, args); collect_poly_args(lhs, arg, args);
expr_ref rest(m_manager); expr_ref rest(m_manager);
@ -842,34 +844,34 @@ void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls,
/** /**
\brief Collect macro candidates for atom \c atom. \brief Collect macro candidates for atom \c atom.
The candidates are stored in \c r. The candidates are stored in \c r.
The following post-condition holds: The following post-condition holds:
for each i in [0, r.size() - 1] for each i in [0, r.size() - 1]
we have a conditional macro of the form we have a conditional macro of the form
r.get_cond(i) IMPLIES f(x_1, ..., x_n) = r.get_def(i) r.get_cond(i) IMPLIES f(x_1, ..., x_n) = r.get_def(i)
where where
f == r.get_fs(i) .., x_n), f is uninterpreted and x_1, ..., x_n are variables. f == r.get_fs(i) .., x_n), f is uninterpreted and x_1, ..., x_n are variables.
r.get_cond(i) and r.get_defs(i) do not contain f or variables not in {x_1, ..., x_n} r.get_cond(i) and r.get_defs(i) do not contain f or variables not in {x_1, ..., x_n}
The idea is to use r.get_defs(i) as the interpretation for f in a model M whenever r.get_cond(i) The idea is to use r.get_defs(i) as the interpretation for f in a model M whenever r.get_cond(i)
Given a model M and values { v_1, ..., v_n } Given a model M and values { v_1, ..., v_n }
Let M' be M{x_1 -> v_1, ..., v_n -> v_n} Let M' be M{x_1 -> v_1, ..., v_n -> v_n}
Note that M'(f(x_1, ..., x_n)) = M(f)(v_1, ..., v_n) Note that M'(f(x_1, ..., x_n)) = M(f)(v_1, ..., v_n)
Then, IF we have that M(f)(v_1, ..., v_n) = M'(r.get_def(i)) AND Then, IF we have that M(f)(v_1, ..., v_n) = M'(r.get_def(i)) AND
M'(r.get_cond(i)) = true M'(r.get_cond(i)) = true
THEN M'(atom) = true THEN M'(atom) = true
That is, if the conditional macro is used then the atom is satisfied when M'(r.get_cond(i)) = true That is, if the conditional macro is used then the atom is satisfied when M'(r.get_cond(i)) = true
IF r.is_ineq(i) = false, then IF r.is_ineq(i) = false, then
M(f)(v_1, ..., v_n) ***MUST BE*** M'(r.get_def(i)) whenever M'(r.get_cond(i)) = true M(f)(v_1, ..., v_n) ***MUST BE*** M'(r.get_def(i)) whenever M'(r.get_cond(i)) = true
IF r.satisfy_atom(i) = true, then we have the stronger property: IF r.satisfy_atom(i) = true, then we have the stronger property:
Then, IF we have that (M'(r.get_cond(i)) = true IMPLIES M(f)(v_1, ..., v_n) = M'(r.get_def(i))) Then, IF we have that (M'(r.get_cond(i)) = true IMPLIES M(f)(v_1, ..., v_n) = M'(r.get_def(i)))
@ -878,8 +880,8 @@ void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls,
void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, macro_candidates & r) { void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, macro_candidates & r) {
expr* lhs, *rhs; expr* lhs, *rhs;
if (m_manager.is_eq(atom, lhs, rhs) || m_manager.is_iff(atom, lhs, rhs)) { if (m_manager.is_eq(atom, lhs, rhs) || m_manager.is_iff(atom, lhs, rhs)) {
if (is_quasi_macro_head(lhs, num_decls) && if (is_quasi_macro_head(lhs, num_decls) &&
!is_forbidden(to_app(lhs)->get_decl()) && !is_forbidden(to_app(lhs)->get_decl()) &&
!occurs(to_app(lhs)->get_decl(), rhs) && !occurs(to_app(lhs)->get_decl(), rhs) &&
!rest_contains_decl(to_app(lhs)->get_decl(), atom)) { !rest_contains_decl(to_app(lhs)->get_decl(), atom)) {
expr_ref cond(m_manager); expr_ref cond(m_manager);
@ -889,9 +891,9 @@ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls,
else if (is_hint_atom(lhs, rhs)) { else if (is_hint_atom(lhs, rhs)) {
insert_quasi_macro(to_app(lhs), num_decls, rhs, 0, false, true, true, r); insert_quasi_macro(to_app(lhs), num_decls, rhs, 0, false, true, true, r);
} }
if (is_quasi_macro_head(rhs, num_decls) && if (is_quasi_macro_head(rhs, num_decls) &&
!is_forbidden(to_app(rhs)->get_decl()) && !is_forbidden(to_app(rhs)->get_decl()) &&
!occurs(to_app(rhs)->get_decl(), lhs) && !occurs(to_app(rhs)->get_decl(), lhs) &&
!rest_contains_decl(to_app(rhs)->get_decl(), atom)) { !rest_contains_decl(to_app(rhs)->get_decl(), atom)) {
expr_ref cond(m_manager); expr_ref cond(m_manager);

View file

@ -1568,6 +1568,9 @@ void cmd_context::validate_model() {
// If r contains as_array/store/map/const expressions, then we do not generate the error. // If r contains as_array/store/map/const expressions, then we do not generate the error.
// TODO: improve evaluator for model expressions. // TODO: improve evaluator for model expressions.
// Note that, if "a" evaluates to false, then the error will be generated. // Note that, if "a" evaluates to false, then the error will be generated.
if (has_quantifiers(r)) {
continue;
}
try { try {
for_each_expr(contains_array, r); for_each_expr(contains_array, r);
} }

View file

@ -27,7 +27,7 @@ Revision History:
#include"ast_smt2_pp.h" #include"ast_smt2_pp.h"
namespace smt { namespace smt {
quantifier_manager_plugin * mk_default_plugin(); quantifier_manager_plugin * mk_default_plugin();
struct quantifier_manager::imp { struct quantifier_manager::imp {
@ -40,7 +40,7 @@ namespace smt {
ptr_vector<quantifier> m_quantifiers; ptr_vector<quantifier> m_quantifiers;
scoped_ptr<quantifier_manager_plugin> m_plugin; scoped_ptr<quantifier_manager_plugin> m_plugin;
unsigned m_num_instances; unsigned m_num_instances;
imp(quantifier_manager & wrapper, context & ctx, smt_params & p, quantifier_manager_plugin * plugin): imp(quantifier_manager & wrapper, context & ctx, smt_params & p, quantifier_manager_plugin * plugin):
m_wrapper(wrapper), m_wrapper(wrapper),
m_context(ctx), m_context(ctx),
@ -85,7 +85,7 @@ namespace smt {
out << max_generation << " : " << max_cost << "\n"; out << max_generation << " : " << max_cost << "\n";
} }
} }
void del(quantifier * q) { void del(quantifier * q) {
if (m_params.m_qi_profile) { if (m_params.m_qi_profile) {
display_stats(verbose_stream(), q); display_stats(verbose_stream(), q);
@ -99,15 +99,15 @@ namespace smt {
} }
bool is_shared(enode * n) const { bool is_shared(enode * n) const {
return m_plugin->is_shared(n); return m_plugin->is_shared(n);
} }
bool add_instance(quantifier * q, app * pat, bool add_instance(quantifier * q, app * pat,
unsigned num_bindings, unsigned num_bindings,
enode * const * bindings, enode * const * bindings,
unsigned max_generation, unsigned max_generation,
unsigned min_top_generation, unsigned min_top_generation,
unsigned max_top_generation, unsigned max_top_generation,
ptr_vector<enode> & used_enodes) { ptr_vector<enode> & used_enodes) {
max_generation = std::max(max_generation, get_generation(q)); max_generation = std::max(max_generation, get_generation(q));
if (m_num_instances > m_params.m_qi_max_instances) if (m_num_instances > m_params.m_qi_max_instances)
@ -136,7 +136,7 @@ namespace smt {
} }
return false; return false;
} }
void init_search_eh() { void init_search_eh() {
m_num_instances = 0; m_num_instances = 0;
ptr_vector<quantifier>::iterator it2 = m_quantifiers.begin(); ptr_vector<quantifier>::iterator it2 = m_quantifiers.begin();
@ -149,7 +149,7 @@ namespace smt {
m_plugin->init_search_eh(); m_plugin->init_search_eh();
TRACE("smt_params", m_params.display(tout); ); TRACE("smt_params", m_params.display(tout); );
} }
void assign_eh(quantifier * q) { void assign_eh(quantifier * q) {
m_plugin->assign_eh(q); m_plugin->assign_eh(q);
} }
@ -175,7 +175,7 @@ namespace smt {
m_plugin->pop(num_scopes); m_plugin->pop(num_scopes);
m_qi_queue.pop_scope(num_scopes); m_qi_queue.pop_scope(num_scopes);
} }
bool can_propagate() { bool can_propagate() {
return m_qi_queue.has_work() || m_plugin->can_propagate(); return m_qi_queue.has_work() || m_plugin->can_propagate();
} }
@ -184,7 +184,7 @@ namespace smt {
m_plugin->propagate(); m_plugin->propagate();
m_qi_queue.instantiate(); m_qi_queue.instantiate();
} }
bool check_quantifier(quantifier* q) { bool check_quantifier(quantifier* q) {
return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // TBD: && !m_context->get_manager().is_rec_fun_def(q); return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // TBD: && !m_context->get_manager().is_rec_fun_def(q);
} }
@ -251,7 +251,7 @@ namespace smt {
quantifier_manager::~quantifier_manager() { quantifier_manager::~quantifier_manager() {
dealloc(m_imp); dealloc(m_imp);
} }
context & quantifier_manager::get_context() const { context & quantifier_manager::get_context() const {
return m_imp->m_context; return m_imp->m_context;
} }
@ -285,16 +285,16 @@ namespace smt {
return m_imp->get_generation(q); return m_imp->get_generation(q);
} }
bool quantifier_manager::add_instance(quantifier * q, app * pat, bool quantifier_manager::add_instance(quantifier * q, app * pat,
unsigned num_bindings, unsigned num_bindings,
enode * const * bindings, enode * const * bindings,
unsigned max_generation, unsigned max_generation,
unsigned min_top_generation, unsigned min_top_generation,
unsigned max_top_generation, unsigned max_top_generation,
ptr_vector<enode> & used_enodes) { ptr_vector<enode> & used_enodes) {
return m_imp->add_instance(q, pat, num_bindings, bindings, max_generation, min_top_generation, max_generation, used_enodes); return m_imp->add_instance(q, pat, num_bindings, bindings, max_generation, min_top_generation, max_generation, used_enodes);
} }
bool quantifier_manager::add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation) { bool quantifier_manager::add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation) {
ptr_vector<enode> tmp; ptr_vector<enode> tmp;
return add_instance(q, 0, num_bindings, bindings, generation, generation, generation, tmp); return add_instance(q, 0, num_bindings, bindings, generation, generation, generation, tmp);
@ -347,7 +347,7 @@ namespace smt {
quantifier_manager::check_model_result quantifier_manager::check_model(proto_model * m, obj_map<enode, app *> const & root2value) { quantifier_manager::check_model_result quantifier_manager::check_model(proto_model * m, obj_map<enode, app *> const & root2value) {
return m_imp->check_model(m, root2value); return m_imp->check_model(m, root2value);
} }
void quantifier_manager::push() { void quantifier_manager::push() {
m_imp->push(); m_imp->push();
} }
@ -367,7 +367,7 @@ namespace smt {
plugin->set_manager(*this); plugin->set_manager(*this);
} }
} }
void quantifier_manager::display(std::ostream & out) const { void quantifier_manager::display(std::ostream & out) const {
} }
@ -382,12 +382,12 @@ namespace smt {
m_imp->display_stats(out, q); m_imp->display_stats(out, q);
} }
ptr_vector<quantifier>::const_iterator quantifier_manager::begin_quantifiers() const { ptr_vector<quantifier>::const_iterator quantifier_manager::begin_quantifiers() const {
return m_imp->m_quantifiers.begin(); return m_imp->m_quantifiers.begin();
} }
ptr_vector<quantifier>::const_iterator quantifier_manager::end_quantifiers() const { ptr_vector<quantifier>::const_iterator quantifier_manager::end_quantifiers() const {
return m_imp->m_quantifiers.end(); return m_imp->m_quantifiers.end();
} }
// The default plugin uses E-matching, MBQI and quick-checker // The default plugin uses E-matching, MBQI and quick-checker
@ -404,13 +404,13 @@ namespace smt {
bool m_active; bool m_active;
public: public:
default_qm_plugin(): default_qm_plugin():
m_qm(0), m_qm(0),
m_context(0), m_context(0),
m_new_enode_qhead(0), m_new_enode_qhead(0),
m_lazy_matching_idx(0), m_lazy_matching_idx(0),
m_active(false) { m_active(false) {
} }
virtual ~default_qm_plugin() { virtual ~default_qm_plugin() {
} }
@ -434,20 +434,18 @@ namespace smt {
virtual bool model_based() const { return m_fparams->m_mbqi; } virtual bool model_based() const { return m_fparams->m_mbqi; }
virtual bool mbqi_enabled(quantifier *q) const { virtual bool mbqi_enabled(quantifier *q) const {
if(!m_fparams->m_mbqi_id) return true; if (!m_fparams->m_mbqi_id) return true;
const symbol &s = q->get_qid(); const symbol &s = q->get_qid();
size_t len = strlen(m_fparams->m_mbqi_id); size_t len = strlen(m_fparams->m_mbqi_id);
if(s == symbol::null || s.is_numerical()) if (s == symbol::null || s.is_numerical())
return len == 0; return len == 0;
return strncmp(s.bare_str(),m_fparams->m_mbqi_id,len) == 0; return strncmp(s.bare_str(), m_fparams->m_mbqi_id, len) == 0;
} }
/* Quantifier id's must begin with the prefix specified by /* Quantifier id's must begin with the prefix specified by parameter
parameter mbqi.id to be instantiated with MBQI. The default mbqi.id to be instantiated with MBQI. The default value is the
value is the empty string, so all quantifiers are empty string, so all quantifiers are instantiated. */
instantiated.
*/
virtual void add(quantifier * q) { virtual void add(quantifier * q) {
if (m_fparams->m_mbqi && mbqi_enabled(q)) { if (m_fparams->m_mbqi && mbqi_enabled(q)) {
m_active = true; m_active = true;
@ -455,8 +453,7 @@ namespace smt {
} }
} }
virtual void del(quantifier * q) { virtual void del(quantifier * q) { }
}
virtual void push() { virtual void push() {
m_mam->push_scope(); m_mam->push_scope();
@ -465,7 +462,7 @@ namespace smt {
m_model_finder->push_scope(); m_model_finder->push_scope();
} }
} }
virtual void pop(unsigned num_scopes) { virtual void pop(unsigned num_scopes) {
m_mam->pop_scope(num_scopes); m_mam->pop_scope(num_scopes);
m_lazy_mam->pop_scope(num_scopes); m_lazy_mam->pop_scope(num_scopes);
@ -473,7 +470,7 @@ namespace smt {
m_model_finder->pop_scope(num_scopes); m_model_finder->pop_scope(num_scopes);
} }
} }
virtual void init_search_eh() { virtual void init_search_eh() {
m_lazy_matching_idx = 0; m_lazy_matching_idx = 0;
if (m_fparams->m_mbqi) { if (m_fparams->m_mbqi) {
@ -516,7 +513,7 @@ namespace smt {
} }
} }
} }
bool use_ematching() const { bool use_ematching() const {
return m_fparams->m_ematching && !m_qm->empty(); return m_fparams->m_ematching && !m_qm->empty();
} }
@ -538,7 +535,7 @@ namespace smt {
} }
virtual void restart_eh() { virtual void restart_eh() {
if (m_fparams->m_mbqi) { if (m_fparams->m_mbqi) {
m_model_finder->restart_eh(); m_model_finder->restart_eh();
m_model_checker->restart_eh(); m_model_checker->restart_eh();
} }
@ -613,7 +610,7 @@ namespace smt {
} }
return FC_DONE; return FC_DONE;
} }
}; };
quantifier_manager_plugin * mk_default_plugin() { quantifier_manager_plugin * mk_default_plugin() {

View file

@ -37,7 +37,7 @@ namespace smt {
public: public:
quantifier_manager(context & ctx, smt_params & fp, params_ref const & p); quantifier_manager(context & ctx, smt_params & fp, params_ref const & p);
~quantifier_manager(); ~quantifier_manager();
context & get_context() const; context & get_context() const;
void set_plugin(quantifier_manager_plugin * plugin); void set_plugin(quantifier_manager_plugin * plugin);
@ -51,12 +51,12 @@ namespace smt {
quantifier_stat * get_stat(quantifier * q) const; quantifier_stat * get_stat(quantifier * q) const;
unsigned get_generation(quantifier * q) const; unsigned get_generation(quantifier * q) const;
bool add_instance(quantifier * q, app * pat, bool add_instance(quantifier * q, app * pat,
unsigned num_bindings, unsigned num_bindings,
enode * const * bindings, enode * const * bindings,
unsigned max_generation, unsigned max_generation,
unsigned min_top_generation, unsigned min_top_generation,
unsigned max_top_generation, unsigned max_top_generation,
ptr_vector<enode> & used_enodes); ptr_vector<enode> & used_enodes);
bool add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation = 0); bool add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation = 0);
@ -78,11 +78,11 @@ namespace smt {
bool mbqi_enabled(quantifier *q) const; // can mbqi instantiate this quantifier? bool mbqi_enabled(quantifier *q) const; // can mbqi instantiate this quantifier?
void adjust_model(proto_model * m); void adjust_model(proto_model * m);
check_model_result check_model(proto_model * m, obj_map<enode, app *> const & root2value); check_model_result check_model(proto_model * m, obj_map<enode, app *> const & root2value);
void push(); void push();
void pop(unsigned num_scopes); void pop(unsigned num_scopes);
void reset(); void reset();
void display(std::ostream & out) const; void display(std::ostream & out) const;
void display_stats(std::ostream & out, quantifier * q) const; void display_stats(std::ostream & out, quantifier * q) const;
@ -97,7 +97,7 @@ namespace smt {
public: public:
quantifier_manager_plugin() {} quantifier_manager_plugin() {}
virtual ~quantifier_manager_plugin() {} virtual ~quantifier_manager_plugin() {}
virtual void set_manager(quantifier_manager & qm) = 0; virtual void set_manager(quantifier_manager & qm) = 0;
virtual quantifier_manager_plugin * mk_fresh() = 0; virtual quantifier_manager_plugin * mk_fresh() = 0;
@ -106,7 +106,7 @@ namespace smt {
virtual void del(quantifier * q) = 0; virtual void del(quantifier * q) = 0;
virtual bool is_shared(enode * n) const = 0; virtual bool is_shared(enode * n) const = 0;
/** /**
\brief This method is invoked whenever q is assigned to true. \brief This method is invoked whenever q is assigned to true.
*/ */
@ -131,9 +131,9 @@ namespace smt {
\brief This method is invoked whenever the solver restarts. \brief This method is invoked whenever the solver restarts.
*/ */
virtual void restart_eh() = 0; virtual void restart_eh() = 0;
/** /**
\brief Return true if the quantifier_manager can propagate information \brief Return true if the quantifier_manager can propagate information
information back into the core. information back into the core.
*/ */
virtual bool can_propagate() const = 0; virtual bool can_propagate() const = 0;
@ -143,11 +143,11 @@ namespace smt {
\brief Return true if the plugin is "model based" \brief Return true if the plugin is "model based"
*/ */
virtual bool model_based() const = 0; virtual bool model_based() const = 0;
/** /**
\brief Is "model based" instantiate allowed to instantiate this quantifier? \brief Is "model based" instantiate allowed to instantiate this quantifier?
*/ */
virtual bool mbqi_enabled(quantifier *q) const {return true;} virtual bool mbqi_enabled(quantifier *q) const {return true;}
/** /**
\brief Give a change to the plugin to adjust the interpretation of unintepreted functions. \brief Give a change to the plugin to adjust the interpretation of unintepreted functions.
@ -161,10 +161,10 @@ namespace smt {
It also provides a mapping from enodes to their interpretations. It also provides a mapping from enodes to their interpretations.
*/ */
virtual quantifier_manager::check_model_result check_model(proto_model * m, obj_map<enode, app *> const & root2value) = 0; virtual quantifier_manager::check_model_result check_model(proto_model * m, obj_map<enode, app *> const & root2value) = 0;
virtual void push() = 0; virtual void push() = 0;
virtual void pop(unsigned num_scopes) = 0; virtual void pop(unsigned num_scopes) = 0;
}; };
}; };