3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-27 02:45:51 +00:00

Merge branch 'unstable' into contrib

This commit is contained in:
Leonardo de Moura 2013-04-09 08:44:57 -07:00
commit f773f35517
177 changed files with 8165 additions and 2548 deletions

View file

@ -61,6 +61,10 @@ Version 4.3.2
- Fixed bugs in the C++ API (Thanks to Andrey Kupriyanov).
- Fixed bug reported at http://z3.codeplex.com/workitem/23 (Thanks to Paul Jackson).
- Fixed bug reported at http://stackoverflow.com/questions/15226944/segmentation-fault-in-z3 (Thanks to Tianhai Liu).
Version 4.3.1
=============

View file

@ -883,6 +883,29 @@ void incremental_example3() {
std::cout << s.check(a2) << "\n";
}
void enum_sort_example() {
std::cout << "enumeration sort example\n";
context ctx;
const char * enum_names[] = { "a", "b", "c" };
func_decl_vector enum_consts(ctx);
func_decl_vector enum_testers(ctx);
sort s = ctx.enumeration_sort("enumT", 3, enum_names, enum_consts, enum_testers);
// enum_consts[0] is a func_decl of arity 0.
// we convert it to an expression using the operator()
expr a = enum_consts[0]();
expr b = enum_consts[1]();
expr x = ctx.constant("x", s);
expr test = (x==a) && (x==b);
std::cout << "1: " << test << std::endl;
tactic qe(ctx, "ctx-solver-simplify");
goal g(ctx);
g.add(test);
expr res(ctx);
apply_result result_of_elimination = qe.apply(g);
goal result_goal = result_of_elimination[0];
std::cout << "2: " << result_goal.as_expr() << std::endl;
}
int main() {
try {
demorgan(); std::cout << "\n";
@ -917,6 +940,7 @@ int main() {
incremental_example1(); std::cout << "\n";
incremental_example2(); std::cout << "\n";
incremental_example3(); std::cout << "\n";
enum_sort_example(); std::cout << "\n";
std::cout << "done\n";
}
catch (exception & ex) {

View file

@ -197,7 +197,7 @@ class JavaExample
TestFailedException
{
Solver s = ctx.mkSolver();
s.assert_(f);
s.add(f);
if (s.check() != sat)
throw new TestFailedException();
if (sat == Status.SATISFIABLE)
@ -213,7 +213,7 @@ class JavaExample
System.out.println("\nTactical solver: " + s);
for (BoolExpr a : g.getFormulas())
s.assert_(a);
s.add(a);
System.out.println("Solver: " + s);
if (s.check() != sat)
@ -266,8 +266,8 @@ class JavaExample
p.add("mbqi", useMBQI);
s.setParameters(p);
for (BoolExpr a : assumptions)
s.assert_(a);
s.assert_(ctx.mkNot(f));
s.add(a);
s.add(ctx.mkNot(f));
Status q = s.check();
switch (q)
@ -299,8 +299,8 @@ class JavaExample
p.add("mbqi", useMBQI);
s.setParameters(p);
for (BoolExpr a : assumptions)
s.assert_(a);
s.assert_(ctx.mkNot(f));
s.add(a);
s.add(ctx.mkNot(f));
Status q = s.check();
switch (q)
@ -326,9 +326,9 @@ class JavaExample
ArithExpr yr = (ArithExpr) ctx.mkConst(ctx.mkSymbol("y"),
ctx.mkRealSort());
Goal g4 = ctx.mkGoal(true, false, false);
g4.assert_(ctx.mkGt(xr, ctx.mkReal(10, 1)));
g4.assert_(ctx.mkEq(yr, ctx.mkAdd(xr, ctx.mkReal(1, 1))));
g4.assert_(ctx.mkGt(yr, ctx.mkReal(1, 1)));
g4.add(ctx.mkGt(xr, ctx.mkReal(10, 1)));
g4.add(ctx.mkEq(yr, ctx.mkAdd(xr, ctx.mkReal(1, 1))));
g4.add(ctx.mkGt(yr, ctx.mkReal(1, 1)));
ApplyResult ar = applyTactic(ctx, ctx.mkTactic("simplify"), g4);
if (ar.getNumSubgoals() == 1
@ -345,7 +345,7 @@ class JavaExample
Solver s = ctx.mkSolver();
for (BoolExpr e : ar.getSubgoals()[0].getFormulas())
s.assert_(e);
s.add(e);
Status q = s.check();
System.out.println("Solver says: " + q);
System.out.println("Model: \n" + s.getModel());
@ -367,7 +367,7 @@ class JavaExample
ctx.mkBitVecSort(32));
ArrayExpr aex = (ArrayExpr) ctx.mkConst(ctx.mkSymbol("MyArray"), asort);
Expr sel = ctx.mkSelect(aex, ctx.mkInt(0));
g.assert_(ctx.mkEq(sel, ctx.mkBV(42, 32)));
g.add(ctx.mkEq(sel, ctx.mkBV(42, 32)));
Symbol xs = ctx.mkSymbol("x");
IntExpr xc = (IntExpr) ctx.mkConst(xs, ctx.getIntSort());
@ -377,11 +377,11 @@ class JavaExample
Expr[] fargs = { ctx.mkConst(xs, ctx.getIntSort()) };
IntExpr fapp = (IntExpr) ctx.mkApp(fd, fargs);
g.assert_(ctx.mkEq(ctx.mkAdd(xc, fapp), ctx.mkInt(123)));
g.add(ctx.mkEq(ctx.mkAdd(xc, fapp), ctx.mkInt(123)));
Solver s = ctx.mkSolver();
for (BoolExpr a : g.getFormulas())
s.assert_(a);
s.add(a);
System.out.println("Solver: " + s);
Status q = s.check();
@ -574,8 +574,8 @@ class JavaExample
ctx.mkEq(X[i][j], ctx.mkInt(instance[i][j]))));
Solver s = ctx.mkSolver();
s.assert_(sudoku_c);
s.assert_(instance_c);
s.add(sudoku_c);
s.add(instance_c);
if (s.check() == Status.SATISFIABLE)
{
@ -798,14 +798,14 @@ class JavaExample
BoolExpr nontrivial_eq = ctx.mkEq(fapp, fapp2);
Goal g = ctx.mkGoal(true, false, false);
g.assert_(trivial_eq);
g.assert_(nontrivial_eq);
g.add(trivial_eq);
g.add(nontrivial_eq);
System.out.println("Goal: " + g);
Solver solver = ctx.mkSolver();
for (BoolExpr a : g.getFormulas())
solver.assert_(a);
solver.add(a);
if (solver.check() != Status.SATISFIABLE)
throw new TestFailedException();
@ -820,7 +820,7 @@ class JavaExample
if (ar.getNumSubgoals() != 1 || !ar.getSubgoals()[0].isDecidedSat())
throw new TestFailedException();
g.assert_(ctx.mkEq(ctx.mkNumeral(1, ctx.mkBitVecSort(32)),
g.add(ctx.mkEq(ctx.mkNumeral(1, ctx.mkBitVecSort(32)),
ctx.mkNumeral(2, ctx.mkBitVecSort(32))));
ar = applyTactic(ctx, ctx.mkTactic("smt"), g);
if (ar.getNumSubgoals() != 1 || !ar.getSubgoals()[0].isDecidedUnsat())
@ -832,7 +832,7 @@ class JavaExample
throw new TestFailedException();
g2 = ctx.mkGoal(true, true, false);
g2.assert_(ctx.mkFalse());
g2.add(ctx.mkFalse());
ar = applyTactic(ctx, ctx.mkTactic("smt"), g2);
if (ar.getNumSubgoals() != 1 || !ar.getSubgoals()[0].isDecidedUnsat())
throw new TestFailedException();
@ -840,10 +840,10 @@ class JavaExample
Goal g3 = ctx.mkGoal(true, true, false);
Expr xc = ctx.mkConst(ctx.mkSymbol("x"), ctx.getIntSort());
Expr yc = ctx.mkConst(ctx.mkSymbol("y"), ctx.getIntSort());
g3.assert_(ctx.mkEq(xc, ctx.mkNumeral(1, ctx.getIntSort())));
g3.assert_(ctx.mkEq(yc, ctx.mkNumeral(2, ctx.getIntSort())));
g3.add(ctx.mkEq(xc, ctx.mkNumeral(1, ctx.getIntSort())));
g3.add(ctx.mkEq(yc, ctx.mkNumeral(2, ctx.getIntSort())));
BoolExpr constr = ctx.mkEq(xc, yc);
g3.assert_(constr);
g3.add(constr);
ar = applyTactic(ctx, ctx.mkTactic("smt"), g3);
if (ar.getNumSubgoals() != 1 || !ar.getSubgoals()[0].isDecidedUnsat())
throw new TestFailedException();
@ -1110,13 +1110,13 @@ class JavaExample
// Use a solver for QF_BV
Solver s = ctx.mkSolver("QF_BV");
s.assert_(eq);
s.add(eq);
Status res = s.check();
System.out.println("solver result: " + res);
// Or perhaps a tactic for QF_BV
Goal g = ctx.mkGoal(true, false, false);
g.assert_(eq);
g.add(eq);
Tactic t = ctx.mkTactic("qfbv");
ApplyResult ar = t.apply(g);
@ -1139,7 +1139,7 @@ class JavaExample
BoolExpr q = ctx.mkEq(x, y);
Goal g = ctx.mkGoal(true, false, false);
g.assert_(q);
g.add(q);
Tactic t1 = ctx.mkTactic("qfbv");
Tactic t2 = ctx.mkTactic("qfbv");
@ -1341,7 +1341,7 @@ class JavaExample
/* assert x >= "big number" */
BoolExpr c1 = ctx.mkGe(x, big_number);
System.out.println("assert: x >= 'big number'");
solver.assert_(c1);
solver.add(c1);
/* create a backtracking point */
System.out.println("push");
@ -1350,7 +1350,7 @@ class JavaExample
/* assert x <= 3 */
BoolExpr c2 = ctx.mkLe(x, three);
System.out.println("assert: x <= 3");
solver.assert_(c2);
solver.add(c2);
/* context is inconsistent at this point */
if (solver.check() != Status.UNSATISFIABLE)
@ -1375,7 +1375,7 @@ class JavaExample
/* assert y > x */
BoolExpr c3 = ctx.mkGt(y, x);
System.out.println("assert: y > x");
solver.assert_(c3);
solver.add(c3);
/* the context is still consistent. */
if (solver.check() != Status.SATISFIABLE)
@ -1911,10 +1911,10 @@ class JavaExample
Solver solver = ctx.mkSolver();
/* assert x < y */
solver.assert_(ctx.mkLt(x, y));
solver.add(ctx.mkLt(x, y));
/* assert x > 2 */
solver.assert_(ctx.mkGt(x, two));
solver.add(ctx.mkGt(x, two));
/* find model for the constraints above */
Model model = null;
@ -1964,9 +1964,9 @@ class JavaExample
Solver solver = ctx.mkSolver();
/* assert tup1 != tup2 */
solver.assert_(ctx.mkNot(ctx.mkEq(tup1, tup2)));
solver.add(ctx.mkNot(ctx.mkEq(tup1, tup2)));
/* assert first tup1 = first tup2 */
solver.assert_(ctx.mkEq(ctx.mkApp(first, tup1), ctx.mkApp(first, tup2)));
solver.add(ctx.mkEq(ctx.mkApp(first, tup1), ctx.mkApp(first, tup2)));
/* find model for the constraints above */
Model model = null;
@ -2014,7 +2014,7 @@ class JavaExample
// Assert all feasible bounds.
for (int i = 0; i < num_Exprs; ++i)
{
solver.assert_(ctx.mkBVULE(to_minimize[i],
solver.add(ctx.mkBVULE(to_minimize[i],
ctx.mkBV(upper[i], 32)));
}
@ -2050,7 +2050,7 @@ class JavaExample
{
last_upper = (upper[i] + lower[i]) / 2;
last_index = i;
solver.assert_(ctx.mkBVULE(to_minimize[i],
solver.add(ctx.mkBVULE(to_minimize[i],
ctx.mkBV(last_upper, 32)));
some_work = true;
break;
@ -2074,7 +2074,7 @@ class JavaExample
Solver solver = ctx.mkSolver();
solver.assert_(ctx.mkBVULE(x, ctx.mkBVAdd(y, z)));
solver.add(ctx.mkBVULE(x, ctx.mkBVAdd(y, z)));
checkSmall(ctx, solver, x, y, z);
}
@ -2120,10 +2120,10 @@ class JavaExample
BoolExpr f3 = ctx.mkOr(ctx.mkNot(pa), ctx.mkNot(pc));
BoolExpr f4 = pd;
solver.assert_(ctx.mkOr(f1, p1));
solver.assert_(ctx.mkOr(f2, p2));
solver.assert_(ctx.mkOr(f3, p3));
solver.assert_(ctx.mkOr(f4, p4));
solver.add(ctx.mkOr(f1, p1));
solver.add(ctx.mkOr(f2, p2));
solver.add(ctx.mkOr(f3, p3));
solver.add(ctx.mkOr(f4, p4));
Status result = solver.check(assumptions);
if (result == Status.UNSATISFIABLE)

View file

@ -30,12 +30,12 @@ CC=getenv("CC", None)
CPPFLAGS=getenv("CPPFLAGS", "")
CXXFLAGS=getenv("CXXFLAGS", "")
LDFLAGS=getenv("LDFLAGS", "")
JAVA=getenv("JAVA", "java")
JAVAC=getenv("JAVAC", "javac")
JAVA_HOME=getenv("JAVA_HOME", None)
JNI_HOME=getenv("JNI_HOME", None)
CXX_COMPILERS=['g++', 'clang++']
C_COMPILERS=['gcc', 'clang']
JAVAC=None
JAR=None
PYTHON_PACKAGE_DIR=distutils.sysconfig.get_python_lib()
BUILD_DIR='build'
REV_BUILD_DIR='..'
@ -206,23 +206,6 @@ def test_openmp(cc):
t.commit()
return exec_compiler_cmd([cc, CPPFLAGS, 'tstomp.cpp', LDFLAGS, '-fopenmp']) == 0
def check_java():
t = TempFile('Hello.java')
t.add('public class Hello { public static void main(String[] args) { System.out.println("Hello, World"); }}\n')
t.commit()
if is_verbose():
print("Testing %s..." % JAVAC)
r = exec_cmd([JAVAC, 'Hello.java'])
if r != 0:
raise MKException('Failed testing Java compiler. Set environment variable JAVAC with the path to the Java compiler')
if is_verbose():
print("Testing %s..." % JAVA)
r = exec_cmd([JAVA, 'Hello'])
rmf('Hello.class')
if r != 0:
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:
@ -230,41 +213,110 @@ def find_jni_h(path):
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(os.path.join(JAVA_HOME, 'include', 'jni.h')):
return
def check_java():
global JNI_HOME
global JAVAC
global JAR
JDK_HOME = getenv('JDK_HOME', None) # we only need to check this locally.
if is_verbose():
print("Finding JAVA_HOME...")
t = TempFile('output')
null = open(os.devnull, 'wb')
print("Finding javac ...")
if JDK_HOME != None:
if IS_WINDOWS:
JAVAC = os.path.join(JDK_HOME, 'bin', 'javac.exe')
else:
JAVAC = os.path.join(JDK_HOME, 'bin', 'javac')
if not os.path.exists(JAVAC):
raise MKException("Failed to detect javac at '%s/bin'; the environment variable JDK_HOME is probably set to the wrong path." % os.path.join(JDK_HOME))
else:
# Search for javac in the path.
ind = 'javac';
if IS_WINDOWS:
ind = ind + '.exe'
paths = os.getenv('PATH', None)
if paths:
spaths = paths.split(os.pathsep)
for i in range(0, len(spaths)):
cmb = os.path.join(spaths[i], ind)
if os.path.exists(cmb):
JAVAC = cmb
break
if JAVAC == None:
raise MKException('No java compiler in the path, please adjust your PATH or set JDK_HOME to the location of the JDK.')
if is_verbose():
print("Finding jar ...")
if IS_WINDOWS:
JAR = os.path.join(os.path.dirname(JAVAC), 'jar.exe')
else:
JAR = os.path.join(os.path.dirname(JAVAC), 'jar')
if not os.path.exists(JAR):
raise MKException("Failed to detect jar at '%s'; the environment variable JDK_HOME is probably set to the wrong path." % os.path.join(JDK_HOME))
if is_verbose():
print("Testing %s..." % JAVAC)
t = TempFile('Hello.java')
t.add('public class Hello { public static void main(String[] args) { System.out.println("Hello, World"); }}\n')
t.commit()
oo = TempFile('output')
eo = TempFile('errout')
try:
subprocess.call([JAVA, '-verbose'], stdout=t.fname, stderr=null)
t.commit()
subprocess.call([JAVAC, 'Hello.java', '-verbose'], stdout=oo.fname, stderr=eo.fname)
oo.commit()
eo.commit()
except:
raise MKException('Failed to find JAVA_HOME')
open_pat = re.compile("\[Opened (.*)\]")
t = open('output', 'r')
for line in t:
m = open_pat.match(line)
if m:
# Remove last 3 directives from m.group(1)
print(m.group(1))
tmp = m.group(1).split(os.sep)
path = string.join(tmp[:len(tmp) - 3], os.sep)
if is_verbose():
print("Checking jni.h...")
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')
raise MKException('Found, but failed to run Java compiler at %s' % (JAVAC))
os.remove('Hello.class')
if is_verbose():
print("Finding jni.h...")
if JNI_HOME != None:
if not os.path.exists(os.path.join(JNI_HOME, 'jni.h')):
raise MKException("Failed to detect jni.h '%s'; the environment variable JNI_HOME is probably set to the wrong path." % os.path.join(JNI_HOME))
else:
# Search for jni.h in the library directories...
t = open('errout', 'r')
open_pat = re.compile("\[search path for class files: (.*)\]")
cdirs = []
for line in t:
m = open_pat.match(line)
if m:
libdirs = m.group(1).split(',')
for libdir in libdirs:
q = os.path.dirname(libdir)
if cdirs.count(q) == 0:
cdirs.append(q)
# ... plus some heuristic ones.
extra_dirs = []
# For the libraries, even the JDK usually uses a JRE that comes with it. To find the
# headers we have to go a little bit higher up.
for dir in cdirs:
extra_dirs.append(os.path.abspath(os.path.join(dir, '..')))
if IS_OSX: # Apparently Apple knows best where to put stuff...
extra_dirs.append('/System/Library/Frameworks/JavaVM.framework/Headers/')
cdirs[len(cdirs):] = extra_dirs
for dir in cdirs:
q = find_jni_h(dir)
if q != False:
JNI_HOME = q
if JNI_HOME == None:
raise MKException("Failed to detect jni.h. Possible solution: set JNI_HOME with the path to JDK.")
def is64():
return sys.maxsize >= 2**32
@ -399,9 +451,8 @@ def display_help(exit_code):
print(" LDFLAGS Linker flags, e.g., -L<lib dir> if you have libraries in a non-standard directory")
print(" CPPFLAGS Preprocessor flags, e.g., -I<include dir> if you have header files in a non-standard directory")
print(" CXXFLAGS C++ compiler flags")
print(" JAVA Java virtual machine (only relevant if -j or --java option is provided)")
print(" JAVAC Java compiler (only relevant if -j or --java option is provided)")
print(" JAVA_HOME JDK installation directory (only relevant if -j or --java option is provided)")
print(" JDK_HOME JDK installation directory (only relevant if -j or --java option is provided)")
print(" JNI_HOME JNI bindings directory (only relevant if -j or --java option is provided)")
exit(exit_code)
# Parse configuration option for mk_make script
@ -1082,11 +1133,14 @@ class JavaDLLComponent(Component):
self.manifest_file = manifest_file
def mk_makefile(self, out):
global JAVAC
global JAR
if is_java_enabled():
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\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)
t = '\t$(CXX) $(CXXFLAGS) $(CXX_OUT_FLAG)api/java/Native$(OBJ_EXT) -I"%s" -I"%s/PLATFORM" -I%s %s/Native.cpp\n' % (JNI_HOME, JNI_HOME, get_component('api').to_src_dir, self.to_src_dir)
if IS_OSX:
t = t.replace('PLATFORM', 'darwin')
elif IS_LINUX:
@ -1108,6 +1162,9 @@ class JavaDLLComponent(Component):
deps += '%s ' % os.path.join(self.to_src_dir, 'enumerations', jfile)
out.write(deps)
out.write('\n')
if IS_WINDOWS:
JAVAC = '"%s"' % JAVAC
JAR = '"%s"' % JAR
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 %s %s.java -d %s\n' % (JAVAC,
@ -1115,7 +1172,7 @@ class JavaDLLComponent(Component):
os.path.join(self.to_src_dir, '*'),
os.path.join('api', 'java', 'classes')))
out.write(t)
out.write('\tjar cfm %s.jar %s -C %s .\n' % (self.package_name,
out.write('\t%s cfm %s.jar %s -C %s .\n' % (JAR, 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)
@ -1387,9 +1444,8 @@ def mk_config():
if is_verbose():
print('64-bit: %s' % is64())
if is_java_enabled():
print('Java Home: %s' % JAVA_HOME)
print('JNI Bindings: %s' % JNI_HOME)
print('Java Compiler: %s' % JAVAC)
print('Java VM: %s' % JAVA)
else:
global CXX, CC, GMP, CPPFLAGS, CXXFLAGS, LDFLAGS
ARITH = "internal"
@ -1491,9 +1547,8 @@ def mk_config():
print('gprof: enabled')
print('Python version: %s' % distutils.sysconfig.get_python_version())
if is_java_enabled():
print('Java Home: %s' % JAVA_HOME)
print('JNI Bindings: %s' % JNI_HOME)
print('Java Compiler: %s' % JAVAC)
print('Java VM: %s' % JAVA)
def mk_install(out):
out.write('install:\n')

View file

@ -373,7 +373,7 @@ extern "C" {
scoped_anum_vector roots(_am);
{
cancel_eh<algebraic_numbers::manager> eh(_am);
api::context::set_interruptable(*(mk_c(c)), eh);
api::context::set_interruptable si(*(mk_c(c)), eh);
scoped_timer timer(mk_c(c)->params().m_timeout, &eh);
vector_var2anum v2a(as);
_am.isolate_roots(_p, v2a, roots);
@ -408,7 +408,7 @@ extern "C" {
}
{
cancel_eh<algebraic_numbers::manager> eh(_am);
api::context::set_interruptable(*(mk_c(c)), eh);
api::context::set_interruptable si(*(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);

View file

@ -681,7 +681,7 @@ extern "C" {
th_rewriter m_rw(m, p);
expr_ref result(m);
cancel_eh<th_rewriter> eh(m_rw);
api::context::set_interruptable(*(mk_c(c)), eh);
api::context::set_interruptable si(*(mk_c(c)), eh);
{
scoped_ctrl_c ctrlc(eh, false, use_ctrl_c);
scoped_timer timer(timeout, &eh);

View file

@ -266,7 +266,7 @@ extern "C" {
lbool r = l_undef;
cancel_eh<api::fixedpoint_context> eh(*to_fixedpoint_ref(d));
unsigned timeout = to_fixedpoint(d)->m_params.get_uint("timeout", mk_c(c)->get_timeout());
api::context::set_interruptable(*(mk_c(c)), eh);
api::context::set_interruptable si(*(mk_c(c)), eh);
{
scoped_timer timer(timeout, &eh);
try {
@ -291,7 +291,7 @@ extern "C" {
lbool r = l_undef;
unsigned timeout = to_fixedpoint(d)->m_params.get_uint("timeout", mk_c(c)->get_timeout());
cancel_eh<api::fixedpoint_context> eh(*to_fixedpoint_ref(d));
api::context::set_interruptable(*(mk_c(c)), eh);
api::context::set_interruptable si(*(mk_c(c)), eh);
{
scoped_timer timer(timeout, &eh);
try {
@ -358,7 +358,7 @@ extern "C" {
v->m_ast_vector.push_back(coll.m_queries[i].get());
}
for (unsigned i = 0; i < coll.m_rels.size(); ++i) {
to_fixedpoint_ref(d)->ctx().register_predicate(coll.m_rels[i].get());
to_fixedpoint_ref(d)->ctx().register_predicate(coll.m_rels[i].get(), true);
}
for (unsigned i = 0; i < coll.m_rules.size(); ++i) {
to_fixedpoint_ref(d)->add_rule(coll.m_rules[i].get(), coll.m_names[i]);
@ -415,7 +415,7 @@ extern "C" {
void Z3_API Z3_fixedpoint_register_relation(Z3_context c,Z3_fixedpoint d, Z3_func_decl f) {
Z3_TRY;
LOG_Z3_fixedpoint_register_relation(c, d, f);
to_fixedpoint_ref(d)->ctx().register_predicate(to_func_decl(f));
to_fixedpoint_ref(d)->ctx().register_predicate(to_func_decl(f), true);
Z3_CATCH;
}

View file

@ -67,7 +67,7 @@ extern "C" {
expr_ref _r(mk_c(c)->m());
{
cancel_eh<polynomial::manager> eh(pm);
api::context::set_interruptable(*(mk_c(c)), eh);
api::context::set_interruptable si(*(mk_c(c)), eh);
scoped_timer timer(mk_c(c)->params().m_timeout, &eh);
pm.psc_chain(_p, _q, v_x, rs);
}

View file

@ -243,7 +243,7 @@ extern "C" {
unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout());
bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false);
cancel_eh<solver> eh(*to_solver_ref(s));
api::context::set_interruptable(*(mk_c(c)), eh);
api::context::set_interruptable si(*(mk_c(c)), eh);
lbool result;
{
scoped_ctrl_c ctrlc(eh, false, use_ctrl_c);

View file

@ -73,7 +73,7 @@ extern "C" {
RESET_ERROR_CODE();
CHECK_SEARCHING(c);
cancel_eh<smt::kernel> eh(mk_c(c)->get_smt_kernel());
api::context::set_interruptable(*(mk_c(c)), eh);
api::context::set_interruptable si(*(mk_c(c)), eh);
flet<bool> _model(mk_c(c)->fparams().m_model, true);
lbool result;
try {
@ -123,7 +123,7 @@ extern "C" {
expr * const* _assumptions = to_exprs(assumptions);
flet<bool> _model(mk_c(c)->fparams().m_model, true);
cancel_eh<smt::kernel> eh(mk_c(c)->get_smt_kernel());
api::context::set_interruptable(*(mk_c(c)), eh);
api::context::set_interruptable si(*(mk_c(c)), eh);
lbool result;
result = mk_c(c)->get_smt_kernel().check(num_assumptions, _assumptions);
if (result != l_false && m) {

View file

@ -410,7 +410,7 @@ extern "C" {
to_tactic_ref(t)->updt_params(p);
api::context::set_interruptable(*(mk_c(c)), eh);
api::context::set_interruptable si(*(mk_c(c)), eh);
{
scoped_ctrl_c ctrlc(eh, false, use_ctrl_c);
scoped_timer timer(timeout, &eh);

View file

@ -63,6 +63,11 @@ namespace z3 {
class statistics;
class apply_result;
class fixedpoint;
template<typename T> class ast_vector_tpl;
typedef ast_vector_tpl<ast> ast_vector;
typedef ast_vector_tpl<expr> expr_vector;
typedef ast_vector_tpl<sort> sort_vector;
typedef ast_vector_tpl<func_decl> func_decl_vector;
inline void set_param(char const * param, char const * value) { Z3_global_param_set(param, value); }
inline void set_param(char const * param, bool value) { Z3_global_param_set(param, value ? "true" : "false"); }
@ -190,7 +195,13 @@ namespace z3 {
Example: Given a context \c c, <tt>c.array_sort(c.int_sort(), c.bool_sort())</tt> is an array sort from integer to Boolean.
*/
sort array_sort(sort d, sort r);
/**
\brief Return an enumeration sort: enum_names[0], ..., enum_names[n-1].
\c cs and \c ts are output parameters. The method stores in \c cs the constants corresponding to the enumerated elements,
and in \c ts the predicates for testing if terms of the enumeration sort correspond to an enumeration.
*/
sort enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts);
func_decl function(symbol const & name, unsigned arity, sort const * domain, sort const & range);
func_decl function(char const * name, unsigned arity, sort const * domain, sort const & range);
func_decl function(char const * name, sort const & domain, sort const & range);
@ -240,8 +251,8 @@ namespace z3 {
array(unsigned sz):m_size(sz) { m_array = new T[sz]; }
~array() { delete[] m_array; }
unsigned size() const { return m_size; }
T & operator[](unsigned i) { assert(i < m_size); return m_array[i]; }
T const & operator[](unsigned i) const { assert(i < m_size); return m_array[i]; }
T & operator[](int i) { assert(0 <= i); assert(static_cast<unsigned>(i) < m_size); return m_array[i]; }
T const & operator[](int i) const { assert(0 <= i); assert(static_cast<unsigned>(i) < m_size); return m_array[i]; }
T const * ptr() const { return m_array; }
T * ptr() { return m_array; }
};
@ -414,6 +425,7 @@ namespace z3 {
bool is_const() const { return arity() == 0; }
expr operator()() const;
expr operator()(unsigned n, expr const * args) const;
expr operator()(expr const & a) const;
expr operator()(int a) const;
@ -1004,7 +1016,7 @@ namespace z3 {
~ast_vector_tpl() { Z3_ast_vector_dec_ref(ctx(), m_vector); }
operator Z3_ast_vector() const { return m_vector; }
unsigned size() const { return Z3_ast_vector_size(ctx(), m_vector); }
T operator[](unsigned i) const { Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast<T>()(ctx(), r); }
T operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast<T>()(ctx(), r); }
void push_back(T const & e) { Z3_ast_vector_push(ctx(), m_vector, e); check_error(); }
void resize(unsigned sz) { Z3_ast_vector_resize(ctx(), m_vector, sz); check_error(); }
T back() const { return operator[](size() - 1); }
@ -1020,11 +1032,6 @@ namespace z3 {
friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; }
};
typedef ast_vector_tpl<ast> ast_vector;
typedef ast_vector_tpl<expr> expr_vector;
typedef ast_vector_tpl<sort> sort_vector;
typedef ast_vector_tpl<func_decl> func_decl_vector;
class func_entry : public object {
Z3_func_entry m_entry;
void init(Z3_func_entry e) {
@ -1105,7 +1112,10 @@ namespace z3 {
func_decl get_const_decl(unsigned i) const { Z3_func_decl r = Z3_model_get_const_decl(ctx(), m_model, i); check_error(); return func_decl(ctx(), r); }
func_decl get_func_decl(unsigned i) const { Z3_func_decl r = Z3_model_get_func_decl(ctx(), m_model, i); check_error(); return func_decl(ctx(), r); }
unsigned size() const { return num_consts() + num_funcs(); }
func_decl operator[](unsigned i) const { return i < num_consts() ? get_const_decl(i) : get_func_decl(i - num_consts()); }
func_decl operator[](int i) const {
assert(0 <= i);
return static_cast<unsigned>(i) < num_consts() ? get_const_decl(i) : get_func_decl(i - num_consts());
}
expr get_const_interp(func_decl c) const {
check_context(*this, c);
@ -1253,7 +1263,7 @@ namespace z3 {
}
void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); }
unsigned size() const { return Z3_goal_size(ctx(), m_goal); }
expr operator[](unsigned i) const { Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); }
expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); }
Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); }
bool inconsistent() const { return Z3_goal_inconsistent(ctx(), m_goal) != 0; }
unsigned depth() const { return Z3_goal_depth(ctx(), m_goal); }
@ -1261,6 +1271,19 @@ namespace z3 {
unsigned num_exprs() const { return Z3_goal_num_exprs(ctx(), m_goal); }
bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal) != 0; }
bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal) != 0; }
expr as_expr() const {
unsigned n = size();
if (n == 0)
return ctx().bool_val(false);
else if (n == 1)
return operator[](0);
else {
array<Z3_ast> args(n);
for (unsigned i = 0; i < n; i++)
args[i] = operator[](i);
return expr(ctx(), Z3_mk_and(ctx(), n, args.ptr()));
}
}
friend std::ostream & operator<<(std::ostream & out, goal const & g) { out << Z3_goal_to_string(g.ctx(), g); return out; }
};
@ -1283,8 +1306,7 @@ namespace z3 {
return *this;
}
unsigned size() const { return Z3_apply_result_get_num_subgoals(ctx(), m_apply_result); }
goal operator[](unsigned i) const { Z3_goal r = Z3_apply_result_get_subgoal(ctx(), m_apply_result, i); check_error(); return goal(ctx(), r); }
goal operator[](int i) const { assert(i >= 0); return this->operator[](static_cast<unsigned>(i)); }
goal operator[](int i) const { assert(0 <= i); Z3_goal r = Z3_apply_result_get_subgoal(ctx(), m_apply_result, i); check_error(); return goal(ctx(), r); }
model convert_model(model const & m, unsigned i = 0) const {
check_context(*this, m);
Z3_model new_m = Z3_apply_result_convert_model(ctx(), m_apply_result, i, m);
@ -1437,6 +1459,17 @@ namespace z3 {
inline sort context::real_sort() { Z3_sort s = Z3_mk_real_sort(m_ctx); check_error(); return sort(*this, s); }
inline sort context::bv_sort(unsigned sz) { Z3_sort s = Z3_mk_bv_sort(m_ctx, sz); check_error(); return sort(*this, s); }
inline sort context::array_sort(sort d, sort r) { Z3_sort s = Z3_mk_array_sort(m_ctx, d, r); check_error(); return sort(*this, s); }
inline sort context::enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts) {
array<Z3_symbol> _enum_names(n);
for (unsigned i = 0; i < n; i++) { _enum_names[i] = Z3_mk_string_symbol(*this, enum_names[i]); }
array<Z3_func_decl> _cs(n);
array<Z3_func_decl> _ts(n);
Z3_symbol _name = Z3_mk_string_symbol(*this, name);
sort s = to_sort(*this, Z3_mk_enumeration_sort(*this, _name, n, _enum_names.ptr(), _cs.ptr(), _ts.ptr()));
check_error();
for (unsigned i = 0; i < n; i++) { cs.push_back(func_decl(*this, _cs[i])); ts.push_back(func_decl(*this, _ts[i])); }
return s;
}
inline func_decl context::function(symbol const & name, unsigned arity, sort const * domain, sort const & range) {
array<Z3_sort> args(arity);
@ -1538,6 +1571,11 @@ namespace z3 {
return expr(ctx(), r);
}
inline expr func_decl::operator()() const {
Z3_ast r = Z3_mk_app(ctx(), *this, 0, 0);
ctx().check_error();
return expr(ctx(), r);
}
inline expr func_decl::operator()(expr const & a) const {
check_context(*this, a);
Z3_ast args[1] = { a };

View file

@ -34,8 +34,7 @@ namespace Microsoft.Z3
public uint NumFields
{
get
{
init();
{
return n;
}
}
@ -48,8 +47,11 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl>() != null);
init();
return m_constructorDecl;
IntPtr constructor = IntPtr.Zero;
IntPtr tester = IntPtr.Zero;
IntPtr[] accessors = new IntPtr[n];
Native.Z3_query_constructor(Context.nCtx, NativeObject, n, ref constructor, ref tester, accessors);
return new FuncDecl(Context, constructor);
}
}
@ -61,8 +63,11 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl>() != null);
init();
return m_testerDecl;
IntPtr constructor = IntPtr.Zero;
IntPtr tester = IntPtr.Zero;
IntPtr[] accessors = new IntPtr[n];
Native.Z3_query_constructor(Context.nCtx, NativeObject, n, ref constructor, ref tester, accessors);
return new FuncDecl(Context, tester);
}
}
@ -74,8 +79,14 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl[]>() != null);
init();
return m_accessorDecls;
IntPtr constructor = IntPtr.Zero;
IntPtr tester = IntPtr.Zero;
IntPtr[] accessors = new IntPtr[n];
Native.Z3_query_constructor(Context.nCtx, NativeObject, n, ref constructor, ref tester, accessors);
FuncDecl[] t = new FuncDecl[n];
for (uint i = 0; i < n; i++)
t[i] = new FuncDecl(Context, accessors[i]);
return t;
}
}
@ -85,25 +96,11 @@ namespace Microsoft.Z3
~Constructor()
{
Native.Z3_del_constructor(Context.nCtx, NativeObject);
}
#region Object invariant
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(m_testerDecl == null || m_constructorDecl != null);
Contract.Invariant(m_testerDecl == null || m_accessorDecls != null);
}
#endregion
}
#region Internal
readonly private uint n = 0;
private FuncDecl m_testerDecl = null;
private FuncDecl m_constructorDecl = null;
private FuncDecl[] m_accessorDecls = null;
private uint n = 0;
internal Constructor(Context ctx, Symbol name, Symbol recognizer, Symbol[] fieldNames,
Sort[] sorts, uint[] sortRefs)
: base(ctx)
@ -129,24 +126,6 @@ namespace Microsoft.Z3
}
private void init()
{
Contract.Ensures(m_constructorDecl != null);
Contract.Ensures(m_testerDecl != null);
Contract.Ensures(m_accessorDecls != null);
if (m_testerDecl != null) return;
IntPtr constructor = IntPtr.Zero;
IntPtr tester = IntPtr.Zero;
IntPtr[] accessors = new IntPtr[n];
Native.Z3_query_constructor(Context.nCtx, NativeObject, n, ref constructor, ref tester, accessors);
m_constructorDecl = new FuncDecl(Context, constructor);
m_testerDecl = new FuncDecl(Context, tester);
m_accessorDecls = new FuncDecl[n];
for (uint i = 0; i < n; i++)
m_accessorDecls[i] = new FuncDecl(Context, accessors[i]);
}
#endregion
}
}

View file

@ -36,8 +36,11 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl[]>() != null);
return _constdecls;
uint n = Native.Z3_get_datatype_sort_num_constructors(Context.nCtx, NativeObject);
FuncDecl[] t = new FuncDecl[n];
for (uint i = 0; i < n; i++)
t[i] = new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, i));
return t;
}
}
@ -49,8 +52,11 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<Expr[]>() != null);
return _consts;
FuncDecl[] cds = ConstDecls;
Expr[] t = new Expr[cds.Length];
for (uint i = 0; i < t.Length; i++)
t[i] = Context.MkApp(cds[i]);
return t;
}
}
@ -62,28 +68,15 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl[]>() != null);
return _testerdecls;
uint n = Native.Z3_get_datatype_sort_num_constructors(Context.nCtx, NativeObject);
FuncDecl[] t = new FuncDecl[n];
for (uint i = 0; i < n; i++)
t[i] = new FuncDecl(Context, Native.Z3_get_datatype_sort_recognizer(Context.nCtx, NativeObject, i));
return t;
}
}
#region Object Invariant
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(this._constdecls != null);
Contract.Invariant(this._testerdecls != null);
Contract.Invariant(this._consts != null);
}
#endregion
#region Internal
readonly private FuncDecl[] _constdecls = null, _testerdecls = null;
readonly private Expr[] _consts = null;
internal EnumSort(Context ctx, Symbol name, Symbol[] enumNames)
: base(ctx)
{
@ -96,15 +89,6 @@ namespace Microsoft.Z3
IntPtr[] n_testers = new IntPtr[n];
NativeObject = Native.Z3_mk_enumeration_sort(ctx.nCtx, name.NativeObject, (uint)n,
Symbol.ArrayToNative(enumNames), n_constdecls, n_testers);
_constdecls = new FuncDecl[n];
for (uint i = 0; i < n; i++)
_constdecls[i] = new FuncDecl(ctx, n_constdecls[i]);
_testerdecls = new FuncDecl[n];
for (uint i = 0; i < n; i++)
_testerdecls[i] = new FuncDecl(ctx, n_testers[i]);
_consts = new Expr[n];
for (uint i = 0; i < n; i++)
_consts[i] = ctx.MkApp(_constdecls[i]);
}
#endregion
};

View file

@ -78,6 +78,14 @@ namespace Microsoft.Z3
}
}
/// <summary>
/// Alias for Assert.
/// </summary>
public void Add(params BoolExpr[] constraints)
{
Assert(constraints);
}
/// <summary>
/// Register predicate as recursive relation.
/// </summary>

View file

@ -90,6 +90,14 @@ namespace Microsoft.Z3
}
}
/// <summary>
/// Alias for Assert.
/// </summary>
public void Add(params BoolExpr[] constraints)
{
Assert(constraints);
}
/// <summary>
/// Indicates whether the goal contains `false'.
/// </summary>

View file

@ -36,7 +36,7 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl>() != null);
return nilDecl;
return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, 0));
}
}
@ -48,7 +48,7 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<Expr>() != null);
return nilConst;
return Context.MkApp(NilDecl);
}
}
@ -60,7 +60,7 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl>() != null);
return isNilDecl;
return new FuncDecl(Context, Native.Z3_get_datatype_sort_recognizer(Context.nCtx, NativeObject, 0));
}
}
@ -72,7 +72,7 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl>() != null);
return consDecl;
return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, 1));
}
}
@ -85,7 +85,7 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl>() != null);
return isConsDecl;
return new FuncDecl(Context, Native.Z3_get_datatype_sort_recognizer(Context.nCtx, NativeObject, 1));
}
}
@ -97,7 +97,7 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl>() != null);
return headDecl;
return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor_accessor(Context.nCtx, NativeObject, 1, 0));
}
}
@ -109,31 +109,11 @@ namespace Microsoft.Z3
get
{
Contract.Ensures(Contract.Result<FuncDecl>() != null);
return tailDecl;
return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor_accessor(Context.nCtx, NativeObject, 1, 1));
}
}
#region Object Invariant
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(nilConst != null);
Contract.Invariant(nilDecl != null);
Contract.Invariant(isNilDecl != null);
Contract.Invariant(consDecl != null);
Contract.Invariant(isConsDecl != null);
Contract.Invariant(headDecl != null);
Contract.Invariant(tailDecl != null);
}
#endregion
#region Internal
readonly private FuncDecl nilDecl, isNilDecl, consDecl, isConsDecl, headDecl, tailDecl;
readonly private Expr nilConst;
#region Internal
internal ListSort(Context ctx, Symbol name, Sort elemSort)
: base(ctx)
{
@ -141,22 +121,12 @@ namespace Microsoft.Z3
Contract.Requires(name != null);
Contract.Requires(elemSort != null);
IntPtr inil = IntPtr.Zero,
iisnil = IntPtr.Zero,
icons = IntPtr.Zero,
iiscons = IntPtr.Zero,
ihead = IntPtr.Zero,
itail = IntPtr.Zero;
IntPtr inil = IntPtr.Zero, iisnil = IntPtr.Zero,
icons = IntPtr.Zero, iiscons = IntPtr.Zero,
ihead = IntPtr.Zero, itail = IntPtr.Zero;
NativeObject = Native.Z3_mk_list_sort(ctx.nCtx, name.NativeObject, elemSort.NativeObject,
ref inil, ref iisnil, ref icons, ref iiscons, ref ihead, ref itail);
nilDecl = new FuncDecl(ctx, inil);
isNilDecl = new FuncDecl(ctx, iisnil);
consDecl = new FuncDecl(ctx, icons);
isConsDecl = new FuncDecl(ctx, iiscons);
headDecl = new FuncDecl(ctx, ihead);
tailDecl = new FuncDecl(ctx, itail);
nilConst = ctx.MkConst(nilDecl);
ref inil, ref iisnil, ref icons, ref iiscons, ref ihead, ref itail);
}
#endregion
};

View file

@ -117,6 +117,14 @@ namespace Microsoft.Z3
}
}
/// <summary>
/// Alias for Assert.
/// </summary>
public void Add(params BoolExpr[] constraints)
{
Assert(constraints);
}
/// <summary>
/// Assert multiple constraints into the solver, and track them (in the unsat) core
/// using the Boolean constants in ps.

View file

@ -16,8 +16,7 @@ public class Constructor extends Z3Object
* @throws Z3Exception
**/
public int getNumFields() throws Z3Exception
{
init();
{
return n;
}
@ -27,8 +26,11 @@ public class Constructor extends Z3Object
**/
public FuncDecl ConstructorDecl() throws Z3Exception
{
init();
return m_constructorDecl;
Native.LongPtr constructor = new Native.LongPtr();
Native.LongPtr tester = new Native.LongPtr();
long[] accessors = new long[n];
Native.queryConstructor(getContext().nCtx(), getNativeObject(), n, constructor, tester, accessors);
return new FuncDecl(getContext(), constructor.value);
}
/**
@ -37,8 +39,11 @@ public class Constructor extends Z3Object
**/
public FuncDecl getTesterDecl() throws Z3Exception
{
init();
return m_testerDecl;
Native.LongPtr constructor = new Native.LongPtr();
Native.LongPtr tester = new Native.LongPtr();
long[] accessors = new long[n];
Native.queryConstructor(getContext().nCtx(), getNativeObject(), n, constructor, tester, accessors);
return new FuncDecl(getContext(), tester.value);
}
/**
@ -47,8 +52,14 @@ public class Constructor extends Z3Object
**/
public FuncDecl[] getAccessorDecls() throws Z3Exception
{
init();
return m_accessorDecls;
Native.LongPtr constructor = new Native.LongPtr();
Native.LongPtr tester = new Native.LongPtr();
long[] accessors = new long[n];
Native.queryConstructor(getContext().nCtx(), getNativeObject(), n, constructor, tester, accessors);
FuncDecl[] t = new FuncDecl[n];
for (int i = 0; i < n; i++)
t[i] = new FuncDecl(getContext(), accessors[i]);
return t;
}
/**
@ -60,9 +71,6 @@ public class Constructor extends Z3Object
}
private int n = 0;
private FuncDecl m_testerDecl = null;
private FuncDecl m_constructorDecl = null;
private FuncDecl[] m_accessorDecls = null;
Constructor(Context ctx, Symbol name, Symbol recognizer,
Symbol[] fieldNames, Sort[] sorts, int[] sortRefs)
@ -87,21 +95,4 @@ public class Constructor extends Z3Object
Sort.arrayToNative(sorts), sortRefs));
}
private void init() throws Z3Exception
{
if (m_testerDecl != null)
return;
Native.LongPtr constructor = new Native.LongPtr();
Native.LongPtr tester = new Native.LongPtr();
long[] accessors = new long[n];
Native.queryConstructor(getContext().nCtx(), getNativeObject(), n,
constructor, tester, accessors);
m_constructorDecl = new FuncDecl(getContext(), constructor.value);
m_testerDecl = new FuncDecl(getContext(), tester.value);
m_accessorDecls = new FuncDecl[n];
for (int i = 0; i < n; i++)
m_accessorDecls[i] = new FuncDecl(getContext(), accessors[i]);
}
}

View file

@ -14,30 +14,39 @@ public class EnumSort extends Sort
/**
* The function declarations of the constants in the enumeration.
**/
public FuncDecl[] getConstDecls()
public FuncDecl[] getConstDecls() throws Z3Exception
{
return _constdecls;
int n = Native.getDatatypeSortNumConstructors(getContext().nCtx(), getNativeObject());
FuncDecl[] t = new FuncDecl[n];
for (int i = 0; i < n; i++)
t[i] = new FuncDecl(getContext(), Native.getDatatypeSortConstructor(getContext().nCtx(), getNativeObject(), i));
return t;
}
/**
* The constants in the enumeration.
**/
public Expr[] getConsts()
{
return _consts;
public Expr[] getConsts() throws Z3Exception
{
FuncDecl[] cds = getConstDecls();
Expr[] t = new Expr[cds.length];
for (int i = 0; i < t.length; i++)
t[i] = getContext().mkApp(cds[i]);
return t;
}
/**
* The test predicates for the constants in the enumeration.
**/
public FuncDecl[] getTesterDecls()
public FuncDecl[] getTesterDecls() throws Z3Exception
{
return _testerdecls;
int n = Native.getDatatypeSortNumConstructors(getContext().nCtx(), getNativeObject());
FuncDecl[] t = new FuncDecl[n];
for (int i = 0; i < n; i++)
t[i] = new FuncDecl(getContext(), Native.getDatatypeSortRecognizer(getContext().nCtx(), getNativeObject(), i));
return t;
}
private FuncDecl[] _constdecls = null, _testerdecls = null;
private Expr[] _consts = null;
EnumSort(Context ctx, Symbol name, Symbol[] enumNames) throws Z3Exception
{
super(ctx);
@ -47,15 +56,6 @@ public class EnumSort extends Sort
long[] n_testers = new long[n];
setNativeObject(Native.mkEnumerationSort(ctx.nCtx(),
name.getNativeObject(), (int) n, Symbol.arrayToNative(enumNames),
n_constdecls, n_testers));
_constdecls = new FuncDecl[n];
for (int i = 0; i < n; i++)
_constdecls[i] = new FuncDecl(ctx, n_constdecls[i]);
_testerdecls = new FuncDecl[n];
for (int i = 0; i < n; i++)
_testerdecls[i] = new FuncDecl(ctx, n_testers[i]);
_consts = new Expr[n];
for (int i = 0; i < n; i++)
_consts[i] = ctx.mkApp(_constdecls[i], (Expr[])null);
n_constdecls, n_testers));
}
};

View file

@ -51,7 +51,7 @@ public class Fixedpoint extends Z3Object
*
* @throws Z3Exception
**/
public void assert_(BoolExpr ... constraints) throws Z3Exception
public void add(BoolExpr ... constraints) throws Z3Exception
{
getContext().checkContextMatch(constraints);
for (BoolExpr a : constraints)

View file

@ -65,7 +65,7 @@ public class Goal extends Z3Object
*
* @throws Z3Exception
**/
public void assert_(BoolExpr ... constraints) throws Z3Exception
public void add(BoolExpr ... constraints) throws Z3Exception
{
getContext().checkContextMatch(constraints);
for (BoolExpr c : constraints)

View file

@ -13,65 +13,68 @@ public class ListSort extends Sort
{
/**
* The declaration of the nil function of this list sort.
* @throws Z3Exception
**/
public FuncDecl getNilDecl()
public FuncDecl getNilDecl() throws Z3Exception
{
return nilDecl;
return new FuncDecl(getContext(), Native.getDatatypeSortConstructor(getContext().nCtx(), getNativeObject(), 0));
}
/**
* The empty list.
* @throws Z3Exception
**/
public Expr getNil()
public Expr getNil() throws Z3Exception
{
return nilConst;
return getContext().mkApp(getNilDecl());
}
/**
* The declaration of the isNil function of this list sort.
* @throws Z3Exception
**/
public FuncDecl getIsNilDecl()
public FuncDecl getIsNilDecl() throws Z3Exception
{
return isNilDecl;
return new FuncDecl(getContext(), Native.getDatatypeSortRecognizer(getContext().nCtx(), getNativeObject(), 0));
}
/**
* The declaration of the cons function of this list sort.
* @throws Z3Exception
**/
public FuncDecl getConsDecl()
public FuncDecl getConsDecl() throws Z3Exception
{
return consDecl;
return new FuncDecl(getContext(), Native.getDatatypeSortConstructor(getContext().nCtx(), getNativeObject(), 1));
}
/**
* The declaration of the isCons function of this list sort.
* @throws Z3Exception
*
**/
public FuncDecl getIsConsDecl()
public FuncDecl getIsConsDecl() throws Z3Exception
{
return isConsDecl;
return new FuncDecl(getContext(), Native.getDatatypeSortRecognizer(getContext().nCtx(), getNativeObject(), 1));
}
/**
* The declaration of the head function of this list sort.
* @throws Z3Exception
**/
public FuncDecl getHeadDecl()
public FuncDecl getHeadDecl() throws Z3Exception
{
return headDecl;
return new FuncDecl(getContext(), Native.getDatatypeSortConstructorAccessor(getContext().nCtx(), getNativeObject(), 1, 0));
}
/**
* The declaration of the tail function of this list sort.
* @throws Z3Exception
**/
public FuncDecl getTailDecl()
public FuncDecl getTailDecl() throws Z3Exception
{
return tailDecl;
return new FuncDecl(getContext(), Native.getDatatypeSortConstructorAccessor(getContext().nCtx(), getNativeObject(), 1, 1));
}
private FuncDecl nilDecl, isNilDecl, consDecl, isConsDecl, headDecl,
tailDecl;
private Expr nilConst;
ListSort(Context ctx, Symbol name, Sort elemSort) throws Z3Exception
{
super(ctx);
@ -83,12 +86,5 @@ public class ListSort extends Sort
setNativeObject(Native.mkListSort(ctx.nCtx(), name.getNativeObject(),
elemSort.getNativeObject(), inil, iisnil, icons, iiscons, ihead,
itail));
nilDecl = new FuncDecl(ctx, inil.value);
isNilDecl = new FuncDecl(ctx, iisnil.value);
consDecl = new FuncDecl(ctx, icons.value);
isConsDecl = new FuncDecl(ctx, iiscons.value);
headDecl = new FuncDecl(ctx, ihead.value);
tailDecl = new FuncDecl(ctx, itail.value);
nilConst = ctx.mkConst(nilDecl);
}
};

View file

@ -94,7 +94,7 @@ public class Solver extends Z3Object
*
* @throws Z3Exception
**/
public void assert_(BoolExpr... constraints) throws Z3Exception
public void add(BoolExpr... constraints) throws Z3Exception
{
getContext().checkContextMatch(constraints);
for (BoolExpr a : constraints)

View file

@ -701,7 +701,7 @@ typedef enum
over Boolean connectives 'and' and 'or'.
- Z3_OP_PR_NFF_NEG: Proof for a (negative) NNF step. Examples:
- Z3_OP_PR_NNF_NEG: Proof for a (negative) NNF step. Examples:
\nicebox{
T1: (not s_1) ~ r_1
...

View file

@ -1,160 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
ast_list.h
Abstract:
Quick hack to have lists of ASTs.
The lists have hash-consing.
This is a substitute for the old expr_lists implemented on top of the ASTs.
The new lists live in a different manager and do not affect the ast_manager.
Author:
Leonardo de Moura (leonardo) 2011-01-06.
Revision History:
--*/
#ifndef _AST_LIST_H_
#define _AST_LIST_H_
#include"ast.h"
template<typename AST>
class ast_list_manager_tpl;
template<typename AST>
class ast_list_tpl {
public:
typedef ast_list_tpl list;
private:
unsigned m_id;
unsigned m_is_nil:1;
unsigned m_ref_count:31;
AST * m_head;
list * m_tail;
ast_list_tpl():
m_is_nil(true),
m_ref_count(0),
m_head(0),
m_tail(0) {
}
ast_list_tpl(AST * h, list * t):
m_is_nil(false),
m_ref_count(0),
m_head(h),
m_tail(t) {
}
friend class ast_list_manager_tpl<AST>;
struct hash_proc;
friend struct hash_proc;
struct hash_proc {
unsigned operator()(ast_list_tpl * l) const {
unsigned h1 = l->m_head ? l->m_head->get_id() : 5;
unsigned h2 = l->m_tail ? l->m_tail->get_id() : 7;
return hash_u_u(h1, h2);
}
};
struct eq_proc;
friend struct eq_proc;
struct eq_proc {
bool operator()(ast_list_tpl * l1, ast_list_tpl * l2) const {
return l1->m_head == l2->m_head && l1->m_tail == l2->m_tail;
}
};
typedef ptr_hashtable<list, hash_proc, eq_proc> table; // for hash consing
public:
unsigned get_id() const { return m_id; }
unsigned get_ref_count() const { return m_ref_count; }
unsigned hash() const { return m_id; }
friend inline bool is_nil(list const * l) { return l->m_is_nil == true; }
friend inline bool is_cons(list const * l) { return !is_nil(l); }
friend inline AST * head(list const * l) { SASSERT(is_cons(l)); return l->m_head; }
friend inline list * tail(list const * l) { SASSERT(is_cons(l)); return l->m_tail; }
};
template<typename AST>
class ast_list_manager_tpl {
public:
typedef ast_list_tpl<AST> list;
typedef obj_hashtable<list> list_set;
private:
typedef typename list::table table;
ast_manager & m_manager;
small_object_allocator m_allocator;
table m_table;
id_gen m_id_gen;
list m_nil;
public:
ast_list_manager_tpl(ast_manager & m):
m_manager(m),
m_nil() {
m_nil.m_id = m_id_gen.mk();
m_nil.m_ref_count = 1;
}
void inc_ref(list * l) {
if (l != 0) {
l->m_ref_count++;
}
}
void dec_ref(list * l) {
while (l != 0) {
SASSERT(l->m_ref_count > 0);
l->m_ref_count--;
if (l->m_ref_count > 0)
return;
SASSERT(l != &m_nil);
m_table.erase(l);
m_manager.dec_ref(l->m_head);
m_id_gen.recycle(l->m_id);
list * old_l = l;
l = l->m_tail;
m_allocator.deallocate(sizeof(list), old_l);
}
}
list * mk_nil() { return &m_nil; }
list * mk_cons(AST * h, list * l) {
list tmp(h, l);
list * r = 0;
if (m_table.find(&tmp, r))
return r;
r = new (m_allocator.allocate(sizeof(list))) list(h, l);
m_manager.inc_ref(h);
inc_ref(l);
r->m_id = m_id_gen.mk();
m_table.insert(r);
return r;
}
};
typedef ast_list_tpl<expr> expr_list;
typedef ast_list_manager_tpl<expr> expr_list_manager;
typedef ast_list_tpl<quantifier> quantifier_list;
typedef ast_list_manager_tpl<quantifier> quantifier_list_manager;
typedef obj_ref<expr_list, expr_list_manager> expr_list_ref;
typedef obj_ref<quantifier_list, quantifier_list_manager> quantifier_list_ref;
typedef ref_vector<expr_list, expr_list_manager> expr_list_ref_vector;
typedef ref_vector<quantifier_list, quantifier_list_manager> quantifier_list_ref_vector;
#endif

View file

@ -134,6 +134,16 @@ bool lt(ast * n1, ast * n2) {
}
}
bool is_sorted(unsigned num, expr * const * ns) {
for (unsigned i = 1; i < num; i++) {
ast * prev = ns[i-1];
ast * curr = ns[i];
if (lt(curr, prev))
return false;
}
return true;
}
bool lex_lt(unsigned num, ast * const * n1, ast * const * n2) {
for (unsigned i = 0; i < num; i ++) {
if (n1[i] == n2[i])

View file

@ -22,6 +22,7 @@ Revision History:
class ast;
bool lt(ast * n1, ast * n2);
bool is_sorted(unsigned num, expr * const * ns);
struct ast_to_lt {
bool operator()(ast * n1, ast * n2) const { return lt(n1, n2); }

View file

@ -766,7 +766,7 @@ bool bv_recognizers::is_zero(expr const * n) const {
return decl->get_parameter(0).get_rational().is_zero();
}
bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, expr*& b) {
bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, expr*& b) const {
if (!is_extract(e)) return false;
low = get_extract_low(e);
high = get_extract_high(e);
@ -774,7 +774,7 @@ bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, ex
return true;
}
bool bv_recognizers::is_bv2int(expr const* e, expr*& r) {
bool bv_recognizers::is_bv2int(expr const* e, expr*& r) const {
if (!is_bv2int(e)) return false;
r = to_app(e)->get_arg(0);
return true;

View file

@ -288,10 +288,10 @@ public:
bool is_extract(expr const * e) const { return is_app_of(e, get_fid(), OP_EXTRACT); }
unsigned get_extract_high(func_decl const * f) const { return f->get_parameter(0).get_int(); }
unsigned get_extract_low(func_decl const * f) const { return f->get_parameter(1).get_int(); }
unsigned get_extract_high(expr const * n) { SASSERT(is_extract(n)); return get_extract_high(to_app(n)->get_decl()); }
unsigned get_extract_low(expr const * n) { SASSERT(is_extract(n)); return get_extract_low(to_app(n)->get_decl()); }
bool is_extract(expr const * e, unsigned & low, unsigned & high, expr * & b);
bool is_bv2int(expr const * e, expr * & r);
unsigned get_extract_high(expr const * n) const { SASSERT(is_extract(n)); return get_extract_high(to_app(n)->get_decl()); }
unsigned get_extract_low(expr const * n) const { SASSERT(is_extract(n)); return get_extract_low(to_app(n)->get_decl()); }
bool is_extract(expr const * e, unsigned & low, unsigned & high, expr * & b) const;
bool is_bv2int(expr const * e, expr * & r) const;
bool is_bv_add(expr const * e) const { return is_app_of(e, get_fid(), OP_BADD); }
bool is_bv_sub(expr const * e) const { return is_app_of(e, get_fid(), OP_BSUB); }
bool is_bv_mul(expr const * e) const { return is_app_of(e, get_fid(), OP_BMUL); }

View file

@ -151,6 +151,10 @@ sort * float_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, paramete
if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) {
m_manager->raise_exception("expecting two integer parameters to floating point sort");
}
if (parameters[0].get_int() <= 1 || parameters[1].get_int() <= 1)
m_manager->raise_exception("floating point sorts need parameters > 1");
if (parameters[0].get_int() > parameters[1].get_int())
m_manager->raise_exception("floating point sorts with ebits > sbits are currently not supported");
return mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
case ROUNDING_MODE_SORT:
return mk_rm_sort();
@ -349,27 +353,22 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters,
sort * fp = mk_float_sort(domain[2]->get_parameter(0).get_int(), domain[1]->get_parameter(0).get_int()+1);
symbol name("asFloat");
return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
}
}
else {
// .. Otherwise we only know how to convert rationals/reals.
if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()))
m_manager->raise_exception("expecting two integer parameters to asFloat");
if (arity != 2 && arity != 3)
m_manager->raise_exception("invalid number of arguments to asFloat operator");
if (!is_rm_sort(domain[0]) || domain[1] != m_real_sort)
m_manager->raise_exception("invalid number of arguments to asFloat operator");
if (arity == 3 && domain[2] != m_int_sort)
m_manager->raise_exception("sort mismatch");
if (!is_rm_sort(domain[0]) ||
!(domain[1] == m_real_sort || is_sort_of(domain[1], m_family_id, FLOAT_SORT)))
m_manager->raise_exception("sort mismatch");
if (arity == 2) {
sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
symbol name("asFloat");
return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
}
else {
if (domain[2] != m_int_sort)
m_manager->raise_exception("sort mismatch");
sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
symbol name("asFloat");
return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
}
sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
symbol name("asFloat");
return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
}
}
@ -492,6 +491,15 @@ void float_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbo
sort_names.push_back(builtin_name("RoundingMode", ROUNDING_MODE_SORT));
}
expr * float_decl_plugin::get_some_value(sort * s) {
SASSERT(s->is_sort_of(m_family_id, FLOAT_SORT));
mpf tmp;
m_fm.mk_nan(s->get_parameter(0).get_int(), s->get_parameter(1).get_int(), tmp);
expr * res = this->mk_value(tmp);
m_fm.del(tmp);
return res;
}
bool float_decl_plugin::is_value(app * e) const {
if (e->get_family_id() != m_family_id)
return false;

View file

@ -140,6 +140,7 @@ public:
unsigned arity, sort * const * domain, sort * range);
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 expr * get_some_value(sort * s);
virtual bool is_value(app* e) const;
virtual bool is_unique_value(app* e) const { return is_value(e); }

View file

@ -596,8 +596,9 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref
is_hint_head(head, vars) must also return true
*/
bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) {
TRACE("macro_util_hint", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n"
<< mk_pp(exception, m_manager) << "\n";);
TRACE("macro_util_hint", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n";
if (exception) tout << mk_pp(exception, m_manager); else tout << "<null>";
tout << "\n";);
ptr_buffer<var> vars;
if (!is_hint_head(head, vars)) {
TRACE("macro_util_hint", tout << "failed because head is not hint head\n";);
@ -791,7 +792,10 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a
mk_add(args.size(), args.c_ptr(), m_manager.get_sort(arg), rest);
expr_ref def(m_manager);
mk_sub(rhs, rest, def);
add_arith_macro_candidate(to_app(arg), num_decls, def, atom, is_ineq, _is_poly_hint, r);
// If is_poly_hint, rhs may contain variables that do not occur in to_app(arg).
// So, we should re-check.
if (!_is_poly_hint || is_poly_hint(def, to_app(arg), 0))
add_arith_macro_candidate(to_app(arg), num_decls, def, atom, is_ineq, _is_poly_hint, r);
}
else if (is_times_minus_one(arg, neg_arg) && is_app(neg_arg)) {
f = to_app(neg_arg)->get_decl();
@ -809,7 +813,10 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a
mk_add(args.size(), args.c_ptr(), m_manager.get_sort(arg), rest);
expr_ref def(m_manager);
mk_sub(rest, rhs, def);
add_arith_macro_candidate(to_app(neg_arg), num_decls, def, atom, is_ineq, _is_poly_hint, r);
// If is_poly_hint, rhs may contain variables that do not occur in to_app(neg_arg).
// So, we should re-check.
if (!_is_poly_hint || is_poly_hint(def, to_app(neg_arg), 0))
add_arith_macro_candidate(to_app(neg_arg), num_decls, def, atom, is_ineq, _is_poly_hint, r);
}
}
}

View file

@ -981,14 +981,6 @@ br_status arith_rewriter::mk_to_real_core(expr * arg, expr_ref & result) {
result = m_util.mk_numeral(a, false);
return BR_DONE;
}
#if 0
// The following rewriting rule is not correct.
// It is used only for making experiments.
if (m_util.is_to_int(arg)) {
result = to_app(arg)->get_arg(0);
return BR_DONE;
}
#endif
// push to_real over OP_ADD, OP_MUL
if (m_push_to_real) {
if (m_util.is_add(arg) || m_util.is_mul(arg)) {

View file

@ -0,0 +1,165 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
ast_counter.cpp
Abstract:
Routines for counting features of terms, such as free variables.
Author:
Nikolaj Bjorner (nbjorner) 2013-03-18.
Revision History:
--*/
#include "ast_counter.h"
#include "var_subst.h"
void counter::update(unsigned el, int delta) {
int & counter = get(el);
SASSERT(!m_stay_non_negative || counter>=0);
SASSERT(!m_stay_non_negative || static_cast<int>(counter)>=-delta);
counter += delta;
}
int & counter::get(unsigned el) {
return m_data.insert_if_not_there2(el, 0)->get_data().m_value;
}
counter & counter::count(unsigned sz, const unsigned * els, int delta) {
for(unsigned i=0; i<sz; i++) {
update(els[i], delta);
}
return *this;
}
unsigned counter::get_positive_count() const {
unsigned cnt = 0;
iterator eit = begin();
iterator eend = end();
for(; eit!=eend; ++eit) {
if( eit->m_value>0 ) {
cnt++;
}
}
return cnt;
}
void counter::collect_positive(uint_set & acc) const {
iterator eit = begin();
iterator eend = end();
for(; eit!=eend; ++eit) {
if(eit->m_value>0) { acc.insert(eit->m_key); }
}
}
bool counter::get_max_positive(unsigned & res) const {
bool found = false;
iterator eit = begin();
iterator eend = end();
for(; eit!=eend; ++eit) {
if( eit->m_value>0 && (!found || eit->m_key>res) ) {
found = true;
res = eit->m_key;
}
}
return found;
}
unsigned counter::get_max_positive() const {
unsigned max_pos;
VERIFY(get_max_positive(max_pos));
return max_pos;
}
int counter::get_max_counter_value() const {
int res = 0;
iterator eit = begin();
iterator eend = end();
for (; eit!=eend; ++eit) {
if( eit->m_value>res ) {
res = eit->m_value;
}
}
return res;
}
void var_counter::count_vars(ast_manager & m, const app * pred, int coef) {
unsigned n = pred->get_num_args();
for (unsigned i = 0; i < n; i++) {
m_sorts.reset();
::get_free_vars(pred->get_arg(i), m_sorts);
for (unsigned j = 0; j < m_sorts.size(); ++j) {
if (m_sorts[j]) {
update(j, coef);
}
}
}
}
unsigned var_counter::get_max_var(bool& has_var) {
has_var = false;
unsigned max_var = 0;
while (!m_todo.empty()) {
expr* e = m_todo.back();
unsigned scope = m_scopes.back();
m_todo.pop_back();
m_scopes.pop_back();
if (m_visited.is_marked(e)) {
continue;
}
m_visited.mark(e, true);
switch(e->get_kind()) {
case AST_QUANTIFIER: {
quantifier* q = to_quantifier(e);
m_todo.push_back(q->get_expr());
m_scopes.push_back(scope + q->get_num_decls());
break;
}
case AST_VAR: {
if (to_var(e)->get_idx() >= scope + max_var) {
has_var = true;
max_var = to_var(e)->get_idx() - scope;
}
break;
}
case AST_APP: {
app* a = to_app(e);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
m_todo.push_back(a->get_arg(i));
m_scopes.push_back(scope);
}
break;
}
default:
UNREACHABLE();
break;
}
}
m_visited.reset();
return max_var;
}
unsigned var_counter::get_max_var(expr* e) {
bool has_var = false;
m_todo.push_back(e);
m_scopes.push_back(0);
return get_max_var(has_var);
}
unsigned var_counter::get_next_var(expr* e) {
bool has_var = false;
m_todo.push_back(e);
m_scopes.push_back(0);
unsigned mv = get_max_var(has_var);
if (has_var) mv++;
return mv;
}

View file

@ -0,0 +1,107 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
ast_counter.h
Abstract:
Routines for counting features of terms, such as free variables.
Author:
Nikolaj Bjorner (nbjorner) 2013-03-18.
Krystof Hoder (t-khoder) 2010-10-10.
Revision History:
Hoisted from dl_util.h 2013-03-18.
--*/
#ifndef _AST_COUNTER_H_
#define _AST_COUNTER_H_
#include "ast.h"
#include "map.h"
#include "uint_set.h"
class counter {
protected:
typedef u_map<int> map_impl;
map_impl m_data;
const bool m_stay_non_negative;
public:
typedef map_impl::iterator iterator;
counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {}
iterator begin() const { return m_data.begin(); }
iterator end() const { return m_data.end(); }
void update(unsigned el, int delta);
int & get(unsigned el);
/**
\brief Increase values of elements in \c els by \c delta.
The function returns a reference to \c *this to allow for expressions like
counter().count(sz, arr).get_positive_count()
*/
counter & count(unsigned sz, const unsigned * els, int delta = 1);
counter & count(const unsigned_vector & els, int delta = 1) {
return count(els.size(), els.c_ptr(), delta);
}
void collect_positive(uint_set & acc) const;
unsigned get_positive_count() const;
bool get_max_positive(unsigned & res) const;
unsigned get_max_positive() const;
/**
Since the default counter value of a counter is zero, the result is never negative.
*/
int get_max_counter_value() const;
};
class var_counter : public counter {
protected:
ptr_vector<sort> m_sorts;
expr_fast_mark1 m_visited;
ptr_vector<expr> m_todo;
unsigned_vector m_scopes;
unsigned get_max_var(bool & has_var);
public:
var_counter(bool stay_non_negative = true): counter(stay_non_negative) {}
void count_vars(ast_manager & m, const app * t, int coef = 1);
unsigned get_max_var(expr* e);
unsigned get_next_var(expr* e);
};
class ast_counter {
typedef obj_map<ast, int> map_impl;
map_impl m_data;
bool m_stay_non_negative;
public:
typedef map_impl::iterator iterator;
ast_counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {}
iterator begin() const { return m_data.begin(); }
iterator end() const { return m_data.end(); }
int & get(ast * el) {
return m_data.insert_if_not_there2(el, 0)->get_data().m_value;
}
void update(ast * el, int delta){
get(el) += delta;
SASSERT(!m_stay_non_negative || get(el) >= 0);
}
void inc(ast * el) { update(el, 1); }
void dec(ast * el) { update(el, -1); }
};
#endif

View file

@ -64,6 +64,7 @@ void bv_rewriter::updt_local_params(params_ref const & _p) {
m_split_concat_eq = p.split_concat_eq();
m_udiv2mul = p.udiv2mul();
m_bvnot2arith = p.bvnot2arith();
m_bv_sort_ac = p.bv_sort_ac();
m_mkbv2num = _p.get_bool("mkbv2num", false);
}
@ -1315,7 +1316,7 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re
return BR_REWRITE2;
}
if (!flattened && !merged && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero()))) {
if (!flattened && !merged && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero())) && (!m_bv_sort_ac || is_sorted(num, args))) {
return BR_FAILED;
}
@ -1331,6 +1332,8 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re
result = new_args[0];
return BR_DONE;
default:
if (m_bv_sort_ac)
std::sort(new_args.begin(), new_args.end(), ast_to_lt());
result = m_util.mk_bv_or(new_args.size(), new_args.c_ptr());
return BR_DONE;
}
@ -1456,7 +1459,8 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r
return BR_REWRITE3;
}
if (!merged && !flattened && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero() && v1 != (rational::power_of_two(sz) - numeral(1)))))
if (!merged && !flattened && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero() && v1 != (rational::power_of_two(sz) - numeral(1)))) &&
(!m_bv_sort_ac || is_sorted(num, args)))
return BR_FAILED;
ptr_buffer<expr> new_args;
@ -1497,6 +1501,8 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r
}
__fallthrough;
default:
if (m_bv_sort_ac)
std::sort(new_args.begin(), new_args.end(), ast_to_lt());
result = m_util.mk_bv_xor(new_args.size(), new_args.c_ptr());
return BR_DONE;
}

View file

@ -68,6 +68,7 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
bool m_split_concat_eq;
bool m_udiv2mul;
bool m_bvnot2arith;
bool m_bv_sort_ac;
bool is_zero_bit(expr * x, unsigned idx);

View file

@ -8,5 +8,6 @@ def_module_params(module_name='rewriter',
("elim_sign_ext", BOOL, True, "expand sign-ext operator using concat and extract"),
("hi_div0", BOOL, True, "use the 'hardware interpretation' for division by zero (for bit-vector terms)"),
("mul2concat", BOOL, False, "replace multiplication by a power of two into a concatenation"),
("bvnot2arith", BOOL, False, "replace (bvnot x) with (bvsub -1 x)")
("bvnot2arith", BOOL, False, "replace (bvnot x) with (bvsub -1 x)"),
("bv_sort_ac", BOOL, False, "sort the arguments of all AC operators")
))

View file

@ -100,3 +100,9 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) {
}
res = cache.find(e);
}
void expr_safe_replace::reset() {
m_src.reset();
m_dst.reset();
m_subst.reset();
}

View file

@ -38,6 +38,8 @@ public:
void operator()(expr_ref& e) { (*this)(e.get(), e); }
void operator()(expr* src, expr_ref& e);
void reset();
};
#endif /* __EXPR_SAFE_REPLACE_H__ */

View file

@ -77,14 +77,23 @@ br_status float_rewriter::mk_to_float(func_decl * f, unsigned num_args, expr * c
return BR_FAILED;
rational q;
if (!m_util.au().is_numeral(args[1], q))
mpf q_mpf;
if (m_util.au().is_numeral(args[1], q)) {
mpf v;
m_util.fm().set(v, ebits, sbits, rm, q.to_mpq());
result = m_util.mk_value(v);
m_util.fm().del(v);
return BR_DONE;
}
else if (m_util.is_value(args[1], q_mpf)) {
mpf v;
m_util.fm().set(v, ebits, sbits, rm, q_mpf);
result = m_util.mk_value(v);
m_util.fm().del(v);
return BR_DONE;
}
else
return BR_FAILED;
mpf v;
m_util.fm().set(v, ebits, sbits, rm, q.to_mpq());
result = m_util.mk_value(v);
m_util.fm().del(v);
return BR_DONE;
}
else if (num_args == 3 &&
m_util.is_rm(m().get_sort(args[0])) &&
@ -217,8 +226,7 @@ br_status float_rewriter::mk_abs(expr * arg1, expr_ref & result) {
result = arg1;
return BR_DONE;
}
sort * s = m().get_sort(arg1);
result = m().mk_ite(m_util.mk_lt(arg1, m_util.mk_pzero(s)),
result = m().mk_ite(m_util.mk_is_sign_minus(arg1),
m_util.mk_uminus(arg1),
arg1);
return BR_REWRITE2;

View file

@ -25,7 +25,8 @@ Revision History:
#include "bool_rewriter.h"
#include "var_subst.h"
#include "ast_pp.h"
#include "ast_counter.h"
#include "expr_safe_replace.h"
//
// Bring quantifiers of common type into prenex form.
@ -42,7 +43,7 @@ public:
void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result) {
quantifier_type qt = Q_none_pos;
pull_quantifiers(fml, qt, vars, result);
pull_quantifier(fml, qt, vars, result);
TRACE("qe_verbose",
tout << mk_pp(fml, m) << "\n";
tout << mk_pp(result, m) << "\n";);
@ -52,7 +53,7 @@ public:
void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result) {
quantifier_type qt = Q_exists_pos;
pull_quantifiers(fml, qt, vars, result);
pull_quantifier(fml, qt, vars, result);
TRACE("qe_verbose",
tout << mk_pp(fml, m) << "\n";
tout << mk_pp(result, m) << "\n";);
@ -61,7 +62,7 @@ public:
void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars) {
quantifier_type qt = is_forall?Q_forall_pos:Q_exists_pos;
expr_ref result(m);
pull_quantifiers(fml, qt, vars, result);
pull_quantifier(fml, qt, vars, result);
TRACE("qe_verbose",
tout << mk_pp(fml, m) << "\n";
tout << mk_pp(result, m) << "\n";);
@ -78,7 +79,57 @@ public:
expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd);
instantiate(m, q, exprs, result);
}
unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names) {
unsigned index = var_counter().get_next_var(fml);
while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) {
quantifier* q = to_quantifier(fml);
index += q->get_num_decls();
if (names) {
names->append(q->get_num_decls(), q->get_decl_names());
}
if (sorts) {
sorts->append(q->get_num_decls(), q->get_decl_sorts());
}
fml = q->get_expr();
}
if (!has_quantifiers(fml)) {
return index;
}
app_ref_vector vars(m);
pull_quantifier(is_forall, fml, vars);
if (vars.empty()) {
return index;
}
// replace vars by de-bruijn indices
expr_safe_replace rep(m);
svector<symbol> bound_names;
ptr_vector<sort> bound_sorts;
for (unsigned i = 0; i < vars.size(); ++i) {
app* v = vars[i].get();
if (names) {
bound_names.push_back(v->get_decl()->get_name());
}
if (sorts) {
bound_sorts.push_back(m.get_sort(v));
}
rep.insert(v, m.mk_var(index++, m.get_sort(v)));
}
if (names && !bound_names.empty()) {
bound_names.reverse();
bound_names.append(*names);
names->reset();
names->append(bound_names);
}
if (sorts && !bound_sorts.empty()) {
bound_sorts.reverse();
bound_sorts.append(*sorts);
sorts->reset();
sorts->append(bound_sorts);
}
rep(fml);
return index;
}
private:
@ -143,7 +194,7 @@ private:
}
void pull_quantifiers(expr* fml, quantifier_type& qt, app_ref_vector& vars, expr_ref& result) {
void pull_quantifier(expr* fml, quantifier_type& qt, app_ref_vector& vars, expr_ref& result) {
if (!has_quantifiers(fml)) {
result = fml;
@ -159,7 +210,7 @@ private:
if (m.is_and(fml)) {
num_args = a->get_num_args();
for (unsigned i = 0; i < num_args; ++i) {
pull_quantifiers(a->get_arg(i), qt, vars, tmp);
pull_quantifier(a->get_arg(i), qt, vars, tmp);
args.push_back(tmp);
}
m_rewriter.mk_and(args.size(), args.c_ptr(), result);
@ -167,25 +218,25 @@ private:
else if (m.is_or(fml)) {
num_args = to_app(fml)->get_num_args();
for (unsigned i = 0; i < num_args; ++i) {
pull_quantifiers(to_app(fml)->get_arg(i), qt, vars, tmp);
pull_quantifier(to_app(fml)->get_arg(i), qt, vars, tmp);
args.push_back(tmp);
}
m_rewriter.mk_or(args.size(), args.c_ptr(), result);
}
else if (m.is_not(fml)) {
pull_quantifiers(to_app(fml)->get_arg(0), negate(qt), vars, tmp);
pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp);
negate(qt);
result = m.mk_not(tmp);
}
else if (m.is_implies(fml)) {
pull_quantifiers(to_app(fml)->get_arg(0), negate(qt), vars, tmp);
pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp);
negate(qt);
pull_quantifiers(to_app(fml)->get_arg(1), qt, vars, result);
pull_quantifier(to_app(fml)->get_arg(1), qt, vars, result);
result = m.mk_implies(tmp, result);
}
else if (m.is_ite(fml)) {
pull_quantifiers(to_app(fml)->get_arg(1), qt, vars, tmp);
pull_quantifiers(to_app(fml)->get_arg(2), qt, vars, result);
pull_quantifier(to_app(fml)->get_arg(1), qt, vars, tmp);
pull_quantifier(to_app(fml)->get_arg(2), qt, vars, result);
result = m.mk_ite(to_app(fml)->get_arg(0), tmp, result);
}
else {
@ -203,7 +254,7 @@ private:
}
set_quantifier_type(qt, q->is_forall());
extract_quantifier(q, vars, tmp);
pull_quantifiers(tmp, qt, vars, result);
pull_quantifier(tmp, qt, vars, result);
break;
}
case AST_VAR:
@ -215,6 +266,7 @@ private:
break;
}
}
};
quantifier_hoister::quantifier_hoister(ast_manager& m) {
@ -237,3 +289,6 @@ void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_
m_impl->pull_quantifier(is_forall, fml, vars);
}
unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names) {
return m_impl->pull_quantifier(is_forall, fml, sorts, names);
}

View file

@ -59,6 +59,15 @@ public:
The list of variables is empty if there are no top-level universal/existential quantifier.
*/
void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars);
/**
\brief Pull top-most universal (is_forall true) or existential (is_forall=false) quantifier up.
Return an expression with de-Bruijn indices and the list of names that were used.
Return index of maximal variable.
*/
unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names);
};
#endif

View file

@ -18,6 +18,7 @@ Author:
#include"ast_pp.h"
#include"ast_util.h"
#include"ast_smt2_pp.h"
#include"ast_ll_pp.h"
poly_simplifier_plugin::poly_simplifier_plugin(symbol const & fname, ast_manager & m, decl_kind add, decl_kind mul, decl_kind uminus, decl_kind sub,
decl_kind num):
@ -173,7 +174,7 @@ void poly_simplifier_plugin::mk_monomial(unsigned num_args, expr * * args, expr_
result = args[0];
break;
default:
std::sort(args, args + num_args, monomial_element_lt_proc(*this));
std::stable_sort(args, args + num_args, monomial_element_lt_proc(*this));
result = mk_mul(num_args, args);
SASSERT(wf_monomial(result));
break;
@ -465,7 +466,9 @@ void poly_simplifier_plugin::mk_sum_of_monomials(expr_ref_vector & monomials, ex
result = monomials.get(0);
break;
default: {
std::sort(monomials.c_ptr(), monomials.c_ptr() + monomials.size(), monomial_lt_proc(*this));
TRACE("mk_sum_sort", tout << "before\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";);
std::stable_sort(monomials.c_ptr(), monomials.c_ptr() + monomials.size(), monomial_lt_proc(*this));
TRACE("mk_sum_sort", tout << "after\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";);
if (is_simple_sum_of_monomials(monomials)) {
mk_sum_of_monomials_core(monomials.size(), monomials.c_ptr(), result);
return;

View file

@ -34,9 +34,9 @@ public:
expr_dependency_ref & core) {
#pragma omp critical (echo_tactic)
{
m_ctx.diagnostic_stream() << m_msg;
m_ctx.regular_stream() << m_msg;
if (m_newline)
m_ctx.diagnostic_stream() << std::endl;
m_ctx.regular_stream() << std::endl;
}
skip_tactic::operator()(in, result, mc, pc, core);
}

View file

@ -80,3 +80,8 @@ void model_v2_pp(std::ostream & out, model_core const & md, bool partial) {
display_constants(out, md);
display_functions(out, md, partial);
}
// debugging support
void pp(model_core const & md) {
model_v2_pp(std::cout, md, false);
}

View file

@ -441,6 +441,7 @@ protected:
unsigned m_sym_idx;
std::string m_path;
str2sort m_sort_dict;
// true if an error occured during the current call to the parse_stream
// function
@ -812,7 +813,8 @@ protected:
}
f = m_manager.mk_func_decl(s, domain.size(), domain.c_ptr(), m_manager.mk_bool_sort());
m_context.register_predicate(f);
m_context.register_predicate(f, true);
while (tok == TK_ID) {
char const* pred_pragma = m_lexer->get_token_data();
if(strcmp(pred_pragma, "printtuples")==0 || strcmp(pred_pragma, "outputtuples")==0) {

View file

@ -233,7 +233,7 @@ namespace datalog {
table_fact row;
for(; it!=iend; ++it) {
it->get_fact(row);
to_remove.append(row);
to_remove.push_back(row);
}
remove_facts(to_remove.size(), to_remove.c_ptr());
}
@ -325,9 +325,20 @@ namespace datalog {
return res;
}
/**
\brief Default method for complementation.
It assumes that the compiler creates only tables with
at most one column (0 or 1 columns).
Complementation of tables with more than one columns
is transformed into a cross product of complements and/or
difference.
*/
table_base * table_base::complement(func_decl* p, const table_element * func_columns) const {
const table_signature & sig = get_signature();
SASSERT(sig.functional_columns()==0 || func_columns!=0);
SASSERT(sig.first_functional() <= 1);
table_base * res = get_plugin().mk_empty(sig);
@ -335,16 +346,14 @@ namespace datalog {
fact.resize(sig.first_functional());
fact.append(sig.functional_columns(), func_columns);
if(sig.first_functional()==0) {
if(empty()) {
if (sig.first_functional() == 0) {
if (empty()) {
res->add_fact(fact);
}
return res;
}
if(sig.first_functional()!=1) { //now we support only tables with one non-functional column
NOT_IMPLEMENTED_YET();
}
VERIFY(sig.first_functional() == 1);
uint64 upper_bound = get_signature()[0];
bool empty_table = empty();
@ -356,51 +365,13 @@ namespace datalog {
warning_msg(buffer.str().c_str());
}
for(table_element i=0; i<upper_bound; i++) {
fact[0]=i;
for(table_element i = 0; i < upper_bound; i++) {
fact[0] = i;
if(empty_table || !contains_fact(fact)) {
res->add_fact(fact);
}
}
return res;
#if 0
svector<unsigned> var_arg_indexes(arity);
var_arg_indexes.fill(0);
svector<unsigned> var_arg_domain_sizes = s;
unsigned var_cnt=var_arg_indexes.size();
table_fact fact;
fact.resize(arity);
fact.fill(0);
unsigned depth=arity;
while(true) {
if(depth==arity) {
SASSERT(!res->contains_fact(fact));
if(empty_table || !contains_fact(fact)) {
res->add_fact(fact);
}
depth--;
}
else if(fact[depth]==s[depth]-1) {
val_indexes[depth]=0;
if(depth==0) {
break;
}
depth--;
}
else {
SASSERT(val_indexes[depth]<var_arg_domain_sizes[depth]);
unsigned arg_idx = var_arg_indexes[depth];
unsigned val_idx = val_indexes[depth]++;
head_args[arg_idx]=ctx.get_arith().mk_numeral(rational(val_idx), true);
depth++;
}
}
return res;
#endif
}
void table_base::display(std::ostream & out) const {
@ -468,23 +439,21 @@ namespace datalog {
expr_ref_vector disjs(m);
expr_ref_vector conjs(m);
dl_decl_util util(m);
bool_rewriter brw(m);
table_fact fact;
iterator it = begin();
iterator iend = end();
for(; it!=iend; ++it) {
for(; it != iend; ++it) {
const row_interface & r = *it;
r.get_fact(fact);
conjs.reset();
for (unsigned i = 0; i < fact.size(); ++i) {
conjs.push_back(m.mk_eq(m.mk_var(i, sig[i]), util.mk_numeral(fact[i], sig[i])));
}
switch(conjs.size()) {
case 0: disjs.push_back(m.mk_true()); break;
case 1: disjs.push_back(conjs[0].get()); break;
default: disjs.push_back(m.mk_and(conjs.size(), conjs.c_ptr())); break;
}
brw.mk_and(conjs.size(), conjs.c_ptr(), fml);
disjs.push_back(fml);
}
bool_rewriter(m).mk_or(disjs.size(), disjs.c_ptr(), fml);
brw.mk_or(disjs.size(), disjs.c_ptr(), fml);
}
}

View file

@ -233,6 +233,7 @@ namespace datalog {
symbol const& get_name() const { return m_name; }
virtual void set_cancel(bool f) {}
relation_manager & get_manager() const { return m_manager; }
ast_manager& get_ast_manager() const { return datalog::get_ast_manager_from_rel_manager(m_manager); }

View file

@ -307,7 +307,7 @@ namespace datalog {
r1->to_formula(concl);
scoped_proof _sp(m);
proof* p = m.mk_asserted(fml);
proof* p = r->get_proof();
proof* premises[2] = { pr, p };
positions.push_back(std::make_pair(0, 1));
@ -320,7 +320,7 @@ namespace datalog {
else {
r2->to_formula(concl);
scoped_proof _sp(m);
proof* p = m.mk_asserted(fml);
proof* p = r->get_proof();
if (sub.empty()) {
pr = p;
}
@ -340,7 +340,7 @@ namespace datalog {
pred = r->get_decl(0);
}
scoped_proof _sp(m);
apply(m, b.m_pc.get(), pr);
apply(m, b.m_ctx.get_proof_converter().get(), pr);
b.m_answer = pr;
return l_true;
}
@ -474,6 +474,9 @@ namespace datalog {
}
proof_ref get_proof(model_ref& md, func_decl* pred, app* prop, unsigned level) {
if (b.m_cancel) {
return proof_ref(0, m);
}
TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";);
expr_ref prop_r(m), prop_v(m), fml(m), prop_body(m), tmp(m), body(m);
@ -497,7 +500,7 @@ namespace datalog {
SASSERT(r);
r->to_formula(fml);
IF_VERBOSE(1, verbose_stream() << mk_pp(fml, m) << "\n";);
prs.push_back(m.mk_asserted(fml));
prs.push_back(r->get_proof());
unsigned sz = r->get_uninterpreted_tail_size();
ptr_vector<sort> rule_vars;
@ -536,8 +539,9 @@ namespace datalog {
model_ref md;
b.m_solver.get_model(md);
IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0););
proof_ref pr = get_proof(md, b.m_query_pred, to_app(level_query), level);
apply(m, b.m_pc.get(), pr);
proof_ref pr(m);
pr = get_proof(md, b.m_query_pred, to_app(level_query), level);
apply(m, b.m_ctx.get_proof_converter().get(), pr);
b.m_answer = pr;
}
@ -1034,7 +1038,7 @@ namespace datalog {
var_subst vs(m, false);
mk_subst(*rules[i], path, trace, sub);
rules[i]->to_formula(fml);
prs.push_back(m.mk_asserted(fml));
prs.push_back(rules[i]->get_proof());
unsigned sz = trace->get_num_args();
if (sub.empty() && sz == 0) {
pr = prs[0].get();
@ -1112,7 +1116,6 @@ namespace datalog {
}
void mk_answer(model_ref& md, expr_ref& trace, expr_ref& path) {
proof_ref pr(m);
IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0););
md->eval(trace, trace);
md->eval(path, path);
@ -1120,7 +1123,11 @@ namespace datalog {
for (unsigned i = 0; i < b.m_solver.size(); ++i) {
verbose_stream() << mk_pp(b.m_solver.get_formulas()[i], m) << "\n";
});
b.m_answer = get_proof(md, to_app(trace), to_app(path));
scoped_proof _sp(m);
proof_ref pr(m);
pr = get_proof(md, to_app(trace), to_app(path));
apply(m, b.m_ctx.get_proof_converter().get(), pr);
b.m_answer = pr;
}
};
@ -1155,6 +1162,9 @@ namespace datalog {
private:
void get_model(unsigned level) {
if (b.m_cancel) {
return;
}
rule_manager& rm = b.m_ctx.get_rule_manager();
expr_ref level_query = mk_level_predicate(b.m_query_pred, level);
model_ref md;
@ -1212,7 +1222,7 @@ namespace datalog {
r1->to_formula(concl);
scoped_proof _sp(m);
proof* p = m.mk_asserted(fml);
proof* p = r->get_proof();
proof* premises[2] = { pr, p };
positions.push_back(std::make_pair(0, 1));
@ -1225,7 +1235,7 @@ namespace datalog {
else {
r2->to_formula(concl);
scoped_proof _sp(m);
proof* p = m.mk_asserted(fml);
proof* p = r->get_proof();
if (sub.empty()) {
pr = p;
}
@ -1245,7 +1255,7 @@ namespace datalog {
pred = r->get_decl(0);
}
scoped_proof _sp(m);
apply(m, b.m_pc.get(), pr);
apply(m, b.m_ctx.get_proof_converter().get(), pr);
b.m_answer = pr;
}
@ -1409,6 +1419,7 @@ namespace datalog {
m_ctx.ensure_opened();
m_rules.reset();
datalog::rule_manager& rule_manager = m_ctx.get_rule_manager();
datalog::rule_set old_rules(m_ctx.get_rules());
datalog::rule_ref_vector query_rules(rule_manager);
@ -1417,16 +1428,14 @@ namespace datalog {
m_ctx.add_rules(query_rules);
expr_ref bg_assertion = m_ctx.get_background_assertion();
model_converter_ref mc = datalog::mk_skip_model_converter();
m_pc = datalog::mk_skip_proof_converter();
m_ctx.set_output_predicate(m_query_pred);
m_ctx.apply_default_transformation(mc, m_pc);
m_ctx.apply_default_transformation();
if (m_ctx.get_params().slice()) {
datalog::rule_transformer transformer(m_ctx);
datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx);
transformer.register_plugin(slice);
m_ctx.transform_rules(transformer, mc, m_pc);
m_ctx.transform_rules(transformer);
m_query_pred = slice->get_predicate(m_query_pred.get());
m_ctx.set_output_predicate(m_query_pred);
}

View file

@ -39,7 +39,6 @@ namespace datalog {
func_decl_ref m_query_pred;
expr_ref m_answer;
volatile bool m_cancel;
proof_converter_ref m_pc;
void checkpoint();

View file

@ -287,9 +287,6 @@ namespace datalog {
bool check_table::well_formed() const {
get_plugin().m_count++;
if (get_plugin().m_count == 497) {
std::cout << "here\n";
}
iterator it = m_tocheck->begin(), end = m_tocheck->end();
for (; it != end; ++it) {
table_fact fact;
@ -354,8 +351,8 @@ namespace datalog {
return result;
}
table_base * check_table::complement(func_decl* p) const {
check_table* result = alloc(check_table, get_plugin(), get_signature(), m_tocheck->complement(p), m_checker->complement(p));
table_base * check_table::complement(func_decl* p, const table_element * func_columns) const {
check_table* result = alloc(check_table, get_plugin(), get_signature(), m_tocheck->complement(p, func_columns), m_checker->complement(p, func_columns));
return result;
}

View file

@ -119,7 +119,7 @@ namespace datalog {
virtual void add_fact(const table_fact & f);
virtual void remove_fact(const table_element* fact);
virtual bool contains_fact(const table_fact & f) const;
virtual table_base * complement(func_decl* p) const;
virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const;
virtual table_base * clone() const;
virtual iterator begin() const { SASSERT(well_formed()); return m_tocheck->begin(); }

View file

@ -229,12 +229,12 @@ public:
status = dlctx.query(m_target);
}
catch (z3_error & ex) {
ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl;
throw ex;
}
catch (z3_exception& ex) {
ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl;
}
dlctx.cleanup();
}
switch (status) {
case l_false:
@ -250,6 +250,7 @@ public:
ctx.regular_stream() << "unknown\n";
switch(dlctx.get_status()) {
case datalog::INPUT_ERROR:
ctx.regular_stream() << "input error\n";
break;
case datalog::MEMOUT:
@ -261,12 +262,21 @@ public:
break;
case datalog::OK:
UNREACHABLE();
break;
case datalog::CANCELED:
ctx.regular_stream() << "canceled\n";
dlctx.display_profile(ctx.regular_stream());
break;
default:
UNREACHABLE();
break;
}
break;
}
dlctx.cleanup();
print_statistics(ctx);
m_target = 0;
}

View file

@ -384,8 +384,8 @@ namespace datalog {
void compiler::get_local_indexes_for_projection(rule * r, unsigned_vector & res) {
SASSERT(r->get_positive_tail_size()==2);
ast_manager & m = m_context.get_manager();
var_counter counter;
counter.count_vars(m, r);
rule_counter counter;
counter.count_rule_vars(m, r);
app * t1 = r->get_tail(0);
app * t2 = r->get_tail(1);
counter.count_vars(m, t1, -1);
@ -707,6 +707,7 @@ namespace datalog {
//update the head relation
make_union(new_head_reg, head_reg, delta_reg, use_widening, acc);
make_dealloc_non_void(new_head_reg, acc);
}
finish:
@ -1028,21 +1029,23 @@ namespace datalog {
func_decl * head_pred = *preds.begin();
const rule_vector & rules = m_rule_set.get_predicate_rules(head_pred);
reg_idx output_delta;
if(!output_deltas.find(head_pred, output_delta)) {
if (!output_deltas.find(head_pred, output_delta)) {
output_delta = execution_context::void_register;
}
rule_vector::const_iterator it = rules.begin();
rule_vector::const_iterator end = rules.end();
for(; it!=end; ++it) {
for (; it != end; ++it) {
rule * r = *it;
SASSERT(r->get_head()->get_decl()==head_pred);
compile_rule_evaluation(r, input_deltas, output_delta, false, acc);
}
if(add_saturation_marks) {
if (add_saturation_marks) {
//now the predicate is saturated, so we may mark it as such
acc.push_back(instruction::mk_mark_saturated(m_context.get_manager(), head_pred));
}
@ -1068,7 +1071,7 @@ namespace datalog {
for(; sit!=send; ++sit) {
func_decl_set & strat_preds = **sit;
if(all_saturated(strat_preds)) {
if (all_saturated(strat_preds)) {
//all predicates in stratum are saturated, so no need to compile rules for them
continue;
}
@ -1084,7 +1087,7 @@ namespace datalog {
tout << "\n";
);
if(is_nonrecursive_stratum(strat_preds)) {
if (is_nonrecursive_stratum(strat_preds)) {
//this stratum contains just a single non-recursive rule
compile_nonrecursive_stratum(strat_preds, input_deltas, output_deltas, add_saturation_marks, acc);
}

View file

@ -45,6 +45,9 @@ Revision History:
#include"dl_mk_partial_equiv.h"
#include"dl_mk_bit_blast.h"
#include"dl_mk_array_blast.h"
#include"dl_mk_karr_invariants.h"
#include"dl_mk_quantifier_abstraction.h"
#include"dl_mk_quantifier_instantiation.h"
#include"datatype_decl_plugin.h"
#include"expr_abstract.h"
@ -223,14 +226,18 @@ namespace datalog {
m_rewriter(m),
m_var_subst(m),
m_rule_manager(*this),
m_transf(*this),
m_trail(*this),
m_pinned(m),
m_vars(m),
m_rule_set(*this),
m_transformed_rule_set(*this),
m_rule_fmls(m),
m_background(m),
m_mc(0),
m_closed(false),
m_saturation_was_run(false),
m_last_status(OK),
m_last_answer(m),
m_engine(LAST_ENGINE),
m_cancel(false) {
@ -295,14 +302,6 @@ namespace datalog {
return m_preds.contains(pred);
}
func_decl * context::try_get_predicate_decl(symbol pred_name) const {
func_decl * res;
if (!m_preds_by_name.find(pred_name, res)) {
return 0;
}
return res;
}
void context::register_variable(func_decl* var) {
m_vars.push_back(m.mk_const(var));
}
@ -354,7 +353,6 @@ namespace datalog {
m_pinned.push_back(decl);
m_preds.insert(decl);
if (named) {
SASSERT(!m_preds_by_name.contains(decl->get_name()));
m_preds_by_name.insert(decl->get_name(), decl);
}
}
@ -441,7 +439,7 @@ namespace datalog {
func_decl* new_pred =
m.mk_fresh_func_decl(prefix, suffix, arity, domain, m.mk_bool_sort());
register_predicate(new_pred);
register_predicate(new_pred, true);
if (m_rel.get()) {
m_rel->inherit_predicate_kind(new_pred, orig_pred);
@ -472,8 +470,11 @@ namespace datalog {
void context::flush_add_rules() {
datalog::rule_manager& rm = get_rule_manager();
datalog::rule_ref_vector rules(rm);
scoped_proof_mode _scp(m, generate_proof_trace()?PGM_FINE:PGM_DISABLED);
for (unsigned i = 0; i < m_rule_fmls.size(); ++i) {
rm.mk_rule(m_rule_fmls[i].get(), rules, m_rule_names[i]);
expr* fml = m_rule_fmls[i].get();
proof* p = generate_proof_trace()?m.mk_asserted(fml):0;
rm.mk_rule(fml, p, rules, m_rule_names[i]);
}
add_rules(rules);
m_rule_fmls.reset();
@ -487,7 +488,11 @@ namespace datalog {
void context::update_rule(expr* rl, symbol const& name) {
datalog::rule_manager& rm = get_rule_manager();
datalog::rule_ref_vector rules(rm);
rm.mk_rule(rl, rules, name);
proof* p = 0;
if (generate_proof_trace()) {
p = m.mk_asserted(rl);
}
rm.mk_rule(rl, p, rules, name);
if (rules.size() != 1) {
std::stringstream strm;
strm << "Rule " << name << " has a non-trivial body. It cannot be modified";
@ -681,7 +686,7 @@ namespace datalog {
todo.push_back(e2);
}
else if (is_quantifier(e)) {
todo.append(to_quantifier(e)->get_expr());
todo.push_back(to_quantifier(e)->get_expr());
}
else if ((m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) &&
m.is_true(e1)) {
@ -735,6 +740,9 @@ namespace datalog {
UNREACHABLE();
break;
}
if (generate_proof_trace() && !r->get_proof()) {
m_rule_manager.mk_rule_asserted_proof(*r.get());
}
}
void context::add_rule(rule_ref& r) {
@ -772,6 +780,10 @@ namespace datalog {
add_fact(head->get_decl(), fact);
}
bool context::has_facts(func_decl * pred) const {
return m_rel && m_rel->has_facts(pred);
}
void context::add_table_fact(func_decl * pred, const table_fact & fact) {
if (get_engine() == DATALOG_ENGINE) {
ensure_rel();
@ -824,28 +836,28 @@ namespace datalog {
m_closed = false;
}
void context::transform_rules(model_converter_ref& mc, proof_converter_ref& pc) {
rule_transformer transf(*this);
transf.register_plugin(alloc(mk_filter_rules,*this));
transf.register_plugin(alloc(mk_simple_joins,*this));
void context::transform_rules() {
m_transf.reset();
m_transf.register_plugin(alloc(mk_filter_rules,*this));
m_transf.register_plugin(alloc(mk_simple_joins,*this));
if (unbound_compressor()) {
transf.register_plugin(alloc(mk_unbound_compressor,*this));
m_transf.register_plugin(alloc(mk_unbound_compressor,*this));
}
if (similarity_compressor()) {
transf.register_plugin(alloc(mk_similarity_compressor, *this,
m_transf.register_plugin(alloc(mk_similarity_compressor, *this,
similarity_compressor_threshold()));
}
transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this));
m_transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this));
transform_rules(transf, mc, pc);
transform_rules(m_transf);
}
void context::transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc) {
void context::transform_rules(rule_transformer& transf) {
SASSERT(m_closed); //we must finish adding rules before we start transforming them
TRACE("dl", display_rules(tout););
if (transf(m_rule_set, mc, pc)) {
if (transf(m_rule_set)) {
//we have already ensured the negation is stratified and transformations
//should not break the stratification
m_rule_set.ensure_closed();
@ -860,34 +872,47 @@ namespace datalog {
m_rule_set.add_rules(rs);
}
void context::apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc) {
ensure_closed();
datalog::rule_transformer transf(*this);
transf.register_plugin(alloc(datalog::mk_coi_filter, *this));
transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this));
void context::record_transformed_rules() {
m_transformed_rule_set.reset();
m_transformed_rule_set.add_rules(m_rule_set);
}
transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 35005));
transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 35000));
transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34990));
transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34980));
void context::apply_default_transformation() {
ensure_closed();
m_transf.reset();
m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this));
m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this));
m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 35005));
m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 35000));
m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34990));
m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34980));
//and another round of inlining
transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34975));
transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34970));
transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34960));
transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34950));
m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34975));
m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34970));
m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34960));
m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34950));
transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34940));
transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34930));
transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34920));
transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34910));
transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34900));
transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890));
transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880));
m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34940));
m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34930));
m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34920));
m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34910));
m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34900));
m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890));
m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880));
transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000));
transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000));
transform_rules(transf, mc, pc);
if (get_params().quantify_arrays()) {
m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000));
m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 32500));
}
m_transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, *this, 32000));
m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000));
m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000));
m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010));
transform_rules(m_transf);
}
void context::collect_params(param_descrs& p) {
@ -928,18 +953,21 @@ namespace datalog {
void context::cancel() {
m_cancel = true;
m_last_status = CANCELED;
m_transf.cancel();
if (m_pdr.get()) m_pdr->cancel();
if (m_bmc.get()) m_bmc->cancel();
if (m_rel.get()) m_rel->cancel();
if (m_tab.get()) m_tab->cancel();
if (m_rel.get()) m_rel->set_cancel(true);
}
void context::cleanup() {
m_cancel = false;
m_last_status = OK;
if (m_pdr.get()) m_pdr->cleanup();
if (m_bmc.get()) m_bmc->cleanup();
if (m_rel.get()) m_rel->cleanup();
if (m_tab.get()) m_tab->cleanup();
if (m_rel.get()) m_rel->set_cancel(false);
}
class context::engine_type_proc {
@ -1031,6 +1059,8 @@ namespace datalog {
}
void context::new_query() {
m_mc = mk_skip_model_converter();
flush_add_rules();
m_last_status = OK;
m_last_answer = 0;
@ -1142,6 +1172,7 @@ namespace datalog {
switch(get_engine()) {
case DATALOG_ENGINE:
return false;
case PDR_ENGINE:
case QPDR_ENGINE:
ensure_pdr();
m_pdr->display_certificate(out);
@ -1160,6 +1191,20 @@ namespace datalog {
}
}
void context::display_profile(std::ostream& out) const {
out << "\n---------------\n";
out << "Original rules\n";
display_rules(out);
out << "\n---------------\n";
out << "Transformed rules\n";
m_transformed_rule_set.display(out);
if (m_rel) {
m_rel->display_profile(out);
}
}
void context::reset_statistics() {
if (m_pdr) {
m_pdr->reset_statistics();
@ -1192,7 +1237,7 @@ namespace datalog {
return m_rel->result_contains_fact(f);
}
// TBD: algebraic data-types declarations will not be printed.
// NB: algebraic data-types declarations will not be printed.
class free_func_visitor {
ast_manager& m;
func_decl_set m_funcs;
@ -1235,7 +1280,7 @@ namespace datalog {
ptr_vector<sort> sorts;
get_free_vars(m_rule_fmls[i].get(), sorts);
if (!sorts.empty()) {
rm.mk_rule(m_rule_fmls[i].get(), rule_refs, m_rule_names[i]);
rm.mk_rule(m_rule_fmls[i].get(), 0, rule_refs, m_rule_names[i]);
m_rule_fmls[i] = m_rule_fmls.back();
m_rule_names[i] = m_rule_names.back();
m_rule_fmls.pop_back();
@ -1252,7 +1297,7 @@ namespace datalog {
}
for (unsigned i = 0; i < m_rule_fmls.size(); ++i) {
rules.push_back(m_rule_fmls[i].get());
names.push_back(m_rule_names[i]);
names.push_back(m_rule_names[i]);
}
}

View file

@ -42,19 +42,18 @@ Revision History:
#include"params.h"
#include"trail.h"
#include"model_converter.h"
#include"proof_converter.h"
#include"model2expr.h"
#include"smt_params.h"
#include"dl_rule_transformer.h"
namespace datalog {
class rule_transformer;
enum execution_result {
OK,
TIMEOUT,
MEMOUT,
INPUT_ERROR
INPUT_ERROR,
CANCELED
};
class context {
@ -85,7 +84,7 @@ namespace datalog {
th_rewriter m_rewriter;
var_subst m_var_subst;
rule_manager m_rule_manager;
rule_transformer m_transf;
trail_stack<context> m_trail;
ast_ref_vector m_pinned;
app_ref_vector m_vars;
@ -94,9 +93,12 @@ namespace datalog {
sym2decl m_preds_by_name;
pred2syms m_argument_var_names;
rule_set m_rule_set;
rule_set m_transformed_rule_set;
expr_ref_vector m_rule_fmls;
svector<symbol> m_rule_names;
expr_ref_vector m_background;
model_converter_ref m_mc;
proof_converter_ref m_pc;
scoped_ptr<pdr::dl_interface> m_pdr;
scoped_ptr<bmc> m_bmc;
@ -110,6 +112,8 @@ namespace datalog {
DL_ENGINE m_engine;
volatile bool m_cancel;
bool is_fact(app * head) const;
bool has_sort_domain(relation_sort s) const;
sort_domain & get_sort_domain(relation_sort s);
@ -140,6 +144,7 @@ namespace datalog {
var_subst & get_var_subst() { return m_var_subst; }
dl_decl_util & get_decl_util() { return m_decl_util; }
bool generate_proof_trace() const { return m_params.generate_proof_trace(); }
bool output_profile() const { return m_params.output_profile(); }
bool fix_unbound_vars() const { return m_params.fix_unbound_vars(); }
symbol default_table() const { return m_params.default_table(); }
@ -178,18 +183,22 @@ namespace datalog {
retrieved by the try_get_predicate_decl() function. Auxiliary predicates introduced
e.g. by rule transformations do not need to be named.
*/
void register_predicate(func_decl * pred, bool named = true);
void register_predicate(func_decl * pred, bool named);
bool is_predicate(func_decl * pred) const;
/**
\brief If a predicate name has a \c func_decl object assigned, return pointer to it;
otherwise return 0.
Not all \c func_decl object used as relation identifiers need to be assigned to their
names. Generally, the names coming from the parses are registered here.
*/
func_decl * try_get_predicate_decl(symbol pred_name) const;
*/
func_decl * try_get_predicate_decl(symbol const& pred_name) const {
func_decl * res = 0;
m_preds_by_name.find(pred_name, res);
return res;
}
/**
\brief Create a fresh head predicate declaration.
@ -240,6 +249,7 @@ namespace datalog {
void add_fact(app * head);
void add_fact(func_decl * pred, const relation_fact & fact);
bool has_facts(func_decl * pred) const;
void add_rule(rule_ref& r);
void add_rules(rule_ref_vector& rs);
@ -313,11 +323,17 @@ namespace datalog {
void reopen();
void ensure_opened();
void transform_rules(model_converter_ref& mc, proof_converter_ref& pc);
void transform_rules(rule_transformer& trans, model_converter_ref& mc, proof_converter_ref& pc);
void replace_rules(rule_set & rs);
model_converter_ref& get_model_converter() { return m_mc; }
void add_model_converter(model_converter* mc) { m_mc = concat(m_mc.get(), mc); }
proof_converter_ref& get_proof_converter() { return m_pc; }
void add_proof_converter(proof_converter* pc) { m_pc = concat(m_pc.get(), pc); }
void apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc);
void transform_rules();
void transform_rules(rule_transformer& transf);
void replace_rules(rule_set & rs);
void record_transformed_rules();
void apply_default_transformation();
void collect_params(param_descrs& r);
@ -342,6 +358,8 @@ namespace datalog {
void display_smt2(unsigned num_queries, expr* const* queries, std::ostream& out);
void display_profile(std::ostream& out) const;
// -----------------------------------
//
// basic usage methods
@ -349,6 +367,7 @@ namespace datalog {
// -----------------------------------
void cancel();
bool canceled() const { return m_cancel; }
void cleanup();
void reset_cancel() { cleanup(); }

View file

@ -58,14 +58,18 @@ namespace datalog {
reset_timelimit();
}
rel_context& execution_context::get_rel_context() {
return m_context.get_rel_context();
}
struct compare_size_proc {
typedef std::pair<unsigned, unsigned> pr;
bool operator()(pr const& a, pr const& b) const {
return a.second > b.second;
}
};
void execution_context::report_big_relations(unsigned threshold, std::ostream & out) {
void execution_context::report_big_relations(unsigned threshold, std::ostream & out) const {
unsigned n = register_count();
svector<std::pair<unsigned, unsigned> > sizes;
size_t total_bytes = 0;
@ -110,6 +114,7 @@ namespace datalog {
bool execution_context::should_terminate() {
return
m_context.canceled() ||
memory::above_high_watermark() ||
(m_stopwatch &&
m_timelimit_ms != 0 &&
@ -135,7 +140,7 @@ namespace datalog {
process_costs();
}
void instruction::display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const {
void instruction::display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const {
out << indentation;
display_head_impl(ctx, out);
if (ctx.output_profile()) {
@ -182,7 +187,7 @@ namespace datalog {
virtual void make_annotations(execution_context & ctx) {
ctx.set_register_annotation(m_reg, m_pred->get_name().bare_str());
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
const char * rel_name = m_pred->get_name().bare_str();
if (m_store) {
out << "store " << m_reg << " into " << rel_name;
@ -213,7 +218,7 @@ namespace datalog {
virtual void make_annotations(execution_context & ctx) {
ctx.set_register_annotation(m_reg, "alloc");
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "dealloc " << m_reg;
}
};
@ -248,7 +253,7 @@ namespace datalog {
ctx.set_register_annotation(m_src, str);
}
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << (m_clone ? "clone " : "move ") << m_src << " into " << m_tgt;
}
};
@ -304,11 +309,11 @@ namespace datalog {
virtual void make_annotations(execution_context & ctx) {
m_body->make_annotations(ctx);
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const {
out << "while";
print_container(m_controls, out);
}
virtual void display_body_impl(rel_context & ctx, std::ostream & out, std::string indentation) const {
virtual void display_body_impl(rel_context const & ctx, std::ostream & out, std::string indentation) const {
m_body->display_indented(ctx, out, indentation+" ");
}
};
@ -385,7 +390,7 @@ namespace datalog {
ctx.get_register_annotation(m_rel1, a1);
ctx.set_register_annotation(m_res, "join " + a1 + " " + a2);
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const {
out << "join " << m_rel1;
print_container(m_cols1, out);
out << " and " << m_rel2;
@ -434,7 +439,7 @@ namespace datalog {
a << "filter_equal " << m_col << " val: " << ctx.get_rel_context().get_rmanager().to_nice_string(m_value);
ctx.set_register_annotation(m_reg, a.str());
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "filter_equal " << m_reg << " col: " << m_col << " val: "
<< ctx.get_rmanager().to_nice_string(m_value);
}
@ -476,7 +481,7 @@ namespace datalog {
}
return true;
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "filter_identical " << m_reg << " ";
print_container(m_cols, out);
}
@ -519,7 +524,7 @@ namespace datalog {
}
return true;
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "filter_interpreted " << m_reg << " using "
<< mk_pp(m_cond, m_cond.get_manager());
}
@ -619,12 +624,16 @@ namespace datalog {
return true;
}
virtual void make_annotations(execution_context & ctx) {
std::string str;
if (ctx.get_register_annotation(m_tgt, str) && m_delta!=execution_context::void_register) {
ctx.set_register_annotation(m_delta, "delta of "+str);
std::string str = "union";
if (!ctx.get_register_annotation(m_tgt, str)) {
ctx.set_register_annotation(m_tgt, "union");
}
if (m_delta != execution_context::void_register) {
str = "delta of " + str;
}
ctx.set_register_annotation(m_delta, str);
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << (m_widen ? "widen " : "union ") << m_src << " into " << m_tgt;
if (m_delta!=execution_context::void_register) {
out << " with delta " << m_delta;
@ -678,7 +687,7 @@ namespace datalog {
return true;
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << (m_projection ? "project " : "rename ") << m_src << " into " << m_tgt;
out << (m_projection ? " deleting columns " : " with cycle ");
print_container(m_cols, out);
@ -739,7 +748,7 @@ namespace datalog {
}
return true;
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "join_project " << m_rel1;
print_container(m_cols1, out);
out << " and " << m_rel2;
@ -800,7 +809,7 @@ namespace datalog {
}
return true;
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "select_equal_and_project " << m_src <<" into " << m_result << " col: " << m_col
<< " val: " << ctx.get_rmanager().to_nice_string(m_value);
}
@ -854,7 +863,7 @@ namespace datalog {
}
return true;
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "filter_by_negation on " << m_tgt;
print_container(m_cols1, out);
out << " with " << m_neg_rel;
@ -892,7 +901,7 @@ namespace datalog {
ctx.set_reg(m_tgt, rel);
return true;
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "mk_unary_singleton into " << m_tgt << " sort:"
<< ctx.get_rmanager().to_nice_string(m_sig[0]) << " val:"
<< ctx.get_rmanager().to_nice_string(m_sig[0], m_fact[0]);
@ -922,7 +931,7 @@ namespace datalog {
ctx.set_reg(m_tgt, ctx.get_rel_context().get_rmanager().mk_full_relation(m_sig, m_pred));
return true;
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "mk_total into " << m_tgt << " sort:"
<< ctx.get_rmanager().to_nice_string(m_sig);
}
@ -947,7 +956,7 @@ namespace datalog {
ctx.get_rel_context().get_rmanager().mark_saturated(m_pred);
return true;
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "mark_saturated " << m_pred->get_name().bare_str();
}
virtual void make_annotations(execution_context & ctx) {
@ -970,7 +979,7 @@ namespace datalog {
}
return true;
}
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "instr_assert_signature of " << m_tgt << " signature:";
print_container(m_sig, out);
}
@ -1042,7 +1051,7 @@ namespace datalog {
}
}
void instruction_block::display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const {
void instruction_block::display_indented(rel_context const& ctx, std::ostream & out, std::string indentation) const {
instr_seq_type::const_iterator it = m_data.begin();
instr_seq_type::const_iterator end = m_data.end();
for(; it!=end; ++it) {

View file

@ -31,6 +31,7 @@ namespace datalog {
class execution_context;
class instruction_block;
class rel_context;
inline void check_overflow(unsigned i) {
if (i == UINT_MAX) {
@ -78,7 +79,7 @@ namespace datalog {
void reset();
rel_context & get_rel_context() { return m_context.get_rel_context(); };
rel_context & get_rel_context();
void set_timelimit(unsigned time_in_ms);
void reset_timelimit();
@ -91,10 +92,9 @@ namespace datalog {
If register contains zero, it should be treated as if it contains an empty relation.
*/
reg_type reg(reg_idx i) {
if (i>=m_registers.size()) {
check_overflow(i);
m_registers.resize(i+1,0);
reg_type reg(reg_idx i) const {
if (i >= m_registers.size()) {
return 0;
}
return m_registers[i];
}
@ -102,27 +102,29 @@ namespace datalog {
\brief Return value of the register and assign zero into it place.
*/
reg_type release_reg(reg_idx i) {
SASSERT(i<m_registers.size());
SASSERT(i < m_registers.size());
SASSERT(m_registers[i]);
reg_type res = m_registers[i];
m_registers[i] = 0;
return res;
}
/**
\brief Assign value to a register. If it was non-empty, deallocate its content first.
*/
void set_reg(reg_idx i, reg_type val) {
if(i>=m_registers.size()) {
if (i >= m_registers.size()) {
check_overflow(i);
m_registers.resize(i+1,0);
}
if(m_registers[i]) {
if (m_registers[i]) {
m_registers[i]->deallocate();
}
m_registers[i]=val;
m_registers[i] = val;
}
void make_empty(reg_idx i) {
if(reg(i)) {
if (reg(i)) {
set_reg(i, 0);
}
}
@ -130,14 +132,16 @@ namespace datalog {
unsigned register_count() const {
return m_registers.size();
}
bool get_register_annotation(reg_idx reg, std::string & res) const {
return m_reg_annotation.find(reg, res);
}
void set_register_annotation(reg_idx reg, std::string str) {
m_reg_annotation.insert(reg, str);
}
void report_big_relations(unsigned threshold, std::ostream & out);
void report_big_relations(unsigned threshold, std::ostream & out) const;
};
@ -208,7 +212,7 @@ namespace datalog {
The newline character at the end should not be printed.
*/
virtual void display_head_impl(rel_context & ctx, std::ostream & out) const {
virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const {
out << "<instruction>";
}
/**
@ -216,7 +220,7 @@ namespace datalog {
Each line must be prepended by \c indentation and ended by a newline character.
*/
virtual void display_body_impl(rel_context & ctx, std::ostream & out, std::string indentation) const {}
virtual void display_body_impl(rel_context const & ctx, std::ostream & out, std::string indentation) const {}
public:
typedef execution_context::reg_type reg_type;
typedef execution_context::reg_idx reg_idx;
@ -227,10 +231,10 @@ namespace datalog {
virtual void make_annotations(execution_context & ctx) = 0;
void display(rel_context & ctx, std::ostream & out) const {
void display(rel_context const& ctx, std::ostream & out) const {
display_indented(ctx, out, "");
}
void display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const;
void display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const;
static instruction * mk_load(ast_manager & m, func_decl * pred, reg_idx tgt);
/**
@ -329,10 +333,10 @@ namespace datalog {
void make_annotations(execution_context & ctx);
void display(rel_context & ctx, std::ostream & out) const {
void display(rel_context const & ctx, std::ostream & out) const {
display_indented(ctx, out, "");
}
void display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const;
void display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const;
};

View file

@ -21,6 +21,7 @@ Revision History:
#include "optional.h"
#include "ast_pp.h"
#include "dl_interval_relation.h"
#include "bool_rewriter.h"
namespace datalog {
@ -30,8 +31,7 @@ namespace datalog {
interval_relation_plugin::interval_relation_plugin(relation_manager& m):
relation_plugin(interval_relation_plugin::get_name(), m),
m_empty(m_dep),
m_arith(get_ast_manager()),
m_bsimp(get_ast_manager()) {
m_arith(get_ast_manager()) {
}
bool interval_relation_plugin::can_handle_signature(const relation_signature & sig) {
@ -374,7 +374,6 @@ namespace datalog {
void interval_relation::to_formula(expr_ref& fml) const {
ast_manager& m = get_plugin().get_ast_manager();
arith_util& arith = get_plugin().m_arith;
basic_simplifier_plugin& bsimp = get_plugin().m_bsimp;
expr_ref_vector conjs(m);
relation_signature const& sig = get_signature();
for (unsigned i = 0; i < sig.size(); ++i) {
@ -405,7 +404,8 @@ namespace datalog {
}
}
}
bsimp.mk_and(conjs.size(), conjs.c_ptr(), fml);
bool_rewriter br(m);
br.mk_and(conjs.size(), conjs.c_ptr(), fml);
}

View file

@ -34,7 +34,6 @@ namespace datalog {
v_dependency_manager m_dep;
interval m_empty;
arith_util m_arith;
basic_simplifier_plugin m_bsimp;
class join_fn;
class project_fn;

View file

@ -30,7 +30,8 @@ namespace datalog {
m(ctx.get_manager()),
a(m),
rm(ctx.get_rule_manager()),
m_rewriter(m, m_params){
m_rewriter(m, m_params),
m_simplifier(ctx) {
m_params.set_bool("expand_select_store",true);
m_rewriter.updt_params(m_params);
}
@ -197,39 +198,31 @@ namespace datalog {
}
fml2 = m.mk_implies(body, head);
rm.mk_rule(fml2, new_rules, r.name());
proof_ref p(m);
rm.mk_rule(fml2, p, new_rules, r.name());
SASSERT(new_rules.size() == 1);
TRACE("dl", new_rules[0]->display(m_ctx, tout << "new rule\n"););
rules.add_rule(new_rules[0].get());
if (m_pc) {
new_rules[0]->to_formula(fml2);
m_pc->insert(fml1, fml2);
rule_ref new_rule(rm);
if (m_simplifier.transform_rule(new_rules[0].get(), new_rule)) {
rules.add_rule(new_rule.get());
rm.mk_rule_rewrite_proof(r, *new_rule.get());
}
return true;
}
rule_set * mk_array_blast::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
ref<equiv_proof_converter> epc;
if (pc) {
epc = alloc(equiv_proof_converter, m);
}
m_pc = epc.get();
rule_set * mk_array_blast::operator()(rule_set const & source) {
rule_set* rules = alloc(rule_set, m_ctx);
rule_set::iterator it = source.begin(), end = source.end();
bool change = false;
for (; it != end; ++it) {
for (; !m_ctx.canceled() && it != end; ++it) {
change = blast(**it, *rules) || change;
}
if (!change) {
dealloc(rules);
rules = 0;
}
if (pc) {
pc = concat(pc.get(), epc.get());
}
return rules;
}

View file

@ -22,6 +22,7 @@ Revision History:
#include"dl_context.h"
#include"dl_rule_set.h"
#include"dl_rule_transformer.h"
#include"dl_mk_interp_tail_simplifier.h"
#include "equiv_proof_converter.h"
#include "array_decl_plugin.h"
@ -37,7 +38,7 @@ namespace datalog {
rule_manager& rm;
params_ref m_params;
th_rewriter m_rewriter;
equiv_proof_converter* m_pc;
mk_interp_tail_simplifier m_simplifier;
typedef obj_map<app, var*> defs_t;
@ -49,13 +50,13 @@ namespace datalog {
public:
/**
\brief Create rule transformer that extracts universal quantifiers (over recursive predicates).
\brief Create rule transformer that removes array stores and selects by ackermannization.
*/
mk_array_blast(context & ctx, unsigned priority);
virtual ~mk_array_blast();
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
};

View file

@ -21,7 +21,9 @@ Revision History:
#include "bit_blaster_rewriter.h"
#include "rewriter_def.h"
#include "ast_pp.h"
#include "expr_safe_replace.h"
#include "filter_model_converter.h"
#include "dl_mk_interp_tail_simplifier.h"
namespace datalog {
@ -35,6 +37,73 @@ namespace datalog {
// P(bv(x,y)) :- P_bv(x,y)
// Query
// this model converter should be composed with a filter converter
// that gets rid of the new functions.
class bit_blast_model_converter : public model_converter {
ast_manager& m;
bv_util m_bv;
func_decl_ref_vector m_old_funcs;
func_decl_ref_vector m_new_funcs;
public:
bit_blast_model_converter(ast_manager& m):
m(m),
m_bv(m),
m_old_funcs(m),
m_new_funcs(m) {}
void insert(func_decl* old_f, func_decl* new_f) {
m_old_funcs.push_back(old_f);
m_new_funcs.push_back(new_f);
}
virtual model_converter * translate(ast_translation & translator) {
return alloc(bit_blast_model_converter, m);
}
virtual void operator()(model_ref & model) {
for (unsigned i = 0; i < m_new_funcs.size(); ++i) {
func_decl* p = m_new_funcs[i].get();
func_decl* q = m_old_funcs[i].get();
func_interp* f = model->get_func_interp(p);
expr_ref body(m);
unsigned arity_p = p->get_arity();
unsigned arity_q = q->get_arity();
SASSERT(0 < arity_p);
model->register_decl(p, f);
func_interp* g = alloc(func_interp, m, arity_q);
if (f) {
body = f->get_interp();
SASSERT(!f->is_partial());
SASSERT(body);
}
else {
body = m.mk_false();
}
unsigned idx = 0;
expr_ref arg(m), proj(m);
expr_safe_replace sub(m);
for (unsigned j = 0; j < arity_q; ++j) {
sort* s = q->get_domain(j);
arg = m.mk_var(j, s);
if (m_bv.is_bv_sort(s)) {
expr* args[1] = { arg };
unsigned sz = m_bv.get_bv_size(s);
for (unsigned k = 0; k < sz; ++k) {
proj = m.mk_app(m_bv.get_family_id(), OP_BIT2BOOL, 1, args);
sub.insert(m.mk_var(idx++, m.mk_bool_sort()), proj);
}
}
else {
sub.insert(m.mk_var(idx++, s), arg);
}
}
sub(body);
g->set_else(body);
model->register_decl(q, g);
}
}
};
class expand_mkbv_cfg : public default_rewriter_cfg {
@ -43,7 +112,8 @@ namespace datalog {
ast_manager& m;
bv_util m_util;
expr_ref_vector m_args, m_f_vars, m_g_vars;
func_decl_ref_vector m_pinned;
func_decl_ref_vector m_old_funcs;
func_decl_ref_vector m_new_funcs;
obj_map<func_decl,func_decl*> m_pred2blast;
@ -57,10 +127,14 @@ namespace datalog {
m_args(m),
m_f_vars(m),
m_g_vars(m),
m_pinned(m)
m_old_funcs(m),
m_new_funcs(m)
{}
~expand_mkbv_cfg() {}
func_decl_ref_vector const& old_funcs() const { return m_old_funcs; }
func_decl_ref_vector const& new_funcs() const { return m_new_funcs; }
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
rule_manager& rm = m_context.get_rule_manager();
@ -105,13 +179,18 @@ namespace datalog {
domain.push_back(m.get_sort(m_args[i].get()));
}
g = m_context.mk_fresh_head_predicate(f->get_name(), symbol("bv"), m_args.size(), domain.c_ptr(), f);
m_pinned.push_back(g);
m_old_funcs.push_back(f);
m_new_funcs.push_back(g);
m_pred2blast.insert(f, g);
// Create rule f(mk_mkbv(args)) :- g(args)
fml = m.mk_implies(m.mk_app(g, m_g_vars.size(), m_g_vars.c_ptr()), m.mk_app(f, m_f_vars.size(), m_f_vars.c_ptr()));
rm.mk_rule(fml, m_rules, g->get_name());
proof_ref pr(m);
if (m_context.generate_proof_trace()) {
pr = m.mk_asserted(fml); // or a def?
}
rm.mk_rule(fml, pr, m_rules, g->get_name());
}
result = m.mk_app(g, m_args.size(), m_args.c_ptr());
result_pr = 0;
@ -134,18 +213,25 @@ namespace datalog {
ast_manager & m;
params_ref m_params;
rule_ref_vector m_rules;
mk_interp_tail_simplifier m_simplifier;
bit_blaster_rewriter m_blaster;
expand_mkbv m_rewriter;
bool blast(expr_ref& fml) {
bool blast(rule *r, expr_ref& fml) {
proof_ref pr(m);
expr_ref fml1(m), fml2(m);
m_blaster(fml, fml1, pr);
m_rewriter(fml1, fml2);
TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml1, m) << " -> " << mk_pp(fml2, m) << "\n";);
if (fml2 != fml) {
fml = fml2;
expr_ref fml1(m), fml2(m), fml3(m);
rule_ref r2(m_context.get_rule_manager());
// We need to simplify rule before bit-blasting.
if (!m_simplifier.transform_rule(r, r2)) {
r2 = r;
}
r2->to_formula(fml1);
m_blaster(fml1, fml2, pr);
m_rewriter(fml2, fml3);
TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml2, m) << " -> " << mk_pp(fml3, m) << "\n";);
if (fml3 != fml) {
fml = fml3;
return true;
}
else {
@ -163,6 +249,7 @@ namespace datalog {
m(ctx.get_manager()),
m_params(ctx.get_params().p),
m_rules(ctx.get_rule_manager()),
m_simplifier(ctx),
m_blaster(ctx.get_manager(), m_params),
m_rewriter(ctx.get_manager(), ctx, m_rules) {
m_params.set_bool("blast_full", true);
@ -170,24 +257,25 @@ namespace datalog {
m_blaster.updt_params(m_params);
}
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
// TODO mc, pc
rule_set * operator()(rule_set const & source) {
// TODO pc
if (!m_context.get_params().bit_blast()) {
return 0;
}
if (m_context.get_engine() != PDR_ENGINE) {
return 0;
}
rule_manager& rm = m_context.get_rule_manager();
unsigned sz = source.get_num_rules();
expr_ref fml(m);
reset();
rule_set * result = alloc(rule_set, m_context);
for (unsigned i = 0; i < sz; ++i) {
for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) {
rule * r = source.get_rule(i);
r->to_formula(fml);
if (blast(fml)) {
rm.mk_rule(fml, m_rules, r->name());
r->to_formula(fml);
if (blast(r, fml)) {
proof_ref pr(m);
if (m_context.generate_proof_trace()) {
pr = m.mk_asserted(fml); // loses original proof of r.
}
rm.mk_rule(fml, pr, m_rules, r->name());
}
else {
m_rules.push_back(r);
@ -197,6 +285,18 @@ namespace datalog {
for (unsigned i = 0; i < m_rules.size(); ++i) {
result->add_rule(m_rules.get(i));
}
if (m_context.get_model_converter()) {
filter_model_converter* fmc = alloc(filter_model_converter, m);
bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m);
func_decl_ref_vector const& old_funcs = m_rewriter.m_cfg.old_funcs();
func_decl_ref_vector const& new_funcs = m_rewriter.m_cfg.new_funcs();
for (unsigned i = 0; i < old_funcs.size(); ++i) {
fmc->insert(new_funcs[i]);
bvmc->insert(old_funcs[i], new_funcs[i]);
}
m_context.add_model_converter(concat(bvmc, fmc));
}
return result;
}
@ -210,8 +310,8 @@ namespace datalog {
dealloc(m_impl);
}
rule_set * mk_bit_blast::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
return (*m_impl)(source, mc, pc);
rule_set * mk_bit_blast::operator()(rule_set const & source) {
return (*m_impl)(source);
}
};

View file

@ -7,7 +7,7 @@ Module Name:
Abstract:
<abstract>
Functor for bit-blasting a rule set
Author:
@ -19,32 +19,17 @@ Revision History:
#ifndef _DL_MK_BIT_BLAST_H_
#define _DL_MK_BIT_BLAST_H_
#include<utility>
#include"map.h"
#include"obj_pair_hashtable.h"
#include"dl_context.h"
#include"dl_rule_set.h"
#include"dl_rule_transformer.h"
namespace datalog {
/**
\brief Functor for bit-blasting a rule set.
*/
class mk_bit_blast : public rule_transformer::plugin {
class impl;
impl* m_impl;
void blast(expr_ref& b);
void reset();
impl* m_impl;
public:
mk_bit_blast(context & ctx, unsigned priority = 35000);
~mk_bit_blast();
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
~mk_bit_blast();
rule_set * operator()(rule_set const & source);
};
};

View file

@ -133,7 +133,7 @@ namespace datalog {
tail.push_back(to_app(fml));
is_neg.push_back(false);
res = rm.mk(head, tail.size(), tail.c_ptr(), is_neg.c_ptr(), tgt->name());
if (m_pc) {
if (m_ctx.generate_proof_trace()) {
src.to_formula(fml1);
tgt->to_formula(fml2);
res->to_formula(fml);
@ -142,12 +142,13 @@ namespace datalog {
sort* domain[3] = { ps, ps, m.mk_bool_sort() };
func_decl* merge = m.mk_func_decl(symbol("merge-clauses"), 3, domain, ps); // TBD: ad-hoc proof rule
expr* args[3] = { m.mk_asserted(fml1), m.mk_asserted(fml2), fml };
m_pc->insert(m.mk_app(merge, 3, args));
// ...m_pc->insert(m.mk_app(merge, 3, args));
#else
svector<std::pair<unsigned, unsigned> > pos;
vector<expr_ref_vector> substs;
proof* p = m.mk_asserted(fml1);
m_pc->insert(m.mk_hyper_resolve(1, &p, fml, pos, substs));
proof* p = src.get_proof();
p = m.mk_hyper_resolve(1, &p, fml, pos, substs);
res->set_proof(m, p);
#endif
}
tgt = res;
@ -170,13 +171,7 @@ namespace datalog {
return true;
}
rule_set * mk_coalesce::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
m_pc = 0;
ref<replace_proof_converter> rpc;
if (pc) {
rpc = alloc(replace_proof_converter, m);
m_pc = rpc.get();
}
rule_set * mk_coalesce::operator()(rule_set const & source) {
rule_set* rules = alloc(rule_set, m_ctx);
rule_set::decl2rules::iterator it = source.begin_grouped_rules(), end = source.end_grouped_rules();
for (; it != end; ++it) {
@ -195,9 +190,6 @@ namespace datalog {
rules->add_rule(r1.get());
}
}
if (pc) {
pc = concat(pc.get(), rpc.get());
}
return rules;
}

View file

@ -37,7 +37,6 @@ namespace datalog {
rule_manager& rm;
expr_ref_vector m_sub1, m_sub2;
unsigned m_idx;
replace_proof_converter* m_pc;
void mk_pred(app_ref& pred, app* p1, app* p2);
@ -53,7 +52,7 @@ namespace datalog {
*/
mk_coalesce(context & ctx);
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
};
};

View file

@ -33,10 +33,7 @@ namespace datalog {
// -----------------------------------
rule_set * mk_coi_filter::operator()(
rule_set const & source,
model_converter_ref& mc,
proof_converter_ref& pc)
rule_set * mk_coi_filter::operator()(rule_set const & source)
{
if (source.get_num_rules()==0) {
return 0;
@ -81,7 +78,7 @@ namespace datalog {
if (interesting_preds.contains(pred)) {
res->add_rule(r);
}
else if (mc.get()) {
else if (m_context.get_model_converter()) {
pruned_preds.insert(pred);
}
}
@ -90,14 +87,14 @@ namespace datalog {
res = 0;
}
if (res && mc) {
if (res && m_context.get_model_converter()) {
decl_set::iterator end = pruned_preds.end();
decl_set::iterator it = pruned_preds.begin();
extension_model_converter* mc0 = alloc(extension_model_converter, m);
for (; it != end; ++it) {
mc0->insert(*it, m.mk_true());
}
mc = concat(mc.get(), mc0);
m_context.add_model_converter(mc0);
}
return res.detach();

View file

@ -38,10 +38,7 @@ namespace datalog {
m(ctx.get_manager()),
m_context(ctx) {}
rule_set * operator()(rule_set const & source,
model_converter_ref& mc,
proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
};
};

View file

@ -174,11 +174,9 @@ namespace datalog {
}
}
#if 1
virtual void deallocate() {
get_plugin().recycle(this);
}
#endif
public:
@ -708,8 +706,8 @@ namespace datalog {
}
rule * mk_explanations::get_e_rule(rule * r) {
var_counter ctr;
ctr.count_vars(m_manager, r);
rule_counter ctr;
ctr.count_rule_vars(m_manager, r);
unsigned max_var;
unsigned next_var = ctr.get_max_positive(max_var) ? (max_var+1) : 0;
unsigned head_var = next_var++;
@ -875,14 +873,12 @@ namespace datalog {
}
}
rule_set * mk_explanations::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
SASSERT(!mc && !pc);
rule_set * mk_explanations::operator()(rule_set const & source) {
if(source.get_num_rules()==0) {
return 0;
}
m_context.collect_predicates(m_original_preds);
rule_set * res = alloc(rule_set, m_context);
transform_facts(m_context.get_rel_context().get_rmanager());
transform_rules(source, *res);

View file

@ -82,7 +82,7 @@ namespace datalog {
return get_union_decl(m_context);
}
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
static expr* get_explanation(relation_base const& r);
};

View file

@ -168,7 +168,15 @@ namespace datalog {
fml = m.mk_implies(m.mk_and(fmls.size(), fmls.c_ptr()), r.get_head());
TRACE("dl", tout << "new rule\n" << mk_pp(fml, m) << "\n";);
rule_ref_vector rules(rm);
rm.mk_rule(fml, rules, r.name());
proof_ref pr(m);
if (m_ctx.generate_proof_trace()) {
scoped_proof _scp(m);
expr_ref fml1(m);
r.to_formula(fml1);
pr = m.mk_rewrite(fml1, fml);
pr = m.mk_modus_ponens(r.get_proof(), pr);
}
rm.mk_rule(fml, pr, rules, r.name());
for (unsigned i = 0; i < rules.size(); ++i) {
new_rules.add_rule(rules[i].get());
m_quantifiers.insert(rules[i].get(), alloc(quantifier_ref_vector, qs));
@ -347,7 +355,7 @@ namespace datalog {
m_quantifiers.reset();
}
rule_set * mk_extract_quantifiers::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
rule_set * mk_extract_quantifiers::operator()(rule_set const & source) {
reset();
rule_set::iterator it = source.begin(), end = source.end();
for (; !m_has_quantifiers && it != end; ++it) {

View file

@ -77,7 +77,7 @@ namespace datalog {
void set_query(func_decl* q);
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
bool has_quantifiers() { return m_has_quantifiers; }

View file

@ -90,6 +90,7 @@ namespace datalog {
rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)0);
filter_rule->set_accounting_parent_object(m_context, m_current);
m_result->add_rule(filter_rule);
m_context.get_rule_manager().mk_rule_asserted_proof(*filter_rule);
}
else {
dealloc(key);
@ -135,12 +136,13 @@ namespace datalog {
}
new_is_negated.push_back(r->is_neg_tail(i));
}
if(rule_modified) {
if (rule_modified) {
remove_duplicate_tails(new_tail, new_is_negated);
SASSERT(new_tail.size() == new_is_negated.size());
rule * new_rule = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.c_ptr(), new_is_negated.c_ptr());
new_rule->set_accounting_parent_object(m_context, m_current);
m_result->add_rule(new_rule);
m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule);
m_modified = true;
}
else {
@ -148,7 +150,7 @@ namespace datalog {
}
}
rule_set * mk_filter_rules::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
rule_set * mk_filter_rules::operator()(rule_set const & source) {
// TODO mc, pc
m_tail2filter.reset();
m_result = alloc(rule_set, m_context);

View file

@ -72,7 +72,7 @@ namespace datalog {
/**
\brief Return a new rule set where only filter rules contain atoms with repeated variables and/or values.
*/
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
};
};

View file

@ -35,7 +35,7 @@ namespace datalog {
// -----------------------------------
void mk_interp_tail_simplifier::rule_substitution::reset(rule * r) {
unsigned var_cnt = m_context.get_rule_manager().get_var_counter().get_max_var(*r)+1;
unsigned var_cnt = m_context.get_rule_manager().get_counter().get_max_rule_var(*r)+1;
m_subst.reset();
m_subst.reserve(1, var_cnt);
m_rule = r;
@ -296,18 +296,40 @@ namespace datalog {
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,
proof_ref & result_pr)
{
if (m.is_not(f)) {
if (m.is_not(f) && (m.is_and(args[0]) || m.is_or(args[0]))) {
SASSERT(num==1);
if (m.is_and(args[0]) || m.is_or(args[0])) {
expr_ref e(m.mk_not(args[0]),m);
if (push_toplevel_junction_negation_inside(e)) {
result = e;
return BR_REWRITE2;
}
expr_ref tmp(m);
app* a = to_app(args[0]);
m_app_args.reset();
for (unsigned i = 0; i < a->get_num_args(); ++i) {
m_brwr.mk_not(a->get_arg(i), tmp);
m_app_args.push_back(tmp);
}
if (m.is_and(args[0])) {
result = m.mk_or(m_app_args.size(), m_app_args.c_ptr());
}
else {
result = m.mk_and(m_app_args.size(), m_app_args.c_ptr());
}
return BR_REWRITE2;
}
if (!m.is_and(f) && !m.is_or(f)) {
return BR_FAILED;
}
if (num == 0) {
if (m.is_and(f)) {
result = m.mk_true();
}
else {
result = m.mk_false();
}
return BR_DONE;
}
if (num == 1) {
result = args[0];
return BR_DONE;
}
if (!m.is_and(f) && !m.is_or(f)) { return BR_FAILED; }
if (num<2) { return BR_FAILED; }
m_app_args.reset();
m_app_args.append(num, args);
@ -318,30 +340,18 @@ namespace datalog {
bool have_rewritten_args = false;
if (m.is_or(f) || m.is_and(f)) {
have_rewritten_args = detect_equivalences(m_app_args, m.is_or(f));
#if 0
if (have_rewritten_args) {
std::sort(m_app_args.c_ptr(), m_app_args.c_ptr()+m_app_args.size(), m_expr_cmp);
app_ref orig(m.mk_app(f, num, args),m);
app_ref res(m.mk_app(f, m_app_args.size(), m_app_args.c_ptr()),m);
std::cout<<"s:"<<mk_pp(orig, m)<<"\n";
std::cout<<"t:"<<mk_pp(res, m)<<"\n";
}
#endif
}
have_rewritten_args = detect_equivalences(m_app_args, m.is_or(f));
if (m_app_args.size()==1) {
result = m_app_args[0].get();
}
else {
if (m.is_and(f)) {
m_brwr.mk_and(m_app_args.size(), m_app_args.c_ptr(), result);
result = m.mk_and(m_app_args.size(), m_app_args.c_ptr());
}
else {
SASSERT(m.is_or(f));
m_brwr.mk_or(m_app_args.size(), m_app_args.c_ptr(), result);
result = m.mk_or(m_app_args.size(), m_app_args.c_ptr());
}
}
@ -469,7 +479,7 @@ namespace datalog {
start:
unsigned u_len = r->get_uninterpreted_tail_size();
unsigned len = r->get_tail_size();
if (u_len==len) {
if (u_len == len) {
res = r;
return true;
}
@ -504,34 +514,29 @@ namespace datalog {
expr_ref simp_res(m);
simplify_expr(itail.get(), simp_res);
modified |= itail.get()!=simp_res.get();
if (is_app(simp_res.get())) {
itail = to_app(simp_res.get());
}
else if (m.is_bool(simp_res)) {
itail = m.mk_eq(simp_res, m.mk_true());
}
else {
throw default_exception("simplification resulted in non-boolean non-function");
}
if (m.is_false(itail.get())) {
//the tail member is never true, so we may delete the rule
modified |= itail.get() != simp_res.get();
if (m.is_false(simp_res)) {
TRACE("dl", r->display(m_context, tout << "rule is infeasible\n"););
return false;
}
if (!m.is_true(itail.get())) {
//if the simplified tail is not a tautology, we add it to the rule
tail.push_back(itail);
tail_neg.push_back(false);
}
else {
modified = true;
}
SASSERT(m.is_bool(simp_res));
SASSERT(tail.size() == tail_neg.size());
if (modified) {
expr_ref_vector conjs(m);
flatten_and(simp_res, conjs);
for (unsigned i = 0; i < conjs.size(); ++i) {
expr* e = conjs[i].get();
if (is_app(e)) {
tail.push_back(to_app(e));
}
else {
tail.push_back(m.mk_eq(e, m.mk_true()));
}
tail_neg.push_back(false);
}
SASSERT(tail.size() == tail_neg.size());
res = m_context.get_rule_manager().mk(head, tail.size(), tail.c_ptr(), tail_neg.c_ptr());
res->set_accounting_parent_object(m_context, r);
}
@ -541,8 +546,8 @@ namespace datalog {
rule_ref pro_var_eq_result(m_context.get_rule_manager());
if (propagate_variable_equivalences(res, pro_var_eq_result)) {
SASSERT(var_counter().get_max_var(*r.get())==0 ||
var_counter().get_max_var(*r.get()) > var_counter().get_max_var(*pro_var_eq_result.get()));
SASSERT(rule_counter().get_max_rule_var(*r.get())==0 ||
rule_counter().get_max_rule_var(*r.get()) > rule_counter().get_max_rule_var(*pro_var_eq_result.get()));
r = pro_var_eq_result;
goto start;
}
@ -554,11 +559,13 @@ namespace datalog {
bool mk_interp_tail_simplifier::transform_rules(const rule_set & orig, rule_set & tgt) {
bool modified = false;
rule_manager& rm = m_context.get_rule_manager();
rule_set::iterator rit = orig.begin();
rule_set::iterator rend = orig.end();
for (; rit!=rend; ++rit) {
rule_ref new_rule(m_context.get_rule_manager());
rule_ref new_rule(rm);
if (transform_rule(*rit, new_rule)) {
rm.mk_rule_rewrite_proof(**rit, *new_rule.get());
bool is_modified = *rit != new_rule;
modified |= is_modified;
tgt.add_rule(new_rule);
@ -570,8 +577,7 @@ namespace datalog {
return modified;
}
rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
// TODO mc, pc
rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source) {
if (source.get_num_rules() == 0) {
return 0;
}

View file

@ -93,7 +93,7 @@ namespace datalog {
*/
bool transform_rule(rule * r, rule_ref& res);
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
};
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,136 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
dl_mk_karr_invariants.h
Abstract:
Extract integer linear invariants.
Author:
Nikolaj Bjorner (nbjorner) 2013-03-08
Revision History:
--*/
#ifndef _DL_MK_KARR_INVARIANTS_H_
#define _DL_MK_KARR_INVARIANTS_H_
#include"dl_context.h"
#include"dl_rule_set.h"
#include"dl_rule_transformer.h"
#include"arith_decl_plugin.h"
#include"hilbert_basis.h"
namespace datalog {
/**
\brief Rule transformer that strengthens bodies with invariants.
*/
struct matrix {
vector<vector<rational> > A;
vector<rational> b;
svector<bool> eq;
unsigned size() const { return A.size(); }
void reset() { A.reset(); b.reset(); eq.reset(); }
matrix& operator=(matrix const& other);
void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); }
void display(std::ostream& out) const;
static void display_row(
std::ostream& out, vector<rational> const& row, rational const& b, bool is_eq);
static void display_ineq(
std::ostream& out, vector<rational> const& row, rational const& b, bool is_eq);
};
class mk_karr_invariants : public rule_transformer::plugin {
class add_invariant_model_converter;
context& m_ctx;
ast_manager& m;
rule_manager& rm;
context m_inner_ctx;
arith_util a;
void update_body(rel_context& rctx, rule_set& result, rule& r);
public:
mk_karr_invariants(context & ctx, unsigned priority);
virtual ~mk_karr_invariants();
virtual void cancel();
rule_set * operator()(rule_set const & source);
};
class karr_relation;
class karr_relation_plugin : public relation_plugin {
arith_util a;
hilbert_basis m_hb;
class join_fn;
class project_fn;
class rename_fn;
class union_fn;
class filter_equal_fn;
class filter_identical_fn;
class filter_interpreted_fn;
friend class karr_relation;
public:
karr_relation_plugin(relation_manager& rm):
relation_plugin(karr_relation_plugin::get_name(), rm),
a(get_ast_manager())
{}
virtual bool can_handle_signature(const relation_signature & sig) {
for (unsigned i = 0; i < sig.size(); ++i) {
if (a.is_int(sig[i])) {
return true;
}
}
return false;
}
static symbol get_name() { return symbol("karr_relation"); }
virtual void set_cancel(bool f);
virtual relation_base * mk_empty(const relation_signature & s);
virtual relation_base * mk_full(func_decl* p, const relation_signature & s);
static karr_relation& get(relation_base& r);
static karr_relation const & get(relation_base const& r);
virtual relation_join_fn * mk_join_fn(
const relation_base & t1, const relation_base & t2,
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2);
virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt,
const unsigned * removed_cols);
virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len,
const unsigned * permutation_cycle);
virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src,
const relation_base * delta);
virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt,
const unsigned * identical_cols);
virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value,
unsigned col);
virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition);
private:
bool dualizeI(matrix& dst, matrix const& src);
void dualizeH(matrix& dst, matrix const& src);
};
};
#endif /* _DL_MK_KARR_INVARIANTS_H_ */

View file

@ -0,0 +1,113 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
dl_mk_loop_counter.cpp
Abstract:
Add loop counter argument to relations.
Author:
Nikolaj Bjorner (nbjorner) 2013-03-31
Revision History:
--*/
#include"dl_mk_loop_counter.h"
#include"dl_context.h"
namespace datalog {
mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority):
plugin(priority),
m(ctx.get_manager()),
a(m),
m_refs(m) {
}
mk_loop_counter::~mk_loop_counter() { }
app_ref mk_loop_counter::add_arg(app* fn, unsigned idx) {
expr_ref_vector args(m);
func_decl* new_fn, *old_fn = fn->get_decl();
args.append(fn->get_num_args(), fn->get_args());
args.push_back(m.mk_var(idx, a.mk_int()));
if (!m_old2new.find(old_fn, new_fn)) {
ptr_vector<sort> domain;
domain.append(fn->get_num_args(), old_fn->get_domain());
domain.push_back(a.mk_int());
new_fn = m.mk_func_decl(old_fn->get_name(), domain.size(), domain.c_ptr(), old_fn->get_range());
m_old2new.insert(old_fn, new_fn);
m_new2old.insert(new_fn, old_fn);
m_refs.push_back(new_fn);
}
return app_ref(m.mk_app(new_fn, args.size(), args.c_ptr()), m);
}
rule_set * mk_loop_counter::operator()(rule_set const & source) {
m_refs.reset();
m_old2new.reset();
m_new2old.reset();
context& ctx = source.get_context();
rule_manager& rm = source.get_rule_manager();
rule_set * result = alloc(rule_set, ctx);
unsigned sz = source.get_num_rules();
rule_ref new_rule(rm);
app_ref_vector tail(m);
app_ref head(m);
svector<bool> neg;
rule_counter& vc = rm.get_counter();
for (unsigned i = 0; i < sz; ++i) {
tail.reset();
neg.reset();
rule & r = *source.get_rule(i);
unsigned cnt = vc.get_max_rule_var(r)+1;
unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size();
for (unsigned j = 0; j < utsz; ++j, ++cnt) {
tail.push_back(add_arg(r.get_tail(j), cnt));
neg.push_back(r.is_neg_tail(j));
ctx.register_predicate(tail.back()->get_decl(), false);
}
for (unsigned j = utsz; j < tsz; ++j) {
tail.push_back(r.get_tail(j));
neg.push_back(false);
}
head = add_arg(r.get_head(), cnt);
ctx.register_predicate(head->get_decl(), false);
// set the loop counter to be an increment of the previous
bool found = false;
unsigned last = head->get_num_args()-1;
for (unsigned j = 0; !found && j < utsz; ++j) {
if (head->get_decl() == tail[j]->get_decl()) {
tail.push_back(m.mk_eq(head->get_arg(last),
a.mk_add(tail[j]->get_arg(last),
a.mk_numeral(rational(1), true))));
neg.push_back(false);
found = true;
}
}
// initialize loop counter to 0 if none was found.
if (!found) {
expr_ref_vector args(m);
args.append(head->get_num_args(), head->get_args());
args[last] = a.mk_numeral(rational(0), true);
head = m.mk_app(head->get_decl(), args.size(), args.c_ptr());
}
new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true);
result->add_rule(new_rule);
}
// model converter: remove references to extra argument.
// proof converter: remove references to extra argument as well.
return result;
}
};

View file

@ -0,0 +1,47 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
dl_mk_loop_counter.h
Abstract:
Add loop counter argument to relations.
Author:
Nikolaj Bjorner (nbjorner) 2013-03-31
Revision History:
--*/
#ifndef _DL_MK_LOOP_COUNTER_H_
#define _DL_MK_LOOP_COUNTER_H_
#include"dl_rule_transformer.h"
#include"arith_decl_plugin.h"
namespace datalog {
class mk_loop_counter : public rule_transformer::plugin {
ast_manager& m;
arith_util a;
func_decl_ref_vector m_refs;
obj_map<func_decl, func_decl*> m_new2old;
obj_map<func_decl, func_decl*> m_old2new;
app_ref add_arg(app* fn, unsigned idx);
public:
mk_loop_counter(context & ctx, unsigned priority = 33000);
~mk_loop_counter();
rule_set * operator()(rule_set const & source);
func_decl* get_old(func_decl* f) const { return m_new2old.find(f); }
};
};
#endif /* _DL_MK_LOOP_COUNTER_H_ */

View file

@ -317,8 +317,8 @@ namespace datalog {
m_rules.push_back(r);
}
rule_set * mk_magic_sets::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
SASSERT(!mc && !pc);
rule_set * mk_magic_sets::operator()(rule_set const & source) {
SASSERT(!m_context.get_model_converter());
unsigned init_rule_cnt = source.get_num_rules();
{
func_decl_set intentional;

View file

@ -121,7 +121,7 @@ namespace datalog {
*/
mk_magic_sets(context & ctx, rule * goal_rule);
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
};
};

View file

@ -86,8 +86,8 @@ namespace datalog {
}
rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
// TODO mc, pc
rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source) {
// TODO mc
if (source.get_num_rules() == 0) {
return 0;

View file

@ -35,7 +35,7 @@ namespace datalog {
m(ctx.get_manager()),
m_context(ctx) {}
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
private:

View file

@ -0,0 +1,367 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
dl_mk_quantifier_abstraction.cpp
Abstract:
Create quantified Horn clauses from benchmarks with arrays.
Author:
Ken McMillan
Andrey Rybalchenko
Nikolaj Bjorner (nbjorner) 2013-04-02
Revision History:
--*/
#include "dl_mk_quantifier_abstraction.h"
#include "dl_context.h"
#include "expr_safe_replace.h"
#include "expr_abstract.h"
namespace datalog {
// model converter:
// Given model for P^(x, y, i, a[i])
// create model: P(x,y,a) == forall i . P^(x,y,i,a[i])
// requires substitution and list of bound variables.
class mk_quantifier_abstraction::qa_model_converter : public model_converter {
ast_manager& m;
func_decl_ref_vector m_old_funcs;
func_decl_ref_vector m_new_funcs;
vector<expr_ref_vector> m_subst;
vector<sort_ref_vector> m_sorts;
vector<svector<bool> > m_bound;
public:
qa_model_converter(ast_manager& m):
m(m), m_old_funcs(m), m_new_funcs(m) {}
virtual ~qa_model_converter() {}
virtual model_converter * translate(ast_translation & translator) {
return alloc(qa_model_converter, m);
}
void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, sort_ref_vector& sorts, svector<bool> const& bound) {
m_old_funcs.push_back(old_p);
m_new_funcs.push_back(new_p);
m_subst.push_back(sub);
m_bound.push_back(bound);
m_sorts.push_back(sorts);
}
virtual void operator()(model_ref & old_model) {
model_ref new_model = alloc(model, m);
for (unsigned i = 0; i < m_new_funcs.size(); ++i) {
func_decl* p = m_new_funcs[i].get();
func_decl* q = m_old_funcs[i].get();
expr_ref_vector const& sub = m_subst[i];
sort_ref_vector const& sorts = m_sorts[i];
svector<bool> const& is_bound = m_bound[i];
func_interp* f = old_model->get_func_interp(p);
expr_ref body(m);
unsigned arity_p = p->get_arity();
unsigned arity_q = q->get_arity();
SASSERT(0 < arity_p);
func_interp* g = alloc(func_interp, m, arity_q);
if (f) {
body = f->get_interp();
SASSERT(!f->is_partial());
SASSERT(body);
}
else {
body = m.mk_false();
}
// Create quantifier wrapper around body.
TRACE("dl", tout << mk_pp(body, m) << "\n";);
// 1. replace variables by the compound terms from
// the original predicate.
expr_safe_replace rep(m);
for (unsigned i = 0; i < sub.size(); ++i) {
rep.insert(m.mk_var(i, m.get_sort(sub[i])), sub[i]);
}
rep(body);
rep.reset();
TRACE("dl", tout << mk_pp(body, m) << "\n";);
// 2. replace bound variables by constants.
expr_ref_vector consts(m), bound(m), free(m);
svector<symbol> names;
ptr_vector<sort> bound_sorts;
for (unsigned i = 0; i < sorts.size(); ++i) {
sort* s = sorts[i];
consts.push_back(m.mk_fresh_const("C", s));
rep.insert(m.mk_var(i, s), consts.back());
if (is_bound[i]) {
bound.push_back(consts.back());
names.push_back(symbol(i));
bound_sorts.push_back(s);
}
else {
free.push_back(consts.back());
}
}
rep(body);
rep.reset();
TRACE("dl", tout << mk_pp(body, m) << "\n";);
// 3. abstract and quantify those variables that should be bound.
expr_abstract(m, 0, bound.size(), bound.c_ptr(), body, body);
body = m.mk_forall(names.size(), bound_sorts.c_ptr(), names.c_ptr(), body);
TRACE("dl", tout << mk_pp(body, m) << "\n";);
// 4. replace remaining constants by variables.
for (unsigned i = 0; i < free.size(); ++i) {
rep.insert(free[i].get(), m.mk_var(i, m.get_sort(free[i].get())));
}
rep(body);
g->set_else(body);
TRACE("dl", tout << mk_pp(body, m) << "\n";);
new_model->register_decl(q, g);
}
old_model = new_model;
}
};
mk_quantifier_abstraction::mk_quantifier_abstraction(
context & ctx, unsigned priority):
plugin(priority),
m(ctx.get_manager()),
m_ctx(ctx),
a(m),
m_refs(m) {
}
mk_quantifier_abstraction::~mk_quantifier_abstraction() {
}
func_decl* mk_quantifier_abstraction::declare_pred(func_decl* old_p) {
if (m_ctx.is_output_predicate(old_p)) {
return 0;
}
unsigned sz = old_p->get_arity();
unsigned num_arrays = 0;
for (unsigned i = 0; i < sz; ++i) {
if (a.is_array(old_p->get_domain(i))) {
num_arrays++;
}
}
if (num_arrays == 0) {
return 0;
}
func_decl* new_p = 0;
if (!m_old2new.find(old_p, new_p)) {
expr_ref_vector sub(m), vars(m);
svector<bool> bound;
sort_ref_vector domain(m), sorts(m);
expr_ref arg(m);
for (unsigned i = 0; i < sz; ++i) {
sort* s0 = old_p->get_domain(i);
unsigned lookahead = 0;
sort* s = s0;
while (a.is_array(s)) {
lookahead += get_array_arity(s);
s = get_array_range(s);
}
arg = m.mk_var(bound.size() + lookahead, s0);
s = s0;
while (a.is_array(s)) {
unsigned arity = get_array_arity(s);
expr_ref_vector args(m);
for (unsigned j = 0; j < arity; ++j) {
sort* s1 = get_array_domain(s, j);
domain.push_back(s1);
args.push_back(m.mk_var(bound.size(), s1));
bound.push_back(true);
sorts.push_back(s1);
}
arg = mk_select(arg, args.size(), args.c_ptr());
s = get_array_range(s);
}
domain.push_back(s);
bound.push_back(false);
sub.push_back(arg);
sorts.push_back(s0);
}
SASSERT(old_p->get_range() == m.mk_bool_sort());
new_p = m.mk_func_decl(old_p->get_name(), domain.size(), domain.c_ptr(), old_p->get_range());
m_refs.push_back(new_p);
m_ctx.register_predicate(new_p, false);
if (m_mc) {
m_mc->insert(old_p, new_p, sub, sorts, bound);
}
m_old2new.insert(old_p, new_p);
}
return new_p;
}
app_ref mk_quantifier_abstraction::mk_head(app* p, unsigned idx) {
func_decl* new_p = declare_pred(p->get_decl());
if (!new_p) {
return app_ref(p, m);
}
expr_ref_vector args(m);
expr_ref arg(m);
unsigned sz = p->get_num_args();
for (unsigned i = 0; i < sz; ++i) {
arg = p->get_arg(i);
sort* s = m.get_sort(arg);
while (a.is_array(s)) {
unsigned arity = get_array_arity(s);
for (unsigned j = 0; j < arity; ++j) {
args.push_back(m.mk_var(idx++, get_array_domain(s, j)));
}
arg = mk_select(arg, arity, args.c_ptr()+args.size()-arity);
s = get_array_range(s);
}
args.push_back(arg);
}
TRACE("dl",
tout << mk_pp(new_p, m) << "\n";
for (unsigned i = 0; i < args.size(); ++i) {
tout << mk_pp(args[i].get(), m) << "\n";
});
return app_ref(m.mk_app(new_p, args.size(), args.c_ptr()), m);
}
app_ref mk_quantifier_abstraction::mk_tail(app* p) {
func_decl* old_p = p->get_decl();
func_decl* new_p = declare_pred(old_p);
if (!new_p) {
return app_ref(p, m);
}
SASSERT(new_p->get_arity() > old_p->get_arity());
unsigned num_extra_args = new_p->get_arity() - old_p->get_arity();
var_shifter shift(m);
expr_ref p_shifted(m);
shift(p, num_extra_args, p_shifted);
app* ps = to_app(p_shifted);
expr_ref_vector args(m);
app_ref_vector pats(m);
sort_ref_vector vars(m);
svector<symbol> names;
expr_ref arg(m);
unsigned idx = 0;
unsigned sz = p->get_num_args();
for (unsigned i = 0; i < sz; ++i) {
arg = ps->get_arg(i);
sort* s = m.get_sort(arg);
bool is_pattern = false;
while (a.is_array(s)) {
is_pattern = true;
unsigned arity = get_array_arity(s);
for (unsigned j = 0; j < arity; ++j) {
vars.push_back(get_array_domain(s, j));
names.push_back(symbol(idx));
args.push_back(m.mk_var(idx++, vars.back()));
}
arg = mk_select(arg, arity, args.c_ptr()+args.size()-arity);
s = get_array_range(s);
}
if (is_pattern) {
pats.push_back(to_app(arg));
}
args.push_back(arg);
}
expr* pat = 0;
expr_ref pattern(m);
pattern = m.mk_pattern(pats.size(), pats.c_ptr());
pat = pattern.get();
app_ref result(m);
symbol qid, skid;
result = m.mk_app(new_p, args.size(), args.c_ptr());
result = m.mk_eq(m.mk_forall(vars.size(), vars.c_ptr(), names.c_ptr(), result, 1, qid, skid, 1, &pat), m.mk_true());
return result;
}
expr * mk_quantifier_abstraction::mk_select(expr* arg, unsigned num_args, expr* const* args) {
ptr_vector<expr> args2;
args2.push_back(arg);
args2.append(num_args, args);
return a.mk_select(args2.size(), args2.c_ptr());
}
rule_set * mk_quantifier_abstraction::operator()(rule_set const & source) {
TRACE("dl", tout << "quantify " << source.get_num_rules() << " " << m_ctx.get_params().quantify_arrays() << "\n";);
if (!m_ctx.get_params().quantify_arrays()) {
return 0;
}
unsigned sz = source.get_num_rules();
for (unsigned i = 0; i < sz; ++i) {
rule& r = *source.get_rule(i);
if (r.has_negation()) {
return 0;
}
}
m_refs.reset();
m_old2new.reset();
m_new2old.reset();
rule_manager& rm = source.get_rule_manager();
rule_ref new_rule(rm);
expr_ref_vector tail(m);
app_ref head(m);
expr_ref fml(m);
rule_counter& vc = rm.get_counter();
if (m_ctx.get_model_converter()) {
m_mc = alloc(qa_model_converter, m);
}
rule_set * result = alloc(rule_set, m_ctx);
for (unsigned i = 0; i < sz; ++i) {
tail.reset();
rule & r = *source.get_rule(i);
TRACE("dl", r.display(m_ctx, tout); );
unsigned cnt = vc.get_max_rule_var(r)+1;
unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size();
for (unsigned j = 0; j < utsz; ++j) {
tail.push_back(mk_tail(r.get_tail(j)));
}
for (unsigned j = utsz; j < tsz; ++j) {
tail.push_back(r.get_tail(j));
}
head = mk_head(r.get_head(), cnt);
fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), head);
rule_ref_vector added_rules(rm);
proof_ref pr(m);
rm.mk_rule(fml, pr, added_rules);
result->add_rules(added_rules.size(), added_rules.c_ptr());
TRACE("dl", added_rules.back()->display(m_ctx, tout););
}
// proof converter: proofs are not necessarily preserved using this transformation.
if (m_old2new.empty()) {
dealloc(result);
dealloc(m_mc);
result = 0;
}
else {
m_ctx.add_model_converter(m_mc);
}
m_mc = 0;
return result;
}
};

View file

@ -0,0 +1,64 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
dl_mk_quantifier_abstraction.h
Abstract:
Convert clauses with array arguments to predicates
into Quantified Horn clauses.
Author:
Ken McMillan
Andrey Rybalchenko
Nikolaj Bjorner (nbjorner) 2013-04-02
Revision History:
Based on approach suggested in SAS 2013 paper
"On Solving Universally Quantified Horn Clauses"
--*/
#ifndef _DL_MK_QUANTIFIER_ABSTRACTION_H_
#define _DL_MK_QUANTIFIER_ABSTRACTION_H_
#include"dl_rule_transformer.h"
#include"array_decl_plugin.h"
namespace datalog {
class context;
class mk_quantifier_abstraction : public rule_transformer::plugin {
class qa_model_converter;
ast_manager& m;
context& m_ctx;
array_util a;
func_decl_ref_vector m_refs;
obj_map<func_decl, func_decl*> m_new2old;
obj_map<func_decl, func_decl*> m_old2new;
qa_model_converter* m_mc;
func_decl* declare_pred(func_decl* old_p);
app_ref mk_head(app* p, unsigned idx);
app_ref mk_tail(app* p);
expr* mk_select(expr* a, unsigned num_args, expr* const* args);
public:
mk_quantifier_abstraction(context & ctx, unsigned priority);
virtual ~mk_quantifier_abstraction();
rule_set * operator()(rule_set const & source);
};
};
#endif /* _DL_MK_QUANTIFIER_ABSTRACTION_H_ */

View file

@ -0,0 +1,299 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
dl_mk_quantifier_instantiation.cpp
Abstract:
Convert Quantified Horn clauses into non-quantified clauses using
instantiation.
Author:
Ken McMillan
Andrey Rybalchenko
Nikolaj Bjorner (nbjorner) 2013-04-02
Revision History:
Based on approach suggested in the SAS 2013 paper
"On Solving Universally Quantified Horn Clauses"
--*/
#include "dl_mk_quantifier_instantiation.h"
#include "dl_context.h"
#include "pattern_inference.h"
namespace datalog {
mk_quantifier_instantiation::mk_quantifier_instantiation(
context & ctx, unsigned priority):
plugin(priority),
m(ctx.get_manager()),
m_ctx(ctx),
m_var2cnst(m),
m_cnst2var(m) {
}
mk_quantifier_instantiation::~mk_quantifier_instantiation() {
}
void mk_quantifier_instantiation::extract_quantifiers(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs) {
conjs.reset();
qs.reset();
unsigned tsz = r.get_tail_size();
for (unsigned j = 0; j < tsz; ++j) {
conjs.push_back(r.get_tail(j));
}
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)) {
qs.push_back(q);
conjs[j] = conjs.back();
conjs.pop_back();
--j;
}
}
}
void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, expr_ref_vector & conjs) {
expr_ref qe(m);
qe = q;
m_var2cnst(qe);
q = to_quantifier(qe);
if (q->get_num_patterns() == 0) {
proof_ref new_pr(m);
pattern_inference_params params;
pattern_inference infer(m, params);
infer(q, qe, new_pr);
q = to_quantifier(qe);
}
unsigned num_patterns = q->get_num_patterns();
for (unsigned i = 0; i < num_patterns; ++i) {
expr * pat = q->get_pattern(i);
SASSERT(m.is_pattern(pat));
instantiate_quantifier(q, to_app(pat), conjs);
}
}
void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs) {
m_binding.reset();
m_binding.resize(q->get_num_decls());
term_pairs todo;
match(0, pat, 0, todo, q, conjs);
}
void mk_quantifier_instantiation::match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs) {
TRACE("dl", tout << "match" << mk_pp(pat, m) << "\n";);
while (j < todo.size()) {
expr* p = todo[j].first;
expr* t = todo[j].second;
if (is_var(p)) {
unsigned idx = to_var(p)->get_idx();
if (!m_binding[idx]) {
m_binding[idx] = t;
match(i, pat, j + 1, todo, q, conjs);
m_binding[idx] = 0;
return;
}
++j;
continue;
}
if (!is_app(p)) {
return;
}
app* a1 = to_app(p);
unsigned id = t->get_id();
unsigned next_id = id;
unsigned sz = todo.size();
do {
expr* t2 = m_terms[next_id];
if (is_app(t2)) {
app* a2 = to_app(t2);
if (a1->get_decl() == a2->get_decl() &&
a1->get_num_args() == a2->get_num_args()) {
for (unsigned k = 0; k < a1->get_num_args(); ++k) {
todo.push_back(std::make_pair(a1->get_arg(k), a2->get_arg(k)));
}
match(i, pat, j + 1, todo, q, conjs);
todo.resize(sz);
}
}
next_id = m_uf.next(next_id);
}
while (next_id != id);
return;
}
if (i == pat->get_num_args()) {
yield_binding(q, conjs);
return;
}
expr* arg = pat->get_arg(i);
ptr_vector<expr>* terms = 0;
if (m_funs.find(to_app(arg)->get_decl(), terms)) {
for (unsigned k = 0; k < terms->size(); ++k) {
todo.push_back(std::make_pair(arg, (*terms)[k]));
match(i + 1, pat, j, todo, q, conjs);
todo.pop_back();
}
}
}
void mk_quantifier_instantiation::yield_binding(quantifier* q, expr_ref_vector& conjs) {
DEBUG_CODE(
for (unsigned i = 0; i < m_binding.size(); ++i) {
SASSERT(m_binding[i]);
});
m_binding.reverse();
expr_ref res(m);
instantiate(m, q, m_binding.c_ptr(), res);
m_binding.reverse();
m_cnst2var(res);
conjs.push_back(res);
TRACE("dl", tout << mk_pp(q, m) << "\n==>\n" << mk_pp(res, m) << "\n";);
}
void mk_quantifier_instantiation::collect_egraph(expr* e) {
expr* e1, *e2;
m_todo.push_back(e);
expr_fast_mark1 visited;
while (!m_todo.empty()) {
e = m_todo.back();
m_todo.pop_back();
if (visited.is_marked(e)) {
continue;
}
unsigned n = e->get_id();
if (n >= m_terms.size()) {
m_terms.resize(n+1);
}
m_terms[n] = e;
visited.mark(e);
if (m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) {
m_uf.merge(e1->get_id(), e2->get_id());
}
if (is_app(e)) {
app* ap = to_app(e);
ptr_vector<expr>* terms = 0;
if (!m_funs.find(ap->get_decl(), terms)) {
terms = alloc(ptr_vector<expr>);
m_funs.insert(ap->get_decl(), terms);
}
terms->push_back(e);
m_todo.append(ap->get_num_args(), ap->get_args());
}
}
}
void mk_quantifier_instantiation::instantiate_rule(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs, rule_set& rules) {
rule_manager& rm = m_ctx.get_rule_manager();
expr_ref fml(m), cnst(m);
var_ref var(m);
ptr_vector<sort> sorts;
r.get_vars(sorts);
m_uf.reset();
m_terms.reset();
m_var2cnst.reset();
m_cnst2var.reset();
fml = m.mk_and(conjs.size(), conjs.c_ptr());
for (unsigned i = 0; i < sorts.size(); ++i) {
if (!sorts[i]) {
sorts[i] = m.mk_bool_sort();
}
var = m.mk_var(i, sorts[i]);
cnst = m.mk_fresh_const("C", sorts[i]);
m_var2cnst.insert(var, cnst);
m_cnst2var.insert(cnst, var);
}
fml = m.mk_and(conjs.size(), conjs.c_ptr());
m_var2cnst(fml);
collect_egraph(fml);
for (unsigned i = 0; i < qs.size(); ++i) {
instantiate_quantifier(qs[i].get(), conjs);
}
obj_map<func_decl, ptr_vector<expr>*>::iterator it = m_funs.begin(), end = m_funs.end();
for (; it != end; ++it) {
dealloc(it->m_value);
}
m_funs.reset();
fml = m.mk_and(conjs.size(), conjs.c_ptr());
fml = m.mk_implies(fml, r.get_head());
TRACE("dl", r.display(m_ctx, tout); tout << mk_pp(fml, m) << "\n";);
rule_ref_vector added_rules(rm);
proof_ref pr(m);
rm.mk_rule(fml, pr, added_rules);
if (r.get_proof()) {
// use def-axiom to encode that new rule is a weakening of the original.
proof* p1 = r.get_proof();
for (unsigned i = 0; i < added_rules.size(); ++i) {
rule* r2 = added_rules[i].get();
r2->to_formula(fml);
pr = m.mk_modus_ponens(m.mk_def_axiom(m.mk_implies(m.get_fact(p1), fml)), p1);
r2->set_proof(m, pr);
}
}
rules.add_rules(added_rules.size(), added_rules.c_ptr());
}
rule_set * mk_quantifier_instantiation::operator()(rule_set const & source) {
TRACE("dl", tout << m_ctx.get_params().instantiate_quantifiers() << "\n";);
if (!m_ctx.get_params().instantiate_quantifiers()) {
return 0;
}
bool has_quantifiers = false;
unsigned sz = source.get_num_rules();
for (unsigned i = 0; !has_quantifiers && i < sz; ++i) {
rule& r = *source.get_rule(i);
has_quantifiers = has_quantifiers || r.has_quantifiers();
if (r.has_negation()) {
return 0;
}
}
if (!has_quantifiers) {
return 0;
}
expr_ref_vector conjs(m);
quantifier_ref_vector qs(m);
rule_set * result = alloc(rule_set, m_ctx);
bool instantiated = false;
for (unsigned i = 0; i < sz; ++i) {
rule * r = source.get_rule(i);
extract_quantifiers(*r, conjs, qs);
if (qs.empty()) {
result->add_rule(r);
}
else {
instantiate_rule(*r, conjs, qs, *result);
instantiated = true;
}
}
// model convertion: identity function.
if (!instantiated) {
dealloc(result);
result = 0;
}
return result;
}
};

View file

@ -0,0 +1,136 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
dl_mk_quantifier_instantiation.h
Abstract:
Convert Quantified Horn clauses into non-quantified clauses using
instantiation.
Author:
Ken McMillan
Andrey Rybalchenko
Nikolaj Bjorner (nbjorner) 2013-04-02
Revision History:
Based on approach suggested in the SAS 2013 paper
"On Solving Universally Quantified Horn Clauses"
--*/
#ifndef _DL_MK_QUANTIFIER_INSTANTIATION_H_
#define _DL_MK_QUANTIFIER_INSTANTIATION_H_
#include"dl_rule_transformer.h"
#include"expr_safe_replace.h"
namespace datalog {
class context;
class mk_quantifier_instantiation : public rule_transformer::plugin {
typedef svector<std::pair<expr*,expr*> > term_pairs;
class union_find {
unsigned_vector m_find;
unsigned_vector m_size;
unsigned_vector m_next;
void ensure_size(unsigned v) {
while (v >= get_num_vars()) {
mk_var();
}
}
public:
unsigned mk_var() {
unsigned r = m_find.size();
m_find.push_back(r);
m_size.push_back(1);
m_next.push_back(r);
return r;
}
unsigned get_num_vars() const { return m_find.size(); }
unsigned find(unsigned v) const {
if (v >= get_num_vars()) {
return v;
}
while (true) {
unsigned new_v = m_find[v];
if (new_v == v)
return v;
v = new_v;
}
}
unsigned next(unsigned v) const {
if (v >= get_num_vars()) {
return v;
}
return m_next[v];
}
bool is_root(unsigned v) const {
return v >= get_num_vars() || m_find[v] == v;
}
void merge(unsigned v1, unsigned v2) {
unsigned r1 = find(v1);
unsigned r2 = find(v2);
if (r1 == r2)
return;
ensure_size(v1);
ensure_size(v2);
if (m_size[r1] > m_size[r2])
std::swap(r1, r2);
m_find[r1] = r2;
m_size[r2] += m_size[r1];
std::swap(m_next[r1], m_next[r2]);
}
void reset() {
m_find.reset();
m_next.reset();
m_size.reset();
}
};
ast_manager& m;
context& m_ctx;
expr_safe_replace m_var2cnst;
expr_safe_replace m_cnst2var;
union_find m_uf;
ptr_vector<expr> m_todo;
ptr_vector<expr> m_terms;
ptr_vector<expr> m_binding;
obj_map<func_decl, ptr_vector<expr>*> m_funs;
void extract_quantifiers(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs);
void collect_egraph(expr* e);
void instantiate_rule(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs, rule_set& rules);
void instantiate_quantifier(quantifier* q, expr_ref_vector & conjs);
void instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs);
void match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs);
void yield_binding(quantifier* q, expr_ref_vector& conjs);
public:
mk_quantifier_instantiation(context & ctx, unsigned priority);
virtual ~mk_quantifier_instantiation();
rule_set * operator()(rule_set const & source);
};
};
#endif /* _DL_MK_QUANTIFIER_INSTANTIATION_H_ */

View file

@ -65,8 +65,8 @@ namespace datalog {
// -----------------------------------
bool rule_unifier::unify_rules(const rule& tgt, unsigned tgt_idx, const rule& src) {
var_counter& vc = m_rm.get_var_counter();
unsigned var_cnt = std::max(vc.get_max_var(tgt), vc.get_max_var(src))+1;
rule_counter& vc = m_rm.get_counter();
unsigned var_cnt = std::max(vc.get_max_rule_var(tgt), vc.get_max_rule_var(src))+1;
m_subst.reset();
m_subst.reserve(2, var_cnt);
@ -181,10 +181,10 @@ namespace datalog {
}
if (m_unifier.apply(tgt, tail_index, src, res)) {
if (m_pc) {
if (m_context.generate_proof_trace()) {
expr_ref_vector s1 = m_unifier.get_rule_subst(tgt, true);
expr_ref_vector s2 = m_unifier.get_rule_subst(src, false);
datalog::resolve_rule(m_pc, tgt, src, tail_index, s1, s2, *res.get());
datalog::resolve_rule(tgt, src, tail_index, s1, s2, *res.get());
}
return true;
}
@ -241,8 +241,10 @@ namespace datalog {
return false;
}
//these conditions are optional, they avoid possible exponential increase
//in the size of the problem
//
// these conditions are optional, they avoid possible exponential increase
// in the size of the problem
//
return
//m_head_pred_non_empty_tails_ctr.get(pred)<=1
@ -733,7 +735,7 @@ namespace datalog {
}
// initialize substitution.
var_counter& vc = m_rm.get_var_counter();
rule_counter& vc = m_rm.get_counter();
unsigned max_var = 0;
for (unsigned i = 0; i < sz; ++i) {
rule* r = acc[i].get();
@ -820,7 +822,7 @@ namespace datalog {
del_rule(r2, j);
}
max_var = std::max(max_var, vc.get_max_var(*r.get()));
max_var = std::max(max_var, vc.get_max_rule_var(*r.get()));
m_subst.reserve_vars(max_var+1);
}
@ -837,11 +839,10 @@ namespace datalog {
return done_something;
}
rule_set * mk_rule_inliner::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
rule_set * mk_rule_inliner::operator()(rule_set const & source) {
bool something_done = false;
ref<horn_subsume_model_converter> hsmc;
ref<replace_proof_converter> hpc;
if (source.get_num_rules() == 0) {
return 0;
@ -855,14 +856,10 @@ namespace datalog {
}
if (mc) {
if (m_context.get_model_converter()) {
hsmc = alloc(horn_subsume_model_converter, m);
}
if (pc) {
hpc = alloc(replace_proof_converter, m);
}
m_mc = hsmc.get();
m_pc = hpc.get();
scoped_ptr<rule_set> res = alloc(rule_set, m_context);
@ -886,12 +883,7 @@ namespace datalog {
res = 0;
}
else {
if (mc) {
mc = concat(mc.get(), hsmc.get());
}
if (pc) {
pc = concat(pc.get(), hpc.get());
}
m_context.add_model_converter(hsmc.get());
}
return res.detach();

View file

@ -114,7 +114,6 @@ namespace datalog {
ast_counter m_tail_pred_ctr;
rule_set m_inlined_rules;
horn_subsume_model_converter* m_mc;
replace_proof_converter* m_pc;
//used in try_to_inline_rule and do_eager_inlining
@ -188,7 +187,6 @@ namespace datalog {
m_pinned(m_rm),
m_inlined_rules(m_context),
m_mc(0),
m_pc(0),
m_unifier(ctx),
m_head_index(m),
m_tail_index(m),
@ -198,7 +196,7 @@ namespace datalog {
{}
virtual ~mk_rule_inliner() { }
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
};
};

View file

@ -42,7 +42,7 @@ namespace datalog {
/**
Allows to traverse head and positive tails in a single for loop starting from -1
*/
app * get_by_tail_index(rule * r, int idx) {
static app * get_by_tail_index(rule * r, int idx) {
if(idx==-1) {
return r->get_head();
}
@ -51,11 +51,11 @@ namespace datalog {
}
template<typename T>
int aux_compare(T a, T b) {
static int aux_compare(T a, T b) {
return (a>b) ? 1 : ( (a==b) ? 0 : -1);
}
int compare_var_args(app* t1, app* t2) {
static int compare_var_args(app* t1, app* t2) {
SASSERT(t1->get_num_args()==t2->get_num_args());
int res;
unsigned n = t1->get_num_args();
@ -73,7 +73,7 @@ namespace datalog {
return 0;
}
int compare_args(app* t1, app* t2, int & skip_countdown) {
static int compare_args(app* t1, app* t2, int & skip_countdown) {
SASSERT(t1->get_num_args()==t2->get_num_args());
int res;
unsigned n = t1->get_num_args();
@ -98,7 +98,7 @@ namespace datalog {
Two rules are in the same rough similarity class if they differ only in constant arguments
of positive uninterpreted predicates.
*/
int rough_compare(rule * r1, rule * r2) {
static int rough_compare(rule * r1, rule * r2) {
int res = aux_compare(r1->get_tail_size(), r2->get_tail_size());
if(res!=0) { return res; }
res = aux_compare(r1->get_uninterpreted_tail_size(), r2->get_uninterpreted_tail_size());
@ -129,7 +129,7 @@ namespace datalog {
\c r1 and \c r2 must be equal according to the \c rough_compare function for this function
to be called.
*/
int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) {
static int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) {
SASSERT(rough_compare(r1, r2)==0);
int pos_tail_sz = r1->get_positive_tail_size();
for(int i=-1; i<pos_tail_sz; i++) {
@ -165,7 +165,7 @@ namespace datalog {
typedef svector<const_info> info_vector;
void collect_const_indexes(app * t, int tail_index, info_vector & res) {
static void collect_const_indexes(app * t, int tail_index, info_vector & res) {
unsigned n = t->get_num_args();
for(unsigned i=0; i<n; i++) {
if(is_var(t->get_arg(i))) {
@ -175,7 +175,7 @@ namespace datalog {
}
}
void collect_const_indexes(rule * r, info_vector & res) {
static void collect_const_indexes(rule * r, info_vector & res) {
collect_const_indexes(r->get_head(), -1, res);
unsigned pos_tail_sz = r->get_positive_tail_size();
for(unsigned i=0; i<pos_tail_sz; i++) {
@ -184,7 +184,7 @@ namespace datalog {
}
template<class T>
void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) {
static void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) {
unsigned const_cnt = const_infos.size();
tgt.reset();
for(unsigned i=0; i<const_cnt; i++) {
@ -198,7 +198,7 @@ namespace datalog {
}
}
template<class T>
void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) {
static void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) {
unsigned const_cnt = const_infos.size();
tgt.reset();
for(unsigned i=0; i<const_cnt; i++) {
@ -215,7 +215,7 @@ namespace datalog {
\brief From the \c tail_indexes and \c arg_indexes remove elements corresponding to constants
that are the same in rules \c *first ... \c *(after_last-1).
*/
void remove_stable_constants(rule_vector::iterator first, rule_vector::iterator after_last,
static void remove_stable_constants(rule_vector::iterator first, rule_vector::iterator after_last,
info_vector & const_infos) {
SASSERT(after_last-first>1);
unsigned const_cnt = const_infos.size();
@ -252,7 +252,7 @@ namespace datalog {
first constant that is equal to it in all the rules. If there is no such, it will contain
its own index.
*/
void detect_equal_constants(rule_vector::iterator first, rule_vector::iterator after_last,
static void detect_equal_constants(rule_vector::iterator first, rule_vector::iterator after_last,
info_vector & const_infos) {
SASSERT(first!=after_last);
unsigned const_cnt = const_infos.size();
@ -302,7 +302,7 @@ namespace datalog {
}
}
unsigned get_constant_count(rule * r) {
static unsigned get_constant_count(rule * r) {
unsigned res = r->get_head()->get_num_args() - count_variable_arguments(r->get_head());
unsigned pos_tail_sz = r->get_positive_tail_size();
for(unsigned i=0; i<pos_tail_sz; i++) {
@ -311,7 +311,7 @@ namespace datalog {
return res;
}
bool initial_comparator(rule * r1, rule * r2) {
static bool initial_comparator(rule * r1, rule * r2) {
int res = rough_compare(r1, r2);
if(res!=0) { return res>0; }
return total_compare(r1, r2)>0;
@ -372,10 +372,10 @@ namespace datalog {
new_negs.push_back(r->is_neg_tail(i));
}
var_counter var_ctr;
var_ctr.count_vars(m_manager, r);
rule_counter ctr;
ctr.count_rule_vars(m_manager, r);
unsigned max_var_idx, new_var_idx_base;
if(var_ctr.get_max_positive(max_var_idx)) {
if(ctr.get_max_positive(max_var_idx)) {
new_var_idx_base = max_var_idx+1;
}
else {
@ -500,8 +500,8 @@ namespace datalog {
}
}
rule_set * mk_similarity_compressor::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
// TODO mc, pc
rule_set * mk_similarity_compressor::operator()(rule_set const & source) {
// TODO mc
m_modified = false;
unsigned init_rule_cnt = source.get_num_rules();
SASSERT(m_rules.empty());

View file

@ -69,7 +69,7 @@ namespace datalog {
public:
mk_similarity_compressor(context & ctx, unsigned threshold_count);
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
};
};

View file

@ -310,8 +310,8 @@ namespace datalog {
}
void register_rule(rule * r) {
var_counter counter;
counter.count_vars(m, r, 1);
rule_counter counter;
counter.count_rule_vars(m, r, 1);
ptr_vector<app> & rule_content =
m_rules_content.insert_if_not_there2(r, ptr_vector<app>())->get_data().m_value;
@ -706,19 +706,19 @@ namespace datalog {
negs.c_ptr());
new_rule->set_accounting_parent_object(m_context, orig_r);
m_context.get_rule_manager().mk_rule_rewrite_proof(*orig_r, *new_rule);
result->add_rule(new_rule);
}
while(!m_introduced_rules.empty()) {
while (!m_introduced_rules.empty()) {
result->add_rule(m_introduced_rules.back());
m_context.get_rule_manager().mk_rule_asserted_proof(*m_introduced_rules.back());
m_introduced_rules.pop_back();
}
return result;
}
};
rule_set * mk_simple_joins::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
// TODO mc, pc
rule_set * mk_simple_joins::operator()(rule_set const & source) {
rule_set rs_aux_copy(m_context);
rs_aux_copy.add_rules(source);
if(!rs_aux_copy.is_closed()) {

View file

@ -53,7 +53,7 @@ namespace datalog {
public:
mk_simple_joins(context & ctx);
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
};
};

View file

@ -164,10 +164,8 @@ namespace datalog {
TRACE("dl", tout << "does not have fact\n" << mk_pp(fact, m) << "\n";);
return false;
}
expr_ref fml(m);
proof_ref new_p(m);
r->to_formula(fml);
new_p = m.mk_asserted(fml);
new_p = r->get_proof();
m_pinned_exprs.push_back(new_p);
m_todo.pop_back();
m_new_proof.insert(p, new_p);
@ -784,6 +782,9 @@ namespace datalog {
rm.fix_unbound_vars(new_rule, false);
TRACE("dl", r.display(m_ctx, tout << "replacing:\n"); new_rule->display(m_ctx, tout << "by:\n"););
if (m_ctx.generate_proof_trace()) {
rm.mk_rule_asserted_proof(*new_rule.get());
}
}
else {
new_rule = &r;
@ -801,7 +802,7 @@ namespace datalog {
}
}
rule_set * mk_slice::operator()(rule_set const & src, model_converter_ref& mc, proof_converter_ref& pc) {
rule_set * mk_slice::operator()(rule_set const & src) {
for (unsigned i = 0; i < src.get_num_rules(); ++i) {
if (src.get_rule(i)->has_quantifiers()) {
return 0;
@ -809,10 +810,10 @@ namespace datalog {
}
ref<slice_proof_converter> spc;
ref<slice_model_converter> smc;
if (pc) {
spc = alloc(slice_proof_converter, m_ctx);
if (m_ctx.generate_proof_trace()) {
spc = alloc(slice_proof_converter, m_ctx);
}
if (mc) {
if (m_ctx.get_model_converter()) {
smc = alloc(slice_model_converter, *this, m);
}
m_pc = spc.get();
@ -834,8 +835,8 @@ namespace datalog {
m_mc->add_sliceable(it->m_key, it->m_value);
}
}
pc = concat(pc.get(), spc.get());
mc = concat(mc.get(), smc.get());
m_ctx.add_proof_converter(spc.get());
m_ctx.add_model_converter(smc.get());
return result;
}

View file

@ -102,7 +102,7 @@ namespace datalog {
virtual ~mk_slice() { }
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
func_decl* get_predicate(func_decl* p) { func_decl* q = p; m_predicates.find(p, q); return q; }

View file

@ -166,7 +166,8 @@ namespace datalog {
res = m_context.get_rule_manager().mk(head, tail.size(), tail.c_ptr(), tail_neg.c_ptr());
res->set_accounting_parent_object(m_context, r);
m_context.get_rule_manager().fix_unbound_vars(res, true);
m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *res.get());
return true;
}
@ -208,10 +209,10 @@ namespace datalog {
continue;
}
rule * defining_rule;
TRUSTME(m_total_relation_defining_rules.find(head_pred, defining_rule));
if(defining_rule) {
VERIFY(m_total_relation_defining_rules.find(head_pred, defining_rule));
if (defining_rule) {
rule_ref totality_rule(m_context.get_rule_manager());
TRUSTME(transform_rule(defining_rule, subs_index, totality_rule));
VERIFY(transform_rule(defining_rule, subs_index, totality_rule));
if(defining_rule!=totality_rule) {
modified = true;
}
@ -331,8 +332,8 @@ namespace datalog {
}
}
rule_set * mk_subsumption_checker::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
// TODO mc, pc
rule_set * mk_subsumption_checker::operator()(rule_set const & source) {
// TODO mc
m_have_new_total_rule = false;
collect_ground_unconditional_rule_heads(source);

View file

@ -84,7 +84,7 @@ namespace datalog {
reset_dealloc_values(m_ground_unconditional_rule_heads);
}
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
rule_set * operator()(rule_set const & source);
};
};

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