diff --git a/.gitignore b/.gitignore
index 3d6e631f1..a935d9dba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,8 @@
 *~
 *.pyc
+*.pyo
+# Ignore callgrind files
+callgrind.out.*
 # .hpp files are automatically generated
 *.hpp
 .z3-trace
diff --git a/README b/README
index 13f3d4fa4..1ca0cd577 100644
--- a/README
+++ b/README
@@ -17,22 +17,24 @@ Execute:
    make
    sudo make install
 
-It will install z3 executable at /usr/bin, libraries at /usr/lib, and include files at /usr/include.
-You can change the installation p
+By default, it will install z3 executable at PREFIX/bin, libraries at PREFIX/lib, and include files at PREFIX/include,
+where PREFIX is the installation prefix used for installing Python in your system.
+It is usually /usr for most Linux distros, and /usr/local for FreeBSD.
+Use the following commands to install in a different prefix (e.g., /home/leo)
 
-Use the following commands to install in a different prefix (e.g., /home/leo), and the Z3 python
-bindings in a different python package directory.
-
-  python scripts/mk_make.py --prefix=/home/leo --pydir=/home/leo/python
+  python scripts/mk_make.py --prefix=/home/leo
   cd build
   make
-  sudo make install
+  make install
+
+In this example, the Z3 Python bindings will be stored at /home/leo/lib/pythonX.Y/dist-packages,
+where X.Y corresponds to the python version in your system.
 
 To uninstall Z3, use
 
   sudo make uninstall
 
-3) Building Z3 using clang and clang++ on Linux/OSX
+4) Building Z3 using clang and clang++ on Linux/OSX
 Remark: clang does not support OpenMP yet.   
 
    CXX=clang++ CC=clang python scripts/mk_make.py
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index 2c8d93acd..104828a45 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -9,6 +9,8 @@ Version 4.3.2
 
 - Added support for FreeBSD. Z3 can be compiled on FreeBSD using g++. 
 
+- Added support for Python 3.x.
+
 - Reverted to `(set-option :global-decls false)` as the default. In Z3 4.3.0 and Z3 4.3.1, this option was set to true.
   Thanks to Julien Henry for reporting this problem.
 
@@ -30,6 +32,27 @@ Version 4.3.2
   
 - Fixed problem in the pretty printer. It was not introducing quotes for attribute names such as |foo:10|.
 
+- Fixed bug when using assumptions (Thanks to Philippe Suter and Etienne Kneuss)
+  Consider the following example:
+      (assert F)
+      (check-sat a)
+      (check-sat)
+  If 'F' is unstatisfiable independently of the assumption 'a', and 
+  the inconsistenty can be detected by just performing propagation,
+  Then, version <= 4.3.1 may return
+      unsat
+      sat
+  instead of
+      unsat
+      unsat
+  We say may because 'F' may have other unsatisfiable cores.
+
+- Fixed bug reported at http://stackoverflow.com/questions/13923316/unprintable-solver-model
+
+- Fixed timers on Linux and FreeBSD.
+
+- Fixed crash reported at http://z3.codeplex.com/workitem/11.
+
 Version 4.3.1
 =============
 
diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp
index ab6e67ab9..9e92d99ab 100644
--- a/examples/c++/example.cpp
+++ b/examples/c++/example.cpp
@@ -812,6 +812,68 @@ void tst_visit() {
     visit(f);
 }
 
+void incremental_example1() {
+    std::cout << "incremental example1\n";
+    context c;
+    expr x = c.int_const("x");
+    solver s(c);
+    s.add(x > 0);
+    std::cout << s.check() << "\n";
+    // We can add more formulas to the solver
+    s.add(x < 0);
+    // and, invoke s.check() again...
+    std::cout << s.check() << "\n";
+}
+
+void incremental_example2() {
+    // In this example, we show how push() and pop() can be used
+    // to remove formulas added to the solver.
+    std::cout << "incremental example2\n";
+    context c;
+    expr x = c.int_const("x");
+    solver s(c);
+    s.add(x > 0);
+    std::cout << s.check() << "\n";
+    // push() creates a backtracking point (aka a snapshot).
+    s.push();
+    // We can add more formulas to the solver
+    s.add(x < 0);
+    // and, invoke s.check() again...
+    std::cout << s.check() << "\n";
+    // pop() will remove all formulas added between this pop() and the matching push()
+    s.pop();
+    // The context is satisfiable again
+    std::cout << s.check() << "\n";
+    // and contains only x > 0
+    std::cout << s << "\n";
+}
+
+void incremental_example3() {
+    // In this example, we show how to use assumptions to "remove" 
+    // formulas added to a solver. Actually, we disable them.
+    std::cout << "incremental example3\n";
+    context c;
+    expr x = c.int_const("x");
+    solver s(c);
+    s.add(x > 0);
+    std::cout << s.check() << "\n";
+    // Now, suppose we want to add x < 0 to the solver, but we also want
+    // to be able to disable it later.
+    // To do that, we create an auxiliary Boolean variable
+    expr b = c.bool_const("b");
+    // and, assert (b implies x < 0)
+    s.add(implies(b, x < 0));
+    // Now, we check whether s is satisfiable under the assumption "b" is true.
+    expr_vector a1(c);
+    a1.push_back(b);
+    std::cout << s.check(a1) << "\n";
+    // To "disable" (x > 0), we may just ask with the assumption "not b" or not provide any assumption.
+    std::cout << s.check() << "\n";
+    expr_vector a2(c);
+    a2.push_back(!b);
+    std::cout << s.check(a2) << "\n";
+}
+
 int main() {
     try {
         demorgan(); std::cout << "\n";
@@ -842,6 +904,9 @@ int main() {
         tactic_example9(); std::cout << "\n";
         tactic_qe(); std::cout << "\n";
         tst_visit(); std::cout << "\n";
+	incremental_example1(); std::cout << "\n";
+	incremental_example2(); std::cout << "\n";
+	incremental_example3(); std::cout << "\n";
         std::cout << "done\n";
     }
     catch (exception & ex) {
diff --git a/examples/python/example.py b/examples/python/example.py
index a8a764a4d..879c17c43 100644
--- a/examples/python/example.py
+++ b/examples/python/example.py
@@ -4,5 +4,5 @@ x = Real('x')
 y = Real('y')
 s = Solver()
 s.add(x + y > 5, x > 1, y > 1)
-print s.check()
-print s.model()
+print(s.check())
+print(s.model())
diff --git a/scripts/mk_util.py b/scripts/mk_util.py
index 3ffa7e313..e4f860a95 100644
--- a/scripts/mk_util.py
+++ b/scripts/mk_util.py
@@ -7,11 +7,6 @@
 # Author: Leonardo de Moura (leonardo)
 ############################################
 import sys
-
-if sys.version >= "3":
-    print "ERROR: python 2.x required."
-    exit(1)
-
 import os
 import glob
 import re
@@ -73,7 +68,7 @@ VER_MAJOR=None
 VER_MINOR=None
 VER_BUILD=None
 VER_REVISION=None
-PREFIX='/usr'
+PREFIX=os.path.split(os.path.split(os.path.split(PYTHON_PACKAGE_DIR)[0])[0])[0]
 GMP=False
 VS_PAR=False
 VS_PAR_NUM=8
@@ -134,8 +129,7 @@ def exec_cmd(cmd):
     first = True
     for e in cmd:
         if first:
-            # Allow spaces in the executable name
-	    first = False
+            first = False
             new_cmd.append(e)
         else:
             if e != "":
@@ -166,7 +160,7 @@ def exec_compiler_cmd(cmd):
 
 def test_cxx_compiler(cc):
     if is_verbose():
-        print "Testing %s..." % cc
+        print("Testing %s..." % cc)
     t = TempFile('tst.cpp')
     t.add('#include<iostream>\nint main() { return 0; }\n')
     t.commit()
@@ -174,7 +168,7 @@ def test_cxx_compiler(cc):
 
 def test_c_compiler(cc):
     if is_verbose():
-        print "Testing %s..." % cc
+        print("Testing %s..." % cc)
     t = TempFile('tst.c')
     t.add('#include<stdio.h>\nint main() { return 0; }\n')
     t.commit()
@@ -182,7 +176,7 @@ def test_c_compiler(cc):
 
 def test_gmp(cc):
     if is_verbose():
-        print "Testing GMP..."
+        print("Testing GMP...")
     t = TempFile('tstgmp.cpp')
     t.add('#include<gmp.h>\nint main() { mpz_t t; mpz_init(t); mpz_clear(t); return 0; }\n')
     t.commit()
@@ -190,7 +184,7 @@ def test_gmp(cc):
 
 def test_openmp(cc):
     if is_verbose():
-        print "Testing OpenMP..."
+        print("Testing OpenMP...")
     t = TempFile('tstomp.cpp')
     t.add('#include<omp.h>\nint main() { return omp_in_parallel() ? 1 : 0; }\n')
     t.commit()
@@ -201,12 +195,12 @@ def check_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
+        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
+        print("Testing %s..." % JAVA)
     r = exec_cmd([JAVA, 'Hello'])
     rmf('Hello.class')
     if r != 0:
@@ -224,11 +218,11 @@ def find_java_home():
     global JAVA_HOME
     if JAVA_HOME != None:
         if is_verbose():
-            print "Checking jni.h..."
+            print("Checking jni.h...")
         if os.path.exists(os.path.join(JAVA_HOME, 'include', 'jni.h')):
             return
     if is_verbose():
-        print "Finding JAVA_HOME..."
+        print("Finding JAVA_HOME...")
     t = TempFile('output')
     null = open(os.devnull, 'wb')
     try: 
@@ -242,17 +236,17 @@ def find_java_home():
         m = open_pat.match(line)
         if m:
             # Remove last 3 directives from m.group(1)
-	    print 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..."
+                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
+                print('JAVA_HOME=%s' % JAVA_HOME)
             return
     raise MKException('Failed to find JAVA_HOME')
 
@@ -261,7 +255,7 @@ def is64():
 
 def check_ar():
     if is_verbose():
-        print "Testing ar..."
+        print("Testing ar...")
     if which('ar')== None:
         raise MKException('ar (archive tool) was not found')
 
@@ -322,7 +316,7 @@ def dos2unix(fname):
         fout.close()
         shutil.move(fname_new, fname)
         if is_verbose():
-            print "dos2unix '%s'" % fname
+            print("dos2unix '%s'" % fname)
 
 def dos2unix_tree_core(pattern, dir, files):
     for filename in files:
@@ -339,7 +333,7 @@ def check_eol():
         # Linux/OSX/BSD check if the end-of-line is cr/lf
         if is_cr_lf('LICENSE.txt'):
             if is_verbose():
-                print "Fixing end of line..."
+                print("Fixing end of line...")
             dos2unix_tree()
 
 if os.name == 'nt':
@@ -355,42 +349,41 @@ elif os.name == 'posix':
         IS_LINUX=True
 
 def display_help(exit_code):
-    print "mk_make.py: Z3 Makefile generator\n"
-    print "This script generates the Makefile for the Z3 theorem prover."
-    print "It must be executed from the Z3 root directory."
-    print "\nOptions:"
-    print "  -h, --help                    display this message."
-    print "  -s, --silent                  do not print verbose messages."
+    print("mk_make.py: Z3 Makefile generator\n")
+    print("This script generates the Makefile for the Z3 theorem prover.")
+    print("It must be executed from the Z3 root directory.")
+    print("\nOptions:")
+    print("  -h, --help                    display this message.")
+    print("  -s, --silent                  do not print verbose messages.")
     if not IS_WINDOWS:
-        print "  -p <dir>, --prefix=<dir>      installation prefix (default: %s)." % PREFIX
-        print "  -y <dir>, --pydir=<dir>       installation prefix for Z3 python bindings (default: %s)." % PYTHON_PACKAGE_DIR
+        print("  -p <dir>, --prefix=<dir>      installation prefix (default: %s)." % PREFIX)
     else:
-        print "  --parallel=num                use cl option /MP with 'num' parallel processes"
-    print "  -b <sudir>, --build=<subdir>  subdirectory where Z3 will be built (default: build)."
-    print "  -d, --debug                   compile Z3 in debug mode."
-    print "  -t, --trace                   enable tracing in release mode."
+        print("  --parallel=num                use cl option /MP with 'num' parallel processes")
+    print("  -b <sudir>, --build=<subdir>  subdirectory where Z3 will be built (default: build).")
+    print("  -d, --debug                   compile Z3 in debug mode.")
+    print("  -t, --trace                   enable tracing in release mode.")
     if IS_WINDOWS:
-        print "  -x, --x64                     create 64 binary when using Visual Studio."
-    print "  -m, --makefiles               generate only makefiles."
+        print("  -x, --x64                     create 64 binary when using Visual Studio.")
+    print("  -m, --makefiles               generate only makefiles.")
     if IS_WINDOWS:
-        print "  -v, --vsproj                  generate Visual Studio Project Files."
+        print("  -v, --vsproj                  generate Visual Studio Project Files.")
     if IS_WINDOWS:
-        print "  -n, --nodotnet                do not generate Microsoft.Z3.dll make rules."
-    print "  -j, --java                    generate Java bindinds."
-    print "  --staticlib                   build Z3 static library."
+        print("  -n, --nodotnet                do not generate Microsoft.Z3.dll make rules.")
+    print("  -j, --java                    generate Java bindinds.")
+    print("  --staticlib                   build Z3 static library.")
     if not IS_WINDOWS:
-        print "  -g, --gmp                     use GMP."
-    print ""
-    print "Some influential environment variables:"
+        print("  -g, --gmp                     use GMP.")
+    print("")
+    print("Some influential environment variables:")
     if not IS_WINDOWS:
-        print "  CXX        C++ compiler"
-        print "  CC         C compiler"
-        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("  CXX        C++ compiler")
+        print("  CC         C compiler")
+        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)")
     exit(exit_code)
 
 # Parse configuration option for mk_make script
@@ -399,11 +392,11 @@ def parse_options():
     global DOTNET_ENABLED, JAVA_ENABLED, STATIC_LIB, PREFIX, GMP, PYTHON_PACKAGE_DIR
     try:
         options, remainder = getopt.gnu_getopt(sys.argv[1:], 
-                                               'b:dsxhmcvtnp:gjy:', 
+                                               'b:dsxhmcvtnp:gj', 
                                                ['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj',
-                                                'trace', 'nodotnet', 'staticlib', 'prefix=', 'gmp', 'java', 'pydir=', 'parallel='])
+                                                'trace', 'nodotnet', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel='])
     except:
-        print "ERROR: Invalid command line option"
+        print("ERROR: Invalid command line option")
         display_help(1)
 
     for opt, arg in options:
@@ -435,18 +428,19 @@ def parse_options():
             STATIC_LIB = True
         elif not IS_WINDOWS and opt in ('-p', '--prefix'):
             PREFIX = arg
+            PYTHON_PACKAGE_DIR = os.path.join(PREFIX, 'lib', 'python%s' % distutils.sysconfig.get_python_version(), 'dist-packages')
+            mk_dir(PYTHON_PACKAGE_DIR)
+            if sys.version >= "3":
+                mk_dir(os.path.join(PYTHON_PACKAGE_DIR, '__pycache__'))
         elif IS_WINDOWS and opt == '--parallel':
             VS_PAR = True
             VS_PAR_NUM = int(arg)
-        elif opt in ('-y', '--pydir'):
-            PYTHON_PACKAGE_DIR = arg
-            mk_dir(PYTHON_PACKAGE_DIR)
         elif opt in ('-g', '--gmp'):
             GMP = True
         elif opt in ('-j', '--java'):
             JAVA_ENABLED = True
         else:
-            print "ERROR: Invalid command line option '%s'" % opt
+            print("ERROR: Invalid command line option '%s'" % opt)
             display_help(1)
 
 # Return a list containing a file names included using '#include' in
@@ -497,7 +491,7 @@ def set_z3py_dir(p):
         raise MKException("Python bindings directory '%s' does not exist" % full)
     Z3PY_SRC_DIR = full
     if VERBOSE:
-        print "Python bindinds directory was detected."
+        print("Python bindinds directory was detected.")
 
 _UNIQ_ID = 0
 
@@ -781,7 +775,7 @@ def comp_components(c1, c2):
 
 # Sort components based on (reverse) definition time
 def sort_components(cnames):
-    return sorted(cnames, cmp=comp_components)
+    return sorted(cnames, key=lambda c: get_component(c).id, reverse=True)
 
 class ExeComponent(Component):
     def __init__(self, name, exe_name, path, deps, install):
@@ -1196,7 +1190,7 @@ class PythonExampleComponent(ExampleComponent):
         for py in filter(lambda f: f.endswith('.py'), os.listdir(full)):
             shutil.copyfile(os.path.join(full, py), os.path.join(BUILD_DIR, py))
             if is_verbose():
-                print "Copied Z3Py example '%s' to '%s'" % (py, BUILD_DIR)
+                print("Copied Z3Py example '%s' to '%s'" % (py, BUILD_DIR))
         out.write('_ex_%s: \n\n' % self.name)
 
 
@@ -1208,7 +1202,7 @@ def reg_component(name, c):
     _ComponentNames.add(name)
     _Name2Component[name] = c
     if VERBOSE:
-        print "New component: '%s'" % name
+        print("New component: '%s'" % name)
 
 def add_lib(name, deps=[], path=None, includes2install=[]):
     c = LibComponent(name, path, deps, includes2install)
@@ -1315,11 +1309,11 @@ def mk_config():
 
         # End of Windows VS config.mk
         if is_verbose():
-            print '64-bit:         %s' % is64()
+            print('64-bit:         %s' % is64())
             if is_java_enabled():
-                print 'Java Home:      %s' % JAVA_HOME
-                print 'Java Compiler:  %s' % JAVAC
-                print 'Java VM:        %s' % JAVA
+                print('Java Home:      %s' % JAVA_HOME)
+                print('Java Compiler:  %s' % JAVAC)
+                print('Java VM:        %s' % JAVA)
     else:
         global CXX, CC, GMP, CPPFLAGS, CXXFLAGS, LDFLAGS
         ARITH = "internal"
@@ -1401,17 +1395,18 @@ def mk_config():
         config.write('SLINK_EXTRA_FLAGS=%s\n' % SLIBEXTRAFLAGS)
         config.write('SLINK_OUT_FLAG=-o \n')
         if is_verbose():
-            print 'Host platform:  %s' % sysname
-            print 'C++ Compiler:   %s' % CXX
-            print 'C Compiler  :   %s' % CC
-            print 'Arithmetic:     %s' % ARITH
-            print 'OpenMP:         %s' % HAS_OMP
-            print 'Prefix:         %s' % PREFIX
-            print '64-bit:         %s' % is64()
+            print('Host platform:  %s' % sysname)
+            print('C++ Compiler:   %s' % CXX)
+            print('C Compiler  :   %s' % CC)
+            print('Arithmetic:     %s' % ARITH)
+            print('OpenMP:         %s' % HAS_OMP)
+            print('Prefix:         %s' % PREFIX)
+            print('64-bit:         %s' % is64())
+            print('Python version: %s' % distutils.sysconfig.get_python_version())
             if is_java_enabled():
-                print 'Java Home:      %s' % JAVA_HOME
-                print 'Java Compiler:  %s' % JAVAC
-                print 'Java VM:        %s' % JAVA
+                print('Java Home:      %s' % JAVA_HOME)
+                print('Java Compiler:  %s' % JAVAC)
+                print('Java VM:        %s' % JAVA)
 
 def mk_install(out):
     out.write('install:\n')
@@ -1420,15 +1415,30 @@ def mk_install(out):
     out.write('\t@mkdir -p %s\n' % os.path.join('$(PREFIX)', 'lib'))
     for c in get_components():
         c.mk_install(out)
-    out.write('\t@cp z3*.pyc %s\n' % PYTHON_PACKAGE_DIR)
+    out.write('\t@cp z3*.py %s\n' % PYTHON_PACKAGE_DIR)
+    if sys.version >= "3":
+        out.write('\t@cp %s*.pyc %s\n' % (os.path.join('__pycache__', 'z3'),
+                                          os.path.join(PYTHON_PACKAGE_DIR, '__pycache__')))
+    else:
+        out.write('\t@cp z3*.pyc %s\n' % PYTHON_PACKAGE_DIR)
     out.write('\t@echo Z3 was successfully installed.\n')
+    if PYTHON_PACKAGE_DIR != distutils.sysconfig.get_python_lib():
+        if os.uname()[0] == 'Darwin':
+            LD_LIBRARY_PATH = "DYLD_LIBRARY_PATH"
+        else:
+            LD_LIBRARY_PATH = "LD_LIBRARY_PATH"
+        out.write('\t@echo Z3 shared libraries were installed at \'%s\', make sure this directory is in your %s environment variable.\n' %
+                  (os.path.join(PREFIX, 'lib'), LD_LIBRARY_PATH))
+        out.write('\t@echo Z3Py was installed at \'%s\', make sure this directory is in your PYTHONPATH environment variable.' % PYTHON_PACKAGE_DIR)
     out.write('\n')    
 
 def mk_uninstall(out):
     out.write('uninstall:\n')
     for c in get_components():
         c.mk_uninstall(out)
+    out.write('\t@rm -f %s*.py\n' % os.path.join(PYTHON_PACKAGE_DIR, 'z3'))
     out.write('\t@rm -f %s*.pyc\n' % os.path.join(PYTHON_PACKAGE_DIR, 'z3'))
+    out.write('\t@rm -f %s*.pyc\n' % os.path.join(PYTHON_PACKAGE_DIR, '__pycache__', 'z3'))
     out.write('\t@echo Z3 was successfully uninstalled.\n')
     out.write('\n')    
 
@@ -1437,7 +1447,7 @@ def mk_makefile():
     mk_dir(BUILD_DIR)
     mk_config()
     if VERBOSE:
-        print "Writing %s" % os.path.join(BUILD_DIR, 'Makefile')
+        print("Writing %s" % os.path.join(BUILD_DIR, 'Makefile'))
     out = open(os.path.join(BUILD_DIR, 'Makefile'), 'w')
     out.write('# Automatically generated file.\n')
     out.write('include config.mk\n')
@@ -1447,6 +1457,8 @@ def mk_makefile():
         if c.main_component():
             out.write(' %s' % c.name)
     out.write('\n\t@echo Z3 was successfully built.\n')
+    out.write("\t@echo \"Z3Py scripts can already be executed in the \'%s\' directory.\"\n" % BUILD_DIR)
+    out.write("\t@echo \"Z3Py scripts stored in arbitrary directories can be also executed if \'%s\' directory is added to the PYTHONPATH environment variable.\"\n" % BUILD_DIR)
     if not IS_WINDOWS:
         out.write("\t@echo Use the following command to install Z3 at prefix $(PREFIX).\n")
         out.write('\t@echo "    sudo make install"\n')
@@ -1465,24 +1477,24 @@ def mk_makefile():
         mk_uninstall(out)
     # Finalize
     if VERBOSE:
-        print "Makefile was successfully generated."
+        print("Makefile was successfully generated.")
         if not IS_WINDOWS:
-            print "  python packages dir:", PYTHON_PACKAGE_DIR
+            print("  python packages dir: %s" % PYTHON_PACKAGE_DIR)
         if DEBUG_MODE:
-            print "  compilation mode: Debug"
+            print("  compilation mode: Debug")
         else:
-            print "  compilation mode: Release"
+            print("  compilation mode: Release")
         if IS_WINDOWS:
             if VS_X64:
-                print "  platform: x64\n"
-                print "To build Z3, open a [Visual Studio x64 Command Prompt], then"
+                print("  platform: x64\n")
+                print("To build Z3, open a [Visual Studio x64 Command Prompt], then")
             else:
-                print "  platform: x86"
-                print "To build Z3, open a [Visual Studio Command Prompt], then"
-            print "type 'cd %s && nmake'\n" % os.path.join(os.getcwd(), BUILD_DIR)
-            print 'Remark: to open a Visual Studio Command Prompt, go to: "Start > All Programs > Visual Studio > Visual Studio Tools"'
+                print("  platform: x86")
+                print("To build Z3, open a [Visual Studio Command Prompt], then")
+            print("type 'cd %s && nmake'\n" % os.path.join(os.getcwd(), BUILD_DIR))
+            print('Remark: to open a Visual Studio Command Prompt, go to: "Start > All Programs > Visual Studio > Visual Studio Tools"')
         else:
-            print "Type 'cd %s; make' to build Z3" % BUILD_DIR
+            print("Type 'cd %s; make' to build Z3" % BUILD_DIR)
         
 # Generate automatically generated source code
 def mk_auto_src():
@@ -1577,7 +1589,7 @@ def def_module_params(module_name, export, params, class_name=None, description=
     out.write('};\n')
     out.write('#endif\n')
     if is_verbose():
-        print "Generated '%s'" % hpp
+        print("Generated '%s'" % hpp)
 
 def max_memory_param():
     return ('max_memory', UINT, UINT_MAX, 'maximum amount of memory in megabytes')
@@ -1591,6 +1603,10 @@ PYG_GLOBALS = { 'UINT' : UINT, 'BOOL' : BOOL, 'DOUBLE' : DOUBLE, 'STRING' : STRI
                 'max_steps_param' : max_steps_param,
                 'def_module_params' : def_module_params }
 
+def _execfile(file, globals=globals(), locals=locals()):
+    with open(file, "r") as fh:
+        exec(fh.read()+"\n", globals, locals)
+
 # Execute python auxiliary scripts that generate extra code for Z3.
 def exec_pyg_scripts():
     global CURR_PYG
@@ -1599,7 +1615,7 @@ def exec_pyg_scripts():
             if f.endswith('.pyg'):
                 script = os.path.join(root, f)
                 CURR_PYG = script
-                execfile(script, PYG_GLOBALS)
+                _execfile(script, PYG_GLOBALS)
 
 # TODO: delete after src/ast/pattern/expr_pattern_match
 # database.smt ==> database.h
@@ -1612,7 +1628,7 @@ def mk_pat_db():
         fout.write('"%s\\n"\n' % line.strip('\n'))
     fout.write(';\n')    
     if VERBOSE:
-        print "Generated '%s'" % os.path.join(c.src_dir, 'database.h')
+        print("Generated '%s'" % os.path.join(c.src_dir, 'database.h'))
 
 # Update version numbers
 def update_version():
@@ -1637,7 +1653,7 @@ def mk_version_dot_h(major, minor, build, revision):
     fout.write('#define Z3_BUILD_NUMBER    %s\n' % build)
     fout.write('#define Z3_REVISION_NUMBER %s\n' % revision)
     if VERBOSE:
-        print "Generated '%s'" % os.path.join(c.src_dir, 'version.h')
+        print("Generated '%s'" % os.path.join(c.src_dir, 'version.h'))
 
 # Update version number in AssemblyInfo.cs files
 def update_all_assembly_infos(major, minor, build, revision):
@@ -1686,13 +1702,13 @@ def update_assembly_info_version(assemblyinfo, major, minor, build, revision, is
         else:
             fout.write(line)
     # if VERBOSE:
-    #    print "%s version numbers updated at '%s'" % (num_updates, assemblyinfo)
+    #    print("%s version numbers updated at '%s'" % (num_updates, assemblyinfo))
     assert num_updates == 2, "unexpected number of version number updates"
     fin.close()
     fout.close()
     shutil.move(tmp, assemblyinfo)
     if VERBOSE:
-        print "Updated '%s'" % assemblyinfo
+        print("Updated '%s'" % assemblyinfo)
 
 ADD_TACTIC_DATA=[]
 ADD_PROBE_DATA=[]
@@ -1734,7 +1750,7 @@ def mk_install_tactic_cpp(cnames, path):
                         added_include = True
                         fout.write('#include"%s"\n' % h_file)
                     try: 
-                        exec line.strip('\n ') in globals()
+                        exec(line.strip('\n '), globals())
                     except:
                         raise MKException("Failed processing ADD_TACTIC command at '%s'\n%s" % (fullname, line))
                 if probe_pat.match(line):
@@ -1742,7 +1758,7 @@ def mk_install_tactic_cpp(cnames, path):
                         added_include = True
                         fout.write('#include"%s"\n' % h_file)
                     try: 
-                        exec line.strip('\n ') in globals()
+                        exec(line.strip('\n '), globals())
                     except:
                         raise MKException("Failed processing ADD_PROBE command at '%s'\n%s" % (fullname, line))
     # First pass will just generate the tactic factories
@@ -1761,7 +1777,7 @@ def mk_install_tactic_cpp(cnames, path):
         fout.write('  ADD_PROBE("%s", "%s", %s);\n' % data)
     fout.write('}\n')
     if VERBOSE:
-        print "Generated '%s'" % fullname
+        print("Generated '%s'" % fullname)
 
 def mk_all_install_tactic_cpps():
     if not ONLY_MAKEFILES:
@@ -1824,7 +1840,7 @@ def mk_mem_initializer_cpp(cnames, path):
         fout.write('\n')
     fout.write('}\n')
     if VERBOSE:
-        print "Generated '%s'" % fullname
+        print("Generated '%s'" % fullname)
 
 def mk_all_mem_initializer_cpps():
     if not ONLY_MAKEFILES:
@@ -1881,7 +1897,7 @@ def mk_gparams_register_modules(cnames, path):
         fout.write('gparams::register_module_descr("%s", "%s");\n' % (mod, descr))
     fout.write('}\n')
     if VERBOSE:
-        print "Generated '%s'" % fullname
+        print("Generated '%s'" % fullname)
 
 def mk_all_gparams_register_modules():
     if not ONLY_MAKEFILES:
@@ -1914,7 +1930,7 @@ def mk_def_file(c):
                     i = i + 1
                 num = num + 1
     if VERBOSE:
-        print "Generated '%s'" % defname
+        print("Generated '%s'" % defname)
 
 def mk_def_files():
     if not ONLY_MAKEFILES:
@@ -1922,19 +1938,35 @@ def mk_def_files():
             if c.require_def_file():
                 mk_def_file(c)
 
-def cp_z3pyc_to_build():
+def cp_z3py_to_build():
     mk_dir(BUILD_DIR)
+    # Erase existing .pyc files
+    for root, dirs, files in os.walk(Z3PY_SRC_DIR): 
+        for f in files:
+            if f.endswith('.pyc'):
+                rmf(os.path.join(root, f))
+    # Compile Z3Py files
     if compileall.compile_dir(Z3PY_SRC_DIR, force=1) != 1:
         raise MKException("failed to compile Z3Py sources")
-    for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(Z3PY_SRC_DIR)):
-        try:
-            os.remove(os.path.join(BUILD_DIR, pyc))
-        except:
-            pass
-        shutil.copyfile(os.path.join(Z3PY_SRC_DIR, pyc), os.path.join(BUILD_DIR, pyc))
-        os.remove(os.path.join(Z3PY_SRC_DIR, pyc))
+    # Copy sources to build
+    for py in filter(lambda f: f.endswith('.py'), os.listdir(Z3PY_SRC_DIR)):
+        shutil.copyfile(os.path.join(Z3PY_SRC_DIR, py), os.path.join(BUILD_DIR, py))
         if is_verbose():
-            print "Generated '%s'" % pyc
+            print("Copied '%s'" % py)
+    # Python 2.x support
+    for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(Z3PY_SRC_DIR)):
+        shutil.copyfile(os.path.join(Z3PY_SRC_DIR, pyc), os.path.join(BUILD_DIR, pyc))
+        if is_verbose():
+            print("Generated '%s'" % pyc)
+    # Python 3.x support
+    src_pycache = os.path.join(Z3PY_SRC_DIR, '__pycache__')
+    if os.path.exists(src_pycache):
+        for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(src_pycache)):
+            target_pycache = os.path.join(BUILD_DIR, '__pycache__')
+            mk_dir(target_pycache)
+            shutil.copyfile(os.path.join(src_pycache, pyc), os.path.join(target_pycache, pyc))
+            if is_verbose():
+                print("Generated '%s'" % pyc)
 
 def mk_bindings(api_files):
     if not ONLY_MAKEFILES:
@@ -1945,13 +1977,13 @@ def mk_bindings(api_files):
         for api_file in api_files:
             api_file_path = api.find_file(api_file, api.name)
             new_api_files.append(os.path.join(api_file_path.src_dir, api_file))
-        g = {}
+        g = globals()
         g["API_FILES"] = new_api_files
         if is_java_enabled():
             check_java()
             mk_z3consts_java(api_files)
-        execfile(os.path.join('scripts', 'update_api.py'), g) # HACK
-        cp_z3pyc_to_build()
+        _execfile(os.path.join('scripts', 'update_api.py'), g) # HACK
+        cp_z3py_to_build()
                           
 # Extract enumeration types from API files, and add python definitions.
 def mk_z3consts_py(api_files):
@@ -2014,7 +2046,8 @@ def mk_z3consts_py(api_files):
                 if m:
                     name = words[1]
                     z3consts.write('# enum %s\n' % name)
-                    for k, i in decls.iteritems():
+                    for k in decls:
+                        i = decls[k]
                         z3consts.write('%s = %s\n' % (k, i))
                     z3consts.write('\n')
                     mode = SEARCHING
@@ -2028,7 +2061,7 @@ def mk_z3consts_py(api_files):
                     idx = idx + 1
             linenum = linenum + 1
     if VERBOSE:
-        print "Generated '%s'" % os.path.join(Z3PY_SRC_DIR, 'z3consts.py')
+        print("Generated '%s'" % os.path.join(Z3PY_SRC_DIR, 'z3consts.py'))
                 
 
 # Extract enumeration types from z3_api.h, and add .Net definitions
@@ -2098,7 +2131,8 @@ def mk_z3consts_dotnet(api_files):
                         z3consts.write('  /// <summary>%s</summary>\n' % name)
                         z3consts.write('  public enum %s {\n' % name)
                         z3consts.write
-                        for k, i in decls.iteritems():
+                        for k in decls:
+                            i = decls[k]
                             z3consts.write('  %s = %s,\n' % (k, i))
                         z3consts.write('  }\n\n')
                     mode = SEARCHING
@@ -2113,7 +2147,7 @@ def mk_z3consts_dotnet(api_files):
             linenum = linenum + 1
     z3consts.write('}\n');
     if VERBOSE:
-        print "Generated '%s'" % os.path.join(dotnet.src_dir, 'Enumerations.cs')
+        print("Generated '%s'" % os.path.join(dotnet.src_dir, 'Enumerations.cs'))
 
 
 # Extract enumeration types from z3_api.h, and add Java definitions
@@ -2187,7 +2221,8 @@ def mk_z3consts_java(api_files):
                         efile.write('public enum %s {\n' % name)
                         efile.write
                         first = True
-                        for k, i in decls.iteritems():
+                        for k in decls:
+                            i = decls[k]
                             if first:
                                first = False 
                             else:
@@ -2218,7 +2253,7 @@ def mk_z3consts_java(api_files):
                     idx = idx + 1
             linenum = linenum + 1
     if VERBOSE:
-        print "Generated '%s'" % ('%s' % gendir)
+        print("Generated '%s'" % ('%s' % gendir))
 
 def mk_gui_str(id):
     return '4D2F40D8-E5F9-473B-B548-%012d' % id
@@ -2305,7 +2340,7 @@ def mk_vs_proj(name, components):
     f.write('  </ImportGroup>\n')
     f.write('</Project>\n')
     if is_verbose():
-        print "Generated '%s'" % proj_name
+        print("Generated '%s'" % proj_name)
 
 def mk_win_dist(build_path, dist_path):
     for c in get_components():
diff --git a/scripts/update_api.py b/scripts/update_api.py
index a636a1a02..08dd012e3 100644
--- a/scripts/update_api.py
+++ b/scripts/update_api.py
@@ -84,6 +84,19 @@ def lib():
         raise Z3Exception("init(Z3_LIBRARY_PATH) must be invoked before using Z3-python")
   return _lib
 
+def _to_ascii(s):
+  if isinstance(s, str):
+    return s.encode('ascii')
+  else:
+    return s
+
+if sys.version < '3':
+  def _to_pystr(s):
+     return s
+else:
+  def _to_pystr(s):
+     return s.decode('utf-8')
+
 def init(PATH):
   global _lib
   _lib = ctypes.CDLL(PATH)
@@ -146,20 +159,22 @@ next_type_id = FIRST_OBJ_ID
 
 def def_Type(var, c_type, py_type):
     global next_type_id
-    exec ('%s = %s' % (var, next_type_id)) in globals()
+    exec('%s = %s' % (var, next_type_id), globals())
     Type2Str[next_type_id]   = c_type
     Type2PyStr[next_type_id] = py_type
     next_type_id    = next_type_id + 1
 
 def def_Types():
-    pat1 = re.compile(" *def_Type.*")
+    import re
+    pat1 = re.compile(" *def_Type\(\'(.*)\',[^\']*\'(.*)\',[^\']*\'(.*)\'\)[ \t]*")
     for api_file in API_FILES:
         api = open(api_file, 'r')
         for line in api:
             m = pat1.match(line)
             if m:
-                eval(line)
-    for k, v in Type2Str.iteritems():
+                def_Type(m.group(1), m.group(2), m.group(3))
+    for k in Type2Str:
+        v = Type2Str[k]
         if is_obj(k):
             Type2Dotnet[k] = v
 
@@ -258,7 +273,7 @@ def param2java(p):
         elif param_type(p) == STRING:
             return "StringPtr"
         else:
-            print "ERROR: unreachable code"
+            print("ERROR: unreachable code")
             assert(False)
             exit(1)
     if k == IN_ARRAY or k == INOUT_ARRAY or k == OUT_ARRAY:
@@ -313,6 +328,17 @@ def display_args(num):
             core_py.write(", ")
         core_py.write("a%s" % i)
 
+def display_args_to_z3(params):
+    i = 0
+    for p in params:
+        if i > 0:
+            core_py.write(", ")
+        if param_type(p) == STRING:
+            core_py.write("_to_ascii(a%s)" % i)
+        else:
+            core_py.write("a%s" % i)
+        i = i + 1
+
 def mk_py_wrappers():
     core_py.write("\n")
     for sig in _API2PY:
@@ -327,13 +353,15 @@ def mk_py_wrappers():
             core_py.write("  r = lib().%s(" % name)
         else:
             core_py.write("  lib().%s(" % name)
-        display_args(num)
+        display_args_to_z3(params)
         core_py.write(")\n")
         if len(params) > 0 and param_type(params[0]) == CONTEXT:
             core_py.write("  err = lib().Z3_get_error_code(a0)\n")
             core_py.write("  if err != Z3_OK:\n")
             core_py.write("    raise Z3Exception(lib().Z3_get_error_msg_ex(a0, err))\n")
-        if result != VOID:
+        if result == STRING:
+            core_py.write("  return _to_pystr(r)\n")
+        elif result != VOID:
             core_py.write("  return r\n")
         core_py.write("\n")
 
@@ -356,7 +384,8 @@ def mk_dotnet():
     dotnet.write('#pragma warning disable 1591\n\n');
     dotnet.write('namespace Microsoft.Z3\n')
     dotnet.write('{\n')
-    for k, v in Type2Str.iteritems():
+    for k in Type2Str:
+        v = Type2Str[k]
         if is_obj(k):
             dotnet.write('    using %s = System.IntPtr;\n' % v)
     dotnet.write('\n');
@@ -579,7 +608,7 @@ def mk_java():
     java_wrapper.write('  }                                                                    \n\n')
     java_wrapper.write('#define RELEASELONGAELEMS(OLD,NEW)                                   \\\n')
     java_wrapper.write('  delete [] NEW;                                                     \n\n')
-    java_wrapper.write('#define GETLONGAREGION(T,OLD,Z,SZ,NEW)				    \\\n')
+    java_wrapper.write('#define GETLONGAREGION(T,OLD,Z,SZ,NEW)                              \\\n')
     java_wrapper.write('  {                                                                 \\\n')
     java_wrapper.write('    jlong * temp = new jlong[SZ];                                   \\\n')
     java_wrapper.write('    jenv->GetLongArrayRegion(OLD,Z,(jsize)SZ,(jlong*)temp);         \\\n')
@@ -702,7 +731,7 @@ def mk_java():
     java_wrapper.write('}\n')
     java_wrapper.write('#endif\n')
     if is_verbose():
-        print "Generated '%s'" % java_nativef
+        print("Generated '%s'" % java_nativef)
 
 def mk_log_header(file, name, params):
     file.write("void log_%s(" % name)
@@ -710,7 +739,7 @@ def mk_log_header(file, name, params):
     for p in params:
         if i > 0:
             file.write(", ");
-	file.write("%s a%s" % (param2str(p), i))
+        file.write("%s a%s" % (param2str(p), i))
         i = i + 1
     file.write(")");
 
@@ -981,8 +1010,8 @@ exe_c.close()
 core_py.close()
 
 if is_verbose():
-    print "Generated '%s'" % os.path.join(api_dir, 'api_log_macros.h')
-    print "Generated '%s'" % os.path.join(api_dir, 'api_log_macros.cpp')
-    print "Generated '%s'" % os.path.join(api_dir, 'api_commands.cpp')
-    print "Generated '%s'" % os.path.join(get_z3py_dir(), 'z3core.py')
-    print "Generated '%s'" % os.path.join(dotnet_dir, 'Native.cs')
+    print("Generated '%s'" % os.path.join(api_dir, 'api_log_macros.h'))
+    print("Generated '%s'" % os.path.join(api_dir, 'api_log_macros.cpp'))
+    print("Generated '%s'" % os.path.join(api_dir, 'api_commands.cpp'))
+    print("Generated '%s'" % os.path.join(get_z3py_dir(), 'z3core.py'))
+    print("Generated '%s'" % os.path.join(dotnet_dir, 'Native.cs'))
diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp
index 7dc8d1a12..9ebc771f0 100644
--- a/src/api/api_context.cpp
+++ b/src/api/api_context.cpp
@@ -106,11 +106,11 @@ namespace api {
         m_error_handler = &default_error_handler;
 
         m_basic_fid = m().get_basic_family_id();
-        m_arith_fid = m().get_family_id("arith");
-        m_bv_fid    = m().get_family_id("bv");
-        m_array_fid = m().get_family_id("array");
-        m_dt_fid    = m().get_family_id("datatype");
-        m_datalog_fid = m().get_family_id("datalog_relation");
+        m_arith_fid = m().mk_family_id("arith");
+        m_bv_fid    = m().mk_family_id("bv");
+        m_array_fid = m().mk_family_id("array");
+        m_dt_fid    = m().mk_family_id("datatype");
+        m_datalog_fid = m().mk_family_id("datalog_relation");
         m_dt_plugin = static_cast<datatype_decl_plugin*>(m().get_plugin(m_dt_fid));
 
         if (!m_user_ref_count) {
diff --git a/src/api/api_context.h b/src/api/api_context.h
index edb79b2d5..896011615 100644
--- a/src/api/api_context.h
+++ b/src/api/api_context.h
@@ -54,7 +54,7 @@ namespace api {
         datalog::dl_decl_util      m_datalog_util;
 
         // Support for old solver API
-        smt_params           m_fparams;
+        smt_params                 m_fparams;
         smt::kernel *              m_solver;     // General purpose solver for backward compatibility
         // -------------------------------
 
diff --git a/src/api/api_datalog.h b/src/api/api_datalog.h
index 1dc0a9cbd..51dbb72ec 100644
--- a/src/api/api_datalog.h
+++ b/src/api/api_datalog.h
@@ -55,6 +55,7 @@ namespace api {
         std::string get_last_status();
         std::string to_string(unsigned num_queries, expr*const* queries);
         void cancel() { m_context.cancel(); }
+        void reset_cancel() { m_context.reset_cancel(); }
 
         unsigned get_num_levels(func_decl* pred);
         expr_ref get_cover_delta(int level, func_decl* pred);
diff --git a/src/api/ml/Makefile.build b/src/api/ml/Makefile.build
index 27c798bbf..0a737e356 100644
--- a/src/api/ml/Makefile.build
+++ b/src/api/ml/Makefile.build
@@ -13,7 +13,7 @@ XCDBG=-g $(CFLAGS)
 XCOPT=-ccopt -Ox -ccopt -Oy- $(CFLAGS)
 # ole32 is needed by camlidl (COM support)
 XLIB=-cclib ole32.lib
-AR=lib /nologo /LIBPATH:../../build ../../z3.lib /out:
+AR=lib /nologo /LIBPATH:../../build ../../libz3.lib /out:
 O=obj
 A=lib
 else
diff --git a/src/api/ml/README-linux b/src/api/ml/README-linux
index a726c0c94..5ee20bb27 100644
--- a/src/api/ml/README-linux
+++ b/src/api/ml/README-linux
@@ -1,22 +1,22 @@
-The OCaml API for Z3 was tested using OCaml 3.12.1.
-You also need CamlIDL to be able to generate the OCaml API.
-
-- To download OCaml:
-  http://caml.inria.fr/ocaml/      
-
-- To download CamlIDL:
-  http://forge.ocamlcore.org/projects/camlidl/
-
-- To build the OCaml API for Z3:
-  ./build-lib.sh
-
-Remark: The OCaml and C compiler tool chains must be configured in your environment.
-
-Remark: Building the OCaml API copies some pathnames into files,
-so the OCaml API must be recompiled if the Z3 library files are moved.
-
-See ../examples/ocaml/build-test.sh for an example of how to compile and link with Z3.
-
-Acknowledgements:
-The OCaml interface for Z3 was written by Josh Berdine and Jakob Lichtenberg. 
-Many thanks to them!
+The OCaml API for Z3 was tested using OCaml 3.12.1.
+You also need CamlIDL to be able to generate the OCaml API.
+
+- To download OCaml:
+  http://caml.inria.fr/ocaml/      
+
+- To download CamlIDL:
+  http://forge.ocamlcore.org/projects/camlidl/
+
+- To build the OCaml API for Z3:
+  ./build-lib.sh
+
+Remark: The OCaml and C compiler tool chains must be configured in your environment.
+
+Remark: Building the OCaml API copies some pathnames into files,
+so the OCaml API must be recompiled if the Z3 library files are moved.
+
+See ../examples/ocaml/build-test.sh for an example of how to compile and link with Z3.
+
+Acknowledgements:
+The OCaml interface for Z3 was written by Josh Berdine and Jakob Lichtenberg. 
+Many thanks to them!
diff --git a/src/api/ml/README-osx b/src/api/ml/README-osx
index a726c0c94..5ee20bb27 100644
--- a/src/api/ml/README-osx
+++ b/src/api/ml/README-osx
@@ -1,22 +1,22 @@
-The OCaml API for Z3 was tested using OCaml 3.12.1.
-You also need CamlIDL to be able to generate the OCaml API.
-
-- To download OCaml:
-  http://caml.inria.fr/ocaml/      
-
-- To download CamlIDL:
-  http://forge.ocamlcore.org/projects/camlidl/
-
-- To build the OCaml API for Z3:
-  ./build-lib.sh
-
-Remark: The OCaml and C compiler tool chains must be configured in your environment.
-
-Remark: Building the OCaml API copies some pathnames into files,
-so the OCaml API must be recompiled if the Z3 library files are moved.
-
-See ../examples/ocaml/build-test.sh for an example of how to compile and link with Z3.
-
-Acknowledgements:
-The OCaml interface for Z3 was written by Josh Berdine and Jakob Lichtenberg. 
-Many thanks to them!
+The OCaml API for Z3 was tested using OCaml 3.12.1.
+You also need CamlIDL to be able to generate the OCaml API.
+
+- To download OCaml:
+  http://caml.inria.fr/ocaml/      
+
+- To download CamlIDL:
+  http://forge.ocamlcore.org/projects/camlidl/
+
+- To build the OCaml API for Z3:
+  ./build-lib.sh
+
+Remark: The OCaml and C compiler tool chains must be configured in your environment.
+
+Remark: Building the OCaml API copies some pathnames into files,
+so the OCaml API must be recompiled if the Z3 library files are moved.
+
+See ../examples/ocaml/build-test.sh for an example of how to compile and link with Z3.
+
+Acknowledgements:
+The OCaml interface for Z3 was written by Josh Berdine and Jakob Lichtenberg. 
+Many thanks to them!
diff --git a/src/api/ml/README-test-linux b/src/api/ml/README-test-linux
index 34900883d..fc15fb2a2 100644
--- a/src/api/ml/README-test-linux
+++ b/src/api/ml/README-test-linux
@@ -1,17 +1,17 @@
-This directory contains scripts to build the test application using
-OCaml. You also need CamlIDL to be able to generate the OCaml API.
-
-- To download OCaml:
-  http://caml.inria.fr/ocaml/      
-
-- To download CamlIDL:
-  http://forge.ocamlcore.org/projects/camlidl/
-
-- One must build the OCaml library before compiling the example.
-  Go to directory ../ocaml
-
-- Use 'build-test.sh' to build the test application using the OCaml compiler.
-
-Remark: The OCaml and C compiler tool chains must be configured in your environment.
-  
-- Use 'exec.sh' to execute test_mlapi. The script sets LD_LIBRARY_PATH, and invokes test_mlapi.
+This directory contains scripts to build the test application using
+OCaml. You also need CamlIDL to be able to generate the OCaml API.
+
+- To download OCaml:
+  http://caml.inria.fr/ocaml/      
+
+- To download CamlIDL:
+  http://forge.ocamlcore.org/projects/camlidl/
+
+- One must build the OCaml library before compiling the example.
+  Go to directory ../ocaml
+
+- Use 'build-test.sh' to build the test application using the OCaml compiler.
+
+Remark: The OCaml and C compiler tool chains must be configured in your environment.
+  
+- Use 'exec.sh' to execute test_mlapi. The script sets LD_LIBRARY_PATH, and invokes test_mlapi.
diff --git a/src/api/ml/README-test-osx b/src/api/ml/README-test-osx
index bfc6b115e..3a20d1f1d 100644
--- a/src/api/ml/README-test-osx
+++ b/src/api/ml/README-test-osx
@@ -1,17 +1,17 @@
-This directory contains scripts to build the test application using
-OCaml. You also need CamlIDL to be able to generate the OCaml API.
-
-- To download OCaml:
-  http://caml.inria.fr/ocaml/      
-
-- To download CamlIDL:
-  http://forge.ocamlcore.org/projects/camlidl/
-
-- One must build the OCaml library before compiling the example.
-  Go to directory ../ocaml
-
-- Use 'build-test.sh' to build the test application using the OCaml compiler.
-
-Remark: The OCaml and C compiler tool chains must be configured in your environment.
-  
-- Use 'exec.sh' to execute test_mlapi. The script sets DYLD_LIBRARY_PATH, and invokes test_mlapi.
+This directory contains scripts to build the test application using
+OCaml. You also need CamlIDL to be able to generate the OCaml API.
+
+- To download OCaml:
+  http://caml.inria.fr/ocaml/      
+
+- To download CamlIDL:
+  http://forge.ocamlcore.org/projects/camlidl/
+
+- One must build the OCaml library before compiling the example.
+  Go to directory ../ocaml
+
+- Use 'build-test.sh' to build the test application using the OCaml compiler.
+
+Remark: The OCaml and C compiler tool chains must be configured in your environment.
+  
+- Use 'exec.sh' to execute test_mlapi. The script sets DYLD_LIBRARY_PATH, and invokes test_mlapi.
diff --git a/src/api/ml/exec.sh b/src/api/ml/exec.sh
index a1d3c8e49..573ec6ddf 100644
--- a/src/api/ml/exec.sh
+++ b/src/api/ml/exec.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
-export LD_LIBRARY_PATH=../../lib:$LD_LIBRARY_PATH	# for linux
-export DYLD_LIBRARY_PATH=../../lib:$DYLD_LIBRARY_PATH	# for osx
-./test_mlapi
+#!/bin/sh
+export LD_LIBRARY_PATH=../../lib:$LD_LIBRARY_PATH	# for linux
+export DYLD_LIBRARY_PATH=../../lib:$DYLD_LIBRARY_PATH	# for osx
+./test_mlapi
diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml
index 4d391c06f..705f9a3e7 100644
--- a/src/api/ml/z3.ml
+++ b/src/api/ml/z3.ml
@@ -229,16 +229,6 @@ and param_kind =
   | PK_OTHER
   | PK_INVALID
 
-and search_failure =
-  | NO_FAILURE
-  | UNKNOWN
-  | TIMEOUT
-  | MEMOUT_WATERMARK
-  | CANCELED
-  | NUM_CONFLICTS
-  | THEORY
-  | QUANTIFIERS
-
 and ast_print_mode =
   | PRINT_SMTLIB_FULL
   | PRINT_LOW_LEVEL
@@ -1598,6 +1588,9 @@ external stats_get_uint_value : context -> stats -> int -> int
 external stats_get_double_value : context -> stats -> int -> float
 	= "camlidl_z3_Z3_stats_get_double_value"
 
+external get_implied_equalities : context -> solver -> ast array -> lbool * int array
+	= "camlidl_z3_Z3_get_implied_equalities"
+
 
 (* Internal auxiliary functions: *)
 (*
@@ -2988,9 +2981,6 @@ external check : context -> lbool
 external check_assumptions : context -> ast array -> int -> ast array -> lbool * model * ast * int * ast array
 	= "camlidl_z3V3_Z3_check_assumptions"
 
-external get_implied_equalities : context -> ast array -> lbool * int array
-	= "camlidl_z3V3_Z3_get_implied_equalities"
-
 external del_model : context -> model -> unit
 	= "camlidl_z3V3_Z3_del_model"
 
diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli
index 4dd3d5b14..2eb9eecb7 100644
--- a/src/api/ml/z3.mli
+++ b/src/api/ml/z3.mli
@@ -229,16 +229,6 @@ and param_kind =
   | PK_OTHER
   | PK_INVALID
 
-and search_failure =
-  | NO_FAILURE
-  | UNKNOWN
-  | TIMEOUT
-  | MEMOUT_WATERMARK
-  | CANCELED
-  | NUM_CONFLICTS
-  | THEORY
-  | QUANTIFIERS
-
 and ast_print_mode =
   | PRINT_SMTLIB_FULL
   | PRINT_LOW_LEVEL
@@ -866,23 +856,9 @@ and goal_prec =
     - PK_OTHER all internal parameter kinds which are not exposed in the API.
     - PK_INVALID invalid parameter.
 *)
-(**
-    {!search_failure}
-   The different kinds of search failure types.
-
-   - NO_FAILURE: The last search was successful
-   - UNKNOWN: Undocumented failure reason
-   - TIMEOUT: Timeout
-   - MEMOUT_WATERMAK: Search hit a memory high-watermak limit
-   - CANCELED: External cancel flag was set
-   - NUM_CONFLICTS: Maximum number of conflicts was reached
-   - THEORY: Theory is incomplete
-   - QUANTIFIERS: Logical context contains universal quantifiers
-*)
 (**
     {!ast_print_mode}
    Z3 pretty printing modes (See {!set_ast_print_mode}).
-
    - PRINT_SMTLIB_FULL: Print AST nodes in SMTLIB verbose format.
    - PRINT_LOW_LEVEL: Print AST nodes using a low-level format.
    - PRINT_SMTLIB_COMPLIANT: Print AST nodes in SMTLIB 1.x compliant format.
@@ -891,7 +867,6 @@ and goal_prec =
 (**
     {!error_code}
    Z3 error codes
-
    - OK: No error.
    - SORT_ERROR: User tried to build an invalid (type incorrect) AST.
    - IOB: Index out of bounds.
@@ -908,7 +883,6 @@ and goal_prec =
 *)
 (**
   Definitions for update_api.py
-
   def_Type('CONFIG', 'config', 'Config')
   def_Type('CONTEXT', 'context', 'ContextObj')
   def_Type('AST', 'ast', 'Ast')
@@ -5043,6 +5017,30 @@ external stats_get_uint_value : context -> stats -> int -> int
 external stats_get_double_value : context -> stats -> int -> float
 	= "camlidl_z3_Z3_stats_get_double_value"
 
+(**
+       {2 {L Deprecated Constraints API}}
+*)
+(**
+       Summary: Retrieve congruence class representatives for terms.
+       The function can be used for relying on Z3 to identify equal terms under the current
+       set of assumptions. The array of terms and array of class identifiers should have
+       the same length. The class identifiers are numerals that are assigned to the same
+       value for their corresponding terms if the current context forces the terms to be
+       equal. You cannot deduce that terms corresponding to different numerals must be all different,
+       (especially when using non-convex theories).
+       All implied equalities are returned by this call.
+       This means that two terms map to the same class identifier if and only if
+       the current context implies that they are equal.
+       A side-effect of the function is a satisfiability check on the assertions on the solver that is passed in.
+       The function return L_FALSE if the current assertions are not satisfiable.
+       - {b See also}: {!check_and_get_model}
+       - {b See also}: {!check}
+       @deprecated To be moved outside of API.
+       def_API('get_implied_equalities', UINT, (_in(CONTEXT), _in(SOLVER), _in(UINT), _in_array(2, AST), _out_array(2, UINT)))
+*)
+external get_implied_equalities : context -> solver -> ast array -> lbool * int array
+	= "camlidl_z3_Z3_get_implied_equalities"
+
 
 (**
    {2 {L Legacy V3 API}}
@@ -8941,27 +8939,6 @@ external check : context -> lbool
 external check_assumptions : context -> ast array -> int -> ast array -> lbool * model * ast * int * ast array
 	= "camlidl_z3V3_Z3_check_assumptions"
 
-(**
-       Summary: Retrieve congruence class representatives for terms.
-       The function can be used for relying on Z3 to identify equal terms under the current
-       set of assumptions. The array of terms and array of class identifiers should have
-       the same length. The class identifiers are numerals that are assigned to the same
-       value for their corresponding terms if the current context forces the terms to be
-       equal. You cannot deduce that terms corresponding to different numerals must be all different,
-       (especially when using non-convex theories).
-       All implied equalities are returned by this call.
-       This means that two terms map to the same class identifier if and only if
-       the current context implies that they are equal.
-       A side-effect of the function is a satisfiability check.
-       The function return L_FALSE if the current assertions are not satisfiable.
-       - {b See also}: {!check_and_get_model}
-       - {b See also}: {!check}
-       @deprecated Subsumed by solver API
-       def_API('get_implied_equalities', UINT, (_in(CONTEXT), _in(UINT), _in_array(1, AST), _out_array(1, UINT)))
-*)
-external get_implied_equalities : context -> ast array -> lbool * int array
-	= "camlidl_z3V3_Z3_get_implied_equalities"
-
 (**
        Summary: Delete a model object.
        - {b See also}: {!check_and_get_model}
diff --git a/src/api/ml/z3_stubs.c b/src/api/ml/z3_stubs.c
index 0cf20fb2e..bad4338de 100644
--- a/src/api/ml/z3_stubs.c
+++ b/src/api/ml/z3_stubs.c
@@ -594,30 +594,7 @@ value _v1;
   return _v1;
 }
 
-int camlidl_transl_table_z3_enum_8[8] = {
-  Z3_NO_FAILURE,
-  Z3_UNKNOWN,
-  Z3_TIMEOUT,
-  Z3_MEMOUT_WATERMARK,
-  Z3_CANCELED,
-  Z3_NUM_CONFLICTS,
-  Z3_THEORY,
-  Z3_QUANTIFIERS,
-};
-
-void camlidl_ml2c_z3_Z3_search_failure(value _v1, Z3_search_failure * _c2, camlidl_ctx _ctx)
-{
-  (*_c2) = camlidl_transl_table_z3_enum_8[Int_val(_v1)];
-}
-
-value camlidl_c2ml_z3_Z3_search_failure(Z3_search_failure * _c2, camlidl_ctx _ctx)
-{
-value _v1;
-  _v1 = camlidl_find_enum((*_c2), camlidl_transl_table_z3_enum_8, 8, "typedef Z3_search_failure: bad enum  value");
-  return _v1;
-}
-
-int camlidl_transl_table_z3_enum_9[4] = {
+int camlidl_transl_table_z3_enum_8[4] = {
   Z3_PRINT_SMTLIB_FULL,
   Z3_PRINT_LOW_LEVEL,
   Z3_PRINT_SMTLIB_COMPLIANT,
@@ -626,7 +603,7 @@ int camlidl_transl_table_z3_enum_9[4] = {
 
 void camlidl_ml2c_z3_Z3_ast_print_mode(value _v1, Z3_ast_print_mode * _c2, camlidl_ctx _ctx)
 {
-  (*_c2) = camlidl_transl_table_z3_enum_9[Int_val(_v1)];
+  (*_c2) = camlidl_transl_table_z3_enum_8[Int_val(_v1)];
 }
 
 value camlidl_c2ml_z3_Z3_ast_print_mode(Z3_ast_print_mode * _c2, camlidl_ctx _ctx)
@@ -642,7 +619,7 @@ value _v1;
   return _v1;
 }
 
-int camlidl_transl_table_z3_enum_10[13] = {
+int camlidl_transl_table_z3_enum_9[13] = {
   Z3_OK,
   Z3_SORT_ERROR,
   Z3_IOB,
@@ -660,13 +637,13 @@ int camlidl_transl_table_z3_enum_10[13] = {
 
 void camlidl_ml2c_z3_Z3_error_code(value _v1, Z3_error_code * _c2, camlidl_ctx _ctx)
 {
-  (*_c2) = camlidl_transl_table_z3_enum_10[Int_val(_v1)];
+  (*_c2) = camlidl_transl_table_z3_enum_9[Int_val(_v1)];
 }
 
 value camlidl_c2ml_z3_Z3_error_code(Z3_error_code * _c2, camlidl_ctx _ctx)
 {
 value _v1;
-  _v1 = camlidl_find_enum((*_c2), camlidl_transl_table_z3_enum_10, 13, "typedef Z3_error_code: bad enum  value");
+  _v1 = camlidl_find_enum((*_c2), camlidl_transl_table_z3_enum_9, 13, "typedef Z3_error_code: bad enum  value");
   return _v1;
 }
 
@@ -698,7 +675,7 @@ void check_error_code (Z3_context c)
 /* Disable default error handler, all error checking is done by check_error_code */
 void* error_handler_static = NULL;
 
-int camlidl_transl_table_z3_enum_11[4] = {
+int camlidl_transl_table_z3_enum_10[4] = {
   Z3_GOAL_PRECISE,
   Z3_GOAL_UNDER,
   Z3_GOAL_OVER,
@@ -707,7 +684,7 @@ int camlidl_transl_table_z3_enum_11[4] = {
 
 void camlidl_ml2c_z3_Z3_goal_prec(value _v1, Z3_goal_prec * _c2, camlidl_ctx _ctx)
 {
-  (*_c2) = camlidl_transl_table_z3_enum_11[Int_val(_v1)];
+  (*_c2) = camlidl_transl_table_z3_enum_10[Int_val(_v1)];
 }
 
 value camlidl_c2ml_z3_Z3_goal_prec(Z3_goal_prec * _c2, camlidl_ctx _ctx)
@@ -11110,6 +11087,56 @@ check_error_code(c);
   return _vres;
 }
 
+value camlidl_z3_Z3_get_implied_equalities(
+	value _v_c,
+	value _v_s,
+	value _v_terms)
+{
+  Z3_context c; /*in*/
+  Z3_solver s; /*in*/
+  unsigned int num_terms; /*in*/
+  Z3_ast const *terms; /*in*/
+  unsigned int *class_ids; /*out*/
+  Z3_lbool _res;
+  struct camlidl_ctx_struct _ctxs = { CAMLIDL_TRANSIENT, NULL };
+  camlidl_ctx _ctx = &_ctxs;
+  mlsize_t _c1;
+  mlsize_t _c2;
+  value _v3;
+  mlsize_t _c4;
+  value _v5;
+  value _vresult;
+  value _vres[2] = { 0, 0, };
+
+  camlidl_ml2c_z3_Z3_context(_v_c, &c, _ctx);
+  camlidl_ml2c_z3_Z3_solver(_v_s, &s, _ctx);
+  _c1 = Wosize_val(_v_terms);
+  terms = camlidl_malloc(_c1 * sizeof(Z3_ast const ), _ctx);
+  for (_c2 = 0; _c2 < _c1; _c2++) {
+    _v3 = Field(_v_terms, _c2);
+    camlidl_ml2c_z3_Z3_ast(_v3, &terms[_c2], _ctx);
+  }
+  num_terms = _c1;
+  class_ids = camlidl_malloc(num_terms * sizeof(unsigned int ), _ctx);
+  _res = Z3_get_implied_equalities(c, s, num_terms, terms, class_ids);
+  Begin_roots_block(_vres, 2)
+    _vres[0] = camlidl_c2ml_z3_Z3_lbool(&_res, _ctx);
+    _vres[1] = camlidl_alloc(num_terms, 0);
+    for (_c4 = 0; _c4 < num_terms; _c4++) {
+      _v5 = Val_int(class_ids[_c4]);
+      modify(&Field(_vres[1], _c4), _v5);
+    }
+    _vresult = camlidl_alloc_small(2, 0);
+    Field(_vresult, 0) = _vres[0];
+    Field(_vresult, 1) = _vres[1];
+  End_roots()
+  camlidl_free(_ctx);
+  /* begin user-supplied deallocation sequence */
+check_error_code(c);
+  /* end user-supplied deallocation sequence */
+  return _vresult;
+}
+
 void camlidl_ml2c_z3V3_Z3_symbol(value _v1, Z3_symbol * _c2, camlidl_ctx _ctx)
 {
   *_c2 = *((Z3_symbol *) Bp_val(_v1));
@@ -18321,50 +18348,6 @@ value camlidl_z3V3_Z3_check_assumptions(
   return _vresult;
 }
 
-value camlidl_z3V3_Z3_get_implied_equalities(
-	value _v_c,
-	value _v_terms)
-{
-  Z3_context c; /*in*/
-  unsigned int num_terms; /*in*/
-  Z3_ast const *terms; /*in*/
-  unsigned int *class_ids; /*out*/
-  Z3_lbool _res;
-  struct camlidl_ctx_struct _ctxs = { CAMLIDL_TRANSIENT, NULL };
-  camlidl_ctx _ctx = &_ctxs;
-  mlsize_t _c1;
-  mlsize_t _c2;
-  value _v3;
-  mlsize_t _c4;
-  value _v5;
-  value _vresult;
-  value _vres[2] = { 0, 0, };
-
-  camlidl_ml2c_z3V3_Z3_context(_v_c, &c, _ctx);
-  _c1 = Wosize_val(_v_terms);
-  terms = camlidl_malloc(_c1 * sizeof(Z3_ast const ), _ctx);
-  for (_c2 = 0; _c2 < _c1; _c2++) {
-    _v3 = Field(_v_terms, _c2);
-    camlidl_ml2c_z3V3_Z3_ast(_v3, &terms[_c2], _ctx);
-  }
-  num_terms = _c1;
-  class_ids = camlidl_malloc(num_terms * sizeof(unsigned int ), _ctx);
-  _res = Z3_get_implied_equalities(c, num_terms, terms, class_ids);
-  Begin_roots_block(_vres, 2)
-    _vres[0] = camlidl_c2ml_z3V3_Z3_lbool(&_res, _ctx);
-    _vres[1] = camlidl_alloc(num_terms, 0);
-    for (_c4 = 0; _c4 < num_terms; _c4++) {
-      _v5 = Val_int(class_ids[_c4]);
-      modify(&Field(_vres[1], _c4), _v5);
-    }
-    _vresult = camlidl_alloc_small(2, 0);
-    Field(_vresult, 0) = _vres[0];
-    Field(_vresult, 1) = _vres[1];
-  End_roots()
-  camlidl_free(_ctx);
-  return _vresult;
-}
-
 value camlidl_z3V3_Z3_del_model(
 	value _v_c,
 	value _v_m)
diff --git a/src/api/python/z3.py b/src/api/python/z3.py
index 924ac0ea5..c138bcd62 100644
--- a/src/api/python/z3.py
+++ b/src/api/python/z3.py
@@ -37,15 +37,24 @@ Z3 exceptions:
 ...   # the expression x + y is type incorrect
 ...   n = x + y
 ... except Z3Exception as ex:
-...   print "failed:", ex
+...   print("failed: %s" % ex)
 failed: 'sort mismatch'
 """
 from z3core import *
 from z3types import *
 from z3consts import *
 from z3printer import *
+from fractions import Fraction
+import sys
 import io
 
+if sys.version < '3':
+    def _is_int(v):
+        return isinstance(v, int) or isinstance(v, long)
+else:
+    def _is_int(v):
+        return isinstance(v, int)
+
 def enable_trace(msg):
     Z3_enable_trace(msg)
 
@@ -102,12 +111,12 @@ _error_handler_fptr = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_uint)
 # list of arguments.
 def _get_args(args):
     try:
-	if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)):
-	    return args[0]
-	else:
-	    return args
+        if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)):
+            return args[0]
+        else:
+            return args
     except:  # len is not necessarily defined when args is not a sequence (use reflection?)
-	return args
+        return args
 
 def _Z3python_error_handler_core(c, e):
     # Do nothing error handler, just avoid exit(0)
@@ -140,7 +149,8 @@ class Context:
         if __debug__:
             _z3_assert(len(args) % 2 == 0, "Argument list must have an even number of elements.")
         conf = Z3_mk_config()
-        for key, value in kws.iteritems():
+        for key in kws:
+            value = kws[key]
             Z3_set_param_value(conf, str(key).upper(), _to_param_value(value))
         prev = None
         for a in args:
@@ -209,10 +219,12 @@ def set_param(*args, **kws):
     if __debug__:
         _z3_assert(len(args) % 2 == 0, "Argument list must have an even number of elements.")
     new_kws = {}
-    for k, v in kws.iteritems():
+    for k in kws:
+        v = kws[k]
         if not set_pp_option(k, v):
             new_kws[k] = v
-    for key, value in new_kws.iteritems():
+    for key in new_kws:
+        value = new_kws[key]
         Z3_global_param_set(str(key).upper(), _to_param_value(value))
     prev = None
     for a in args:
@@ -240,7 +252,7 @@ def get_param(name):
     """
     ptr = (ctypes.c_char_p * 1)()
     if Z3_global_param_get(str(name), ptr):
-        r = str(ptr[0])
+        r = z3core._to_pystr(ptr[0])
         return r
     raise Z3Exception("failed to retrieve value for '%s'" % name)
 
@@ -899,11 +911,22 @@ def _coerce_exprs(a, b, ctx=None):
     b = s.cast(b)
     return (a, b)
     
+def _reduce(f, l, a):
+    r = a
+    for e in l:
+        r = f(r, e)
+    return r
+
 def _coerce_expr_list(alist, ctx=None):
-    if filter(is_expr, alist) == []:
-        alist = map(lambda a: _py2expr(a, ctx), alist)
-    s = reduce(_coerce_expr_merge, alist, None)
-    return map(lambda a: s.cast(a), alist)
+    has_expr = False
+    for a in alist:
+        if is_expr(a):
+            has_expr = True
+            break
+    if not has_expr:
+        alist = [ _py2expr(a, ctx) for a in alist ]
+    s = _reduce(_coerce_expr_merge, alist, None)
+    return [ s.cast(a) for a in alist ]
 
 def is_expr(a):
     """Return `True` if `a` is a Z3 expression.
@@ -1518,7 +1541,7 @@ def MultiPattern(*args):
     """
     if __debug__:
         _z3_assert(len(args) > 0, "At least one argument expected")
-        _z3_assert(all(map(is_expr, args)), "Z3 expressions expected")
+        _z3_assert(all([ is_expr(a) for a in args ]), "Z3 expressions expected")
     ctx = args[0].ctx
     args, sz = _to_ast_array(args)
     return PatternRef(Z3_mk_pattern(ctx.ref(), sz, args), ctx)
@@ -1695,9 +1718,9 @@ def is_quantifier(a):
 def _mk_quantifier(is_forall, vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
     if __debug__:
         _z3_assert(is_bool(body), "Z3 expression expected")
-        _z3_assert(is_const(vs) or (len(vs) > 0 and all(map(is_const, vs))), "Invalid bounded variable(s)")
-        _z3_assert(all(map(lambda a: is_pattern(a) or is_expr(a), patterns)), "Z3 patterns expected")
-        _z3_assert(all(map(is_expr, no_patterns)), "no patterns are Z3 expressions")
+        _z3_assert(is_const(vs) or (len(vs) > 0 and all([ is_const(v) for v in vs])), "Invalid bounded variable(s)")
+        _z3_assert(all([is_pattern(a) or is_expr(a) for a in patterns]), "Z3 patterns expected")
+        _z3_assert(all([is_expr(p) for p in no_patterns]), "no patterns are Z3 expressions")
     ctx = body.ctx
     if is_app(vs):
         vs = [vs]
@@ -1706,7 +1729,7 @@ def _mk_quantifier(is_forall, vs, body, weight=1, qid="", skid="", patterns=[],
     for i in range(num_vars):
         ## TODO: Check if is constant
         _vs[i] = vs[i].as_ast()
-    patterns = map(_to_pattern, patterns)
+    patterns = [ _to_pattern(p) for p in patterns ]
     num_pats = len(patterns)
     _pats = (Pattern * num_pats)()
     for i in range(num_pats):
@@ -2008,7 +2031,7 @@ class ArithRef(ExprRef):
 
     def __truediv__(self, other):
         """Create the Z3 expression `other/self`."""
-        self.__div__(other)
+        return self.__div__(other)
 
     def __rdiv__(self, other):
         """Create the Z3 expression `other/self`.
@@ -2029,7 +2052,7 @@ class ArithRef(ExprRef):
 
     def __rtruediv__(self, other):
         """Create the Z3 expression `other/self`."""
-        self.__rdiv__(other)
+        return self.__rdiv__(other)
 
     def __mod__(self, other):
         """Create the Z3 expression `other%self`.
@@ -2413,11 +2436,11 @@ class IntNumRef(ArithRef):
         >>> v + 1
         1 + 1
         >>> v.as_long() + 1
-        2L
+        2
         """
         if __debug__:
             _z3_assert(self.is_int(), "Integer value expected")
-        return long(self.as_string())
+        return int(self.as_string())
 
     def as_string(self):
         """Return a Z3 integer numeral as a Python string.
@@ -2464,8 +2487,8 @@ class RatNumRef(ArithRef):
         10000000000
         >>> v + 1
         10000000000 + 1
-        >>> v.numerator_as_long() + 1
-        10000000001L
+        >>> v.numerator_as_long() + 1 == 10000000001
+        True
         """
         return self.numerator().as_long()
         
@@ -2476,7 +2499,7 @@ class RatNumRef(ArithRef):
         >>> v
         1/3
         >>> v.denominator_as_long()
-        3L
+        3
         """
         return self.denominator().as_long()
 
@@ -2501,6 +2524,15 @@ class RatNumRef(ArithRef):
         """
         return Z3_get_numeral_string(self.ctx_ref(), self.as_ast())
 
+    def as_fraction(self):
+        """Return a Z3 rational as a Python Fraction object.
+        
+        >>> v = RealVal("1/5")
+        >>> v.as_fraction()
+        Fraction(1, 5)
+        """
+        return Fraction(self.numerator_as_long(), self.denominator_as_long())
+
 class AlgebraicNumRef(ArithRef):
     """Algebraic irrational values."""
 
@@ -2529,7 +2561,7 @@ class AlgebraicNumRef(ArithRef):
 def _py2expr(a, ctx=None):
     if isinstance(a, bool):
         return BoolVal(a, ctx)
-    if isinstance(a, int) or isinstance(a, long):
+    if _is_int(a):
         return IntVal(a, ctx)
     if isinstance(a, float):
         return RealVal(a, ctx)
@@ -2576,9 +2608,7 @@ def _to_int_str(val):
             return "1"
         else:
             return "0"
-    elif isinstance(val, int):
-        return str(val)
-    elif isinstance(val, long):
+    elif _is_int(val):
         return str(val)
     elif isinstance(val, str):
         return val
@@ -2625,8 +2655,8 @@ def RatVal(a, b, ctx=None):
     Real
     """
     if __debug__:
-        _z3_assert(isinstance(a, int) or isinstance(a, str) or isinstance(a, long), "First argument cannot be converted into an integer")
-        _z3_assert(isinstance(b, int) or isinstance(b, str) or isinstance(a, long), "Second argument cannot be converted into an integer")
+        _z3_assert(_is_int(a) or isinstance(a, str), "First argument cannot be converted into an integer")
+        _z3_assert(_is_int(b) or isinstance(b, str), "Second argument cannot be converted into an integer")
     return simplify(RealVal(a, ctx)/RealVal(b, ctx))
 
 def Q(a, b, ctx=None):
@@ -3078,7 +3108,7 @@ class BitVecRef(ExprRef):
 
     def __truediv__(self, other):
         """Create the Z3 expression (signed) division `self / other`."""
-        self.__div__(other)
+        return self.__div__(other)
 
     def __rdiv__(self, other):
         """Create the Z3 expression (signed) division `other / self`.
@@ -3098,7 +3128,7 @@ class BitVecRef(ExprRef):
 
     def __rtruediv__(self, other):
         """Create the Z3 expression (signed) division `other / self`."""
-        self.__rdiv__(other)
+        return self.__rdiv__(other)
 
     def __mod__(self, other):
         """Create the Z3 expression (signed) mod `self % other`.
@@ -3218,9 +3248,9 @@ class BitVecRef(ExprRef):
         >>> BitVecVal(4, 3)
         4
         >>> BitVecVal(4, 3).as_signed_long()
-        -4L
+        -4
         >>> simplify(BitVecVal(4, 3) >> 1).as_signed_long()
-        -2L
+        -2
         >>> simplify(BitVecVal(4, 3) >> 1)
         6
         >>> simplify(LShR(BitVecVal(4, 3), 1))
@@ -3284,32 +3314,32 @@ class BitVecNumRef(BitVecRef):
         >>> v = BitVecVal(0xbadc0de, 32)
         >>> v
         195936478
-        >>> print "0x%.8x" % v.as_long()
+        >>> print("0x%.8x" % v.as_long())
         0x0badc0de
         """
-        return long(self.as_string())
+        return int(self.as_string())
 
     def as_signed_long(self):
         """Return a Z3 bit-vector numeral as a Python long (bignum) numeral. The most significant bit is assumed to be the sign.
         
         >>> BitVecVal(4, 3).as_signed_long()
-        -4L
+        -4
         >>> BitVecVal(7, 3).as_signed_long()
-        -1L
+        -1
         >>> BitVecVal(3, 3).as_signed_long()
-        3L
-        >>> BitVecVal(2L**32 - 1, 32).as_signed_long()
-        -1L
-        >>> BitVecVal(2L**64 - 1, 64).as_signed_long()
-        -1L
+        3
+        >>> BitVecVal(2**32 - 1, 32).as_signed_long()
+        -1
+        >>> BitVecVal(2**64 - 1, 64).as_signed_long()
+        -1
         """
-        sz = long(self.size())
+        sz = self.size()
         val = self.as_long()
-        if val >= 2L**(sz - 1):
-            val = val - 2L**sz
-        if val < -2L**(sz - 1):
-            val = val + 2L**sz
-        return val
+        if val >= 2**(sz - 1):
+            val = val - 2**sz
+        if val < -2**(sz - 1):
+            val = val + 2**sz
+        return int(val)
 
     def as_string(self):
         return Z3_get_numeral_string(self.ctx_ref(), self.as_ast())
@@ -3379,7 +3409,7 @@ def BitVecVal(val, bv, ctx=None):
     >>> v = BitVecVal(10, 32)
     >>> v
     10
-    >>> print "0x%.8x" % v.as_long()
+    >>> print("0x%.8x" % v.as_long())
     0x0000000a
     """
     if is_bv_sort(bv):
@@ -3440,12 +3470,12 @@ def Concat(*args):
     Concat(Concat(1, 1 + 1), 1)
     >>> simplify(Concat(v, v+1, v))
     289
-    >>> print "%.3x" % simplify(Concat(v, v+1, v)).as_long()
+    >>> print("%.3x" % simplify(Concat(v, v+1, v)).as_long())
     121
     """
     args = _get_args(args)
     if __debug__:
-        _z3_assert(all(map(is_bv, args)), "All arguments must be Z3 bit-vector expressions.")
+        _z3_assert(all([is_bv(a) for a in args]), "All arguments must be Z3 bit-vector expressions.")
         _z3_assert(len(args) >= 2, "At least two arguments expected.")
     ctx = args[0].ctx
     r   = args[0]
@@ -3615,9 +3645,9 @@ def LShR(a, b):
     >>> BitVecVal(4, 3)
     4
     >>> BitVecVal(4, 3).as_signed_long()
-    -4L
+    -4
     >>> simplify(BitVecVal(4, 3) >> 1).as_signed_long()
-    -2L
+    -2
     >>> simplify(BitVecVal(4, 3) >> 1)
     6
     >>> simplify(LShR(BitVecVal(4, 3), 1))
@@ -3682,7 +3712,7 @@ def SignExt(n, a):
     254
     >>> v.size()
     8
-    >>> print "%.x" % v.as_long()
+    >>> print("%.x" % v.as_long())
     fe
     """
     if __debug__:
@@ -3727,12 +3757,12 @@ def RepeatBitVec(n, a):
     >>> n.size()
     32
     >>> v0 = BitVecVal(10, 4)
-    >>> print "%.x" % v0.as_long()
+    >>> print("%.x" % v0.as_long())
     a
     >>> v = simplify(RepeatBitVec(4, v0))
     >>> v.size()
     16
-    >>> print "%.x" % v.as_long()
+    >>> print("%.x" % v.as_long())
     aaaa
     """
     if __debug__:
@@ -4006,7 +4036,7 @@ def Map(f, *args):
     if __debug__:
         _z3_assert(len(args) > 0, "At least one Z3 array expression expected")
         _z3_assert(is_func_decl(f), "First argument must be a Z3 function declaration")
-        _z3_assert(all(map(is_array, args)), "Z3 array expected expected")
+        _z3_assert(all([is_array(a) for a in args]), "Z3 array expected expected")
         _z3_assert(len(args) == f.arity(), "Number of arguments mismatch")
     _args, sz = _to_ast_array(args)
     ctx = f.ctx
@@ -4100,7 +4130,7 @@ class Datatype:
         if __debug__:
             _z3_assert(isinstance(name, str), "String expected")
             _z3_assert(isinstance(rec_name, str), "String expected")
-            _z3_assert(all(map(_valid_accessor, args)), "Valid list of accessors expected. An accessor is a pair of the form (String, Datatype|Sort)")
+            _z3_assert(all([_valid_accessor(a) for a in args]), "Valid list of accessors expected. An accessor is a pair of the form (String, Datatype|Sort)")
         self.constructors.append((name, rec_name, args))
 
     def declare(self, name, *args):
@@ -4187,9 +4217,9 @@ def CreateDatatypes(*ds):
     ds = _get_args(ds)
     if __debug__:
         _z3_assert(len(ds) > 0, "At least one Datatype must be specified")
-        _z3_assert(all(map(lambda d: isinstance(d, Datatype), ds)), "Arguments must be Datatypes")
-        _z3_assert(all(map(lambda d: d.ctx == ds[0].ctx, ds)), "Context mismatch")
-        _z3_assert(all(map(lambda d: d.constructors != [], ds)), "Non-empty Datatypes expected")
+        _z3_assert(all([isinstance(d, Datatype) for d in ds]), "Arguments must be Datatypes")
+        _z3_assert(all([d.ctx == ds[0].ctx for d in  ds]), "Context mismatch")
+        _z3_assert(all([d.constructors != [] for d in ds]), "Non-empty Datatypes expected")
     ctx = ds[0].ctx
     num    = len(ds)
     names  = (Symbol * num)()
@@ -4355,7 +4385,7 @@ def EnumSort(name, values, ctx=None):
     """
     if __debug__:
         _z3_assert(isinstance(name, str), "Name must be a string")
-        _z3_assert(all(map(lambda v: isinstance(v, str), values)), "Eumeration sort values must be strings")
+        _z3_assert(all([isinstance(v, str) for v in values]), "Eumeration sort values must be strings")
         _z3_assert(len(values) > 0, "At least one value expected")
     ctx = _get_ctx(ctx)
     num = len(values)
@@ -4369,7 +4399,7 @@ def EnumSort(name, values, ctx=None):
     V = []
     for i in range(num):
         V.append(FuncDeclRef(_values[i], ctx))
-    V = map(lambda a: a(), V)
+    V = [a() for a in V]
     return S, V
 
 #########################################
@@ -4432,7 +4462,8 @@ def args2params(arguments, keywords, ctx=None):
         else:
             r.set(prev, a)
             prev = None
-    for k, v in keywords.iteritems():
+    for k in keywords:
+        v = keywords[k]
         r.set(k, v)
     return r
 
@@ -4469,7 +4500,7 @@ class ParamDescrsRef:
         return Z3_param_descrs_get_kind(self.ctx.ref(), self.descr, to_symbol(n, self.ctx))
     
     def __getitem__(self, arg):
-        if isinstance(arg, int) or isinstance(arg, long):
+        if _is_int(arg):
             return self.get_name(arg)
         else:
             return self.get_kind(arg)
@@ -5057,7 +5088,7 @@ class FuncEntry:
         >>> try:
         ...   e.arg_value(2)
         ... except IndexError:
-        ...   print "index error"
+        ...   print("index error")
         index error
         """
         if idx >= self.num_args():
@@ -5122,7 +5153,10 @@ class FuncInterp(Z3PPObject):
             Z3_func_interp_dec_ref(self.ctx.ref(), self.f)
 
     def else_value(self):
-        """Return the `else` value for a function interpretation.
+        """
+        Return the `else` value for a function interpretation.
+        Return None if Z3 did not specify the `else` value for
+        this object.
 
         >>> f = Function('f', IntSort(), IntSort())
         >>> s = Solver()
@@ -5135,7 +5169,11 @@ class FuncInterp(Z3PPObject):
         >>> m[f].else_value()
         1
         """
-        return _to_expr_ref(Z3_func_interp_get_else(self.ctx.ref(), self.f), self.ctx)
+        r = Z3_func_interp_get_else(self.ctx.ref(), self.f)
+        if r:
+            return _to_expr_ref(r, self.ctx)
+        else:
+            return None
 
     def num_entries(self):
         """Return the number of entries/points in the function interpretation `self`.
@@ -5428,7 +5466,7 @@ class ModelRef(Z3PPObject):
         1
         >>> m[f]
         [1 -> 0, else -> 0]
-        >>> for d in m: print "%s -> %s" % (d, m[d])
+        >>> for d in m: print("%s -> %s" % (d, m[d]))
         x -> 1
         f -> [1 -> 0, else -> 0]
         """
@@ -5499,16 +5537,16 @@ class Statistics:
         if in_html_mode():
             out = io.StringIO()
             even = True
-            out.write(u'<table border="1" cellpadding="2" cellspacing="0">')
+            out.write(u('<table border="1" cellpadding="2" cellspacing="0">'))
             for k, v in self:
                 if even:
-                    out.write(u'<tr style="background-color:#CFCFCF">')
+                    out.write(u('<tr style="background-color:#CFCFCF">'))
                     even = False
                 else:
-                    out.write(u'<tr>')
+                    out.write(u('<tr>'))
                     even = True
-                out.write(u'<td>%s</td><td>%s</td></tr>' % (k, v))
-            out.write(u'</table>')
+                out.write(u('<td>%s</td><td>%s</td></tr>' % (k, v)))
+            out.write(u('</table>'))
             return out.getvalue()
         else:
             return Z3_stats_to_string(self.ctx.ref(), self.stats)
@@ -5806,7 +5844,7 @@ class Solver(Z3PPObject):
         >>> s.assert_and_track(x > 0,  'p1')
         >>> s.assert_and_track(x != 1, 'p2')
         >>> s.assert_and_track(x < 0,  p3)
-        >>> print s.check()
+        >>> print(s.check())
         unsat
         >>> c = s.unsat_core()
         >>> len(c)
@@ -5954,7 +5992,7 @@ class Solver(Z3PPObject):
     
     def help(self):
         """Display a string describing all available options."""
-        print Z3_solver_get_help(self.ctx.ref(), self.solver)
+        print(Z3_solver_get_help(self.ctx.ref(), self.solver))
 
     def param_descrs(self):
         """Return the parameter description set."""
@@ -6025,7 +6063,7 @@ class Fixedpoint(Z3PPObject):
         else:
             self.fixedpoint = fixedpoint
         Z3_fixedpoint_inc_ref(self.ctx.ref(), self.fixedpoint)
-	self.vars = []
+        self.vars = []
 
     def __del__(self):
         if self.fixedpoint != None:
@@ -6039,8 +6077,8 @@ class Fixedpoint(Z3PPObject):
 
     def help(self):
         """Display a string describing all available options."""
-        print Z3_fixedpoint_get_help(self.ctx.ref(), self.fixedpoint)
-	    
+        print(Z3_fixedpoint_get_help(self.ctx.ref(), self.fixedpoint))
+            
     def param_descrs(self):
         """Return the parameter description set."""
         return ParamDescrsRef(Z3_fixedpoint_get_param_descrs(self.ctx.ref(), self.fixedpoint), self.ctx)
@@ -6052,11 +6090,11 @@ class Fixedpoint(Z3PPObject):
         for arg in args:
             if isinstance(arg, Goal) or isinstance(arg, AstVector):
                 for f in arg:
-		    f = self.abstract(f)
+                    f = self.abstract(f)
                     Z3_fixedpoint_assert(self.ctx.ref(), self.fixedpoint, f.as_ast())
             else:
                 arg = s.cast(arg)
-		arg = self.abstract(arg)
+                arg = self.abstract(arg)
                 Z3_fixedpoint_assert(self.ctx.ref(), self.fixedpoint, arg.as_ast())
 
     def add(self, *args):
@@ -6072,38 +6110,38 @@ class Fixedpoint(Z3PPObject):
         self.assert_exprs(*args)
 
     def add_rule(self, head, body = None, name = None):
-	"""Assert rules defining recursive predicates to the fixedpoint solver.
+        """Assert rules defining recursive predicates to the fixedpoint solver.
         >>> a = Bool('a')
-	>>> b = Bool('b')
+        >>> b = Bool('b')
         >>> s = Fixedpoint()
-	>>> s.register_relation(a.decl())
-	>>> s.register_relation(b.decl())
-	>>> s.fact(a)
+        >>> s.register_relation(a.decl())
+        >>> s.register_relation(b.decl())
+        >>> s.fact(a)
         >>> s.rule(b, a)
-	>>> s.query(b)
-	sat
-	"""
-	if name == None:
-	    name = ""
+        >>> s.query(b)
+        sat
+        """
+        if name == None:
+            name = ""
         name = to_symbol(name, self.ctx)
-	if body == None:
-	    head = self.abstract(head)
-	    Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, head.as_ast(), name)	    
-	else:
-	    body = _get_args(body)
-	    f    = self.abstract(Implies(And(body),head))
-	    Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name)
-	
+        if body == None:
+            head = self.abstract(head)
+            Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, head.as_ast(), name)            
+        else:
+            body = _get_args(body)
+            f    = self.abstract(Implies(And(body),head))
+            Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name)
+        
     def rule(self, head, body = None, name = None):
-	"""Assert rules defining recursive predicates to the fixedpoint solver. Alias for add_rule."""
-	self.add_rule(head, body, name)
-	
+        """Assert rules defining recursive predicates to the fixedpoint solver. Alias for add_rule."""
+        self.add_rule(head, body, name)
+        
     def fact(self, head, name = None):
-	"""Assert facts defining recursive predicates to the fixedpoint solver. Alias for add_rule."""
-	self.add_rule(head, None, name)
+        """Assert facts defining recursive predicates to the fixedpoint solver. Alias for add_rule."""
+        self.add_rule(head, None, name)
 
     def query(self, *query):
-	"""Query the fixedpoint engine whether formula is derivable.
+        """Query the fixedpoint engine whether formula is derivable.
            You can also pass an tuple or list of recursive predicates.
         """
         query = _get_args(query)
@@ -6134,17 +6172,17 @@ class Fixedpoint(Z3PPObject):
 
     def update_rule(self, head, body, name):
         """update rule"""
-	if name == None:
-	    name = ""
+        if name == None:
+            name = ""
         name = to_symbol(name, self.ctx)
         body = _get_args(body)
         f    = self.abstract(Implies(And(body),head))
-	Z3_fixedpoint_update_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name)
+        Z3_fixedpoint_update_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name)
 
-    def get_answer(self):	
-	"""Retrieve answer from last query call."""
-	r = Z3_fixedpoint_get_answer(self.ctx.ref(), self.fixedpoint)
-	return _to_expr_ref(r, self.ctx)
+    def get_answer(self):       
+        """Retrieve answer from last query call."""
+        r = Z3_fixedpoint_get_answer(self.ctx.ref(), self.fixedpoint)
+        return _to_expr_ref(r, self.ctx)
 
     def get_num_levels(self, predicate):
         """Retrieve number of levels used for predicate in PDR engine"""
@@ -6160,40 +6198,40 @@ class Fixedpoint(Z3PPObject):
         Z3_fixedpoint_add_cover(self.ctx.ref(), self.fixedpoint, level, predicate.ast, property.ast)
 
     def register_relation(self, *relations):
-	"""Register relation as recursive"""
-	relations = _get_args(relations)
-	for f in relations:
-	    Z3_fixedpoint_register_relation(self.ctx.ref(), self.fixedpoint, f.ast)
+        """Register relation as recursive"""
+        relations = _get_args(relations)
+        for f in relations:
+            Z3_fixedpoint_register_relation(self.ctx.ref(), self.fixedpoint, f.ast)
 
     def set_predicate_representation(self, f, *representations):
-	"""Control how relation is represented"""
-	representations = _get_args(representations)
-	representations = map(to_symbol, representations)
-	sz = len(representations)
-	args = (Symbol * sz)()
-	for i in range(sz):
-	    args[i] = representations[i]
-	Z3_fixedpoint_set_predicate_representation(self.ctx.ref(), self.fixedpoint, f.ast, sz, args)
+        """Control how relation is represented"""
+        representations = _get_args(representations)
+        representations = [to_symbol(s) for s in representations]
+        sz = len(representations)
+        args = (Symbol * sz)()
+        for i in range(sz):
+            args[i] = representations[i]
+        Z3_fixedpoint_set_predicate_representation(self.ctx.ref(), self.fixedpoint, f.ast, sz, args)
 
     def parse_string(self, s):
-	"""Parse rules and queries from a string"""
-	return AstVector(Z3_fixedpoint_from_string(self.ctx.ref(), self.fixedpoint, s), self.ctx)
-	
+        """Parse rules and queries from a string"""
+        return AstVector(Z3_fixedpoint_from_string(self.ctx.ref(), self.fixedpoint, s), self.ctx)
+        
     def parse_file(self, f):
-	"""Parse rules and queries from a file"""
-	return AstVector(Z3_fixedpoint_from_file(self.ctx.ref(), self.fixedpoint, f), self.ctx)
+        """Parse rules and queries from a file"""
+        return AstVector(Z3_fixedpoint_from_file(self.ctx.ref(), self.fixedpoint, f), self.ctx)
 
     def get_rules(self):
-	"""retrieve rules that have been added to fixedpoint context"""
-	return AstVector(Z3_fixedpoint_get_rules(self.ctx.ref(), self.fixedpoint), self.ctx)
+        """retrieve rules that have been added to fixedpoint context"""
+        return AstVector(Z3_fixedpoint_get_rules(self.ctx.ref(), self.fixedpoint), self.ctx)
 
     def get_assertions(self):
-	"""retrieve assertions that have been added to fixedpoint context"""
-	return AstVector(Z3_fixedpoint_get_assertions(self.ctx.ref(), self.fixedpoint), self.ctx)
+        """retrieve assertions that have been added to fixedpoint context"""
+        return AstVector(Z3_fixedpoint_get_assertions(self.ctx.ref(), self.fixedpoint), self.ctx)
 
     def __repr__(self):
         """Return a formatted string with all added rules and constraints."""
-	return self.sexpr()
+        return self.sexpr()
 
     def sexpr(self):
         """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format.        
@@ -6201,16 +6239,16 @@ class Fixedpoint(Z3PPObject):
         return Z3_fixedpoint_to_string(self.ctx.ref(), self.fixedpoint, 0, (Ast * 0)())
 
     def to_string(self, queries):
-	"""Return a formatted string (in Lisp-like format) with all added constraints.
+        """Return a formatted string (in Lisp-like format) with all added constraints.
            We say the string is in s-expression format.
-	   Include also queries.
+           Include also queries.
         """
-	args, len = _to_ast_array(queries)
+        args, len = _to_ast_array(queries)
         return Z3_fixedpoint_to_string(self.ctx.ref(), self.fixedpoint, len, args)
     
     def statistics(self):
         """Return statistics for the last `query()`.
-	"""
+        """
         return Statistics(Z3_fixedpoint_get_statistics(self.ctx.ref(), self.fixedpoint), self.ctx)
 
     def reason_unknown(self):
@@ -6219,21 +6257,21 @@ class Fixedpoint(Z3PPObject):
         return Z3_fixedpoint_get_reason_unknown(self.ctx.ref(), self.fixedpoint)
 
     def declare_var(self, *vars):
-	"""Add variable or several variables.
-	The added variable or variables will be bound in the rules
-	and queries
-	"""
-	vars = _get_args(vars)
-	for v in vars:
-	    self.vars += [v]
-	
+        """Add variable or several variables.
+        The added variable or variables will be bound in the rules
+        and queries
+        """
+        vars = _get_args(vars)
+        for v in vars:
+            self.vars += [v]
+        
     def abstract(self, fml, is_forall=True):
-	if self.vars == []:
-	    return fml
-	if is_forall:
-	    return ForAll(self.vars, fml)
-	else:
-	    return Exists(self.vars, fml)
+        if self.vars == []:
+            return fml
+        if is_forall:
+            return ForAll(self.vars, fml)
+        else:
+            return Exists(self.vars, fml)
 
 #########################################
 #
@@ -6425,7 +6463,7 @@ class Tactic:
 
     def help(self):
         """Display a string containing a description of the available options for the `self` tactic."""
-        print Z3_tactic_get_help(self.ctx.ref(), self.tactic)
+        print(Z3_tactic_get_help(self.ctx.ref(), self.tactic))
 
     def param_descrs(self):
         """Return the parameter description set."""
@@ -6521,7 +6559,7 @@ def ParOr(*ts, **ks):
     if __debug__:
         _z3_assert(len(ts) >= 2, "At least two arguments expected")
     ctx = _get_ctx(ks.get('ctx', None))
-    ts  = map(lambda t: _to_tactic(t, ctx), ts)
+    ts  = [ _to_tactic(t, ctx) for t in ts ]
     sz  = len(ts)
     _args = (TacticObj * sz)()
     for i in range(sz):
@@ -6566,7 +6604,7 @@ def Repeat(t, max=4294967295, ctx=None):
     >>> c = And(Or(x == 0, x == 1), Or(y == 0, y == 1), x > y)
     >>> t = Repeat(OrElse(Tactic('split-clause'), Tactic('skip')))
     >>> r = t(c)
-    >>> for subgoal in r: print subgoal
+    >>> for subgoal in r: print(subgoal)
     [x == 0, y == 0, x > y]
     [x == 0, y == 1, x > y]
     [x == 1, y == 0, x > y]
@@ -6608,19 +6646,19 @@ def describe_tactics():
     """Display a (tabular) description of all available tactics in Z3."""
     if in_html_mode():
         even = True
-        print '<table border="1" cellpadding="2" cellspacing="0">'
+        print('<table border="1" cellpadding="2" cellspacing="0">')
         for t in tactics():
             if even:
-                print '<tr style="background-color:#CFCFCF">'
+                print('<tr style="background-color:#CFCFCF">')
                 even = False
             else:
-                print '<tr>'
+                print('<tr>')
                 even = True
-            print '<td>%s</td><td>%s</td></tr>' % (t, insert_line_breaks(tactic_description(t), 40))
-        print '</table>'
+            print('<td>%s</td><td>%s</td></tr>' % (t, insert_line_breaks(tactic_description(t), 40)))
+        print('</table>')
     else:
         for t in tactics():
-            print '%s : %s' % (t, tactic_description(t))
+            print('%s : %s' % (t, tactic_description(t)))
 
 class Probe:
     """Probes are used to inspect a goal (aka problem) and collect information that may be used to decide which solver and/or preprocessing step will be used."""
@@ -6631,7 +6669,7 @@ class Probe:
             self.probe = probe
         elif isinstance(probe, float):
             self.probe = Z3_probe_const(self.ctx.ref(), probe)
-        elif isinstance(probe, int) or isinstance(probe, long):
+        elif _is_int(probe):
             self.probe = Z3_probe_const(self.ctx.ref(), float(probe))
         elif isinstance(probe, bool):
             if probe:
@@ -6796,19 +6834,19 @@ def describe_probes():
     """Display a (tabular) description of all available probes in Z3."""
     if in_html_mode():
         even = True
-        print '<table border="1" cellpadding="2" cellspacing="0">'
+        print('<table border="1" cellpadding="2" cellspacing="0">')
         for p in probes():
             if even:
-                print '<tr style="background-color:#CFCFCF">'
+                print('<tr style="background-color:#CFCFCF">')
                 even = False
             else:
-                print '<tr>'
+                print('<tr>')
                 even = True
-            print '<td>%s</td><td>%s</td></tr>' % (p, insert_line_breaks(probe_description(p), 40))
-        print '</table>'
+            print('<td>%s</td><td>%s</td></tr>' % (p, insert_line_breaks(probe_description(p), 40)))
+        print('</table>')
     else:
         for p in probes():
-            print '%s : %s' % (p, probe_description(p))
+            print('%s : %s' % (p, probe_description(p)))
 
 def _probe_nary(f, args, ctx):
     if __debug__:
@@ -6904,7 +6942,7 @@ def simplify(a, *arguments, **keywords):
 
 def help_simplify():
     """Return a string describing all options available for Z3 `simplify` procedure."""
-    print Z3_simplify_get_help(main_ctx().ref())
+    print(Z3_simplify_get_help(main_ctx().ref()))
 
 def simplify_param_descrs():
     """Return the set of parameter descriptions for Z3 `simplify` procedure."""
@@ -6927,7 +6965,7 @@ def substitute(t, *m):
             m = _get_args(m1)
     if __debug__:
         _z3_assert(is_expr(t), "Z3 expression expected")
-        _z3_assert(all(map(lambda p: isinstance(p, tuple) and is_expr(p[0]) and is_expr(p[1]) and p[0].sort().eq(p[1].sort()), m)), "Z3 invalid substitution, expression pairs expected.")
+        _z3_assert(all([isinstance(p, tuple) and is_expr(p[0]) and is_expr(p[1]) and p[0].sort().eq(p[1].sort()) for p in m]), "Z3 invalid substitution, expression pairs expected.")
     num = len(m)
     _from = (Ast * num)()
     _to   = (Ast * num)()
@@ -6949,7 +6987,7 @@ def substitute_vars(t, *m):
     """
     if __debug__:
         _z3_assert(is_expr(t), "Z3 expression expected")
-        _z3_assert(all(map(is_expr, m)), "Z3 invalid substitution, list of expressions expected.")
+        _z3_assert(all([is_expr(n) for n in m]), "Z3 invalid substitution, list of expressions expected.")
     num = len(m)
     _to   = (Ast * num)()
     for i in range(num):
@@ -6976,7 +7014,7 @@ def Sum(*args):
         _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression")
     args  = _coerce_expr_list(args, ctx)
     if is_bv(args[0]):
-        return reduce(lambda a, b: a + b, args, 0)
+        return _reduce(lambda a, b: a + b, args, 0)
     else:
         _args, sz = _to_ast_array(args)
         return ArithRef(Z3_mk_add(ctx.ref(), sz, _args), ctx)
@@ -7001,7 +7039,7 @@ def Product(*args):
         _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression")
     args  = _coerce_expr_list(args, ctx)
     if is_bv(args[0]):
-        return reduce(lambda a, b: a * b, args, 1)
+        return _reduce(lambda a, b: a * b, args, 1)
     else:
         _args, sz = _to_ast_array(args)
         return ArithRef(Z3_mk_mul(ctx.ref(), sz, _args), ctx)
@@ -7021,18 +7059,18 @@ def solve(*args, **keywords):
     s.set(**keywords)
     s.add(*args)
     if keywords.get('show', False):
-        print s
+        print(s)
     r = s.check()
     if r == unsat:
-        print "no solution"
+        print("no solution")
     elif r == unknown:
-        print "failed to solve"
+        print("failed to solve")
         try:
-            print s.model()
+            print(s.model())
         except Z3Exception:
             return
     else:
-        print s.model()
+        print(s.model())
 
 def solve_using(s, *args, **keywords):
     """Solve the constraints `*args` using solver `s`.
@@ -7047,21 +7085,21 @@ def solve_using(s, *args, **keywords):
     s.set(**keywords)
     s.add(*args)
     if keywords.get('show', False):
-        print "Problem:"
-        print s
+        print("Problem:")
+        print(s)
     r = s.check()
     if r == unsat:
-        print "no solution"
+        print("no solution")
     elif r == unknown:
-        print "failed to solve"
+        print("failed to solve")
         try:
-            print s.model()
+            print(s.model())
         except Z3Exception:
             return
     else:
         if keywords.get('show', False):
-            print "Solution:"
-        print s.model()
+            print("Solution:")
+        print(s.model())
 
 def prove(claim, **keywords):
     """Try to prove the given claim.
@@ -7079,16 +7117,16 @@ def prove(claim, **keywords):
     s.set(**keywords)
     s.add(Not(claim))
     if keywords.get('show', False):
-        print s
+        print(s)
     r = s.check()
     if r == unsat:
-        print "proved"
+        print("proved")
     elif r == unknown:
-        print "failed to prove"
-        print s.model()
+        print("failed to prove")
+        print(s.model())
     else:
-        print "counterexample"
-        print s.model()
+        print("counterexample")
+        print(s.model())
 
 def _solve_html(*args, **keywords):
     """Version of funcion `solve` used in RiSE4Fun."""
@@ -7096,21 +7134,21 @@ def _solve_html(*args, **keywords):
     s.set(**keywords)
     s.add(*args)
     if keywords.get('show', False):
-        print "<b>Problem:</b>"
-        print s
+        print("<b>Problem:</b>")
+        print(s)
     r = s.check()
     if r == unsat:
-        print "<b>no solution</b>"
+        print("<b>no solution</b>")
     elif r == unknown:
-        print "<b>failed to solve</b>"
+        print("<b>failed to solve</b>")
         try:
-            print s.model()
+            print(s.model())
         except Z3Exception:
             return
     else:
         if keywords.get('show', False):
-            print "<b>Solution:</b>"
-        print s.model()
+            print("<b>Solution:</b>")
+        print(s.model())
 
 def _solve_using_html(s, *args, **keywords):
     """Version of funcion `solve_using` used in RiSE4Fun."""
@@ -7119,21 +7157,21 @@ def _solve_using_html(s, *args, **keywords):
     s.set(**keywords)
     s.add(*args)
     if keywords.get('show', False):
-        print "<b>Problem:</b>"
-        print s
+        print("<b>Problem:</b>")
+        print(s)
     r = s.check()
     if r == unsat:
-        print "<b>no solution</b>"
+        print("<b>no solution</b>")
     elif r == unknown:
-        print "<b>failed to solve</b>"
+        print("<b>failed to solve</b>")
         try:
-            print s.model()
+            print(s.model())
         except Z3Exception:
             return
     else:
         if keywords.get('show', False):
-            print "<b>Solution:</b>"
-        print s.model()
+            print("<b>Solution:</b>")
+        print(s.model())
 
 def _prove_html(claim, **keywords):
     """Version of funcion `prove` used in RiSE4Fun."""
@@ -7143,23 +7181,24 @@ def _prove_html(claim, **keywords):
     s.set(**keywords)
     s.add(Not(claim))
     if keywords.get('show', False):
-        print s
+        print(s)
     r = s.check()
     if r == unsat:
-        print "<b>proved</b>"
+        print("<b>proved</b>")
     elif r == unknown:
-        print "<b>failed to prove</b>"
-        print s.model()
+        print("<b>failed to prove</b>")
+        print(s.model())
     else:
-        print "<b>counterexample</b>"
-        print s.model()
+        print("<b>counterexample</b>")
+        print(s.model())
 
 def _dict2sarray(sorts, ctx):
     sz = len(sorts)
     _names = (Symbol * sz)()
     _sorts = (Sort * sz) ()
     i = 0
-    for k, v in sorts.iteritems():
+    for k in sorts:
+        v = sorts[k]
         if __debug__:
             _z3_assert(isinstance(k, str), "String expected")
             _z3_assert(is_sort(v), "Z3 sort expected")
@@ -7173,7 +7212,8 @@ def _dict2darray(decls, ctx):
     _names = (Symbol * sz)()
     _decls = (FuncDecl * sz) ()
     i = 0
-    for k, v in decls.iteritems():
+    for k in decls:
+        v = decls[k]
         if __debug__:
             _z3_assert(isinstance(k, str), "String expected")
             _z3_assert(is_func_decl(v) or is_const(v), "Z3 declaration or constant expected")
diff --git a/src/api/python/z3num.py b/src/api/python/z3num.py
index 581536e44..75cabbb27 100644
--- a/src/api/python/z3num.py
+++ b/src/api/python/z3num.py
@@ -8,6 +8,7 @@
 from z3 import *
 from z3core import *
 from z3printer import *
+from fractions import Fraction
 
 def _to_numeral(num, ctx=None):
     if isinstance(num, Numeral):
@@ -170,6 +171,14 @@ class Numeral:
         assert(self.is_integer())
         return long(Z3_get_numeral_string(self.ctx_ref(), self.as_ast()))
 
+    def as_fraction(self):
+        """ Return a numeral (that is a rational) as a Python Fraction.
+        >>> Numeral("1/5").as_fraction()
+        Fraction(1, 5)
+        """
+        assert(self.is_rational())
+        return Fraction(self.numerator().as_long(), self.denominator().as_long())
+
     def approx(self, precision=10):
         """Return a numeral that approximates the numeral `self`. 
         The result `r` is such that |r - self| <= 1/10^precision 
diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py
index 920de1a3b..d3dc43d3e 100644
--- a/src/api/python/z3printer.py
+++ b/src/api/python/z3printer.py
@@ -74,6 +74,15 @@ def _is_add(k):
 def _is_sub(k):
     return k == Z3_OP_SUB or k == Z3_OP_BSUB
 
+import sys
+if sys.version < '3':
+    import codecs
+    def u(x):
+        return codecs.unicode_escape_decode(x)[0]
+else:
+    def u(x):
+        return x
+
 _z3_infix_compact = [ Z3_OP_MUL, Z3_OP_BMUL, Z3_OP_POWER, Z3_OP_DIV, Z3_OP_IDIV, Z3_OP_MOD, Z3_OP_BSDIV, Z3_OP_BSMOD ]
 
 _ellipses = '...'
@@ -161,15 +170,19 @@ def _get_precedence(k):
     return _z3_precedence.get(k, 100000)
 
 _z3_html_op_to_str = {}
-for _k, _v in _z3_op_to_str.iteritems():
+for _k in _z3_op_to_str:
+    _v = _z3_op_to_str[_k]
     _z3_html_op_to_str[_k] = _v
-for _k, _v in _z3_pre_html_op_to_str.iteritems():
+for _k in _z3_pre_html_op_to_str:
+    _v = _z3_pre_html_op_to_str[_k]
     _z3_html_op_to_str[_k] = _v
 
 _z3_html_precedence = {}
-for _k, _v in _z3_precedence.iteritems():
+for _k in _z3_precedence:
+    _v = _z3_precedence[_k]
     _z3_html_precedence[_k] = _v
-for _k, _v in _z3_pre_html_precedence.iteritems():
+for _k in _z3_pre_html_precedence:
+    _v = _z3_pre_html_precedence[_k]
     _z3_html_precedence[_k] = _v
 
 _html_infix_map = {}
@@ -237,7 +250,7 @@ class FormatObject:
 
 class NAryFormatObject(FormatObject):
     def __init__(self, fs):
-        assert all(map(lambda a: isinstance(a, FormatObject), fs))
+        assert all([isinstance(a, FormatObject) for a in fs])
         self.children = fs
     def children(self):
         return self.children
@@ -246,7 +259,7 @@ class ComposeFormatObject(NAryFormatObject):
     def is_compose(sef):
         return True
     def as_tuple(self):
-        return ('compose', map(lambda a: a.as_tuple(), self.children))
+        return ('compose', [ a.as_tuple() for a in self.children ])
     def space_upto_nl(self):
         r = 0
         for child in self.children:
@@ -256,13 +269,13 @@ class ComposeFormatObject(NAryFormatObject):
                 return (r, True)
         return (r, False)
     def flat(self):
-        return compose(map(lambda a: a.flat(), self.children))
+        return compose([a.flat() for a in self.children ])
 
 class ChoiceFormatObject(NAryFormatObject):
     def is_choice(sef):
         return True
     def as_tuple(self):
-        return ('choice', map(lambda a: a.as_tuple(), self.children))
+        return ('choice', [ a.as_tuple() for a in self.children ])
     def space_upto_nl(self):
         return self.children[0].space_upto_nl()
     def flat(self):
@@ -388,11 +401,11 @@ class PP:
         if not self.bounded or self.pos <= self.max_width:
             sz = _len(f)
             if self.bounded and self.pos + sz > self.max_width:
-                self.out.write(_ellipses)
+                self.out.write(u(_ellipses))
             else:
                 self.pos = self.pos + sz
                 self.ribbon_pos = self.ribbon_pos + sz
-                self.out.write(unicode(f.string))
+                self.out.write(u(f.string))
 
     def pp_compose(self, f, indent):
         for c in f.children:
@@ -410,11 +423,11 @@ class PP:
         self.ribbon_pos = 0
         self.line = self.line + 1
         if self.line < self.max_lines: 
-            self.out.write(unicode('\n'))
+            self.out.write(u('\n'))
             for i in range(indent):
-                self.out.write(unicode(' '))
+                self.out.write(u(' '))
         else:
-            self.out.write(unicode('\n...'))
+            self.out.write(u('\n...'))
             raise StopPPException()
 
     def pp(self, f, indent):
@@ -791,7 +804,11 @@ class Formatter:
                 r.append(self.pp_ellipses())
                 break
         if sz <= self.max_args:
-            else_pp = self.pp_expr(f.else_value(), 0, [])
+            else_val = f.else_value()
+            if else_val == None:
+                else_pp  = to_format('#unspecified')
+            else:
+                else_pp  = self.pp_expr(else_val, 0, [])
             r.append(group(seq((to_format('else'), else_pp), self.pp_arrow())))
         return seq3(r, '[', ']')
 
@@ -953,23 +970,23 @@ def in_html_mode():
 
 def pp(a):
     if _support_pp(a):
-        print obj_to_string(a)
+        print(obj_to_string(a))
     else:
-        print a
+        print(a)
 
 def print_matrix(m):
     z3._z3_assert(isinstance(m, list) or isinstance(m, tuple), "matrix expected")
     if not in_html_mode():
-        print obj_to_string(m)
+        print(obj_to_string(m))
     else:
-        print '<table cellpadding="2", cellspacing="0", border="1">'
+        print('<table cellpadding="2", cellspacing="0", border="1">')
         for r in m:
             z3._z3_assert(isinstance(r, list) or isinstance(r, tuple), "matrix expected")
-            print '<tr>'
+            print('<tr>')
             for c in r:
-                print '<td>%s</td>' % c
-            print '</tr>'
-        print '</table>'
+                print('<td>%s</td>' % c)
+            print('</tr>')
+        print('</table>')
     
 def insert_line_breaks(s, width):
     """Break s in lines of size width (approx)"""
@@ -980,9 +997,9 @@ def insert_line_breaks(s, width):
     w = 0
     for i in range(sz):
         if w > width and s[i] == ' ':
-            new_str.write(u'<br />')
+            new_str.write(u('<br />'))
             w = 0
         else:
-            new_str.write(unicode(s[i]))
+            new_str.write(u(s[i]))
         w = w + 1
     return new_str.getvalue()
diff --git a/src/api/z3_api.h b/src/api/z3_api.h
index e12ce3591..98bde7bcf 100644
--- a/src/api/z3_api.h
+++ b/src/api/z3_api.h
@@ -1080,6 +1080,7 @@ typedef enum {
     Z3_PK_INVALID
 } Z3_param_kind;
 
+#ifdef CorML3
 /**
    \mlonly {!search_failure} \endmlonly \conly \brief
    The different kinds of search failure types.
@@ -1103,6 +1104,7 @@ typedef enum {
     Z3_THEORY,        
     Z3_QUANTIFIERS
 } Z3_search_failure;
+#endif
 
 /**
    \mlonly {!ast_print_mode} \endmlonly \conly \brief
@@ -6922,12 +6924,15 @@ END_MLAPI_EXCLUDE
         );
 
     /*@}*/
-    
+#endif
+
+
     /**
        @name Deprecated Constraints API
     */
     /*@{*/
 
+#ifdef CorML3
     /**
        \brief Set the SMTLIB logic to be used in the given logical context.
        It is incorrect to invoke this function after invoking
@@ -7109,7 +7114,9 @@ END_MLAPI_EXCLUDE
         __out Z3_model * m, __out Z3_ast* proof, 
         __inout unsigned* core_size, __inout_ecount(num_assumptions) Z3_ast core[]
         );
+#endif
 
+#ifdef CorML4
     /**
        \brief Retrieve congruence class representatives for terms.
 
@@ -7140,7 +7147,9 @@ END_MLAPI_EXCLUDE
         __in_ecount(num_terms) Z3_ast const terms[],
         __out_ecount(num_terms) unsigned class_ids[]
         );
+#endif
 
+#ifdef CorML3
     /**
        \brief Delete a model object.
        
diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp
index a89cc18d0..752bad072 100644
--- a/src/ast/arith_decl_plugin.cpp
+++ b/src/ast/arith_decl_plugin.cpp
@@ -206,6 +206,21 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) {
     func_decl * e_decl  = m->mk_const_decl(symbol("euler"), r, func_decl_info(id, OP_E));
     m_e = m->mk_const(e_decl);
     m->inc_ref(m_e);
+    
+    func_decl * z_pw_z_int = m->mk_const_decl(symbol("0^0-int"), i, func_decl_info(id, OP_0_PW_0_INT));
+    m_0_pw_0_int = m->mk_const(z_pw_z_int);
+    m->inc_ref(m_0_pw_0_int);
+
+    func_decl * z_pw_z_real = m->mk_const_decl(symbol("0^0-real"), r, func_decl_info(id, OP_0_PW_0_REAL));
+    m_0_pw_0_real = m->mk_const(z_pw_z_real);
+    m->inc_ref(m_0_pw_0_real);
+    
+    MK_OP(m_neg_root_decl, "neg-root", OP_NEG_ROOT, r);
+    MK_UNARY(m_div_0_decl, "/0", OP_DIV_0, r);
+    MK_UNARY(m_idiv_0_decl, "div0", OP_IDIV_0, i);
+    MK_UNARY(m_mod_0_decl, "mod0", OP_MOD_0, i);
+    MK_UNARY(m_u_asin_decl, "asin-u", OP_U_ASIN, r);
+    MK_UNARY(m_u_acos_decl, "acos-u", OP_U_ACOS, r);
 }
 
 arith_decl_plugin::arith_decl_plugin():
@@ -253,7 +268,15 @@ arith_decl_plugin::arith_decl_plugin():
     m_acosh_decl(0),
     m_atanh_decl(0),
     m_pi(0),
-    m_e(0) {
+    m_e(0),
+    m_0_pw_0_int(0),
+    m_0_pw_0_real(0),
+    m_neg_root_decl(0),
+    m_div_0_decl(0),
+    m_idiv_0_decl(0),
+    m_mod_0_decl(0),
+    m_u_asin_decl(0),
+    m_u_acos_decl(0) {
 }
 
 arith_decl_plugin::~arith_decl_plugin() {
@@ -303,6 +326,14 @@ void arith_decl_plugin::finalize() {
     DEC_REF(m_atanh_decl);
     DEC_REF(m_pi);
     DEC_REF(m_e);
+    DEC_REF(m_0_pw_0_int);
+    DEC_REF(m_0_pw_0_real);
+    DEC_REF(m_neg_root_decl);
+    DEC_REF(m_div_0_decl);
+    DEC_REF(m_idiv_0_decl);
+    DEC_REF(m_mod_0_decl);
+    DEC_REF(m_u_asin_decl);
+    DEC_REF(m_u_acos_decl);
     m_manager->dec_array_ref(m_small_ints.size(), m_small_ints.c_ptr());
     m_manager->dec_array_ref(m_small_reals.size(), m_small_reals.c_ptr());
 }
@@ -347,6 +378,14 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) {
     case OP_ATANH:     return m_atanh_decl;
     case OP_PI:        return m_pi->get_decl();
     case OP_E:         return m_e->get_decl();
+    case OP_0_PW_0_INT:  return m_0_pw_0_int->get_decl();
+    case OP_0_PW_0_REAL: return m_0_pw_0_real->get_decl();
+    case OP_NEG_ROOT:    return m_neg_root_decl;
+    case OP_DIV_0:       return m_div_0_decl;
+    case OP_IDIV_0:      return m_idiv_0_decl;
+    case OP_MOD_0:       return m_mod_0_decl;
+    case OP_U_ASIN:      return m_u_asin_decl;
+    case OP_U_ACOS:      return m_u_acos_decl;
     default: return 0;
     }
 }
@@ -426,12 +465,20 @@ static bool has_real_arg(ast_manager * m, unsigned num_args, expr * const * args
             return true;
     return false;
 }
+
+static bool is_const_op(decl_kind k) {
+    return 
+        k == OP_PI || 
+        k == OP_E  ||
+        k == OP_0_PW_0_INT ||
+        k == OP_0_PW_0_REAL;
+}
     
 func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, 
                                           unsigned arity, sort * const * domain, sort * range) {
     if (k == OP_NUM)
         return mk_num_decl(num_parameters, parameters, arity);
-    if (arity == 0 && k != OP_PI && k != OP_E) {
+    if (arity == 0 && !is_const_op(k)) {
         m_manager->raise_exception("no arguments supplied to arithmetical operator");
         return 0;
     }
@@ -448,7 +495,7 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
                                           unsigned num_args, expr * const * args, sort * range) {
     if (k == OP_NUM)
         return mk_num_decl(num_parameters, parameters, num_args);
-    if (num_args == 0  && k != OP_PI && k != OP_E) {
+    if (num_args == 0 && !is_const_op(k)) {
         m_manager->raise_exception("no arguments supplied to arithmetical operator");
         return 0;
     }
@@ -573,18 +620,7 @@ expr * arith_decl_plugin::get_some_value(sort * s) {
     return mk_numeral(rational(0), s == m_int_decl);
 }
 
-arith_util::arith_util(ast_manager & m):
-    m_manager(m),
-    m_afid(m.get_family_id("arith")),
-    m_plugin(0) {
-}
-
-void arith_util::init_plugin() {
-    SASSERT(m_plugin == 0);
-    m_plugin = static_cast<arith_decl_plugin*>(m_manager.get_plugin(m_afid));
-}
-
-bool arith_util::is_numeral(expr const * n, rational & val, bool & is_int) const {
+bool arith_recognizers::is_numeral(expr const * n, rational & val, bool & is_int) const {
     if (!is_app_of(n, m_afid, OP_NUM))
         return false;
     func_decl * decl = to_app(n)->get_decl();
@@ -593,6 +629,17 @@ bool arith_util::is_numeral(expr const * n, rational & val, bool & is_int) const
     return true;
 }
 
+arith_util::arith_util(ast_manager & m):
+    arith_recognizers(m.mk_family_id("arith")),
+    m_manager(m),
+    m_plugin(0) {
+}
+
+void arith_util::init_plugin() {
+    SASSERT(m_plugin == 0);
+    m_plugin = static_cast<arith_decl_plugin*>(m_manager.get_plugin(m_afid));
+}
+
 bool arith_util::is_irrational_algebraic_numeral(expr const * n, algebraic_numbers::anum & val) {
     if (!is_app_of(n, m_afid, OP_IRRATIONAL_ALGEBRAIC_NUM))
         return false;
diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h
index c39768d4c..53ab1881b 100644
--- a/src/ast/arith_decl_plugin.h
+++ b/src/ast/arith_decl_plugin.h
@@ -35,6 +35,7 @@ enum arith_sort_kind {
 enum arith_op_kind {
     OP_NUM, // rational & integers
     OP_IRRATIONAL_ALGEBRAIC_NUM,  // irrationals that are roots of polynomials with integer coefficients
+    //
     OP_LE,
     OP_GE,
     OP_LT,
@@ -67,6 +68,15 @@ enum arith_op_kind {
     // constants
     OP_PI,
     OP_E,
+    // under-specified symbols
+    OP_0_PW_0_INT,    // 0^0 for integers
+    OP_0_PW_0_REAL,   // 0^0 for reals
+    OP_NEG_ROOT,      // x^n when n is even and x is negative
+    OP_DIV_0,         // x/0
+    OP_IDIV_0,        // x div 0
+    OP_MOD_0,         // x mod 0
+    OP_U_ASIN,        // asin(x) for x < -1 or x > 1
+    OP_U_ACOS,        // acos(x) for x < -1 or x > 1
     LAST_ARITH_OP
 };
 
@@ -126,7 +136,16 @@ protected:
 
     app       * m_pi;
     app       * m_e;
-    
+ 
+    app       * m_0_pw_0_int;
+    app       * m_0_pw_0_real;
+    func_decl * m_neg_root_decl;
+    func_decl * m_div_0_decl;
+    func_decl * m_idiv_0_decl;
+    func_decl * m_mod_0_decl;
+    func_decl * m_u_asin_decl;
+    func_decl * m_u_acos_decl;
+   
     ptr_vector<app> m_small_ints;
     ptr_vector<app> m_small_reals;
 
@@ -182,41 +201,33 @@ public:
     
     app * mk_e() const { return m_e; }
 
+    app * mk_0_pw_0_int() const { return m_0_pw_0_int; }
+    
+    app * mk_0_pw_0_real() const { return m_0_pw_0_real; }
+
     virtual expr * get_some_value(sort * s);
 
     virtual void set_cancel(bool f);
 };
 
-class arith_util {
-    ast_manager &       m_manager;
+/**
+   \brief Procedures for recognizing arithmetic expressions.
+   We don't need access to ast_manager, and operations can be simultaneously
+   executed in different threads.
+*/
+class arith_recognizers {
+protected:
     family_id           m_afid;
-    arith_decl_plugin * m_plugin;
-
-    void init_plugin();
-
-    arith_decl_plugin & plugin() const {
-        if (!m_plugin) const_cast<arith_util*>(this)->init_plugin();
-        SASSERT(m_plugin != 0);
-        return *m_plugin;
-    }
-    
 public:
-    arith_util(ast_manager & m);
+    arith_recognizers(family_id id):m_afid(id) {}
 
-    ast_manager & get_manager() const { return m_manager; }
     family_id get_family_id() const { return m_afid; }
 
-    algebraic_numbers::manager & am() { 
-        return plugin().am(); 
-    }
-
     bool is_arith_expr(expr const * n) const { return is_app(n) && to_app(n)->get_family_id() == m_afid; }
+    bool is_irrational_algebraic_numeral(expr const * n) const { return is_app_of(n, m_afid, OP_IRRATIONAL_ALGEBRAIC_NUM); }
     bool is_numeral(expr const * n, rational & val, bool & is_int) const;
     bool is_numeral(expr const * n, rational & val) const { bool is_int; return is_numeral(n, val, is_int); }
     bool is_numeral(expr const * n) const { return is_app_of(n, m_afid, OP_NUM); }
-    bool is_irrational_algebraic_numeral(expr const * n) const { return is_app_of(n, m_afid, OP_IRRATIONAL_ALGEBRAIC_NUM); }
-    bool is_irrational_algebraic_numeral(expr const * n, algebraic_numbers::anum & val);
-    algebraic_numbers::anum const & to_irrational_algebraic_numeral(expr const * n);
     bool is_zero(expr const * n) const { rational val; return is_numeral(n, val) && val.is_zero(); }
     bool is_minus_one(expr * n) const { rational tmp; return is_numeral(n, tmp) && tmp.is_minus_one(); }
     // return true if \c n is a term of the form (* -1 r)
@@ -227,6 +238,7 @@ public:
         }
         return false;
     }
+
     bool is_le(expr const * n) const { return is_app_of(n, m_afid, OP_LE); }
     bool is_ge(expr const * n) const { return is_app_of(n, m_afid, OP_GE); }
     bool is_lt(expr const * n) const { return is_app_of(n, m_afid, OP_LT); }
@@ -245,14 +257,13 @@ public:
     bool is_power(expr const * n) const { return is_app_of(n, m_afid, OP_POWER); }
     
     bool is_int(sort const * s) const { return is_sort_of(s, m_afid, INT_SORT); }
-    bool is_int(expr const * n) const { return is_int(m_manager.get_sort(n)); }
+    bool is_int(expr const * n) const { return is_int(get_sort(n)); }
     bool is_real(sort const * s) const { return is_sort_of(s, m_afid, REAL_SORT); }
-    bool is_real(expr const * n) const { return is_real(m_manager.get_sort(n)); }
+    bool is_real(expr const * n) const { return is_real(get_sort(n)); }
     bool is_int_real(sort const * s) const { return s->get_family_id() == m_afid; }
-    bool is_int_real(expr const * n) const { return is_int_real(m_manager.get_sort(n)); }
+    bool is_int_real(expr const * n) const { return is_int_real(get_sort(n)); }
 
     MATCH_UNARY(is_uminus);
-
     MATCH_BINARY(is_sub);
     MATCH_BINARY(is_add);
     MATCH_BINARY(is_mul);
@@ -265,6 +276,34 @@ public:
     MATCH_BINARY(is_div);
     MATCH_BINARY(is_idiv);
 
+    bool is_pi(expr * arg) { return is_app_of(arg, m_afid, OP_PI); }
+    bool is_e(expr * arg) { return is_app_of(arg, m_afid, OP_E); }
+};
+
+class arith_util : public arith_recognizers {
+    ast_manager &       m_manager;
+    arith_decl_plugin * m_plugin;
+
+    void init_plugin();
+
+    arith_decl_plugin & plugin() const {
+        if (!m_plugin) const_cast<arith_util*>(this)->init_plugin();
+        SASSERT(m_plugin != 0);
+        return *m_plugin;
+    }
+    
+public:
+    arith_util(ast_manager & m);
+
+    ast_manager & get_manager() const { return m_manager; }
+
+    algebraic_numbers::manager & am() { 
+        return plugin().am(); 
+    }
+
+    bool is_irrational_algebraic_numeral(expr const * n) const { return is_app_of(n, m_afid, OP_IRRATIONAL_ALGEBRAIC_NUM); }
+    bool is_irrational_algebraic_numeral(expr const * n, algebraic_numbers::anum & val);
+    algebraic_numbers::anum const & to_irrational_algebraic_numeral(expr const * n);
     
     sort * mk_int() { return m_manager.mk_sort(m_afid, INT_SORT); }
     sort * mk_real() { return m_manager.mk_sort(m_afid, REAL_SORT); }
@@ -320,12 +359,18 @@ public:
     app * mk_acosh(expr * arg) { return m_manager.mk_app(m_afid, OP_ACOSH, arg); }
     app * mk_atanh(expr * arg) { return m_manager.mk_app(m_afid, OP_ATANH, arg); }
 
-    bool is_pi(expr * arg) { return is_app_of(arg, m_afid, OP_PI); }
-    bool is_e(expr * arg) { return is_app_of(arg, m_afid, OP_E); }
-
     app * mk_pi() { return plugin().mk_pi(); }
     app * mk_e()  { return plugin().mk_e(); }
 
+    app * mk_0_pw_0_int() { return plugin().mk_0_pw_0_int(); }
+    app * mk_0_pw_0_real() { return plugin().mk_0_pw_0_real(); }
+    app * mk_div0(expr * arg) { return m_manager.mk_app(m_afid, OP_DIV_0, arg); }
+    app * mk_idiv0(expr * arg) { return m_manager.mk_app(m_afid, OP_IDIV_0, arg); }
+    app * mk_mod0(expr * arg) { return m_manager.mk_app(m_afid, OP_MOD_0, arg); }
+    app * mk_neg_root(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_NEG_ROOT, arg1, arg2); }
+    app * mk_u_asin(expr * arg) { return m_manager.mk_app(m_afid, OP_U_ASIN, arg); }
+    app * mk_u_acos(expr * arg) { return m_manager.mk_app(m_afid, OP_U_ACOS, arg); }
+    
     /**
        \brief Return the equality (= lhs rhs), but it makes sure that 
        if one of the arguments is a numeral, then it will be in the right-hand-side;
diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp
index 23d5145ea..47842ae90 100644
--- a/src/ast/array_decl_plugin.cpp
+++ b/src/ast/array_decl_plugin.cpp
@@ -113,15 +113,14 @@ func_decl * array_decl_plugin::mk_const(sort * s, unsigned arity, sort * const *
         m_manager->raise_exception("invalid const array definition, invalid domain size");
         return 0;
     }
-    unsigned num_parameters = s->get_num_parameters();
-
-    if (num_parameters == 0) {
-        m_manager->raise_exception("parameter mismatch");
+    if (!is_array_sort(s)) {
+        m_manager->raise_exception("invalid const array definition, parameter is not an array sort");
+        return 0;
+    }
+    if (!m_manager->compatible_sorts(get_array_range(s), domain[0])) {
+        m_manager->raise_exception("invalid const array definition, sort mismatch between array range and argument");
         return 0;
     }
-
-    // TBD check that range sort corresponds to last parameter.
-        
     parameter param(s);
     func_decl_info info(m_family_id, OP_CONST_ARRAY, 1, &param);
     info.m_private_parameters = true;
@@ -542,6 +541,16 @@ bool array_decl_plugin::is_fully_interp(sort const * s) const {
     return m_manager->is_fully_interp(get_array_range(s));
 }
 
+func_decl * array_recognizers::get_as_array_func_decl(app * n) const { 
+    SASSERT(is_as_array(n)); 
+    return to_func_decl(n->get_decl()->get_parameter(0).get_ast()); 
+}
+
+array_util::array_util(ast_manager& m): 
+    array_recognizers(m.mk_family_id("array")),
+    m_manager(m) {
+}
+
 bool array_util::is_as_array_tree(expr * n) {
     ptr_buffer<expr, 32> todo;
     todo.push_back(n);
diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h
index 68c473560..2184b0088 100644
--- a/src/ast/array_decl_plugin.h
+++ b/src/ast/array_decl_plugin.h
@@ -129,27 +129,34 @@ class array_decl_plugin : public decl_plugin {
     virtual bool is_fully_interp(sort const * s) const;
 };
 
-class array_util {
-    ast_manager & m_manager;
-    family_id    m_fid;
+class array_recognizers {
+protected:
+    family_id m_fid;
 public:
-    array_util(ast_manager& m): m_manager(m), m_fid(m.get_family_id("array")) {}
-    ast_manager & get_manager() const { return m_manager; }
+    array_recognizers(family_id fid):m_fid(fid) {}
     family_id get_family_id() const { return m_fid; }
     bool is_array(sort* s) const { return is_sort_of(s, m_fid, ARRAY_SORT);}
-    bool is_array(expr* n) const { return is_array(m_manager.get_sort(n)); }
+    bool is_array(expr* n) const { return is_array(get_sort(n)); }
     bool is_select(expr* n) const { return is_app_of(n, m_fid, OP_SELECT); }
     bool is_store(expr* n) const { return is_app_of(n, m_fid, OP_STORE); }
     bool is_const(expr* n) const { return is_app_of(n, m_fid, OP_CONST_ARRAY); }
     bool is_map(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAP); }
     bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); }
-    bool is_as_array_tree(expr * n);
     bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); }
     bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); }
     bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); }
     bool is_map(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_MAP); }
     bool is_as_array(func_decl* f) const { return is_decl_of(f, m_fid, OP_AS_ARRAY); }
-    func_decl * get_as_array_func_decl(app * n) const { SASSERT(is_as_array(n)); return to_func_decl(n->get_decl()->get_parameter(0).get_ast()); }
+    func_decl * get_as_array_func_decl(app * n) const;
+};
+
+class array_util : public array_recognizers {
+    ast_manager & m_manager;
+public:
+    array_util(ast_manager& m);
+    ast_manager & get_manager() const { return m_manager; }
+
+    bool is_as_array_tree(expr * n);
 
     app * mk_store(unsigned num_args, expr * const * args) {
         return m_manager.mk_app(m_fid, OP_STORE, 0, 0, num_args, args);
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index 3fb422a2e..486aa9646 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -137,7 +137,7 @@ void display_parameters(std::ostream & out, unsigned n, parameter const * p) {
 //
 // -----------------------------------
 
-family_id family_manager::get_family_id(symbol const & s) {
+family_id family_manager::mk_family_id(symbol const & s) {
     family_id r; 
     if (m_families.find(s, r)) {
         return r;
@@ -149,7 +149,15 @@ family_id family_manager::get_family_id(symbol const & s) {
     return r;
 }
 
-bool family_manager::has_family(symbol const & s) {
+family_id family_manager::get_family_id(symbol const & s) const {
+    family_id r; 
+    if (m_families.find(s, r))
+        return r;
+    else
+        return null_family_id;
+}
+
+bool family_manager::has_family(symbol const & s) const {
     return m_families.contains(s);
 }
 
@@ -374,6 +382,31 @@ quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sort
     memcpy(const_cast<expr **>(get_no_patterns()), no_patterns, sizeof(expr *) * num_no_patterns);
 }
 
+// -----------------------------------
+//
+// Auxiliary functions
+//
+// -----------------------------------
+
+sort * get_sort(expr const * n) {
+    while (true) {
+        switch(n->get_kind()) {
+        case AST_APP: 
+            return to_app(n)->get_decl()->get_range();
+        case AST_VAR:
+            return to_var(n)->get_sort();
+        case AST_QUANTIFIER:
+            // The sort of the quantifier is the sort of the nested expression.
+            // This code assumes the given expression is well-sorted.
+            n = to_quantifier(n)->get_expr();
+            break;
+        default:
+            UNREACHABLE();
+            return 0;
+        }
+    }
+}
+
 // -----------------------------------
 //
 // AST hash-consing
@@ -1048,6 +1081,16 @@ expr * basic_decl_plugin::get_some_value(sort * s) {
     return 0;
 }
 
+bool basic_recognizers::is_ite(expr const * n, expr * & t1, expr * & t2, expr * & t3) const { 
+    if (is_ite(n)) { 
+        t1 = to_app(n)->get_arg(0); 
+        t2 = to_app(n)->get_arg(1); 
+        t3 = to_app(n)->get_arg(2);
+        return true; 
+    } 
+    return false; 
+}
+
 // -----------------------------------
 //
 // label_decl_plugin 
@@ -1262,12 +1305,12 @@ void ast_manager::init() {
     m_expr_id_gen.reset(0);
     m_decl_id_gen.reset(c_first_decl_id);
     m_some_value_proc = 0;
-    m_basic_family_id          = get_family_id("basic");
-    m_label_family_id          = get_family_id("label");
-    m_pattern_family_id        = get_family_id("pattern");
-    m_model_value_family_id    = get_family_id("model-value");
-    m_user_sort_family_id      = get_family_id("user-sort");
-    m_arith_family_id          = get_family_id("arith");
+    m_basic_family_id          = mk_family_id("basic");
+    m_label_family_id          = mk_family_id("label");
+    m_pattern_family_id        = mk_family_id("pattern");
+    m_model_value_family_id    = mk_family_id("model-value");
+    m_user_sort_family_id      = mk_family_id("user-sort");
+    m_arith_family_id          = mk_family_id("arith");
     basic_decl_plugin * plugin = alloc(basic_decl_plugin);
     register_plugin(m_basic_family_id, plugin);
     m_bool_sort = plugin->mk_bool_sort();
@@ -1400,7 +1443,7 @@ void ast_manager::copy_families_plugins(ast_manager const & from) {
             << ", target has_family: " << m_family_manager.has_family(fid) << "\n";
             if (m_family_manager.has_family(fid)) tout << get_family_id(fid_name) << "\n";);
       if (!m_family_manager.has_family(fid)) {
-          family_id new_fid = get_family_id(fid_name);          
+          family_id new_fid = mk_family_id(fid_name);          
           TRACE("copy_families_plugins", tout << "new target fid created: " << new_fid << " fid_name: " << fid_name << "\n";);
       }
       TRACE("copy_families_plugins", tout << "target fid: " << get_family_id(fid_name) << "\n";);
@@ -1437,7 +1480,7 @@ void ast_manager::set_next_expr_id(unsigned id) {
 unsigned ast_manager::get_node_size(ast const * n) { return ::get_node_size(n); }
 
 void ast_manager::register_plugin(symbol const & s, decl_plugin * plugin) {
-    family_id id = m_family_manager.get_family_id(s);
+    family_id id = m_family_manager.mk_family_id(s);
     SASSERT(is_format_manager() || s != symbol("format"));
     register_plugin(id, plugin);
 }
@@ -1495,20 +1538,6 @@ void ast_manager::register_plugin(family_id id, decl_plugin * plugin) {
     plugin->set_manager(this, id);
 }
 
-sort * ast_manager::get_sort(expr const * n) const {
-    switch(n->get_kind()) {
-    case AST_APP: 
-        return to_app(n)->get_decl()->get_range();
-    case AST_VAR:
-        return to_var(n)->get_sort();
-    case AST_QUANTIFIER:
-        return m_bool_sort;
-    default:
-        UNREACHABLE();
-        return 0;
-    }
-}
-
 bool ast_manager::is_bool(expr const * n) const {
     return get_sort(n) == m_bool_sort;
 }
diff --git a/src/ast/ast.h b/src/ast/ast.h
index e9da41377..3f03b86b9 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -188,10 +188,20 @@ class family_manager {
     svector<symbol>         m_names;
 public:
     family_manager():m_next_id(0) {}
+
+    /**
+       \brief Return the family_id for s, a new id is created if !has_family(s)
+       
+       If has_family(s), then this method is equivalent to get_family_id(s)
+    */
+    family_id mk_family_id(symbol const & s);
+
+    /**
+       \brief Return the family_id for s, return null_family_id if s was not registered in the manager.
+    */
+    family_id get_family_id(symbol const & s) const;
     
-    family_id get_family_id(symbol const & s);
-    
-    bool has_family(symbol const & s);
+    bool has_family(symbol const & s) const;
 
     void get_dom(svector<symbol>& dom) const { m_families.get_dom(dom); }
     
@@ -1287,6 +1297,55 @@ inline bool has_labels(expr const * n) {
     else return false;
 }
 
+sort * get_sort(expr const * n);
+
+class basic_recognizers {
+    family_id m_fid;
+public:
+    basic_recognizers(family_id fid):m_fid(fid) {}
+    bool is_bool(sort const * s) const { return is_sort_of(s, m_fid, BOOL_SORT); }
+    bool is_bool(expr const * n) const { return is_bool(get_sort(n)); }
+    bool is_or(expr const * n) const { return is_app_of(n, m_fid, OP_OR); }
+    bool is_implies(expr const * n) const { return is_app_of(n, m_fid, OP_IMPLIES); }
+    bool is_and(expr const * n) const { return is_app_of(n, m_fid, OP_AND); }
+    bool is_not(expr const * n) const { return is_app_of(n, m_fid, OP_NOT); }
+    bool is_eq(expr const * n) const { return is_app_of(n, m_fid, OP_EQ); }
+    bool is_oeq(expr const * n) const { return is_app_of(n, m_fid, OP_OEQ); }
+    bool is_distinct(expr const * n) const { return is_app_of(n, m_fid, OP_DISTINCT); }
+    bool is_iff(expr const * n) const { return is_app_of(n, m_fid, OP_IFF); }
+    bool is_xor(expr const * n) const { return is_app_of(n, m_fid, OP_XOR); }
+    bool is_ite(expr const * n) const { return is_app_of(n, m_fid, OP_ITE); }
+    bool is_term_ite(expr const * n) const { return is_ite(n) && !is_bool(n); }
+    bool is_true(expr const * n) const { return is_app_of(n, m_fid, OP_TRUE); }
+    bool is_false(expr const * n) const { return is_app_of(n, m_fid, OP_FALSE); }
+    bool is_complement_core(expr const * n1, expr const * n2) const { 
+        return (is_true(n1) && is_false(n2)) || (is_not(n1) && to_app(n1)->get_arg(0) == n2);
+    }
+    bool is_complement(expr const * n1, expr const * n2) const { return is_complement_core(n1, n2) || is_complement_core(n2, n1); }
+    bool is_or(func_decl const * d) const { return is_decl_of(d, m_fid, OP_OR); }
+    bool is_implies(func_decl const * d) const { return is_decl_of(d, m_fid, OP_IMPLIES); }
+    bool is_and(func_decl const * d) const { return is_decl_of(d, m_fid, OP_AND); }
+    bool is_not(func_decl const * d) const { return is_decl_of(d, m_fid, OP_NOT); }
+    bool is_eq(func_decl const * d) const { return is_decl_of(d, m_fid, OP_EQ); }
+    bool is_iff(func_decl const * d) const { return is_decl_of(d, m_fid, OP_IFF); }
+    bool is_xor(func_decl const * d) const { return is_decl_of(d, m_fid, OP_XOR); }
+    bool is_ite(func_decl const * d) const { return is_decl_of(d, m_fid, OP_ITE); }
+    bool is_term_ite(func_decl const * d) const { return is_ite(d) && !is_bool(d->get_range()); }
+    bool is_distinct(func_decl const * d) const { return is_decl_of(d, m_fid, OP_DISTINCT); }
+
+    MATCH_UNARY(is_not);
+    MATCH_BINARY(is_eq);
+    MATCH_BINARY(is_iff);
+    MATCH_BINARY(is_implies);
+    MATCH_BINARY(is_and);
+    MATCH_BINARY(is_or);
+    MATCH_BINARY(is_xor);
+    MATCH_TERNARY(is_and);
+    MATCH_TERNARY(is_or);
+
+    bool is_ite(expr const * n, expr * & t1, expr * & t2, expr * & t3) const;
+};
+
 // -----------------------------------
 //
 // Get Some Value functor
@@ -1404,6 +1463,8 @@ public:
 
     // propagate cancellation signal to decl_plugins
     void set_cancel(bool f);
+    void cancel() { set_cancel(true); }
+    void reset_cancel() { set_cancel(false); }
 
     bool has_trace_stream() const { return m_trace_stream != 0; }
     std::ostream & trace_stream() { SASSERT(has_trace_stream()); return *m_trace_stream; }
@@ -1432,8 +1493,10 @@ public:
 
     small_object_allocator & get_allocator() { return m_alloc; }
     
-    family_id get_family_id(symbol const & s) const { return const_cast<ast_manager*>(this)->m_family_manager.get_family_id(s); }
-    
+    family_id mk_family_id(symbol const & s) { return m_family_manager.mk_family_id(s); }
+    family_id mk_family_id(char const * s) { return mk_family_id(symbol(s)); }
+
+    family_id get_family_id(symbol const & s) const { return m_family_manager.get_family_id(s); }
     family_id get_family_id(char const * s) const { return get_family_id(symbol(s)); }
 
     symbol const & get_family_name(family_id fid) const { return m_family_manager.get_name(fid); }
@@ -1456,7 +1519,7 @@ public:
     
     bool has_plugin(family_id fid) const { return get_plugin(fid) != 0; }
     
-    bool has_plugin(symbol const & s) const { return has_plugin(get_family_id(s)); }
+    bool has_plugin(symbol const & s) const { return m_family_manager.has_family(s) && has_plugin(m_family_manager.get_family_id(s)); }
     
     void get_dom(svector<symbol> & dom) const { m_family_manager.get_dom(dom); }
     
@@ -1546,7 +1609,7 @@ protected:
     }
     
 public:
-    sort * get_sort(expr const * n) const;
+    sort * get_sort(expr const * n) const { return ::get_sort(n); }
     void check_sort(func_decl const * decl, unsigned num_args, expr * const * args) const;
     void check_sorts_core(ast const * n) const;
     bool check_sorts(ast const * n) const;
diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp
index 78a1caf68..66b467b92 100644
--- a/src/ast/ast_smt_pp.cpp
+++ b/src/ast/ast_smt_pp.cpp
@@ -795,11 +795,11 @@ public:
         m_simplify_implies(simplify_implies)
     {
         m_basic_fid = m.get_basic_family_id();
-        m_label_fid = m.get_family_id("label");
-        m_bv_fid    = m.get_family_id("bv");
-        m_arith_fid = m.get_family_id("arith");
-        m_array_fid = m.get_family_id("array");
-        m_dt_fid    = m.get_family_id("datatype");
+        m_label_fid = m.mk_family_id("label");
+        m_bv_fid    = m.mk_family_id("bv");
+        m_arith_fid = m.mk_family_id("arith");
+        m_array_fid = m.mk_family_id("array");
+        m_dt_fid    = m.mk_family_id("datatype");
     }
     
     void operator()(expr* n) {
@@ -1009,7 +1009,7 @@ ast_smt_pp::ast_smt_pp(ast_manager& m):
     m_status("unknown"),
     m_category(),
     m_logic(),
-    m_dt_fid(m.get_family_id("datatype")),
+    m_dt_fid(m.mk_family_id("datatype")),
     m_is_declared(&m_is_declared_default),
     m_simplify_implies(true)
 {}
diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp
index fd15ca681..9c5bccbc6 100644
--- a/src/ast/bv_decl_plugin.cpp
+++ b/src/ast/bv_decl_plugin.cpp
@@ -41,26 +41,6 @@ bv_decl_plugin::bv_decl_plugin():
     m_int_sort(0) {
 }
 
-void bv_decl_plugin::mk_table_upto(unsigned n) {
-    if (m_powers.empty()) {
-        m_powers.push_back(rational(1));
-    }
-    unsigned sz = m_powers.size();
-    rational curr = m_powers[sz - 1];
-    rational two(2);
-    for (unsigned i = sz; i <= n; i++) {
-        curr *= two;
-        m_powers.push_back(curr);
-    }
-}
-
-rational bv_decl_plugin::power_of_two(unsigned n) const {
-    if (n >= m_powers.size()) {
-        const_cast<bv_decl_plugin*>(this)->mk_table_upto(n + 1);
-    }
-    return m_powers[n];
-}
-
 void bv_decl_plugin::set_manager(ast_manager * m, family_id id) {
     decl_plugin::set_manager(m, id);
 
@@ -79,7 +59,7 @@ void bv_decl_plugin::set_manager(ast_manager * m, family_id id) {
     m_xor3 = m_manager->mk_func_decl(symbol("xor3"), 3, d, b, func_decl_info(m_family_id, OP_XOR3));
     m_manager->inc_ref(m_xor3);
 
-    m_int_sort = m_manager->mk_sort(m_manager->get_family_id("arith"), INT_SORT);
+    m_int_sort = m_manager->mk_sort(m_manager->mk_family_id("arith"), INT_SORT);
     SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before bv_decl_plugin.
     m_manager->inc_ref(m_int_sort);
 }
@@ -169,7 +149,7 @@ void bv_decl_plugin::mk_bv_sort(unsigned bv_size) {
             sz = sort_size::mk_very_big();
         }
         else {
-            sz = sort_size(power_of_two(bv_size));
+            sz = sort_size(rational::power_of_two(bv_size));
         }
         m_bv_sorts[bv_size] = m_manager->mk_sort(symbol("bv"), sort_info(m_family_id, BV_SORT, sz, 1, &p));
         m_manager->inc_ref(m_bv_sorts[bv_size]);
@@ -436,7 +416,7 @@ func_decl * bv_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const
     // This cannot be enforced now, since some Z3 modules try to generate these invalid numerals.
     // After SMT-COMP, I should find all offending modules.
     // For now, I will just simplify the numeral here.
-    parameter p0(mod(parameters[0].get_rational(), power_of_two(bv_size)));
+    parameter p0(mod(parameters[0].get_rational(), rational::power_of_two(bv_size)));
     parameter ps[2] = { p0, parameters[1] };
     sort * bv = get_bv_sort(bv_size);
     return m_manager->mk_const_decl(m_bv_sym, bv, func_decl_info(m_family_id, OP_BV_NUM, num_parameters, ps));
@@ -621,7 +601,7 @@ void bv_decl_plugin::get_offset_term(app * a, expr * & t, rational & offset) con
         offset = decl->get_parameter(0).get_rational();
         sz     = decl->get_parameter(1).get_int();
         t      = a->get_arg(1);
-        offset = mod(offset, power_of_two(sz));
+        offset = mod(offset, rational::power_of_two(sz));
     }
     else {
         t      = a;
@@ -729,37 +709,104 @@ expr * bv_decl_plugin::get_some_value(sort * s) {
     return m_manager->mk_app(m_family_id, OP_BV_NUM, 2, p, 0, 0);
 }
 
-bv_util::bv_util(ast_manager & m):
-    m_manager(m) {
-    SASSERT(m.has_plugin(symbol("bv")));
-    m_plugin = static_cast<bv_decl_plugin*>(m.get_plugin(m.get_family_id("bv")));
-}
-
-rational bv_util::norm(rational const & val, unsigned bv_size, bool is_signed) const {
-    rational r = mod(val, power_of_two(bv_size));
+rational bv_recognizers::norm(rational const & val, unsigned bv_size, bool is_signed) const {
+    rational r = mod(val, rational::power_of_two(bv_size));
     SASSERT(!r.is_neg());
     if (is_signed) {
-        if (r >= power_of_two(bv_size - 1)) {
-            r -= power_of_two(bv_size);
+        if (r >= rational::power_of_two(bv_size - 1)) {
+            r -= rational::power_of_two(bv_size);
         }
-        if (r < -power_of_two(bv_size - 1)) { 
-            r += power_of_two(bv_size);
+        if (r < -rational::power_of_two(bv_size - 1)) { 
+            r += rational::power_of_two(bv_size);
         }
     }
     return r;
 }
 
-bool bv_util::has_sign_bit(rational const & n, unsigned bv_size) const {
+bool bv_recognizers::has_sign_bit(rational const & n, unsigned bv_size) const {
     SASSERT(bv_size > 0);
     rational m = norm(n, bv_size, false);
-    rational p = power_of_two(bv_size - 1);
+    rational p = rational::power_of_two(bv_size - 1);
     return m >= p;
 }
 
-bool bv_util::is_bv_sort(sort const * s) const {
+bool bv_recognizers::is_bv_sort(sort const * s) const {
     return (s->get_family_id() == get_fid() && s->get_decl_kind() == BV_SORT && s->get_num_parameters() == 1); 
 }
 
+bool bv_recognizers::is_numeral(expr const * n, rational & val, unsigned & bv_size) const {
+    if (!is_app_of(n, get_fid(), OP_BV_NUM)) {
+        return false;
+    }
+    func_decl * decl = to_app(n)->get_decl();
+    val     = decl->get_parameter(0).get_rational();
+    bv_size = decl->get_parameter(1).get_int();
+    return true;
+}
+
+bool bv_recognizers::is_allone(expr const * e) const {
+    rational r;
+    unsigned bv_size;
+    if (!is_numeral(e, r, bv_size)) {
+        return false;
+    }
+    bool result = (r == rational::power_of_two(bv_size) - rational(1));
+    TRACE("is_allone", tout << r << " " << result << "\n";);
+    return result;
+}
+
+bool bv_recognizers::is_zero(expr const * n) const {
+    if (!is_app_of(n, get_fid(), OP_BV_NUM)) {
+        return false;
+    }
+    func_decl * decl = to_app(n)->get_decl();
+    return decl->get_parameter(0).get_rational().is_zero();
+}
+
+bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, expr*& b) {
+    if (!is_extract(e)) return false;
+    low = get_extract_low(e);
+    high = get_extract_high(e);
+    b = to_app(e)->get_arg(0);
+    return true;
+}
+
+bool bv_recognizers::is_bv2int(expr const* e, expr*& r) {
+    if (!is_bv2int(e)) return false;
+    r = to_app(e)->get_arg(0);
+    return true;
+}
+
+bool bv_recognizers::mult_inverse(rational const & n, unsigned bv_size, rational & result) {
+    if (n.is_one()) {
+        result = n;
+        return true;
+    }
+    
+    if (!mod(n, rational(2)).is_one()) {
+        return false;
+    }
+    
+    rational g;
+    rational x;
+    rational y;
+    g = gcd(n, rational::power_of_two(bv_size), x, y);
+    if (x.is_neg()) {
+        x = mod(x, rational::power_of_two(bv_size));
+    }
+    SASSERT(x.is_pos());
+    SASSERT(mod(x * n, rational::power_of_two(bv_size)).is_one());
+    result = x;
+    return true;
+}
+
+bv_util::bv_util(ast_manager & m):
+    bv_recognizers(m.mk_family_id(symbol("bv"))),
+    m_manager(m) {
+    SASSERT(m.has_plugin(symbol("bv")));
+    m_plugin = static_cast<bv_decl_plugin*>(m.get_plugin(m.mk_family_id("bv")));
+}
+
 app * bv_util::mk_numeral(rational const & val, sort* s) {
     if (!is_bv_sort(s)) {
         return 0;
@@ -774,67 +821,13 @@ app * bv_util::mk_numeral(rational const & val, unsigned bv_size) {
     return m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, 0);
 }
 
-bool bv_util::is_numeral(expr const * n, rational & val, unsigned & bv_size) const {
-    if (!is_app_of(n, get_fid(), OP_BV_NUM)) {
-        return false;
-    }
-    func_decl * decl = to_app(n)->get_decl();
-    val     = decl->get_parameter(0).get_rational();
-    bv_size = decl->get_parameter(1).get_int();
-    return true;
-}
-
-
-bool bv_util::is_allone(expr const * e) const {
-    rational r;
-    unsigned bv_size;
-    if (!is_numeral(e, r, bv_size)) {
-        return false;
-    }
-    bool result = (r == power_of_two(bv_size) - rational(1));
-    TRACE("is_allone", tout << r << " " << result << "\n";);
-    return result;
-}
-
-bool bv_util::is_zero(expr const * n) const {
-    if (!is_app_of(n, get_fid(), OP_BV_NUM)) {
-        return false;
-    }
-    func_decl * decl = to_app(n)->get_decl();
-    return decl->get_parameter(0).get_rational().is_zero();
-}
-
 sort * bv_util::mk_sort(unsigned bv_size) {
     parameter p[1] = { parameter(bv_size) };
     return m_manager.mk_sort(get_fid(), BV_SORT, 1, p);
 }
 
-
-bool bv_util::mult_inverse(rational const & n, unsigned bv_size, rational & result) {
-    if (n.is_one()) {
-        result = n;
-        return true;
-    }
-    
-    if (!mod(n, rational(2)).is_one()) {
-        return false;
-    }
-    
-    rational g;
-    rational x;
-    rational y;
-    g = gcd(n, power_of_two(bv_size), x, y);
-    if (x.is_neg()) {
-        x = mod(x, power_of_two(bv_size));
-    }
-    SASSERT(x.is_pos());
-    SASSERT(mod(x * n, power_of_two(bv_size)).is_one());
-    result = x;
-    return true;
-}
-
 app * bv_util::mk_bv2int(expr* e) {
-    sort* s = m_manager.mk_sort(m_manager.get_family_id("arith"), INT_SORT);
+    sort* s = m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT);
     parameter p(s);
     return m_manager.mk_app(get_fid(), OP_BV2INT, 1, &p, 1, &e); 
 }
diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h
index 34f2baf6b..8ea90f844 100644
--- a/src/ast/bv_decl_plugin.h
+++ b/src/ast/bv_decl_plugin.h
@@ -127,9 +127,6 @@ inline func_decl * get_div0_decl(ast_manager & m, func_decl * decl) {
 
 class bv_decl_plugin : public decl_plugin {
 protected:
-    vector<rational> m_powers;
-    void mk_table_upto(unsigned n);
-
     symbol m_bv_sym;
     symbol m_concat_sym;
     symbol m_sign_extend_sym;
@@ -245,8 +242,6 @@ protected:
 public:
     bv_decl_plugin();
 
-    rational power_of_two(unsigned n) const;
-
     virtual ~bv_decl_plugin() {}
     virtual void finalize();
 
@@ -273,7 +268,70 @@ public:
     virtual expr * get_some_value(sort * s);
 };
 
-class bv_util {
+class bv_recognizers {
+    family_id m_afid;
+public:
+    bv_recognizers(family_id fid):m_afid(fid) {}
+
+    family_id get_fid() const { return m_afid; }
+    family_id get_family_id() const { return get_fid(); }
+
+    bool is_numeral(expr const * n, rational & val, unsigned & bv_size) const;
+    bool is_numeral(expr const * n) const { return is_app_of(n, get_fid(), OP_BV_NUM); }
+    bool is_allone(expr const * e) const;
+    bool is_zero(expr const * e) const;
+    bool is_bv_sort(sort const * s) const;
+    bool is_bv(expr const* e) const {  return is_bv_sort(get_sort(e)); }
+    
+    bool is_concat(expr const * e) const { return is_app_of(e, get_fid(), OP_CONCAT); }
+    bool is_extract(func_decl const * f) const { return is_decl_of(f, get_fid(), OP_EXTRACT); }
+    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);
+    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); }
+    bool is_bv_neg(expr const * e) const { return is_app_of(e, get_fid(), OP_BNEG); }
+    bool is_bv_sdiv(expr const * e) const { return is_app_of(e, get_fid(), OP_BSDIV); }
+    bool is_bv_udiv(expr const * e) const { return is_app_of(e, get_fid(), OP_BUDIV); }
+    bool is_bv_srem(expr const * e) const { return is_app_of(e, get_fid(), OP_BSREM); }
+    bool is_bv_urem(expr const * e) const { return is_app_of(e, get_fid(), OP_BUREM); }
+    bool is_bv_smod(expr const * e) const { return is_app_of(e, get_fid(), OP_BSMOD); }
+    bool is_bv_and(expr const * e) const { return is_app_of(e, get_fid(), OP_BAND); }
+    bool is_bv_or(expr const * e) const { return is_app_of(e, get_fid(), OP_BOR); }
+    bool is_bv_xor(expr const * e) const { return is_app_of(e, get_fid(), OP_BXOR); }
+    bool is_bv_nand(expr const * e) const { return is_app_of(e, get_fid(), OP_BNAND); }
+    bool is_bv_nor(expr const * e) const { return is_app_of(e, get_fid(), OP_BNOR); }
+    bool is_bv_not(expr const * e) const { return is_app_of(e, get_fid(), OP_BNOT); }
+    bool is_bv_ule(expr const * e) const { return is_app_of(e, get_fid(), OP_ULEQ); }
+    bool is_bv_sle(expr const * e) const { return is_app_of(e, get_fid(), OP_SLEQ); }
+    bool is_bit2bool(expr const * e) const { return is_app_of(e, get_fid(), OP_BIT2BOOL); }
+    bool is_bv2int(expr const* e) const { return is_app_of(e, get_fid(), OP_BV2INT); }
+    bool is_int2bv(expr const* e) const { return is_app_of(e, get_fid(), OP_INT2BV); }
+    bool is_mkbv(expr const * e) const { return is_app_of(e, get_fid(), OP_MKBV); }
+    bool is_bv_ashr(expr const * e) const { return is_app_of(e, get_fid(), OP_BASHR); }
+    bool is_bv_lshr(expr const * e) const { return is_app_of(e, get_fid(), OP_BLSHR); }
+    bool is_bv_shl(expr const * e) const { return is_app_of(e, get_fid(), OP_BSHL); }
+    bool is_sign_ext(expr const * e) const { return is_app_of(e, get_fid(), OP_SIGN_EXT); }
+
+    MATCH_BINARY(is_bv_add);
+    MATCH_BINARY(is_bv_mul);
+    MATCH_BINARY(is_bv_sle);
+    MATCH_BINARY(is_bv_ule);
+    MATCH_BINARY(is_bv_shl);
+
+    rational norm(rational const & val, unsigned bv_size, bool is_signed) const ;
+    rational norm(rational const & val, unsigned bv_size) const { return norm(val, bv_size, false); }
+    bool has_sign_bit(rational const & n, unsigned bv_size) const;
+    bool mult_inverse(rational const & n, unsigned bv_size, rational & result);
+    
+};
+
+class bv_util : public bv_recognizers {
     ast_manager &    m_manager;
     bv_decl_plugin * m_plugin;
 
@@ -282,29 +340,10 @@ public:
 
     ast_manager & get_manager() const { return m_manager; }
 
-    family_id get_fid() const { return m_plugin->get_family_id(); }
-
-    family_id get_family_id() const { return get_fid(); }
-
-    rational power_of_two(unsigned n) const { return m_plugin->power_of_two(n); }
-
-    rational norm(rational const & val, unsigned bv_size, bool is_signed) const ;
-    rational norm(rational const & val, unsigned bv_size) const { return norm(val, bv_size, false); }
-    bool has_sign_bit(rational const & n, unsigned bv_size) const;
     app * mk_numeral(rational const & val, sort* s);
     app * mk_numeral(rational const & val, unsigned bv_size);
     app * mk_numeral(uint64 u, unsigned bv_size) { return mk_numeral(rational(u, rational::ui64()), bv_size); }
     sort * mk_sort(unsigned bv_size);
-    bool is_numeral(expr const * n, rational & val, unsigned & bv_size) const;
-    bool is_numeral(expr const * n) const {
-        return is_app_of(n, get_fid(), OP_BV_NUM);
-    }
-    bool is_allone(expr const * e) const;
-    bool is_zero(expr const * e) const;
-    bool is_bv_sort(sort const * s) const;
-    bool is_bv(expr const* e) const {
-        return is_bv_sort(m_manager.get_sort(e));
-    }
     
     unsigned get_bv_size(sort const * s) const { 
         SASSERT(is_bv_sort(s));
@@ -348,59 +387,6 @@ public:
     app * mk_bvumul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_NO_OVFL, n, m); }
 
     app * mk_bv(unsigned n, expr* const* es) { return m_manager.mk_app(get_fid(), OP_MKBV, n, es); }
-
-    bool is_concat(expr const * e) const { return is_app_of(e, get_fid(), OP_CONCAT); }
-    bool is_extract(func_decl const * f) const { return is_decl_of(f, get_fid(), OP_EXTRACT); }
-    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) {
-        if (!is_extract(e)) return false;
-        low = get_extract_low(e);
-        high = get_extract_high(e);
-        b = to_app(e)->get_arg(0);
-        return true;
-    }
-    bool is_bv2int(expr const* e, expr*& r) {
-        if (!is_bv2int(e)) return false;
-        r = to_app(e)->get_arg(0);
-        return true;
-    }
-    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); }
-    bool is_bv_neg(expr const * e) const { return is_app_of(e, get_fid(), OP_BNEG); }
-    bool is_bv_sdiv(expr const * e) const { return is_app_of(e, get_fid(), OP_BSDIV); }
-    bool is_bv_udiv(expr const * e) const { return is_app_of(e, get_fid(), OP_BUDIV); }
-    bool is_bv_srem(expr const * e) const { return is_app_of(e, get_fid(), OP_BSREM); }
-    bool is_bv_urem(expr const * e) const { return is_app_of(e, get_fid(), OP_BUREM); }
-    bool is_bv_smod(expr const * e) const { return is_app_of(e, get_fid(), OP_BSMOD); }
-    bool is_bv_and(expr const * e) const { return is_app_of(e, get_fid(), OP_BAND); }
-    bool is_bv_or(expr const * e) const { return is_app_of(e, get_fid(), OP_BOR); }
-    bool is_bv_xor(expr const * e) const { return is_app_of(e, get_fid(), OP_BXOR); }
-    bool is_bv_nand(expr const * e) const { return is_app_of(e, get_fid(), OP_BNAND); }
-    bool is_bv_nor(expr const * e) const { return is_app_of(e, get_fid(), OP_BNOR); }
-    bool is_bv_not(expr const * e) const { return is_app_of(e, get_fid(), OP_BNOT); }
-    bool is_bv_ule(expr const * e) const { return is_app_of(e, get_fid(), OP_ULEQ); }
-    bool is_bv_sle(expr const * e) const { return is_app_of(e, get_fid(), OP_SLEQ); }
-    bool is_bit2bool(expr const * e) const { return is_app_of(e, get_fid(), OP_BIT2BOOL); }
-    bool is_bv2int(expr const* e) const { return is_app_of(e, get_fid(), OP_BV2INT); }
-    bool is_int2bv(expr const* e) const { return is_app_of(e, get_fid(), OP_INT2BV); }
-    bool is_mkbv(expr const * e) const { return is_app_of(e, get_fid(), OP_MKBV); }
-    bool is_bv_ashr(expr const * e) const { return is_app_of(e, get_fid(), OP_BASHR); }
-    bool is_bv_lshr(expr const * e) const { return is_app_of(e, get_fid(), OP_BLSHR); }
-    bool is_bv_shl(expr const * e) const { return is_app_of(e, get_fid(), OP_BSHL); }
-    bool is_sign_ext(expr const * e) const { return is_app_of(e, get_fid(), OP_SIGN_EXT); }
-
-    MATCH_BINARY(is_bv_add);
-    MATCH_BINARY(is_bv_mul);
-    MATCH_BINARY(is_bv_sle);
-    MATCH_BINARY(is_bv_ule);
-    MATCH_BINARY(is_bv_shl);
-
-    bool mult_inverse(rational const & n, unsigned bv_size, rational & result);
 };
     
 #endif /* _BV_DECL_PLUGIN_H_ */
diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp
index 5cf841b49..0714af28b 100644
--- a/src/ast/datatype_decl_plugin.cpp
+++ b/src/ast/datatype_decl_plugin.cpp
@@ -673,7 +673,7 @@ bool datatype_decl_plugin::is_value(app * e) const {
 
 datatype_util::datatype_util(ast_manager & m):
     m_manager(m),
-    m_family_id(m.get_family_id("datatype")),
+    m_family_id(m.mk_family_id("datatype")),
     m_asts(m) {
 }
 
diff --git a/src/ast/decl_collector.cpp b/src/ast/decl_collector.cpp
index a83bf6b99..b663a9df3 100644
--- a/src/ast/decl_collector.cpp
+++ b/src/ast/decl_collector.cpp
@@ -45,7 +45,7 @@ decl_collector::decl_collector(ast_manager & m, bool preds):
     m_manager(m),
     m_sep_preds(preds) {
     m_basic_fid = m_manager.get_basic_family_id();
-    m_dt_fid    = m_manager.get_family_id("datatype");
+    m_dt_fid    = m_manager.mk_family_id("datatype");
 }
 
 void decl_collector::visit(ast* n) {
diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp
index 5b73f944a..8ac19c11c 100644
--- a/src/ast/dl_decl_plugin.cpp
+++ b/src/ast/dl_decl_plugin.cpp
@@ -629,7 +629,7 @@ namespace datalog {
         m(m), 
         m_arith(m),
         m_bv(m),
-        m_fid(m.get_family_id(symbol("datalog_relation")))
+        m_fid(m.mk_family_id(symbol("datalog_relation")))
     {}
 
     // create a constant belonging to a given finite domain.
diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp
index dbe7d5232..7f6d7f764 100644
--- a/src/ast/float_decl_plugin.cpp
+++ b/src/ast/float_decl_plugin.cpp
@@ -31,7 +31,7 @@ float_decl_plugin::float_decl_plugin():
 void float_decl_plugin::set_manager(ast_manager * m, family_id id) {
     decl_plugin::set_manager(m, id);
 
-    family_id aid = m_manager->get_family_id("arith");
+    family_id aid = m_manager->mk_family_id("arith");
     m_real_sort = m_manager->mk_sort(aid, REAL_SORT);
     SASSERT(m_real_sort != 0); // arith_decl_plugin must be installed before float_decl_plugin.
     m_manager->inc_ref(m_real_sort);
@@ -42,7 +42,7 @@ void float_decl_plugin::set_manager(ast_manager * m, family_id id) {
     
     if (m_manager->has_plugin(symbol("bv"))) {
         // bv plugin is optional, so m_bv_plugin may be 0
-        m_bv_fid = m_manager->get_family_id("bv");
+        m_bv_fid = m_manager->mk_family_id("bv");
         m_bv_plugin = static_cast<bv_decl_plugin*>(m_manager->get_plugin(m_bv_fid));
     }
 }
@@ -512,7 +512,7 @@ bool float_decl_plugin::is_value(app * e) const {
 
 float_util::float_util(ast_manager & m):
     m_manager(m),
-    m_fid(m.get_family_id("float")),
+    m_fid(m.mk_family_id("float")),
     m_a_util(m) {
     m_plugin = static_cast<float_decl_plugin*>(m.get_plugin(m_fid));
 }
diff --git a/src/ast/format.cpp b/src/ast/format.cpp
index 68ba5ea9a..1a36ca8ae 100644
--- a/src/ast/format.cpp
+++ b/src/ast/format.cpp
@@ -103,7 +103,7 @@ namespace format_ns {
         symbol f("format");
         if (!fm(m).has_plugin(f)) 
             fm(m).register_plugin(f, alloc(format_decl_plugin));
-        return fm(m).get_family_id(f);
+        return fm(m).mk_family_id(f);
     }
 
     static family_id fid(ast_manager & m) {
diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp
index 86f30ed73..e9b9c831e 100644
--- a/src/ast/macros/macro_util.cpp
+++ b/src/ast/macros/macro_util.cpp
@@ -41,7 +41,7 @@ macro_util::macro_util(ast_manager & m, simplifier & s):
 
 arith_simplifier_plugin * macro_util::get_arith_simp() const {
     if (m_arith_simp == 0) {
-        const_cast<macro_util*>(this)->m_arith_simp = static_cast<arith_simplifier_plugin*>(m_simplifier.get_plugin(m_manager.get_family_id("arith")));
+        const_cast<macro_util*>(this)->m_arith_simp = static_cast<arith_simplifier_plugin*>(m_simplifier.get_plugin(m_manager.mk_family_id("arith")));
     }
     SASSERT(m_arith_simp != 0);
     return m_arith_simp;
@@ -49,7 +49,7 @@ arith_simplifier_plugin * macro_util::get_arith_simp() const {
 
 bv_simplifier_plugin * macro_util::get_bv_simp() const {
     if (m_bv_simp == 0) {
-        const_cast<macro_util*>(this)->m_bv_simp = static_cast<bv_simplifier_plugin*>(m_simplifier.get_plugin(m_manager.get_family_id("bv")));
+        const_cast<macro_util*>(this)->m_bv_simp = static_cast<bv_simplifier_plugin*>(m_simplifier.get_plugin(m_manager.mk_family_id("bv")));
     }
     SASSERT(m_bv_simp != 0);
     return m_bv_simp;
diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp
index 773b9a2f5..83362f5b3 100644
--- a/src/ast/pattern/pattern_inference.cpp
+++ b/src/ast/pattern/pattern_inference.cpp
@@ -91,7 +91,7 @@ pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params &
     simplifier(m),
     m_params(params),
     m_bfid(m.get_basic_family_id()),
-    m_afid(m.get_family_id("arith")),
+    m_afid(m.mk_family_id("arith")),
     m_le(m),
     m_nested_arith_only(true),
     m_block_loop_patterns(params.m_pi_block_loop_patterns),
diff --git a/src/ast/pattern/pattern_inference.h b/src/ast/pattern/pattern_inference.h
index 1a179e794..97897835c 100644
--- a/src/ast/pattern/pattern_inference.h
+++ b/src/ast/pattern/pattern_inference.h
@@ -150,7 +150,7 @@ class pattern_inference : public simplifier {
         void save_candidate(expr * n, unsigned delta);
         void reset();
     public:
-        collect(ast_manager & m, pattern_inference & o):m_manager(m), m_owner(o), m_afid(m.get_family_id("arith")) {}
+        collect(ast_manager & m, pattern_inference & o):m_manager(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
         void operator()(expr * n, unsigned num_bindings);
     };
 
diff --git a/src/ast/proof_checker/proof_checker.cpp b/src/ast/proof_checker/proof_checker.cpp
index 240504048..85e0cc791 100644
--- a/src/ast/proof_checker/proof_checker.cpp
+++ b/src/ast/proof_checker/proof_checker.cpp
@@ -85,7 +85,7 @@ proof_checker::proof_checker(ast_manager& m) : m(m), m_todo(m), m_marked(), m_pi
     if (!m.has_plugin(fam_name)) {
         m.register_plugin(fam_name, alloc(hyp_decl_plugin));
     }
-    m_hyp_fid = m.get_family_id(fam_name);
+    m_hyp_fid = m.mk_family_id(fam_name);
     // m_spc_fid = m.get_family_id("spc");
     m_nil = m.mk_const(m_hyp_fid, OP_NIL);
 }
diff --git a/src/ast/reg_decl_plugins.cpp b/src/ast/reg_decl_plugins.cpp
index fd4d49789..ab1844e07 100644
--- a/src/ast/reg_decl_plugins.cpp
+++ b/src/ast/reg_decl_plugins.cpp
@@ -27,25 +27,25 @@ Revision History:
 #include"float_decl_plugin.h"
 
 void reg_decl_plugins(ast_manager & m) {
-    if (!m.get_plugin(m.get_family_id(symbol("arith")))) {
+    if (!m.get_plugin(m.mk_family_id(symbol("arith")))) {
         m.register_plugin(symbol("arith"), alloc(arith_decl_plugin));
     }
-    if (!m.get_plugin(m.get_family_id(symbol("bv")))) {
+    if (!m.get_plugin(m.mk_family_id(symbol("bv")))) {
         m.register_plugin(symbol("bv"), alloc(bv_decl_plugin));
     }
-    if (!m.get_plugin(m.get_family_id(symbol("array")))) {
+    if (!m.get_plugin(m.mk_family_id(symbol("array")))) {
         m.register_plugin(symbol("array"), alloc(array_decl_plugin));
     }
-    if (!m.get_plugin(m.get_family_id(symbol("datatype")))) {
+    if (!m.get_plugin(m.mk_family_id(symbol("datatype")))) {
         m.register_plugin(symbol("datatype"), alloc(datatype_decl_plugin));    
     }
-    if (!m.get_plugin(m.get_family_id(symbol("datalog_relation")))) {
+    if (!m.get_plugin(m.mk_family_id(symbol("datalog_relation")))) {
         m.register_plugin(symbol("datalog_relation"), alloc(datalog::dl_decl_plugin));
     }
-    if (!m.get_plugin(m.get_family_id(symbol("seq")))) {
+    if (!m.get_plugin(m.mk_family_id(symbol("seq")))) {
         m.register_plugin(symbol("seq"), alloc(seq_decl_plugin));
     }
-    if (!m.get_plugin(m.get_family_id(symbol("float")))) {
+    if (!m.get_plugin(m.mk_family_id(symbol("float")))) {
         m.register_plugin(symbol("float"), alloc(float_decl_plugin));
     }
 }
diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp
index 9dbbeb231..0bb7378f4 100644
--- a/src/ast/rewriter/array_rewriter.cpp
+++ b/src/ast/rewriter/array_rewriter.cpp
@@ -292,7 +292,14 @@ br_status array_rewriter::mk_map_core(func_decl * f, unsigned num_args, expr * c
             }
             
             expr * fv = m().mk_app(f, values.size(), values.c_ptr());
-            parameter p(m().get_sort(args[0]));
+            sort * in_s = get_sort(args[0]);
+            ptr_vector<sort> domain;
+            unsigned domain_sz = get_array_arity(in_s);
+            for (unsigned i = 0; i < domain_sz; i++) 
+                domain.push_back(get_array_domain(in_s, i));
+            sort_ref out_s(m());
+            out_s = m_util.mk_array_sort(domain_sz, domain.c_ptr(), f->get_range());
+            parameter p(out_s.get());
             result = m().mk_app(get_fid(), OP_CONST_ARRAY, 1, &p, 1, &fv);
             return BR_REWRITE2;
         }
diff --git a/src/ast/rewriter/bit_blaster/bit_blaster.h b/src/ast/rewriter/bit_blaster/bit_blaster.h
index 42444aebc..7b317c6cb 100644
--- a/src/ast/rewriter/bit_blaster/bit_blaster.h
+++ b/src/ast/rewriter/bit_blaster/bit_blaster.h
@@ -36,7 +36,7 @@ public:
     bit_blaster_cfg(bv_util & u, bit_blaster_params const & p, basic_simplifier_plugin & _s);
 
     ast_manager & m() const { return m_util.get_manager(); }
-    numeral power(unsigned n) const { return m_util.power_of_two(n); }
+    numeral power(unsigned n) const { return rational::power_of_two(n); }
     void mk_xor(expr * a, expr * b, expr_ref & r) { s.mk_xor(a, b, r); }
     void mk_xor3(expr * a, expr * b, expr * c, expr_ref & r);
     void mk_carry(expr * a, expr * b, expr * c, expr_ref & r);
diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp
index 1fd83e91f..80d319377 100644
--- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp
+++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp
@@ -32,7 +32,7 @@ struct blaster_cfg {
     blaster_cfg(bool_rewriter & r, bv_util & u):m_rewriter(r), m_util(u) {}
     
     ast_manager & m() const { return m_util.get_manager(); }
-    numeral power(unsigned n) const { return m_util.power_of_two(n); }
+    numeral power(unsigned n) const { return rational::power_of_two(n); }
     void mk_xor(expr * a, expr * b, expr_ref & r) { m_rewriter.mk_xor(a, b, r); }
     void mk_xor3(expr * a, expr * b, expr * c, expr_ref & r) {
         expr_ref tmp(m());
diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp
index b5f18a461..5b0c38616 100644
--- a/src/ast/rewriter/bool_rewriter.cpp
+++ b/src/ast/rewriter/bool_rewriter.cpp
@@ -27,6 +27,7 @@ void bool_rewriter::updt_params(params_ref const & _p) {
     m_local_ctx            = p.local_ctx();
     m_local_ctx_limit      = p.local_ctx_limit();
     m_blast_distinct       = p.blast_distinct();
+    m_blast_distinct_threshold = p.blast_distinct_threshold();
     m_ite_extra_rules      = p.ite_extra_rules();
 }
 
@@ -746,7 +747,7 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args
         return BR_DONE;
     }
 
-    if (m_blast_distinct) {
+    if (m_blast_distinct && num_args < m_blast_distinct_threshold) {
         ptr_buffer<expr> new_diseqs;
         for (unsigned i = 0; i < num_args; i++) {
             for (unsigned j = i + 1; j < num_args; j++)
diff --git a/src/ast/rewriter/bool_rewriter.h b/src/ast/rewriter/bool_rewriter.h
index b1a177247..ef6dc2d38 100644
--- a/src/ast/rewriter/bool_rewriter.h
+++ b/src/ast/rewriter/bool_rewriter.h
@@ -55,6 +55,7 @@ class bool_rewriter {
     bool           m_local_ctx;
     bool           m_elim_and;
     bool           m_blast_distinct;
+    unsigned       m_blast_distinct_threshold;
     bool           m_ite_extra_rules;
     unsigned       m_local_ctx_limit;
     unsigned       m_local_ctx_cost;
diff --git a/src/ast/rewriter/bool_rewriter_params.pyg b/src/ast/rewriter/bool_rewriter_params.pyg
index a5bcf6f5d..531bf4db9 100644
--- a/src/ast/rewriter/bool_rewriter_params.pyg
+++ b/src/ast/rewriter/bool_rewriter_params.pyg
@@ -6,4 +6,6 @@ def_module_params(module_name='rewriter',
                           ("elim_and", BOOL, False, "conjunctions are rewritten using negation and disjunctions"),
                           ("local_ctx", BOOL, False, "perform local (i.e., cheap) context simplifications"),
                           ("local_ctx_limit", UINT, UINT_MAX, "limit for applying local context simplifier"),
-                          ("blast_distinct", BOOL, False, "expand a distinct predicate into a quadratic number of disequalities")))
+                          ("blast_distinct", BOOL, False, "expand a distinct predicate into a quadratic number of disequalities"), 
+                          ("blast_distinct_threshold", UINT, UINT_MAX, "when blast_distinct is true, only distinct expressions with less than this number of arguments are blasted")  
+                          ))
diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp
index 5fd562676..44efe0199 100644
--- a/src/ast/rewriter/bv_rewriter.cpp
+++ b/src/ast/rewriter/bv_rewriter.cpp
@@ -63,6 +63,7 @@ void bv_rewriter::updt_local_params(params_ref const & _p) {
     m_blast_eq_value = p.blast_eq_value();
     m_split_concat_eq = p.split_concat_eq();
     m_udiv2mul = p.udiv2mul();
+    m_bvnot2arith = p.bvnot2arith();
     m_mkbv2num = _p.get_bool("mkbv2num", false);
 }
 
@@ -283,12 +284,12 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref
 
     if (is_num1 || is_num2) {
         if (is_signed) {
-            lower = - m_util.power_of_two(sz - 1);
-            upper =   m_util.power_of_two(sz - 1) - numeral(1);
+            lower = - rational::power_of_two(sz - 1);
+            upper =   rational::power_of_two(sz - 1) - numeral(1);
         }
         else {
             lower = numeral(0);
-            upper = m_util.power_of_two(sz) - numeral(1);
+            upper = rational::power_of_two(sz) - numeral(1);
         }
     }
 
@@ -387,14 +388,14 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_
     if (is_numeral(arg, v, sz)) {
         sz = high - low + 1;
         if (v.is_neg())
-            mod(v, m_util.power_of_two(sz), v);
+            mod(v, rational::power_of_two(sz), v);
         if (v.is_uint64()) {
             uint64 u  = v.get_uint64();
             uint64 e  = shift_right(u, low) & (shift_left(1ull, sz) - 1ull);
             result    = mk_numeral(numeral(e, numeral::ui64()), sz);
             return BR_DONE;
         }
-        div(v, m_util.power_of_two(low), v);
+        div(v, rational::power_of_two(low), v);
         result = mk_numeral(v, sz);
         return BR_DONE;
     }
@@ -519,7 +520,7 @@ br_status bv_rewriter::mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result) {
             
             SASSERT(r2 < numeral(bv_size));
             SASSERT(r2.is_unsigned());
-            r1 = m_util.norm(r1 * m_util.power_of_two(r2.get_unsigned()), bv_size);
+            r1 = m_util.norm(r1 * rational::power_of_two(r2.get_unsigned()), bv_size);
             result = mk_numeral(r1, bv_size);
             return BR_DONE;
         }
@@ -567,7 +568,7 @@ br_status bv_rewriter::mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result) {
 
             SASSERT(r2.is_unsigned());
             unsigned sh = r2.get_unsigned();
-            div(r1, m_util.power_of_two(sh), r1);
+            div(r1, rational::power_of_two(sh), r1);
             result = mk_numeral(r1, bv_size);
             return BR_DONE;
         }
@@ -626,7 +627,7 @@ br_status bv_rewriter::mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result) {
 
     if (is_num1 && is_num2 && numeral(bv_size) <= r2) {
         if (m_util.has_sign_bit(r1, bv_size))
-            result = mk_numeral(m_util.power_of_two(bv_size) - numeral(1), bv_size);
+            result = mk_numeral(rational::power_of_two(bv_size) - numeral(1), bv_size);
         else
             result = mk_numeral(0, bv_size);
         return BR_DONE;
@@ -635,7 +636,7 @@ br_status bv_rewriter::mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result) {
     if (is_num1 && is_num2) {
         SASSERT(r2 < numeral(bv_size));
         bool   sign = m_util.has_sign_bit(r1, bv_size);
-        div(r1, m_util.power_of_two(r2.get_unsigned()), r1);
+        div(r1, rational::power_of_two(r2.get_unsigned()), r1);
         if (sign) {
             // pad ones.
             numeral p(1);
@@ -697,7 +698,7 @@ br_status bv_rewriter::mk_bv_sdiv_core(expr * arg1, expr * arg2, bool hi_div0, e
                 // The "hardware interpretation" for (bvsdiv x 0) is (ite (bvslt x #x0000) #x0001 #xffff)
                 result = m().mk_ite(m().mk_app(get_fid(), OP_SLT, arg1, mk_numeral(0, bv_size)),
                                     mk_numeral(1, bv_size),
-                                    mk_numeral(m_util.power_of_two(bv_size) - numeral(1), bv_size));
+                                    mk_numeral(rational::power_of_two(bv_size) - numeral(1), bv_size));
                 return BR_REWRITE2;
             }
         }
@@ -746,7 +747,7 @@ br_status bv_rewriter::mk_bv_udiv_core(expr * arg1, expr * arg2, bool hi_div0, e
             }
             else {
                 // The "hardware interpretation" for (bvudiv x 0) is #xffff
-                result = mk_numeral(m_util.power_of_two(bv_size) - numeral(1), bv_size);
+                result = mk_numeral(rational::power_of_two(bv_size) - numeral(1), bv_size);
                 return BR_DONE;
                 
             }
@@ -845,7 +846,7 @@ bool bv_rewriter::is_minus_one_core(expr * arg) const {
     numeral r;
     unsigned bv_size;
     if (is_numeral(arg, r, bv_size)) {
-        return r == (m_util.power_of_two(bv_size) - numeral(1));
+        return r == (rational::power_of_two(bv_size) - numeral(1));
     }
     return false;
 }
@@ -924,7 +925,7 @@ br_status bv_rewriter::mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, e
         if (is_x_minus_one(arg1, x) && x == arg2) {
             bv_size = get_bv_size(arg1);
             expr * x_minus_1 = arg1;
-            expr * minus_one = mk_numeral(m_util.power_of_two(bv_size) - numeral(1), bv_size);
+            expr * minus_one = mk_numeral(rational::power_of_two(bv_size) - numeral(1), bv_size);
             result = m().mk_ite(m().mk_eq(x, mk_numeral(0, bv_size)),
                                 m().mk_app(get_fid(), OP_BUREM0, minus_one),
                                 x_minus_1);
@@ -1068,7 +1069,7 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re
         if (i > 0) 
             prev = new_args.back();
         if (is_numeral(arg, v1, sz1) && prev != 0 && is_numeral(prev, v2, sz2)) {
-            v2  *= m_util.power_of_two(sz1);
+            v2  *= rational::power_of_two(sz1);
             v2  += v1;
             new_args.pop_back();
             new_args.push_back(mk_numeral(v2, sz1+sz2));
@@ -1137,7 +1138,7 @@ br_status bv_rewriter::mk_sign_extend(unsigned n, expr * arg, expr_ref & result)
     if (is_numeral(arg, r, bv_size)) {
         unsigned result_bv_size = bv_size + n;
         r = m_util.norm(r, bv_size, true);
-        mod(r, m_util.power_of_two(result_bv_size), r);
+        mod(r, rational::power_of_two(result_bv_size), r);
         result = mk_numeral(r, result_bv_size);
         return BR_DONE;
     }
@@ -1213,7 +1214,7 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re
         if (m_util.is_bv_not(arg)) {
             expr * atom = to_app(arg)->get_arg(0);
             if (pos_args.is_marked(atom)) {
-                result = mk_numeral(m_util.power_of_two(sz) - numeral(1), sz);
+                result = mk_numeral(rational::power_of_two(sz) - numeral(1), sz);
                 return BR_DONE;
             }
             else if (neg_args.is_marked(atom)) {
@@ -1229,7 +1230,7 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re
                 continue;
             }
             else if (neg_args.is_marked(arg)) {
-                result = mk_numeral(m_util.power_of_two(sz) - numeral(1), sz);
+                result = mk_numeral(rational::power_of_two(sz) - numeral(1), sz);
                 return BR_DONE;
             }
             pos_args.mark(arg, true);
@@ -1237,7 +1238,7 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re
         }
     }
 
-    if (v1 == m_util.power_of_two(sz) - numeral(1)) {
+    if (v1 == rational::power_of_two(sz) - numeral(1)) {
         result = mk_numeral(v1, sz);
         return BR_DONE;
     }
@@ -1294,7 +1295,7 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re
             }
             if (i != low) {
                 unsigned num_sz = i - low;
-                exs.push_back(m_util.mk_numeral(m_util.power_of_two(num_sz) - numeral(1), num_sz));
+                exs.push_back(m_util.mk_numeral(rational::power_of_two(num_sz) - numeral(1), num_sz));
                 low = i;
             }
             while (i < sz && mod(v1, two).is_zero()) {
@@ -1385,7 +1386,7 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r
             else if (pos_args.is_marked(atom)) {
                 pos_args.mark(atom, false);
                 merged = true;
-                v1 = bitwise_xor(v1, m_util.power_of_two(sz) - numeral(1));
+                v1 = bitwise_xor(v1, rational::power_of_two(sz) - numeral(1));
             }
             else {
                 neg_args.mark(atom, true);
@@ -1399,7 +1400,7 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r
             else if (neg_args.is_marked(arg)) {
                 neg_args.mark(arg, false);
                 merged = true;
-                v1 = bitwise_xor(v1, m_util.power_of_two(sz) - numeral(1));
+                v1 = bitwise_xor(v1, rational::power_of_two(sz) - numeral(1));
             }
             else {
                 pos_args.mark(arg, true);
@@ -1455,7 +1456,7 @@ 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 != (m_util.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)))))
         return BR_FAILED;
 
     ptr_buffer<expr> new_args;
@@ -1527,6 +1528,14 @@ br_status bv_rewriter::mk_bv_not(expr * arg, expr_ref & result) {
     }
 #endif
 
+    if (m_bvnot2arith) {
+        // (bvnot x) --> (bvsub -1 x)
+        bv_size = get_bv_size(arg);
+        rational minus_one = (rational::power_of_two(bv_size) - numeral(1));
+        result = m_util.mk_bv_sub(m_util.mk_numeral(minus_one, bv_size), arg);
+        return BR_REWRITE1;
+    }
+
     return BR_FAILED;
 }
 
@@ -1611,7 +1620,7 @@ br_status bv_rewriter::mk_bv_redand(expr * arg, expr_ref & result) {
     numeral r;
     unsigned bv_size;
     if (is_numeral(arg, r, bv_size)) {
-        result = (r == m_util.power_of_two(bv_size) - numeral(1)) ? mk_numeral(1, 1) : mk_numeral(0, 1);
+        result = (r == rational::power_of_two(bv_size) - numeral(1)) ? mk_numeral(1, 1) : mk_numeral(0, 1);
         return BR_DONE;
     }
     return BR_FAILED;
@@ -1707,7 +1716,7 @@ bool bv_rewriter::is_zero_bit(expr * x, unsigned idx) {
     if (is_numeral(x, val, bv_size)) {
         if (val.is_zero())
             return true;
-        div(val, m_util.power_of_two(idx), val);
+        div(val, rational::power_of_two(idx), val);
         return (val % numeral(2)).is_zero();
     }
     if (m_util.is_concat(x)) {
diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h
index ba5ac5580..a94fd18c1 100644
--- a/src/ast/rewriter/bv_rewriter.h
+++ b/src/ast/rewriter/bv_rewriter.h
@@ -67,6 +67,7 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
     bool       m_mkbv2num;
     bool       m_split_concat_eq;
     bool       m_udiv2mul;
+    bool       m_bvnot2arith;
 
     bool is_zero_bit(expr * x, unsigned idx);
 
diff --git a/src/ast/rewriter/bv_rewriter_params.pyg b/src/ast/rewriter/bv_rewriter_params.pyg
index 780d8e724..d9ee9f7a3 100644
--- a/src/ast/rewriter/bv_rewriter_params.pyg
+++ b/src/ast/rewriter/bv_rewriter_params.pyg
@@ -7,4 +7,6 @@ def_module_params(module_name='rewriter',
                           ("blast_eq_value", BOOL, False, "blast (some) Bit-vector equalities into bits"),
                           ("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")))
+                          ("mul2concat", BOOL, False, "replace multiplication by a power of two into a concatenation"),
+                          ("bvnot2arith", BOOL, False, "replace (bvnot x) with (bvsub -1 x)")
+                          ))
diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp
index 9678af216..482e280e3 100644
--- a/src/ast/rewriter/float_rewriter.cpp
+++ b/src/ast/rewriter/float_rewriter.cpp
@@ -443,4 +443,4 @@ br_status float_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result
 
 br_status float_rewriter::mk_to_ieee_bv(expr * arg1, expr_ref & result) {
     return BR_FAILED;
-}
\ No newline at end of file
+}
diff --git a/src/ast/simplifier/bv_elim.cpp b/src/ast/simplifier/bv_elim.cpp
index 3238d13e7..5c19a245e 100644
--- a/src/ast/simplifier/bv_elim.cpp
+++ b/src/ast/simplifier/bv_elim.cpp
@@ -15,7 +15,7 @@ void bv_elim::elim(quantifier* q, quantifier_ref& r) {
     expr_ref         new_body(m_manager);
     expr*            old_body = q->get_expr();
     unsigned num_decls = q->get_num_decls();
-    family_id bfid = m_manager.get_family_id("bv");
+    family_id bfid = m_manager.mk_family_id("bv");
 
     //
     // Traverse sequence of bound variables to eliminate
diff --git a/src/ast/simplifier/bv_simplifier_plugin.cpp b/src/ast/simplifier/bv_simplifier_plugin.cpp
index 2da1f3bab..3ef55baba 100644
--- a/src/ast/simplifier/bv_simplifier_plugin.cpp
+++ b/src/ast/simplifier/bv_simplifier_plugin.cpp
@@ -76,9 +76,9 @@ app * bv_simplifier_plugin::mk_numeral(numeral const & n) {
 }
 
 app * bv_simplifier_plugin::mk_numeral(numeral const& n, unsigned bv_size) {
-    numeral r = mod(n, m_util.power_of_two(bv_size));
+    numeral r = mod(n, rational::power_of_two(bv_size));
     SASSERT(!r.is_neg());
-    SASSERT(r < m_util.power_of_two(bv_size));
+    SASSERT(r < rational::power_of_two(bv_size));
     return m_util.mk_numeral(r, bv_size);
 }
 
@@ -225,7 +225,7 @@ inline uint64 bv_simplifier_plugin::to_uint64(const numeral & n, unsigned bv_siz
     SASSERT(bv_size <= 64);
     numeral tmp = n;
     if (tmp.is_neg()) {
-        tmp = mod(tmp, m_util.power_of_two(bv_size));
+        tmp = mod(tmp, rational::power_of_two(bv_size));
     }
     SASSERT(tmp.is_nonneg());
     SASSERT(tmp.is_uint64());
@@ -235,7 +235,7 @@ inline uint64 bv_simplifier_plugin::to_uint64(const numeral & n, unsigned bv_siz
 #define MK_BV_OP(_oper_,_binop_) \
 rational bv_simplifier_plugin::mk_bv_ ## _oper_(numeral const& a0, numeral const& b0, unsigned sz) { \
     rational r(0), a(a0), b(b0); \
-    numeral p64 = m_util.power_of_two(64); \
+    numeral p64 = rational::power_of_two(64); \
     numeral mul(1); \
     while (sz > 0) { \
         numeral a1 = a % p64; \
@@ -260,7 +260,7 @@ MK_BV_OP(xor,^)
 
 rational bv_simplifier_plugin::mk_bv_not(numeral const& a0, unsigned sz) { 
     rational r(0), a(a0), mul(1);
-    numeral p64 = m_util.power_of_two(64); 
+    numeral p64 = rational::power_of_two(64); 
     while (sz > 0) { 
         numeral a1 = a % p64; 
         uint64 u = ~a1.get_uint64();
@@ -320,12 +320,12 @@ void bv_simplifier_plugin::mk_leq_core(bool is_signed, expr * arg1, expr * arg2,
 
     if (is_num1 || is_num2) {
         if (is_signed) {
-            lower = - m_util.power_of_two(bv_size - 1);
-            upper =   m_util.power_of_two(bv_size - 1) - numeral(1);
+            lower = - rational::power_of_two(bv_size - 1);
+            upper =   rational::power_of_two(bv_size - 1) - numeral(1);
         }
         else {
             lower = numeral(0);
-            upper = m_util.power_of_two(bv_size) - numeral(1);
+            upper = rational::power_of_two(bv_size) - numeral(1);
         }
     }
 
@@ -509,7 +509,7 @@ bool bv_simplifier_plugin::try_mk_extract(unsigned high, unsigned low, expr * ar
 
     if (m_util.is_numeral(a, r, num_bits)) {
         if (r.is_neg()) {
-            r = mod(r, m_util.power_of_two(sz));
+            r = mod(r, rational::power_of_two(sz));
         }
         SASSERT(r.is_nonneg());
         if (r.is_uint64()) {
@@ -520,7 +520,7 @@ bool bv_simplifier_plugin::try_mk_extract(unsigned high, unsigned low, expr * ar
             result = mk_numeral(numeral(e, numeral::ui64()), sz);
             return true;
         }
-        result = mk_numeral(div(r, m_util.power_of_two(low)), sz);
+        result = mk_numeral(div(r, rational::power_of_two(low)), sz);
         return true;
     }
     // (extract[high:low] (extract[high2:low2] x)) == (extract[high+low2 : low+low2] x)
@@ -902,7 +902,7 @@ void bv_simplifier_plugin::mk_concat(unsigned num_args, expr * const * args, exp
         --i;
         expr * arg   = args[i];
         if (is_numeral(arg, arg_val)) {
-            arg_val    *= m_util.power_of_two(shift);
+            arg_val    *= rational::power_of_two(shift);
             val        += arg_val;
             shift      += get_bv_size(arg);
             TRACE("bv_simplifier_plugin", 
@@ -1203,7 +1203,7 @@ bool bv_simplifier_plugin::is_minus_one_core(expr * arg) const {
     unsigned bv_size;
     if (m_util.is_numeral(arg, r, bv_size)) {
         numeral minus_one(-1);
-        minus_one = mod(minus_one, m_util.power_of_two(bv_size));
+        minus_one = mod(minus_one, rational::power_of_two(bv_size));
         return r == minus_one;
     }
     return false;
@@ -1295,7 +1295,7 @@ void bv_simplifier_plugin::mk_sign_extend(unsigned n, expr * arg, expr_ref & res
     if (m_util.is_numeral(arg, r, bv_size)) {
         unsigned result_bv_size = bv_size + n;
         r = norm(r, bv_size, true);
-        r = mod(r, m_util.power_of_two(result_bv_size));
+        r = mod(r, rational::power_of_two(result_bv_size));
         result = mk_numeral(r, result_bv_size);
         TRACE("mk_sign_extend", tout << "n: " << n << "\n"; 
               ast_ll_pp(tout, m_manager, arg); tout << "====>\n"; 
@@ -1373,7 +1373,7 @@ void bv_simplifier_plugin::mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result
     else if (is_num1 && is_num2) {
         SASSERT(r2 < rational(bv_size));
         SASSERT(r2.is_unsigned());
-        result = mk_numeral(r1 * m_util.power_of_two(r2.get_unsigned()), bv_size);
+        result = mk_numeral(r1 * rational::power_of_two(r2.get_unsigned()), bv_size);
     }
 
     //
@@ -1423,7 +1423,7 @@ void bv_simplifier_plugin::mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & resul
     else if (is_num1 && is_num2) {
         SASSERT(r2.is_unsigned());
         unsigned sh = r2.get_unsigned();
-        r1 = div(r1, m_util.power_of_two(sh));
+        r1 = div(r1, rational::power_of_two(sh));
         result = mk_numeral(r1, bv_size);
     }
     //
@@ -1804,8 +1804,8 @@ void bv_simplifier_plugin::mk_bv_rotate_left_core(unsigned shift, numeral r, uns
         result = mk_numeral(r, bv_size);        
     }
     else {
-        rational r1 = div(r, m_util.power_of_two(bv_size - shift)); // shift right
-        rational r2 = (r * m_util.power_of_two(shift)) % m_util.power_of_two(bv_size); // shift left
+        rational r1 = div(r, rational::power_of_two(bv_size - shift)); // shift right
+        rational r2 = (r * rational::power_of_two(shift)) % rational::power_of_two(bv_size); // shift left
         result = mk_numeral(r1 + r2, bv_size);
     }
 }
@@ -1831,8 +1831,8 @@ void bv_simplifier_plugin::mk_bv_rotate_right_core(unsigned shift, numeral r, un
         result = mk_numeral(r, bv_size);
     }
     else {
-        rational r1 = div(r, m_util.power_of_two(shift)); // shift right
-        rational r2 = (r * m_util.power_of_two(bv_size - shift)) % m_util.power_of_two(bv_size); // shift left
+        rational r1 = div(r, rational::power_of_two(shift)); // shift right
+        rational r2 = (r * rational::power_of_two(bv_size - shift)) % rational::power_of_two(bv_size); // shift left
         result = mk_numeral(r1 + r2, bv_size);            
     }
 }
@@ -1935,7 +1935,7 @@ void bv_simplifier_plugin::mk_bv_ashr(expr* arg1, expr* arg2, expr_ref& result)
     else if (is_num1 && is_num2) {
         SASSERT(r2 < rational(bv_size));
         bool   sign = has_sign_bit(r1, bv_size);
-        r1 = div(r1, m_util.power_of_two(r2.get_unsigned()));
+        r1 = div(r1, rational::power_of_two(r2.get_unsigned()));
         if (sign) {
             // pad ones.
             rational p(1);
diff --git a/src/ast/simplifier/bv_simplifier_plugin.h b/src/ast/simplifier/bv_simplifier_plugin.h
index 7f66566b6..36e773de0 100644
--- a/src/ast/simplifier/bv_simplifier_plugin.h
+++ b/src/ast/simplifier/bv_simplifier_plugin.h
@@ -172,7 +172,7 @@ public:
     app * mk_numeral(rational const & n, unsigned bv_size);
     app * mk_numeral(uint64 n, unsigned bv_size) { return mk_numeral(numeral(n, numeral::ui64()), bv_size); }
     app* mk_bv0(unsigned bv_size) { return m_util.mk_numeral(numeral(0), bv_size); }
-    rational mk_allone(unsigned bv_size) { return m_util.power_of_two(bv_size) - numeral(1); }
+    rational mk_allone(unsigned bv_size) { return rational::power_of_two(bv_size) - numeral(1); }
     bool is_minus_one_core(expr * arg) const;
     bool is_x_minus_one(expr * arg, expr * & x);
     void mk_int2bv(expr * arg, sort* range, expr_ref & result);
diff --git a/src/ast/simplifier/simplifier_plugin.h b/src/ast/simplifier/simplifier_plugin.h
index d95547a69..8e176ea6e 100644
--- a/src/ast/simplifier/simplifier_plugin.h
+++ b/src/ast/simplifier/simplifier_plugin.h
@@ -37,7 +37,7 @@ protected:
     void set_reduce_invoked() { m_reduce_invoked = true; }
 
 public:
-    simplifier_plugin(symbol const & fname, ast_manager & m):m_manager(m), m_fid(m.get_family_id(fname)), m_presimp(false), m_reduce_invoked(false) {}
+    simplifier_plugin(symbol const & fname, ast_manager & m):m_manager(m), m_fid(m.mk_family_id(fname)), m_presimp(false), m_reduce_invoked(false) {}
     
     bool reduce_invoked() const { return m_reduce_invoked; }
 
diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp
index 234626365..f40eb2c75 100644
--- a/src/ast/static_features.cpp
+++ b/src/ast/static_features.cpp
@@ -23,8 +23,8 @@ static_features::static_features(ast_manager & m):
     m_manager(m),
     m_autil(m),
     m_bfid(m.get_basic_family_id()),
-    m_afid(m.get_family_id("arith")),
-    m_lfid(m.get_family_id("label")),
+    m_afid(m.mk_family_id("arith")),
+    m_lfid(m.mk_family_id("label")),
     m_label_sym("label"),
     m_pattern_sym("pattern"),
     m_expr_list_sym("expr-list") {
diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp
index 8f65485ae..c1be7a69b 100644
--- a/src/cmd_context/basic_cmds.cpp
+++ b/src/cmd_context/basic_cmds.cpp
@@ -643,7 +643,7 @@ public:
 
     family_id get_array_fid(cmd_context & ctx) {
         if (m_array_fid == null_family_id) {
-            m_array_fid = ctx.m().get_family_id("array");
+            m_array_fid = ctx.m().mk_family_id("array");
         }
         return m_array_fid;
     }
diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp
index e86e56b69..043dc45e6 100644
--- a/src/cmd_context/cmd_context.cpp
+++ b/src/cmd_context/cmd_context.cpp
@@ -343,6 +343,13 @@ cmd_context::~cmd_context() {
     m_check_sat_result = 0;
 }
 
+void cmd_context::set_cancel(bool f) {
+    if (m_solver)
+        m_solver->set_cancel(f);
+    if (has_manager())
+        m().set_cancel(f);
+}
+
 void cmd_context::global_params_updated() {
     m_params.updt_params();
     if (m_solver) {
@@ -1379,7 +1386,7 @@ void cmd_context::set_diagnostic_stream(char const * name) {
 struct contains_array_op_proc {
     struct found {};
     family_id m_array_fid;
-    contains_array_op_proc(ast_manager & m):m_array_fid(m.get_family_id("array")) {}
+    contains_array_op_proc(ast_manager & m):m_array_fid(m.mk_family_id("array")) {}
     void operator()(var * n)        {}
     void operator()(app * n)        { 
         if (n->get_family_id() != m_array_fid)
diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h
index 63e5e7040..07b0cf456 100644
--- a/src/cmd_context/cmd_context.h
+++ b/src/cmd_context/cmd_context.h
@@ -249,6 +249,9 @@ protected:
 public:
     cmd_context(bool main_ctx = true, ast_manager * m = 0, symbol const & l = symbol::null);
     ~cmd_context(); 
+    void set_cancel(bool f);
+    void cancel() { set_cancel(true); }
+    void reset_cancel() { set_cancel(false); }
     context_params  & params() { return m_params; }
     void global_params_updated(); // this method should be invoked when global (and module) params are updated.
     void set_logic(symbol const & s);
diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp
index 6b55d4072..bafd76f0b 100644
--- a/src/cmd_context/pdecl.cpp
+++ b/src/cmd_context/pdecl.cpp
@@ -765,7 +765,7 @@ pdecl_manager::pdecl_manager(ast_manager & m):
     m_allocator(m.get_allocator()),
     m_new_dt_eh(0) {
     m_list = 0;
-    m_datatype_fid = m.get_family_id("datatype");
+    m_datatype_fid = m.mk_family_id("datatype");
 }
 
 pdecl_manager::~pdecl_manager() {
diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp
index 90ad6ea9d..804a134e0 100644
--- a/src/math/polynomial/algebraic_numbers.cpp
+++ b/src/math/polynomial/algebraic_numbers.cpp
@@ -2796,72 +2796,58 @@ namespace algebraic_numbers {
     }
 
     void manager::del(numeral & a) {
-        set_cancel(false);
         return m_imp->del(a);
     }
         
     void manager::reset(numeral & a) {
-        set_cancel(false);
         return m_imp->reset(a);
     }
     
     bool manager::is_zero(numeral const & a) {
-        set_cancel(false);
         return m_imp->is_zero(const_cast<numeral&>(a));
     }
 
     bool manager::is_pos(numeral const & a) {
-        set_cancel(false);
         return m_imp->is_pos(const_cast<numeral&>(a));
     }
 
     bool manager::is_neg(numeral const & a) {
-        set_cancel(false);
         return m_imp->is_neg(const_cast<numeral&>(a));
     }
 
     bool manager::is_rational(numeral const & a) {
-        set_cancel(false);
         return m_imp->is_rational(const_cast<numeral&>(a));
     }
 
     bool manager::is_int(numeral const & a) {
-        set_cancel(false);
         return m_imp->is_int(const_cast<numeral&>(a));
     }
 
     unsigned manager::degree(numeral const & a) {
-        set_cancel(false);
         return m_imp->degree(const_cast<numeral&>(a));
     }
 
     void manager::to_rational(numeral const & a, mpq & r) {
-        set_cancel(false);
         return m_imp->to_rational(const_cast<numeral&>(a), r);
     }
 
     void manager::to_rational(numeral const & a, rational & r) {
-        set_cancel(false);
         return m_imp->to_rational(const_cast<numeral&>(a), r);
     }
     
     void manager::swap(numeral & a, numeral & b) {
-        set_cancel(false);
         return m_imp->swap(a, b);
     }
 
     void manager::int_lt(numeral const & a, numeral & b) {
-        set_cancel(false);
         m_imp->int_lt(const_cast<numeral&>(a), b);
     }
 
     void manager::int_gt(numeral const & a, numeral & b) {
-        set_cancel(false);
         m_imp->int_gt(const_cast<numeral&>(a), b);
     }
 
     void manager::select(numeral const & prev, numeral const & curr, numeral & result) {
-        set_cancel(false);
         m_imp->select(const_cast<numeral&>(prev), const_cast<numeral&>(curr), result);
     }
 
@@ -2878,55 +2864,45 @@ namespace algebraic_numbers {
     }
     
     void manager::set(numeral & a, mpq const & n) {
-        set_cancel(false);
         m_imp->set(a, n);
     }
 
     void manager::set(numeral & a, numeral const & n) {
-        set_cancel(false);
         m_imp->set(a, n);
     }
         
     void manager::isolate_roots(polynomial_ref const & p, numeral_vector & roots) {
-        set_cancel(false);
         m_imp->isolate_roots(p, roots);
     }
 
     void manager::isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots) {
-        set_cancel(false);
         m_imp->isolate_roots(p, x2v, roots);
     }
 
     void manager::isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots, svector<int> & signs) {
-        set_cancel(false);
         m_imp->isolate_roots(p, x2v, roots, signs);
     }
 
     void manager::mk_root(polynomial_ref const & p, unsigned i, numeral & r) {
-        set_cancel(false);
         m_imp->mk_root(p, i, r);
     }
 
     void manager::mk_root(sexpr const * p, unsigned i, numeral & r) {
-        set_cancel(false);
         m_imp->mk_root(p, i, r);
     }
         
     void manager::root(numeral const & a, unsigned k, numeral & b) {
-        set_cancel(false);
         m_imp->root(const_cast<numeral&>(a), k, b);
     }
 
     void manager::power(numeral const & a, unsigned k, numeral & b) {
         TRACE("anum_detail", display_root(tout, a); tout << "^" << k << "\n";);
-        set_cancel(false);
         m_imp->power(const_cast<numeral&>(a), k, b);
         TRACE("anum_detail", tout << "^ result: "; display_root(tout, b); tout << "\n";);
     }
 
     void manager::add(numeral const & a, numeral const & b, numeral & c) {
         TRACE("anum_detail", display_root(tout, a); tout << " + "; display_root(tout, b); tout << "\n";);
-        set_cancel(false);
         m_imp->add(const_cast<numeral&>(a), const_cast<numeral&>(b), c);
         TRACE("anum_detail", tout << "+ result: "; display_root(tout, c); tout << "\n";);
     }
@@ -2939,45 +2915,37 @@ namespace algebraic_numbers {
 
     void manager::sub(numeral const & a, numeral const & b, numeral & c) {
         TRACE("anum_detail", display_root(tout, a); tout << " - "; display_root(tout, b); tout << "\n";);
-        set_cancel(false);
         m_imp->sub(const_cast<numeral&>(a), const_cast<numeral&>(b), c);
         TRACE("anum_detail", tout << "- result: "; display_root(tout, c); tout << "\n";);
     }
 
     void manager::mul(numeral const & a, numeral const & b, numeral & c) {
         TRACE("anum_detail", display_root(tout, a); tout << " * "; display_root(tout, b); tout << "\n";);
-        set_cancel(false);
         m_imp->mul(const_cast<numeral&>(a), const_cast<numeral&>(b), c);
         TRACE("anum_detail", tout << "* result: "; display_root(tout, c); tout << "\n";);
     }
 
     void manager::div(numeral const & a, numeral const & b, numeral & c) {
-        set_cancel(false);
         m_imp->div(const_cast<numeral&>(a), const_cast<numeral&>(b), c);
     }
 
     void manager::neg(numeral & a) {
-        set_cancel(false);
         m_imp->neg(a);
     }
 
     void manager::inv(numeral & a) {
-        set_cancel(false);
         m_imp->inv(a);
     }
 
     int manager::compare(numeral const & a, numeral const & b) {
-        set_cancel(false);
         return m_imp->compare(const_cast<numeral&>(a), const_cast<numeral&>(b));
     }
 
     bool manager::eq(numeral const & a, numeral const & b) {
-        set_cancel(false);
         return m_imp->eq(const_cast<numeral&>(a), const_cast<numeral&>(b));
     }
     
     bool manager::eq(numeral const & a, mpq const & b) {
-        set_cancel(false);
         return m_imp->eq(const_cast<numeral&>(a), b);
     }
 
@@ -2988,12 +2956,10 @@ namespace algebraic_numbers {
     }
 
     bool manager::lt(numeral const & a, numeral const & b) {
-        set_cancel(false);
         return m_imp->lt(const_cast<numeral&>(a), const_cast<numeral&>(b));
     }
     
     bool manager::lt(numeral const & a, mpq const & b) {
-        set_cancel(false);
         return m_imp->lt(const_cast<numeral&>(a), b);
     }
 
@@ -3004,7 +2970,6 @@ namespace algebraic_numbers {
     }
 
     bool manager::gt(numeral const & a, mpq const & b) {
-        set_cancel(false);
         return m_imp->gt(const_cast<numeral&>(a), b);
     }
 
@@ -3073,38 +3038,31 @@ namespace algebraic_numbers {
     }
 
     int manager::eval_sign_at(polynomial_ref const & p, polynomial::var2anum const & x2v) {
-        set_cancel(false);
         SASSERT(&(x2v.m()) == this);
         return m_imp->eval_sign_at(p, x2v);
     }
 
     void manager::display_interval(std::ostream & out, numeral const & a) const {
-        const_cast<manager*>(this)->set_cancel(false);
         m_imp->display_interval(out, a);
     }
 
     void manager::display_decimal(std::ostream & out, numeral const & a, unsigned precision) const {
-        const_cast<manager*>(this)->set_cancel(false);
         m_imp->display_decimal(out, a, precision);
     }
 
     void manager::display_root(std::ostream & out, numeral const & a) const {
-        const_cast<manager*>(this)->set_cancel(false);
         m_imp->display_root(out, a);
     }
 
     void manager::display_mathematica(std::ostream & out, numeral const & a) const {
-        const_cast<manager*>(this)->set_cancel(false);
         m_imp->display_mathematica(out, a);
     }
 
     void manager::display_root_smt2(std::ostream & out, numeral const & a) const {
-        const_cast<manager*>(this)->set_cancel(false);
         m_imp->display_root_smt2(out, a);
     }
 
     void manager::reset_statistics() {
-        set_cancel(false);
         m_imp->reset_statistics();
     }
         
diff --git a/src/math/polynomial/algebraic_numbers.h b/src/math/polynomial/algebraic_numbers.h
index a4669eae6..d11237b86 100644
--- a/src/math/polynomial/algebraic_numbers.h
+++ b/src/math/polynomial/algebraic_numbers.h
@@ -64,8 +64,8 @@ namespace algebraic_numbers {
         static void collect_param_descrs(param_descrs & r) { get_param_descrs(r); }
 
         void set_cancel(bool f);
-        
         void cancel() { set_cancel(true); }
+        void reset_cancel() { set_cancel(false); }
 
         void updt_params(params_ref const & p);
 
diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp
index 4e14c5661..f5d96e740 100644
--- a/src/math/polynomial/polynomial.cpp
+++ b/src/math/polynomial/polynomial.cpp
@@ -2368,7 +2368,6 @@ namespace polynomial {
 
         void checkpoint() {
             if (m_cancel) {
-                set_cancel(false);
                 throw polynomial_exception("canceled");
             }
             cooperate("polynomial");
diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h
index d17d2ac5a..e52dd4fee 100644
--- a/src/math/polynomial/polynomial.h
+++ b/src/math/polynomial/polynomial.h
@@ -220,6 +220,7 @@ namespace polynomial {
 
         void set_cancel(bool f);
         void cancel() { set_cancel(true); }
+        void reset_cancel() { set_cancel(false); }
 
         /**
            \brief Abstract event handler.
diff --git a/src/math/polynomial/polynomial_factorization.cpp b/src/math/polynomial/polynomial_factorization.cpp
index e0f050411..220048a9a 100644
--- a/src/math/polynomial/polynomial_factorization.cpp
+++ b/src/math/polynomial/polynomial_factorization.cpp
@@ -16,7 +16,7 @@ Author:
 Notes:
 
    [1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal, 
-       46(8-10):1853�1859, 1967.
+       46(8-10):1853-1859, 1967.
    [2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third 
        edition, 1997.
    [3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993.
diff --git a/src/math/polynomial/polynomial_factorization.h b/src/math/polynomial/polynomial_factorization.h
index 48b4efd98..f069121ba 100644
--- a/src/math/polynomial/polynomial_factorization.h
+++ b/src/math/polynomial/polynomial_factorization.h
@@ -16,7 +16,7 @@ Author:
 Notes:
 
    [1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal, 
-       46(8-10):1853�1859, 1967.
+       46(8-10):1853-1859, 1967.
    [2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third 
        edition, 1997.
    [3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993.
diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp
index a1e28e727..230d352f3 100644
--- a/src/math/polynomial/upolynomial_factorization.cpp
+++ b/src/math/polynomial/upolynomial_factorization.cpp
@@ -16,7 +16,7 @@ Author:
 Notes:
 
    [1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal, 
-       46(8-10):1853�1859, 1967.
+       46(8-10):1853-1859, 1967.
    [2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third 
        edition, 1997.
    [3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993.
diff --git a/src/math/polynomial/upolynomial_factorization.h b/src/math/polynomial/upolynomial_factorization.h
index e687786da..327fffc9c 100644
--- a/src/math/polynomial/upolynomial_factorization.h
+++ b/src/math/polynomial/upolynomial_factorization.h
@@ -16,7 +16,7 @@ Author:
 Notes:
 
    [1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal, 
-       46(8-10):1853�1859, 1967.
+       46(8-10):1853-1859, 1967.
    [2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third 
        edition, 1997.
    [3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993.
diff --git a/src/math/polynomial/upolynomial_factorization_int.h b/src/math/polynomial/upolynomial_factorization_int.h
index c076b2e6d..92d62301d 100644
--- a/src/math/polynomial/upolynomial_factorization_int.h
+++ b/src/math/polynomial/upolynomial_factorization_int.h
@@ -17,7 +17,7 @@ Author:
 Notes:
 
    [1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal, 
-       46(8-10):1853�1859, 1967.
+       46(8-10):1853-1859, 1967.
    [2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third 
        edition, 1997.
    [3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993.
diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp
index beed0061e..dc4c20aa8 100644
--- a/src/model/model_evaluator.cpp
+++ b/src/model/model_evaluator.cpp
@@ -244,10 +244,10 @@ unsigned model_evaluator::get_num_steps() const {
     return m_imp->get_num_steps();
 }
 
-void model_evaluator::cancel() {
+void model_evaluator::set_cancel(bool f) {
     #pragma omp critical (model_evaluator)
     {
-        m_imp->cancel();
+        m_imp->set_cancel(f);
     }
 }
 
diff --git a/src/model/model_evaluator.h b/src/model/model_evaluator.h
index aad06739b..1a7469c6c 100644
--- a/src/model/model_evaluator.h
+++ b/src/model/model_evaluator.h
@@ -41,7 +41,9 @@ public:
 
     void operator()(expr * t, expr_ref & r);
 
-    void cancel();
+    void set_cancel(bool f);
+    void cancel() { set_cancel(true); }
+    void reset_cancel() { set_cancel(false); }
     void cleanup(params_ref const & p = params_ref());
     void reset(params_ref const & p = params_ref());
     
diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp
index a01d4c322..221c2d2a2 100644
--- a/src/muz_qe/dl_bmc_engine.cpp
+++ b/src/muz_qe/dl_bmc_engine.cpp
@@ -963,7 +963,7 @@ namespace datalog {
             
             
             sort_ref_vector new_sorts(m);
-            family_id dfid = m.get_family_id("datatype");
+            family_id dfid = m.mk_family_id("datatype");
             datatype_decl_plugin* dtp = static_cast<datatype_decl_plugin*>(m.get_plugin(dfid));
             VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), new_sorts));
             
diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp
index bf9c24203..c88e7346e 100644
--- a/src/muz_qe/dl_cmds.cpp
+++ b/src/muz_qe/dl_cmds.cpp
@@ -75,7 +75,7 @@ struct dl_context {
         if (!m_decl_plugin) {
             symbol name("datalog_relation");
             if (m.has_plugin(name)) {
-                m_decl_plugin = static_cast<datalog::dl_decl_plugin*>(m_cmd.m().get_plugin(m.get_family_id(name)));
+                m_decl_plugin = static_cast<datalog::dl_decl_plugin*>(m_cmd.m().get_plugin(m.mk_family_id(name)));
             }
             else {
                 m_decl_plugin = alloc(datalog::dl_decl_plugin);
diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h
index f84050e68..d3309beb5 100644
--- a/src/muz_qe/dl_context.h
+++ b/src/muz_qe/dl_context.h
@@ -349,6 +349,7 @@ namespace datalog {
         void cancel();
 
         void cleanup();
+        void reset_cancel() { cleanup(); }
 
         /**
            \brief check if query 'q' is satisfied under asserted rules and background.
diff --git a/src/muz_qe/dl_mk_slice.cpp b/src/muz_qe/dl_mk_slice.cpp
index 2ff341e07..84b732280 100644
--- a/src/muz_qe/dl_mk_slice.cpp
+++ b/src/muz_qe/dl_mk_slice.cpp
@@ -429,6 +429,29 @@ namespace datalog {
         }
     }
 
+    void mk_slice::filter_unique_vars(rule& r) {
+        // 
+        // Variables that occur in multiple uinterpreted predicates are not sliceable.
+        // 
+        uint_set used_vars;
+        for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
+            app* p = r.get_tail(j);
+            for (unsigned i = 0; i < p->get_num_args(); ++i) {
+                expr* v = p->get_arg(i);
+                if (is_var(v)) {
+                    unsigned vi = to_var(v)->get_idx();
+                    add_var(vi);
+                    if (used_vars.contains(vi)) {
+                        m_var_is_sliceable[vi] = false;
+                    }
+                    else {
+                        used_vars.insert(vi);
+                    }
+                }
+            }
+        }
+    }
+
     void mk_slice::solve_vars(rule& r, uint_set& used_vars, uint_set& parameter_vars) {
         expr_ref_vector conjs = get_tail_conjs(r);
         for (unsigned j = 0; j < conjs.size(); ++j) {
@@ -475,6 +498,7 @@ namespace datalog {
                 }
             }
         }   
+        filter_unique_vars(r);
         //
         // Collect the set of variables that are solved.
         // Collect the occurrence count of the variables per conjunct.
@@ -750,51 +774,11 @@ namespace datalog {
             
             m_solved_vars.reset();
 
-#if 0
-            uint_set used_vars;
-            expr_ref b(m);
-
-        TBD: buggy code:
             for (unsigned i = 0; i < conjs.size(); ++i) {
                 expr* e = conjs[i].get();
-                if (is_eq(e, v, b)) {
-                    if (v >= m_solved_vars.size()) {
-                        m_solved_vars.resize(v+1);
-                    }
-                    if (v < sorts.size() && sorts[v]) {
-                        TRACE("dl", tout << "already bound " << mk_pp(e, m) << "\n";);
-                        add_free_vars(used_vars, e);
-                    }
-                    else if (m_solved_vars[v].get()) {
-                        TRACE("dl", tout << "already solved " << mk_pp(e, m) << "\n";);
-                        add_free_vars(used_vars, e);
-                        add_free_vars(used_vars, m_solved_vars[v].get());
-                        used_vars.insert(v);
-                    }
-                    else {
-                        TRACE("dl", tout << "new solution " << mk_pp(e, m) << "\n";);
-                        m_solved_vars[v] = b;
-                    }
-                }
-                else {
-                    TRACE("dl", tout << "not solved " << mk_pp(e, m) << "\n";);
-                    add_free_vars(used_vars, e);
-                }
+                tail.push_back(to_app(e));                
             }
-#endif
-            for (unsigned i = 0; i < conjs.size(); ++i) {
-                expr* e = conjs[i].get();
-#if 0
-                if (false && is_eq(e, v, b) && m_solved_vars[v].get() && !used_vars.contains(v)) {
-                    TRACE("dl", tout << "removing conjunct: " << mk_pp(e, m) << "\n";);
-                    // skip conjunct
-                }
-#endif
-                tail.push_back(to_app(e));
-                
-            }
-            
-            
+                        
             new_rule = rm.mk(head.get(), tail.size(), tail.c_ptr(), (const bool*) 0);        
 
             rm.fix_unbound_vars(new_rule, false);
diff --git a/src/muz_qe/dl_mk_slice.h b/src/muz_qe/dl_mk_slice.h
index d798430d5..26a8175f2 100644
--- a/src/muz_qe/dl_mk_slice.h
+++ b/src/muz_qe/dl_mk_slice.h
@@ -89,6 +89,8 @@ namespace datalog {
 
         void update_predicate(app* p, app_ref& q);
 
+        void filter_unique_vars(rule& r);
+
         void solve_vars(rule& r, uint_set& used_vars, uint_set& parameter_vars);
 
     public:
diff --git a/src/muz_qe/dl_relation_manager.h b/src/muz_qe/dl_relation_manager.h
index 270e06f12..ecba3d598 100644
--- a/src/muz_qe/dl_relation_manager.h
+++ b/src/muz_qe/dl_relation_manager.h
@@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation
 
 Module Name:
 
-    dl_remation_manager.h
+    dl_relation_manager.h
 
 Abstract:
 
@@ -316,7 +316,7 @@ namespace datalog {
                 oldTgt:=tgt.clone();
                 tgt:=tgt \union src
                 if(tgt!=oldTgt) {
-                    delta:=delta \union src    //also �delta \union tgt� would work
+                    delta:=delta \union src    //also ?delta \union tgt? would work
                 }
             }
 
@@ -488,7 +488,7 @@ namespace datalog {
                 oldTgt:=tgt.clone();
                 tgt:=tgt \union src
                 if(tgt!=oldTgt) {
-                    delta:=delta \union src    //also �delta \union tgt� would work
+                    delta:=delta \union src    //also ?delta \union tgt? would work
                 }
             }
 
diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp
index bd7131fea..d34f8a67f 100644
--- a/src/muz_qe/dl_rule.cpp
+++ b/src/muz_qe/dl_rule.cpp
@@ -74,7 +74,7 @@ namespace datalog {
     class remove_label_cfg : public default_rewriter_cfg {
         family_id m_label_fid;
     public:        
-        remove_label_cfg(ast_manager& m): m_label_fid(m.get_family_id("label")) {}
+        remove_label_cfg(ast_manager& m): m_label_fid(m.get_label_family_id()) {}
         virtual ~remove_label_cfg() {}
 
         br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, 
diff --git a/src/muz_qe/proof_utils.cpp b/src/muz_qe/proof_utils.cpp
index 0b24d6c8b..038b08c5c 100644
--- a/src/muz_qe/proof_utils.cpp
+++ b/src/muz_qe/proof_utils.cpp
@@ -489,7 +489,7 @@ static void permute_unit_resolution(expr_ref_vector& refs, obj_map<proof,proof*>
         parameter const* params = thLemma->get_decl()->get_parameters();
         unsigned num_params = thLemma->get_decl()->get_num_parameters();
         SASSERT(params[0].is_symbol());
-        family_id tid = m.get_family_id(params[0].get_symbol());
+        family_id tid = m.mk_family_id(params[0].get_symbol());
         SASSERT(tid != null_family_id);
         prNew = m.mk_th_lemma(tid, m.get_fact(pr), 
                               premises.size(), premises.c_ptr(), num_params-1, params+1);
diff --git a/src/muz_qe/qe_arith_plugin.cpp b/src/muz_qe/qe_arith_plugin.cpp
index 69c036639..4e158229b 100644
--- a/src/muz_qe/qe_arith_plugin.cpp
+++ b/src/muz_qe/qe_arith_plugin.cpp
@@ -1512,7 +1512,7 @@ public:
 
     public:
         arith_plugin(i_solver_context& ctx, ast_manager& m, smt_params& p): 
-            qe_solver_plugin(m, m.get_family_id("arith"), ctx),
+            qe_solver_plugin(m, m.mk_family_id("arith"), ctx),
             m_util(m, p, ctx),
             m_trail(m)
         {}
@@ -2403,7 +2403,7 @@ public:
         bool                         m_produce_models;
     public:
         nlarith_plugin(i_solver_context& ctx, ast_manager& m, bool produce_models) : 
-            qe_solver_plugin(m, m.get_family_id("arith"), ctx),
+            qe_solver_plugin(m, m.mk_family_id("arith"), ctx),
             m_rewriter(m),
             m_util(m),
             m_replacer(mk_default_expr_replacer(m)),
diff --git a/src/muz_qe/qe_array_plugin.cpp b/src/muz_qe/qe_array_plugin.cpp
index c013f93f4..106a42338 100644
--- a/src/muz_qe/qe_array_plugin.cpp
+++ b/src/muz_qe/qe_array_plugin.cpp
@@ -16,7 +16,7 @@ namespace qe {
     public:
 
         array_plugin(i_solver_context& ctx, ast_manager& m) : 
-            qe_solver_plugin(m, m.get_family_id("array"), ctx),
+            qe_solver_plugin(m, m.mk_family_id("array"), ctx),
             m_replace(mk_default_expr_replacer(m))
         {
         }
diff --git a/src/muz_qe/qe_bv_plugin.cpp b/src/muz_qe/qe_bv_plugin.cpp
index 8712061d6..cae567111 100644
--- a/src/muz_qe/qe_bv_plugin.cpp
+++ b/src/muz_qe/qe_bv_plugin.cpp
@@ -32,7 +32,7 @@ namespace qe {
         bv_util      m_bv;
     public:
         bv_plugin(i_solver_context& ctx, ast_manager& m): 
-            qe_solver_plugin(m, m.get_family_id("bv"), ctx),
+            qe_solver_plugin(m, m.mk_family_id("bv"), ctx),
             m_replace(mk_default_expr_replacer(m)),
             m_bv(m)
         {}
diff --git a/src/muz_qe/qe_datatype_plugin.cpp b/src/muz_qe/qe_datatype_plugin.cpp
index 3978a9ba4..0b51f26af 100644
--- a/src/muz_qe/qe_datatype_plugin.cpp
+++ b/src/muz_qe/qe_datatype_plugin.cpp
@@ -422,7 +422,7 @@ namespace qe {
 
     public:
         datatype_plugin(i_solver_context& ctx, ast_manager& m) : 
-            qe_solver_plugin(m, m.get_family_id("datatype"), ctx),
+            qe_solver_plugin(m, m.mk_family_id("datatype"), ctx),
             m_datatype_util(m),
             m_replace(mk_default_expr_replacer(m)),
             m_trail(m)
diff --git a/src/muz_qe/qe_dl_plugin.cpp b/src/muz_qe/qe_dl_plugin.cpp
index 23f43759d..15e972e88 100644
--- a/src/muz_qe/qe_dl_plugin.cpp
+++ b/src/muz_qe/qe_dl_plugin.cpp
@@ -45,7 +45,7 @@ namespace qe {
         
     public:
         dl_plugin(i_solver_context& ctx, ast_manager& m) : 
-            qe_solver_plugin(m, m.get_family_id("datalog_relation"), ctx),
+            qe_solver_plugin(m, m.mk_family_id("datalog_relation"), ctx),
             m_replace(mk_default_expr_replacer(m)),
             m_util(m),
             m_trail(m)
diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp
index df4a55475..6949c4264 100644
--- a/src/muz_qe/qe_lite.cpp
+++ b/src/muz_qe/qe_lite.cpp
@@ -971,15 +971,15 @@ namespace fm {
         }
         
         bool is_linear_ineq(expr * t) const {
+            bool result = false;
             m.is_not(t, t);
             expr * lhs, * rhs;
-            TRACE("is_occ_bug", tout << mk_pp(t, m) << "\n";);
             if (m_util.is_le(t, lhs, rhs) || m_util.is_ge(t, lhs, rhs)) {
-                if (!m_util.is_numeral(rhs))
-                    return false;
-                return is_linear_pol(lhs);
+                result = m_util.is_numeral(rhs) && is_linear_pol(lhs);
             }
-            return false;
+            TRACE("qe_lite", tout << mk_pp(t, m) << " " << (result?"true":"false") << "\n";);
+
+            return result;
         }
         
         bool is_occ(expr * t) {
@@ -1049,7 +1049,7 @@ namespace fm {
             cnstr->m_xs         = reinterpret_cast<var*>(mem_xs);
             cnstr->m_as         = reinterpret_cast<rational*>(mem_as);
             for (unsigned i = 0; i < num_vars; i++) {
-                TRACE("mk_constraint_bug", tout << "xs[" << i << "]: " << xs[i] << "\n";);
+                TRACE("qe_lite", tout << "xs[" << i << "]: " << xs[i] << "\n";);
                 cnstr->m_xs[i] = xs[i];
                 new (cnstr->m_as + i) rational(as[i]);
             }
@@ -1241,7 +1241,7 @@ namespace fm {
                 if (c2->m_dead)
                     continue;
                 if (subsumes(c, *c2)) {
-                    TRACE("fm_subsumption", display(tout, c); tout << "\nsubsumed:\n"; display(tout, *c2); tout << "\n";);
+                    TRACE("qe_lite", display(tout, c); tout << "\nsubsumed:\n"; display(tout, *c2); tout << "\n";);
                     c2->m_dead = true;
                     continue;
                 }
@@ -1284,12 +1284,12 @@ namespace fm {
         }
         
         void updt_params() {
-            m_fm_real_only   = true;
+            m_fm_real_only   = false;
             m_fm_limit       = 5000000;
             m_fm_cutoff1     = 8;
             m_fm_cutoff2     = 256;
             m_fm_extra       = 0;
-            m_fm_occ         = false;
+            m_fm_occ         = true;
         }
         
         void set_cancel(bool f) {
@@ -1318,7 +1318,7 @@ namespace fm {
                 expr * f = g[i];
                 if (is_occ(f))
                     continue;
-                TRACE("is_occ_bug", tout << "not OCC:\n" << mk_ismt2_pp(f, m) << "\n";);
+                TRACE("qe_lite", tout << "not OCC:\n" << mk_ismt2_pp(f, m) << "\n";);
                 quick_for_each_expr(proc, visited, f);
             }
         }
@@ -1447,6 +1447,7 @@ namespace fm {
             SASSERT(m_uppers.size()    == m_is_int.size());
             SASSERT(m_forbidden.size() == m_is_int.size()); 
             SASSERT(m_var2pos.size()   == m_is_int.size());
+            TRACE("qe_lite", tout << mk_pp(t,m) << " |-> " << x << " forbidden: " << forbidden << "\n";);
             return x;
         }
         
@@ -1468,7 +1469,7 @@ namespace fm {
                 x = mk_var(t);
             SASSERT(m_expr2var.contains(t));
             SASSERT(m_var2expr.get(x) == t);
-            TRACE("to_var_bug", tout << mk_ismt2_pp(t, m) << " --> " << x << "\n";);
+            TRACE("qe_lite", tout << mk_ismt2_pp(t, m) << " --> " << x << "\n";);
             return x;
         }
         
@@ -1488,6 +1489,7 @@ namespace fm {
         
         
         void add_constraint(expr * f, expr_dependency * dep) {
+            TRACE("qe_lite", tout << mk_pp(f, m) << "\n";);
             SASSERT(!m.is_or(f) || m_fm_occ);
             sbuffer<literal> lits;
             sbuffer<var>     xs;
@@ -1524,7 +1526,7 @@ namespace fm {
                         neg = !neg;
                     expr * lhs = to_app(l)->get_arg(0);
                     expr * rhs = to_app(l)->get_arg(1);
-                    m_util.is_numeral(rhs, c);
+                    VERIFY (m_util.is_numeral(rhs, c));
                     if (neg)
                         c.neg();
                     unsigned num_mons;
@@ -1567,7 +1569,7 @@ namespace fm {
                 }
             }
             
-            TRACE("to_var_bug", tout << "before mk_constraint: "; for (unsigned i = 0; i < xs.size(); i++) tout << " " << xs[i]; tout << "\n";);
+            TRACE("qe_lite", tout << "before mk_constraint: "; for (unsigned i = 0; i < xs.size(); i++) tout << " " << xs[i]; tout << "\n";);
             
             constraint * new_c = mk_constraint(lits.size(),
                                                lits.c_ptr(),
@@ -1578,7 +1580,7 @@ namespace fm {
                                                strict,
                                                dep);
             
-            TRACE("to_var_bug", tout << "add_constraint: "; display(tout, *new_c); tout << "\n";);
+            TRACE("qe_lite", tout << "add_constraint: "; display(tout, *new_c); tout << "\n";);
             VERIFY(register_constraint(new_c));
         }
         
@@ -1591,7 +1593,7 @@ namespace fm {
             if (is_false(*c)) {
                 del_constraint(c);
                 m_inconsistent = true;
-                TRACE("add_constraint_bug", tout << "is false "; display(tout, *c); tout << "\n";);
+                TRACE("qe_lite", tout << "is false "; display(tout, *c); tout << "\n";);
                 return false;
             }
             
@@ -1614,7 +1616,7 @@ namespace fm {
                 return true;
             }
             else {
-                TRACE("add_constraint_bug", tout << "all variables are forbidden "; display(tout, *c); tout << "\n";);
+                TRACE("qe_lite", tout << "all variables are forbidden "; display(tout, *c); tout << "\n";);
                 m_new_fmls.push_back(to_expr(*c));
                 del_constraint(c);
                 return false;
@@ -1668,7 +1670,7 @@ namespace fm {
             }
             // x_cost_lt is not a total order on variables
             std::stable_sort(x_cost_vector.begin(), x_cost_vector.end(), x_cost_lt(m_is_int));
-            TRACE("fm", 
+            TRACE("qe_lite", 
                   svector<x_cost>::iterator it2  = x_cost_vector.begin();
                   svector<x_cost>::iterator end2 = x_cost_vector.end();
                   for (; it2 != end2; ++it2) {
@@ -1854,7 +1856,7 @@ namespace fm {
             
             if (new_xs.empty() && (new_c.is_pos() || (!new_strict && new_c.is_zero()))) {
                 // literal is true
-                TRACE("fm", tout << "resolution " << x << " consequent literal is always true: \n";
+                TRACE("qe_lite", tout << "resolution " << x << " consequent literal is always true: \n";
                       display(tout, l);
                       tout << "\n";
                       display(tout, u); tout << "\n";);
@@ -1898,7 +1900,7 @@ namespace fm {
             }
             
             if (tautology) {
-                TRACE("fm", tout << "resolution " << x << " tautology: \n";
+                TRACE("qe_lite", tout << "resolution " << x << " tautology: \n";
                       display(tout, l);
                       tout << "\n";
                       display(tout, u); tout << "\n";);
@@ -1908,7 +1910,7 @@ namespace fm {
             expr_dependency * new_dep = m.mk_join(l.m_dep, u.m_dep);
             
             if (new_lits.empty() && new_xs.empty() && (new_c.is_neg() || (new_strict && new_c.is_zero()))) {
-                TRACE("fm", tout << "resolution " << x << " inconsistent: \n";
+                TRACE("qe_lite", tout << "resolution " << x << " inconsistent: \n";
                       display(tout, l);
                       tout << "\n";
                       display(tout, u); tout << "\n";);
@@ -1926,7 +1928,7 @@ namespace fm {
                                                    new_strict,
                                                    new_dep);
 
-            TRACE("fm", tout << "resolution " << x << "\n";
+            TRACE("qe_lite", tout << "resolution " << x << "\n";
                   display(tout, l);
                   tout << "\n";
                   display(tout, u);
@@ -1949,7 +1951,7 @@ namespace fm {
             if (l.empty() || u.empty()) {
                 // easy case
                 mark_constraints_dead(x);
-                TRACE("fm", tout << "variable was eliminated (trivial case)\n";);
+                TRACE("qe_lite", tout << "variable was eliminated (trivial case)\n";);
                 return true;
             }
             
@@ -1967,7 +1969,7 @@ namespace fm {
             
             m_counter += num_lowers * num_uppers;
             
-            TRACE("fm_bug", tout << "eliminating " << mk_ismt2_pp(m_var2expr.get(x), m) << "\nlowers:\n";
+            TRACE("qe_lite", tout << "eliminating " << mk_ismt2_pp(m_var2expr.get(x), m) << "\nlowers:\n";
                   display_constraints(tout, l); tout << "uppers:\n"; display_constraints(tout, u););
             
             unsigned num_old_cnstrs = num_uppers + num_lowers;
@@ -1977,7 +1979,7 @@ namespace fm {
             for (unsigned i = 0; i < num_lowers; i++) {
                 for (unsigned j = 0; j < num_uppers; j++) {
                     if (m_inconsistent || num_new_cnstrs > limit) {
-                        TRACE("fm", tout << "too many new constraints: " << num_new_cnstrs << "\n";);
+                        TRACE("qe_lite", tout << "too many new constraints: " << num_new_cnstrs << "\n";);
                         del_constraints(new_constraints.size(), new_constraints.c_ptr());
                         return false;
                     }
@@ -2002,7 +2004,7 @@ namespace fm {
                 backward_subsumption(*c);
                 register_constraint(c);
             }
-            TRACE("fm", tout << "variables was eliminated old: " << num_old_cnstrs << " new_constraints: " << sz << "\n";);
+            TRACE("qe_lite", tout << "variables was eliminated old: " << num_old_cnstrs << " new_constraints: " << sz << "\n";);
             return true;
         }
         
@@ -2018,7 +2020,7 @@ namespace fm {
                     if (!c->m_dead) {
                         c->m_dead = true;
                         expr * new_f = to_expr(*c);
-                        TRACE("fm_bug", tout << "asserting...\n" << mk_ismt2_pp(new_f, m) << "\nnew_dep: " << c->m_dep << "\n";);
+                        TRACE("qe_lite", tout << "asserting...\n" << mk_ismt2_pp(new_f, m) << "\nnew_dep: " << c->m_dep << "\n";);
                         m_new_fmls.push_back(new_f);
                     }
                 }
@@ -2049,7 +2051,7 @@ namespace fm {
                 m_new_fmls.push_back(m.mk_false());
             }
             else {
-                TRACE("fm", display(tout););
+                TRACE("qe_lite", display(tout););
                 
                 subsume();
                 var_vector candidates;
diff --git a/src/parsers/smt/smtparser.cpp b/src/parsers/smt/smtparser.cpp
index d3b2feeb7..c1ebd251b 100644
--- a/src/parsers/smt/smtparser.cpp
+++ b/src/parsers/smt/smtparser.cpp
@@ -483,13 +483,13 @@ public:
 class array_sort : public builtin_sort_builder {
 public:
     array_sort(ast_manager& m) : 
-        builtin_sort_builder(m, m.get_family_id("array"), ARRAY_SORT) {}
+        builtin_sort_builder(m, m.mk_family_id("array"), ARRAY_SORT) {}
 };
 
 class bv_sort : public builtin_sort_builder {
 public:
     bv_sort(ast_manager& m) : 
-        builtin_sort_builder(m, m.get_family_id("bv"), BV_SORT) {}
+        builtin_sort_builder(m, m.mk_family_id("bv"), BV_SORT) {}
 };
 
 class user_sort : public sort_builder {    
@@ -538,7 +538,7 @@ class smtparser : public parser {
     public:
         add_plugins(ast_manager& m) {
 #define REGISTER_PLUGIN(NAME, MK) {                             \
-                family_id fid = m.get_family_id(symbol(NAME));  \
+                family_id fid = m.mk_family_id(symbol(NAME));  \
                 if (!m.has_plugin(fid)) {                       \
                     m.register_plugin(fid, MK);                 \
                 }                                                       \
@@ -681,7 +681,7 @@ public:
         smtlib::symtable* table = m_benchmark.get_symtable();
 
         symbol arith("arith");
-        family_id afid = m_manager.get_family_id(arith);
+        family_id afid = m_manager.mk_family_id(arith);
         m_arith_fid = afid;
 
         add_builtin_type("Int", afid, INT_SORT);
@@ -694,7 +694,7 @@ public:
         add_builtins(afid);
         
         symbol bv("bv");
-        family_id bfid = m_manager.get_family_id(bv);
+        family_id bfid = m_manager.mk_family_id(bv);
         m_bv_fid = bfid;        
 
         add_builtins(bfid);
@@ -702,7 +702,7 @@ public:
         add_builtin_type("BitVec", bfid, BV_SORT);
 
         symbol array("array");
-        afid = m_manager.get_family_id(array);
+        afid = m_manager.mk_family_id(array);
         m_array_fid = afid;
 
         add_builtins(afid);
diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp
index c99c362bd..0698f4eaf 100644
--- a/src/parsers/smt2/smt2parser.cpp
+++ b/src/parsers/smt2/smt2parser.cpp
@@ -390,6 +390,7 @@ namespace smt2 {
         void check_float(char const * msg) { if (!curr_is_float()) throw parser_exception(msg); }
 
         void error(unsigned line, unsigned pos, char const * msg) {
+            m_ctx.reset_cancel();
             if (use_vs_format()) {
                 m_ctx.diagnostic_stream() << "Z3(" << line << ", " << pos << "): ERROR: " << msg;
                 if (msg[strlen(msg)-1] != '\n')
diff --git a/src/parsers/util/pattern_validation.h b/src/parsers/util/pattern_validation.h
index d78502a8f..99024097e 100644
--- a/src/parsers/util/pattern_validation.h
+++ b/src/parsers/util/pattern_validation.h
@@ -32,11 +32,10 @@ class pattern_validator {
 public:
     pattern_validator(ast_manager const & m):
         m_bfid(m.get_basic_family_id()),
-        m_lfid(m.get_family_id("label")) {
+        m_lfid(m.get_label_family_id()) {
     }
 
     bool operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n);
-
     bool operator()(unsigned num_new_bindings, expr * n) { return operator()(UINT_MAX, num_new_bindings, n); }
 };
 
diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp
index 5552050db..3155d9c58 100644
--- a/src/smt/asserted_formulas.cpp
+++ b/src/smt/asserted_formulas.cpp
@@ -439,6 +439,8 @@ void asserted_formulas::nnf_cnf() {
         expr_ref   r1(m_manager);
         proof_ref  pr1(m_manager);
         CASSERT("well_sorted",is_well_sorted(m_manager, n));
+        push_todo.reset();
+        push_todo_prs.reset();
         apply_nnf(n, push_todo, push_todo_prs, r1, pr1);
         CASSERT("well_sorted",is_well_sorted(m_manager, r1));
         pr = m_manager.mk_modus_ponens(pr, pr1);
@@ -855,3 +857,8 @@ void asserted_formulas::max_bv_sharing() {
     
 }
 
+#ifdef Z3DEBUG
+void pp(asserted_formulas & f) {
+    f.display(std::cout);
+}
+#endif
diff --git a/src/smt/proto_model/array_factory.cpp b/src/smt/proto_model/array_factory.cpp
index b91857e40..a929f6d9a 100644
--- a/src/smt/proto_model/array_factory.cpp
+++ b/src/smt/proto_model/array_factory.cpp
@@ -34,7 +34,7 @@ func_decl * mk_aux_decl_for_array_sort(ast_manager & m, sort * s) {
 }
 
 array_factory::array_factory(ast_manager & m, proto_model & md):
-    struct_factory(m, m.get_family_id("array"), md) {
+    struct_factory(m, m.mk_family_id("array"), md) {
 }
 
 /**
diff --git a/src/smt/proto_model/datatype_factory.cpp b/src/smt/proto_model/datatype_factory.cpp
index 0ea610869..5be802714 100644
--- a/src/smt/proto_model/datatype_factory.cpp
+++ b/src/smt/proto_model/datatype_factory.cpp
@@ -22,7 +22,7 @@ Revision History:
 #include"ast_ll_pp.h"
 
 datatype_factory::datatype_factory(ast_manager & m, proto_model & md):
-    struct_factory(m, m.get_family_id("datatype"), md),
+    struct_factory(m, m.mk_family_id("datatype"), md),
     m_util(m) {
 }
 
diff --git a/src/smt/proto_model/numeral_factory.cpp b/src/smt/proto_model/numeral_factory.cpp
index 9653322e3..a67b6c075 100644
--- a/src/smt/proto_model/numeral_factory.cpp
+++ b/src/smt/proto_model/numeral_factory.cpp
@@ -24,7 +24,7 @@ app * arith_factory::mk_value_core(rational const & val, sort * s) {
 }
 
 arith_factory::arith_factory(ast_manager & m):
-    numeral_factory(m, m.get_family_id("arith")),
+    numeral_factory(m, m.mk_family_id("arith")),
     m_util(m) {
 }
 
@@ -36,7 +36,7 @@ app * arith_factory::mk_value(rational const & val, bool is_int) {
 }
 
 bv_factory::bv_factory(ast_manager & m):
-    numeral_factory(m, m.get_family_id("bv")),
+    numeral_factory(m, m.mk_family_id("bv")),
     m_util(m) {
 }
 
diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp
index 92110bc1a..d7a06f14f 100644
--- a/src/smt/proto_model/proto_model.cpp
+++ b/src/smt/proto_model/proto_model.cpp
@@ -31,7 +31,7 @@ proto_model::proto_model(ast_manager & m, simplifier & s, params_ref const & p):
     model_core(m),
     m_asts(m),
     m_simplifier(s),
-    m_afid(m.get_family_id(symbol("array"))) {
+    m_afid(m.mk_family_id(symbol("array"))) {
     register_factory(alloc(basic_factory, m));
     m_user_sort_factory = alloc(user_sort_factory, m);
     register_factory(m_user_sort_factory);
diff --git a/src/smt/proto_model/value_factory.cpp b/src/smt/proto_model/value_factory.cpp
index 0b2aded9e..93294d898 100644
--- a/src/smt/proto_model/value_factory.cpp
+++ b/src/smt/proto_model/value_factory.cpp
@@ -51,7 +51,7 @@ expr * basic_factory::get_fresh_value(sort * s) {
 }
 
 user_sort_factory::user_sort_factory(ast_manager & m): 
-    simple_factory<unsigned>(m, m.get_family_id("user-sort")) {
+    simple_factory<unsigned>(m, m.mk_family_id("user-sort")) {
 }
 
 void user_sort_factory::freeze_universe(sort * s) {
diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp
index a7623832f..02ee06985 100644
--- a/src/smt/smt_context.cpp
+++ b/src/smt/smt_context.cpp
@@ -2854,7 +2854,12 @@ namespace smt {
         m_bool_var2assumption.reset();
         m_unsat_core.reset();
         if (num_assumptions > 0) {
-            propagate(); // we must give a chance to the theories to propagate before we create a new scope...
+            // We must give a chance to the theories to propagate before we create a new scope...
+            propagate(); 
+            // Internal backtracking scopes (created with push_scope()) must only be created when we are
+            // in a consistent context.
+            if (inconsistent())
+                return; 
             push_scope();
             for (unsigned i = 0; i < num_assumptions; i++) {
                 expr * curr_assumption = assumptions[i];
@@ -3987,3 +3992,8 @@ namespace smt {
 
 };
 
+#ifdef Z3DEBUG
+void pp(smt::context & c) {
+    c.display(std::cout);
+}
+#endif
diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp
index 779c68625..8ecd079bf 100644
--- a/src/smt/smt_kernel.cpp
+++ b/src/smt/smt_kernel.cpp
@@ -253,12 +253,10 @@ namespace smt {
     }
 
     lbool kernel::setup_and_check() {
-        set_cancel(false);
         return m_imp->setup_and_check();
     }
 
     lbool kernel::check(unsigned num_assumptions, expr * const * assumptions) {
-        set_cancel(false);
         lbool r = m_imp->check(num_assumptions, assumptions);
         TRACE("smt_kernel", tout << "check result: " << r << "\n";);
         return r;
diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp
index 619a7d60c..e69b7a1b6 100644
--- a/src/smt/smt_model_finder.cpp
+++ b/src/smt/smt_model_finder.cpp
@@ -454,8 +454,8 @@ namespace smt {
                 m_model(0),
                 m_eval_cache_range(m),
                 m_new_constraints(0) {
-                m_asimp  = static_cast<arith_simplifier_plugin*>(s.get_plugin(m.get_family_id("arith")));
-                m_bvsimp = static_cast<bv_simplifier_plugin*>(s.get_plugin(m.get_family_id("bv")));
+                m_asimp  = static_cast<arith_simplifier_plugin*>(s.get_plugin(m.mk_family_id("arith")));
+                m_bvsimp = static_cast<bv_simplifier_plugin*>(s.get_plugin(m.mk_family_id("bv")));
             }
 
             ~auf_solver() {
diff --git a/src/smt/smt_model_finder.h b/src/smt/smt_model_finder.h
index 20d9ba6ef..b89603912 100644
--- a/src/smt/smt_model_finder.h
+++ b/src/smt/smt_model_finder.h
@@ -33,7 +33,7 @@ Abstract:
       Lugano, Switzerland, 2010.
 
     - Bugs, Moles and Skeletons: Symbolic Reasoning for Software
-      Development, Leonardo de Moura, Nikolaj Bj�rner, IJCAR,
+      Development, Leonardo de Moura, Nikolaj Bjorner, IJCAR,
       Edinburgh, Scotland, 2010.
 
 Author:
diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp
index f0dc1f5a6..96673e67e 100644
--- a/src/smt/smt_setup.cpp
+++ b/src/smt/smt_setup.cpp
@@ -692,7 +692,7 @@ namespace smt {
     void setup::setup_arith() {
         switch(m_params.m_arith_mode) {
         case AS_NO_ARITH:
-            m_context.register_plugin(alloc(smt::theory_dummy, m_manager.get_family_id("arith"), "no arithmetic"));
+            m_context.register_plugin(alloc(smt::theory_dummy, m_manager.mk_family_id("arith"), "no arithmetic"));
             break;
         case AS_DIFF_LOGIC:
             if (m_params.m_arith_fixnum) {
@@ -734,7 +734,7 @@ namespace smt {
     void setup::setup_bv() {
         switch(m_params.m_bv_mode) {
         case BS_NO_BV:
-            m_context.register_plugin(alloc(smt::theory_dummy, m_manager.get_family_id("bv"), "no bit-vector"));
+            m_context.register_plugin(alloc(smt::theory_dummy, m_manager.mk_family_id("bv"), "no bit-vector"));
             break;
         case BS_BLASTER:
             m_context.register_plugin(alloc(smt::theory_bv, m_manager, m_params, m_params));
@@ -745,7 +745,7 @@ namespace smt {
     void setup::setup_arrays() {
         switch(m_params.m_array_mode) {
         case AR_NO_ARRAY:
-            m_context.register_plugin(alloc(smt::theory_dummy, m_manager.get_family_id("array"), "no array"));
+            m_context.register_plugin(alloc(smt::theory_dummy, m_manager.mk_family_id("array"), "no array"));
             break;
         case AR_SIMPLE:
             m_context.register_plugin(alloc(smt::theory_array, m_manager, m_params));
diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h
index b774fb3d9..fafe73a79 100644
--- a/src/smt/theory_arith_core.h
+++ b/src/smt/theory_arith_core.h
@@ -1294,7 +1294,7 @@ namespace smt {
     
     template<typename Ext>
     theory_arith<Ext>::theory_arith(ast_manager & m, theory_arith_params & params):
-        theory(m.get_family_id("arith")),
+        theory(m.mk_family_id("arith")),
         m_params(params),
         m_util(m),
         m_arith_eq_solver(m),
diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp
index ca6449d1d..c2c50567f 100644
--- a/src/smt/theory_array_base.cpp
+++ b/src/smt/theory_array_base.cpp
@@ -27,7 +27,7 @@ Revision History:
 namespace smt {
 
     theory_array_base::theory_array_base(ast_manager & m):
-        theory(m.get_family_id("array")),
+        theory(m.mk_family_id("array")),
         m_found_unsupported_op(false)
     {
     }
diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp
index e425071d2..559ce155b 100644
--- a/src/smt/theory_bv.cpp
+++ b/src/smt/theory_bv.cpp
@@ -1239,7 +1239,7 @@ namespace smt {
     }
 
     theory_bv::theory_bv(ast_manager & m, theory_bv_params const & params, bit_blaster_params const & bb_params):
-        theory(m.get_family_id("bv")),
+        theory(m.mk_family_id("bv")),
         m_params(params),
         m_util(m),
         m_autil(m),
diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp
index 65abfe238..8c6543eff 100644
--- a/src/smt/theory_datatype.cpp
+++ b/src/smt/theory_datatype.cpp
@@ -454,7 +454,7 @@ namespace smt {
     }
 
     theory_datatype::theory_datatype(ast_manager & m, theory_datatype_params & p):
-        theory(m.get_family_id("datatype")),
+        theory(m.mk_family_id("datatype")),
         m_params(p),
         m_util(m),
         m_find(*this),
diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h
index 4d50bd8bf..21f1262ac 100644
--- a/src/smt/theory_dense_diff_logic_def.h
+++ b/src/smt/theory_dense_diff_logic_def.h
@@ -28,7 +28,7 @@ namespace smt {
 
     template<typename Ext>
     theory_dense_diff_logic<Ext>::theory_dense_diff_logic(ast_manager & m, theory_arith_params & p):
-        theory(m.get_family_id("arith")),
+        theory(m.mk_family_id("arith")),
         m_params(p),
         m_autil(m),
         m_arith_eq_adapter(*this, p, m_autil),
diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h
index 264ab9b2d..4140f683c 100644
--- a/src/smt/theory_diff_logic.h
+++ b/src/smt/theory_diff_logic.h
@@ -306,7 +306,7 @@ namespace smt {
 
     public:    
         theory_diff_logic(ast_manager& m, smt_params & params):
-            theory(m.get_family_id("arith")),
+            theory(m.mk_family_id("arith")),
             m_params(params),
             m_util(m),
             m_arith_eq_adapter(*this, params, m_util),
diff --git a/src/smt/theory_dl.cpp b/src/smt/theory_dl.cpp
index 402ab856c..758f78c2c 100644
--- a/src/smt/theory_dl.cpp
+++ b/src/smt/theory_dl.cpp
@@ -88,7 +88,7 @@ namespace smt {
                 m_th.get_rep(s, r, v);
                 app_ref rep_of(m_th.m());
                 rep_of = m_th.m().mk_app(r, m_node->get_owner());
-                theory_id bv_id = m_th.m().get_family_id("bv");
+                theory_id bv_id = m_th.m().mk_family_id("bv");
                 theory_bv* th_bv = dynamic_cast<theory_bv*>(ctx.get_theory(bv_id));
                 SASSERT(th_bv);
                 rational val;
@@ -106,7 +106,7 @@ namespace smt {
         
     public:
         theory_dl(ast_manager& m):
-            theory(m.get_family_id("datalog_relation")),
+            theory(m.mk_family_id("datalog_relation")),
             m_util(m),
             m_bv(m),
             m_trail(m)
diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h
index ef3924603..d5468df28 100644
--- a/src/smt/theory_seq_empty.h
+++ b/src/smt/theory_seq_empty.h
@@ -32,7 +32,7 @@ namespace smt {
         virtual theory* mk_fresh(context*) { return alloc(theory_seq_empty, get_manager()); }
         virtual char const * get_name() const { return "seq-empty"; }
     public:
-        theory_seq_empty(ast_manager& m):theory(m.get_family_id("seq")), m_used(false) {}
+        theory_seq_empty(ast_manager& m):theory(m.mk_family_id("seq")), m_used(false) {}
     };
 
 };
diff --git a/src/smt/user_plugin/user_smt_theory.cpp b/src/smt/user_plugin/user_smt_theory.cpp
index ab4cc62c4..a2d1e4f37 100644
--- a/src/smt/user_plugin/user_smt_theory.cpp
+++ b/src/smt/user_plugin/user_smt_theory.cpp
@@ -646,7 +646,7 @@ namespace smt {
         context & ctx               = _s.get_context(); // HACK
         symbol _name(name);
         ast_manager & m             = ctx.get_manager();
-        family_id fid               = m.get_family_id(_name);
+        family_id fid               = m.mk_family_id(_name);
         user_decl_plugin * dp       = alloc(user_decl_plugin);
         m.register_plugin(fid, dp);
         simplifier & s              = ctx.get_simplifier();
diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp
index cd4191e76..a98e5be49 100644
--- a/src/solver/combined_solver.cpp
+++ b/src/solver/combined_solver.cpp
@@ -55,13 +55,28 @@ private:
     bool                 m_use_solver1_results;
     ref<solver>          m_solver1;
     ref<solver>          m_solver2;
-    
+    // We delay sending assertions to solver 2
+    // This is relevant for big benchmarks that are meant to be solved
+    // by a non-incremental solver. 
+    bool                 m_solver2_initialized;
+
     bool                 m_ignore_solver1;
     inc_unknown_behavior m_inc_unknown_behavior;
     unsigned             m_inc_timeout;
+    
+    void init_solver2_assertions() {
+        if (m_solver2_initialized)
+            return;
+        unsigned sz = m_solver1->get_num_assertions();
+        for (unsigned i = 0; i < sz; i++) {
+            m_solver2->assert_expr(m_solver1->get_assertion(i));
+        }
+        m_solver2_initialized = true;
+    }
 
     void switch_inc_mode() {
         m_inc_mode = true;
+        init_solver2_assertions();
     }
 
     struct aux_timeout_eh : public event_handler {
@@ -106,6 +121,7 @@ public:
         m_solver1 = s1;
         m_solver2 = s2;
         updt_local_params(p);
+        m_solver2_initialized = false;
         m_inc_mode            = false;
         m_check_sat_executed  = false;
         m_use_solver1_results = true;
@@ -132,13 +148,15 @@ public:
         if (m_check_sat_executed)
             switch_inc_mode();
         m_solver1->assert_expr(t);
-        m_solver2->assert_expr(t);
+        if (m_solver2_initialized)
+            m_solver2->assert_expr(t);
     }
 
     virtual void assert_expr(expr * t, expr * a) {
         if (m_check_sat_executed)
             switch_inc_mode();
         m_solver1->assert_expr(t, a);
+        init_solver2_assertions();
         m_solver2->assert_expr(t, a);
     }
 
diff --git a/src/tactic/arith/bv2int_rewriter.cpp b/src/tactic/arith/bv2int_rewriter.cpp
index 0965f36f2..872981283 100644
--- a/src/tactic/arith/bv2int_rewriter.cpp
+++ b/src/tactic/arith/bv2int_rewriter.cpp
@@ -544,7 +544,7 @@ bool bv2int_rewriter::is_sbv2int(expr* n, expr_ref& s) {
         m_bv.is_extract(e2, lo1, hi1, e3) &&
         lo1 == 0 && hi1 == hi-1 &&
         m_arith.is_numeral(t2, k, is_int) && is_int &&
-        k == m_bv.power_of_two(hi) 
+        k == rational::power_of_two(hi) 
         ) {
         s = e3;
         return true;
diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp
index 188ea7d70..bd5af58f2 100644
--- a/src/tactic/arith/nla2bv_tactic.cpp
+++ b/src/tactic/arith/nla2bv_tactic.cpp
@@ -253,7 +253,7 @@ class nla2bv_tactic : public tactic {
                 s_bv = m_arith.mk_sub(m_arith.mk_numeral(*up, true), s_bv);
             }
             else {
-                s_bv = m_arith.mk_sub(s_bv, m_arith.mk_numeral(m_bv.power_of_two(num_bits-1), true));
+                s_bv = m_arith.mk_sub(s_bv, m_arith.mk_numeral(rational::power_of_two(num_bits-1), true));
             }
             
             m_trail.push_back(s_bv);
diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp
index 8790ca5a7..83a949579 100644
--- a/src/tactic/arith/pb2bv_tactic.cpp
+++ b/src/tactic/arith/pb2bv_tactic.cpp
@@ -583,7 +583,7 @@ private:
                 return false; // size must be even
             // I implemented only the easy (and very common) case, where a_i = 2^{n-i-1} and c = 2^n - 1
             unsigned n = sz/2;
-            if (c != m_bv_util.power_of_two(n) - numeral(1))
+            if (c != rational::power_of_two(n) - numeral(1))
                 return false;
             for (unsigned i = 0; i < n; i++) {
                 monomial const & m1 = p[i*2];
@@ -592,7 +592,7 @@ private:
                     return false;
                 if (m1.m_a != m2.m_a)
                     return false;
-                if (m1.m_a != m_bv_util.power_of_two(n - i - 1))
+                if (m1.m_a != rational::power_of_two(n - i - 1))
                     return false;
             }
             return true;
diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp
index d2292ede9..169e27927 100644
--- a/src/tactic/arith/purify_arith_tactic.cpp
+++ b/src/tactic/arith/purify_arith_tactic.cpp
@@ -99,93 +99,15 @@ Rules
   (mod t1 t2) --> k2 |  same constraints as above
 */
 
-struct purify_arith_decls {
-    ast_manager & m;
-    func_decl * m_int_0_pw_0_decl;    // decl for: int  0^0
-    func_decl * m_real_0_pw_0_decl;   // decl for: rel 0^0
-    func_decl * m_neg_root_decl;  // decl for: even root of negative (real) number 
-    func_decl * m_div_0_decl;     // decl for: x/0
-    func_decl * m_idiv_0_decl;    // decl for: div(x, 0)
-    func_decl * m_mod_0_decl;     // decl for: mod(x, 0)
-    func_decl * m_asin_u_decl;    // decl for: asin(x) when x < -1 or x > 1 
-    func_decl * m_acos_u_decl;    // decl for: acos(x) when x < -1 or x > 1
-    
-    void inc_refs() {
-        m.inc_ref(m_int_0_pw_0_decl);
-        m.inc_ref(m_real_0_pw_0_decl);
-        m.inc_ref(m_neg_root_decl);
-        m.inc_ref(m_div_0_decl);
-        m.inc_ref(m_idiv_0_decl);
-        m.inc_ref(m_mod_0_decl);
-        m.inc_ref(m_asin_u_decl);
-        m.inc_ref(m_acos_u_decl);
-    }
-
-    void dec_refs() {
-        m.dec_ref(m_int_0_pw_0_decl);
-        m.dec_ref(m_real_0_pw_0_decl);
-        m.dec_ref(m_neg_root_decl);
-        m.dec_ref(m_div_0_decl);
-        m.dec_ref(m_idiv_0_decl);
-        m.dec_ref(m_mod_0_decl);
-        m.dec_ref(m_asin_u_decl);
-        m.dec_ref(m_acos_u_decl);
-    }
-
-    purify_arith_decls(arith_util & u):
-        m(u.get_manager()) {
-        sort * i = u.mk_int();
-        sort * r = u.mk_real();
-        m_int_0_pw_0_decl = m.mk_const_decl(symbol("0^0-int"), i);
-        m_real_0_pw_0_decl = m.mk_const_decl(symbol("0^0-real"), r);
-        sort * rr[2] = { r, r };
-        m_neg_root_decl = m.mk_func_decl(symbol("neg-root"), 2, rr, r);
-        m_div_0_decl = m.mk_func_decl(symbol("/0"), 1, &r, r);
-        m_idiv_0_decl = m.mk_func_decl(symbol("div0"), 1, &i, i);
-        m_mod_0_decl = m.mk_func_decl(symbol("mod0"), 1, &i, i);
-        m_asin_u_decl = m.mk_func_decl(symbol("asin-u"), 1, &r, r);
-        m_acos_u_decl = m.mk_func_decl(symbol("acos-u"), 1, &r, r);
-        inc_refs();
-    }
-
-    purify_arith_decls(ast_manager & _m, 
-                       func_decl * int_0_pw_0,
-                       func_decl * real_0_pw_0,
-                       func_decl * neg_root,
-                       func_decl * div_0,
-                       func_decl * idiv_0,
-                       func_decl * mod_0,
-                       func_decl * asin_u,
-                       func_decl * acos_u
-                       ):
-        m(_m),
-        m_int_0_pw_0_decl(int_0_pw_0),
-        m_real_0_pw_0_decl(real_0_pw_0),
-        m_neg_root_decl(neg_root),
-        m_div_0_decl(div_0),
-        m_idiv_0_decl(idiv_0),
-        m_mod_0_decl(mod_0),
-        m_asin_u_decl(asin_u),
-        m_acos_u_decl(acos_u) {
-        inc_refs();
-    }
-    
-    ~purify_arith_decls() { 
-        dec_refs();
-    }
-};
-
 struct purify_arith_proc {
     arith_util &         m_util;
-    purify_arith_decls & m_aux_decls;
     bool                 m_produce_proofs;
     bool                 m_elim_root_objs;
     bool                 m_elim_inverses;
     bool                 m_complete;
 
-    purify_arith_proc(arith_util & u, purify_arith_decls & d, bool produce_proofs, bool elim_root_objs, bool elim_inverses, bool complete):
+    purify_arith_proc(arith_util & u, bool produce_proofs, bool elim_root_objs, bool elim_inverses, bool complete):
         m_util(u),
-        m_aux_decls(d),
         m_produce_proofs(produce_proofs),
         m_elim_root_objs(elim_root_objs),
         m_elim_inverses(elim_inverses),
@@ -247,15 +169,6 @@ struct purify_arith_proc {
 
         expr * mk_fresh_int_var() { return mk_fresh_var(true); }
 
-        func_decl * div0_decl() { return m_owner.m_aux_decls.m_div_0_decl; }
-        func_decl * idiv0_decl() { return m_owner.m_aux_decls.m_idiv_0_decl; }
-        func_decl * mod0_decl() { return m_owner.m_aux_decls.m_mod_0_decl; }
-        func_decl * int_0_pw_0_decl() { return m_owner.m_aux_decls.m_int_0_pw_0_decl; }
-        func_decl * real_0_pw_0_decl() { return m_owner.m_aux_decls.m_real_0_pw_0_decl; }
-        func_decl * neg_root_decl() { return m_owner.m_aux_decls.m_neg_root_decl; }
-        func_decl * asin_u_decl() { return m_owner.m_aux_decls.m_asin_u_decl; }
-        func_decl * acos_u_decl() { return m_owner.m_aux_decls.m_acos_u_decl; }
-        
         expr * mk_int_zero() { return u().mk_numeral(rational(0), true); }
 
         expr * mk_real_zero() { return u().mk_numeral(rational(0), false); }
@@ -332,7 +245,7 @@ struct purify_arith_proc {
             if (complete()) {
                 // y != 0 \/ k = div-0(x)
                 push_cnstr(OR(NOT(EQ(y, mk_real_zero())),
-                              EQ(k, m().mk_app(div0_decl(), x))));
+                              EQ(k, u().mk_div0(x))));
                 push_cnstr_pr(result_pr);
             }
         }
@@ -380,10 +293,10 @@ struct purify_arith_proc {
             push_cnstr_pr(mod_pr);
 
             if (complete()) {
-                push_cnstr(OR(NOT(EQ(y, zero)), EQ(k1, m().mk_app(idiv0_decl(), x))));
+                push_cnstr(OR(NOT(EQ(y, zero)), EQ(k1, u().mk_idiv0(x))));
                 push_cnstr_pr(result_pr);
 
-                push_cnstr(OR(NOT(EQ(y, zero)), EQ(k2, m().mk_app(mod0_decl(), x))));
+                push_cnstr(OR(NOT(EQ(y, zero)), EQ(k2, u().mk_mod0(x))));
                 push_cnstr_pr(mod_pr);
             }
         }
@@ -445,8 +358,7 @@ struct purify_arith_proc {
                 push_cnstr(OR(EQ(x, zero), EQ(k, one)));
                 push_cnstr_pr(result_pr);
                 if (complete()) {
-                    func_decl * z_pw_z = is_int ? int_0_pw_0_decl() : real_0_pw_0_decl();
-                    push_cnstr(OR(NOT(EQ(x, zero)), EQ(k, m().mk_const(z_pw_z))));
+                    push_cnstr(OR(NOT(EQ(x, zero)), EQ(k, is_int ? u().mk_0_pw_0_int() : u().mk_0_pw_0_real())));
                     push_cnstr_pr(result_pr);
                 }
             }
@@ -470,7 +382,7 @@ struct purify_arith_proc {
                     push_cnstr_pr(result_pr);
                     if (complete()) {
                         push_cnstr(OR(u().mk_ge(x, zero),
-                                      EQ(k, m().mk_app(neg_root_decl(), x, u().mk_numeral(n, false)))));
+                                      EQ(k, u().mk_neg_root(x, u().mk_numeral(n, false)))));
                         push_cnstr_pr(result_pr);
                     }
                 }
@@ -561,10 +473,10 @@ struct purify_arith_proc {
                 // x < -1       implies k = asin_u(x) 
                 // x >  1       implies k = asin_u(x) 
                 push_cnstr(OR(u().mk_ge(x, mone),
-                              EQ(k, m().mk_app(asin_u_decl(), x))));
+                              EQ(k, u().mk_u_asin(x))));
                 push_cnstr_pr(result_pr);
                 push_cnstr(OR(u().mk_le(x, one),
-                              EQ(k, m().mk_app(asin_u_decl(), x))));
+                              EQ(k, u().mk_u_asin(x))));
                 push_cnstr_pr(result_pr);
             }
             return BR_DONE;
@@ -603,10 +515,10 @@ struct purify_arith_proc {
                 // x < -1       implies k = acos_u(x) 
                 // x >  1       implies k = acos_u(x) 
                 push_cnstr(OR(u().mk_ge(x, mone),
-                              EQ(k, m().mk_app(acos_u_decl(), x))));
+                              EQ(k, u().mk_u_acos(x))));
                 push_cnstr_pr(result_pr);
                 push_cnstr(OR(u().mk_le(x, one),
-                              EQ(k, m().mk_app(acos_u_decl(), x))));
+                              EQ(k, u().mk_u_acos(x))));
                 push_cnstr_pr(result_pr);
             }
             return BR_DONE;
@@ -835,12 +747,10 @@ struct purify_arith_proc {
 
 class purify_arith_tactic : public tactic {
     arith_util         m_util;
-    purify_arith_decls m_aux_decls;
     params_ref         m_params;
 public:
     purify_arith_tactic(ast_manager & m, params_ref const & p):
         m_util(m),
-        m_aux_decls(m_util),
         m_params(p) {
     }
 
@@ -879,7 +789,7 @@ public:
             bool elim_root_objs = m_params.get_bool("elim_root_objects", true);
             bool elim_inverses  = m_params.get_bool("elim_inverses", true);
             bool complete       = m_params.get_bool("complete", true);
-            purify_arith_proc proc(m_util, m_aux_decls, produce_proofs, elim_root_objs, elim_inverses, complete);
+            purify_arith_proc proc(m_util, produce_proofs, elim_root_objs, elim_inverses, complete);
             
             proc(*(g.get()), mc, produce_models);
             
diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp
index d1dca296a..00e14a41f 100644
--- a/src/tactic/core/elim_uncnstr_tactic.cpp
+++ b/src/tactic/core/elim_uncnstr_tactic.cpp
@@ -647,9 +647,9 @@ class elim_uncnstr_tactic : public tactic {
                     unsigned bv_sz = m_bv_util.get_bv_size(arg1);
                     rational MAX;
                     if (is_signed)
-                        MAX = m_bv_util.power_of_two(bv_sz - 1) - rational(1);
+                        MAX = rational::power_of_two(bv_sz - 1) - rational(1);
                     else
-                        MAX = m_bv_util.power_of_two(bv_sz) - rational(1);
+                        MAX = rational::power_of_two(bv_sz) - rational(1);
                     app * u;
                     bool is_new = mk_fresh_uncnstr_var_for(f, arg1, arg2, u);
                     app * r = m().mk_or(u, m().mk_eq(t, m_bv_util.mk_numeral(MAX, bv_sz)));
@@ -666,7 +666,7 @@ class elim_uncnstr_tactic : public tactic {
                     unsigned bv_sz = m_bv_util.get_bv_size(arg1);
                     rational MIN;
                     if (is_signed)
-                        MIN = -m_bv_util.power_of_two(bv_sz - 1);
+                        MIN = -rational::power_of_two(bv_sz - 1);
                     else
                         MIN = rational(0);
                     app * u;
diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp
index 8a4b31612..b53ad21eb 100644
--- a/src/tactic/fpa/fpa2bv_converter.cpp
+++ b/src/tactic/fpa/fpa2bv_converter.cpp
@@ -32,7 +32,7 @@ fpa2bv_converter::fpa2bv_converter(ast_manager & m) :
 	m_mpz_manager(m_mpf_manager.mpz_manager()),
     m_bv_util(m),
     extra_assertions(m) {
-    m_plugin = static_cast<float_decl_plugin*>(m.get_plugin(m.get_family_id("float")));
+    m_plugin = static_cast<float_decl_plugin*>(m.get_plugin(m.mk_family_id("float")));
 }
 
 fpa2bv_converter::~fpa2bv_converter() {
diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp
index 4813cbe1a..0e63255ca 100644
--- a/src/tactic/portfolio/smt_strategic_solver.cpp
+++ b/src/tactic/portfolio/smt_strategic_solver.cpp
@@ -39,7 +39,7 @@ Notes:
 
 tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const & logic) {
     if (logic=="QF_UF")
-        return mk_qfufbv_tactic(m, p);
+        return mk_qfuf_tactic(m, p);
     else if (logic=="QF_BV")
         return mk_qfbv_tactic(m, p);
     else if (logic=="QF_IDL")
diff --git a/src/tactic/probe.cpp b/src/tactic/probe.cpp
index 2940e93b9..1a696dc78 100644
--- a/src/tactic/probe.cpp
+++ b/src/tactic/probe.cpp
@@ -326,7 +326,7 @@ class num_consts_probe : public probe {
         unsigned      m_counter;
         proc(ast_manager & _m, bool b, char const * family):m(_m), m_bool(b), m_counter(0) {
             if (family != 0)
-                m_fid = m.get_family_id(family);
+                m_fid = m.mk_family_id(family);
             else
                 m_fid = null_family_id;
         }
diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp
index 6b05cff96..6fbf34255 100644
--- a/src/tactic/smtlogics/qflia_tactic.cpp
+++ b/src/tactic/smtlogics/qflia_tactic.cpp
@@ -172,6 +172,8 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) {
     params_ref main_p;
     main_p.set_bool("elim_and", true);
     main_p.set_bool("som", true);
+    main_p.set_bool("blast_distinct", true);
+    main_p.set_uint("blast_distinct_threshold", 128);
     // main_p.set_bool("push_ite_arith", true);
     
     params_ref pull_ite_p;
diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp
index 4bf9e48f4..198872cf5 100644
--- a/src/tactic/tactic.cpp
+++ b/src/tactic/tactic.cpp
@@ -175,7 +175,6 @@ tactic * mk_fail_if_undecided_tactic() {
 
 void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) {
     t.reset_statistics();
-    t.reset_cancel();
     try {
         t(in, result, mc, pc, core);
         t.cleanup();
diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp
index 785a9d82e..ca66b7a14 100644
--- a/src/tactic/tactical.cpp
+++ b/src/tactic/tactical.cpp
@@ -116,7 +116,6 @@ protected:
         m_t2->set_cancel(f);
     }
 
-
     template<typename T>
     tactic * translate_core(ast_manager & m) { 
         tactic * new_t1 = m_t1->translate(m);
diff --git a/src/test/bv_simplifier_plugin.cpp b/src/test/bv_simplifier_plugin.cpp
index 4a472425e..635143021 100644
--- a/src/test/bv_simplifier_plugin.cpp
+++ b/src/test/bv_simplifier_plugin.cpp
@@ -79,7 +79,7 @@ public:
         m_arith(m_manager),
         m_simp(m_manager, m_bsimp, m_bv_params), 
         m_bv_util(m_manager), 
-        m_fid(m_manager.get_family_id("bv")) {
+        m_fid(m_manager.mk_family_id("bv")) {
         reg_decl_plugins(m_manager);
     }
 
@@ -139,7 +139,7 @@ public:
         m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e);
         SASSERT(((a >> 8) | (a << 24)) == u32(e.get()));
 
-        params[0] = parameter(m_manager.mk_sort(m_manager.get_family_id("arith"), INT_SORT));
+        params[0] = parameter(m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT));
         ar = m_manager.mk_app(m_fid, OP_BV2INT, 1, params, 1, es);
 		expr* es2[1] = { ar.get() };
 		params[0] = parameter(32);
diff --git a/src/test/expr_rand.cpp b/src/test/expr_rand.cpp
index 1ceeba8b8..19a07e98a 100644
--- a/src/test/expr_rand.cpp
+++ b/src/test/expr_rand.cpp
@@ -18,7 +18,7 @@ void tst_expr_arith(unsigned num_files) {
     er.seed(rand_seed);
     er.initialize_arith(20);
 
-    family_id fid = m.get_family_id("arith");
+    family_id fid = m.mk_family_id("arith");
     sort* int_ty  = m.mk_sort(fid, INT_SORT, 0, 0);
     sort* real_ty = m.mk_sort(fid, REAL_SORT, 0, 0);
 
@@ -56,7 +56,7 @@ void tst_expr_rand(unsigned num_files) {
     parameter p2(2);
     parameter p8(8);
     parameter p32(32);
-    family_id bvfid = m.get_family_id("bv");
+    family_id bvfid = m.mk_family_id("bv");
     sort* bv1  = m.mk_sort(bvfid, BV_SORT, 1, &p1);
     sort* bv2  = m.mk_sort(bvfid, BV_SORT, 1, &p2);
     sort* bv8  = m.mk_sort(bvfid, BV_SORT, 1, &p8);
diff --git a/src/test/fuzzing/expr_rand.cpp b/src/test/fuzzing/expr_rand.cpp
index e1a7631c4..a2aca7e6e 100644
--- a/src/test/fuzzing/expr_rand.cpp
+++ b/src/test/fuzzing/expr_rand.cpp
@@ -82,7 +82,7 @@ expr* expr_rand::choose_expr(sort* s) {
 
 void expr_rand::initialize_arith(unsigned num_vars) {
     arith_util u(m_manager);
-    family_id afid = m_manager.get_family_id("arith");
+    family_id afid = m_manager.mk_family_id("arith");
     sort* i_ty = m_manager.mk_sort(afid, INT_SORT, 0, 0);
     for(unsigned i = 0; i < num_vars; ++i) {
         add_var(i_ty);
@@ -106,7 +106,7 @@ void expr_rand::initialize_arith(unsigned num_vars) {
 void expr_rand::initialize_bv(unsigned num_vars) {
     bv_util u(m_manager);
     family_id bfid = m_manager.get_basic_family_id();
-    family_id bvfid = m_manager.get_family_id("bv");
+    family_id bvfid = m_manager.mk_family_id("bv");
     
 
     const unsigned num_sizes = 6;
@@ -237,7 +237,7 @@ void expr_rand::initialize_bv(unsigned num_vars) {
 }
 
 void expr_rand::initialize_array(unsigned num_vars, sort* dom, sort* rng) {
-    family_id afid = m_manager.get_family_id("array");
+    family_id afid = m_manager.mk_family_id("array");
     parameter p1(dom), p2(rng);
     parameter ps[2] = { p1, p2 };
     sort* a = m_manager.mk_sort(afid, ARRAY_SORT, 2, ps);
diff --git a/src/test/model_retrieval.cpp b/src/test/model_retrieval.cpp
index da6c3ddd0..f40f89d22 100644
--- a/src/test/model_retrieval.cpp
+++ b/src/test/model_retrieval.cpp
@@ -18,7 +18,7 @@ void tst_model_retrieval()
     ast_manager m;
     reg_decl_plugins(m);
 
-    family_id array_fid = m.get_family_id(symbol("array"));
+    family_id array_fid = m.mk_family_id(symbol("array"));
     array_util au(m);
     
     // arr_s and select_fn creation copy-pasted from z3.cpp
diff --git a/src/util/cancel_eh.h b/src/util/cancel_eh.h
index 74c5040a2..0401e6f03 100644
--- a/src/util/cancel_eh.h
+++ b/src/util/cancel_eh.h
@@ -29,6 +29,7 @@ class cancel_eh : public event_handler {
     T & m_obj;
 public:
     cancel_eh(T & o):m_obj(o) {}
+    ~cancel_eh() { m_obj.reset_cancel(); }
     virtual void operator()() { 
         m_obj.cancel(); 
     }
diff --git a/src/util/params.cpp b/src/util/params.cpp
index 0ee42868d..4aff0de92 100644
--- a/src/util/params.cpp
+++ b/src/util/params.cpp
@@ -933,3 +933,8 @@ void params::set_sym(char const * k, symbol const & v) {
     SET_SYM_VALUE();
 }
 
+#ifdef Z3DEBUG
+void pp(params_ref const & p) {
+    std::cout << p << std::endl;
+}
+#endif
diff --git a/src/util/rational.cpp b/src/util/rational.cpp
index 0a91bd8da..122db7217 100644
--- a/src/util/rational.cpp
+++ b/src/util/rational.cpp
@@ -27,6 +27,31 @@ synch_mpq_manager *  rational::g_mpq_manager = 0;
 rational             rational::m_zero(0);
 rational             rational::m_one(1);
 rational             rational::m_minus_one(-1);
+vector<rational>     rational::m_powers_of_two;
+
+void mk_power_up_to(vector<rational> & pws, unsigned n) {
+    if (pws.empty()) {
+        pws.push_back(rational(1));
+    }
+    unsigned sz = pws.size();
+    rational curr = pws[sz - 1];
+    rational two(2);
+    for (unsigned i = sz; i <= n; i++) {
+        curr *= two;
+        pws.push_back(curr);
+    }
+}
+
+rational rational::power_of_two(unsigned k) {
+    rational result;
+    #pragma omp critical (powers_of_two)
+    {
+        if (k >= m_powers_of_two.size())
+            mk_power_up_to(m_powers_of_two, k+1);
+        result = m_powers_of_two[k];
+    }
+    return result;
+}
 
 void rational::initialize() {
     if (!g_mpq_manager) {
@@ -35,6 +60,7 @@ void rational::initialize() {
 }
 
 void rational::finalize() {
+    m_powers_of_two.finalize();
     dealloc(g_mpq_manager);
     g_mpq_manager = 0;
 }
diff --git a/src/util/rational.h b/src/util/rational.h
index f0406f30a..fc03228bf 100644
--- a/src/util/rational.h
+++ b/src/util/rational.h
@@ -26,14 +26,13 @@ class rational {
     static rational                  m_zero;
     static rational                  m_one;
     static rational                  m_minus_one;
-
+    static vector<rational>          m_powers_of_two;
     static synch_mpq_manager *       g_mpq_manager;
-
+    
     static synch_mpq_manager & m() { return *g_mpq_manager; }
 
 public:
     static void initialize();
-
     static void finalize();
     /*
       ADD_INITIALIZER('rational::initialize();')
@@ -272,6 +271,8 @@ public:
         return result;
     }
 
+    static rational power_of_two(unsigned k);
+
     bool is_power_of_two(unsigned & shift) {
         return m().is_power_of_two(m_val, shift);
     }
diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp
index d475e5489..d0a79cec6 100644
--- a/src/util/scoped_timer.cpp
+++ b/src/util/scoped_timer.cpp
@@ -73,9 +73,6 @@ struct scoped_timer::imp {
     pthread_cond_t   m_condition_var;
 #elif defined(_LINUX_) || defined(_FREEBSD_)
     // Linux & FreeBSD
-    static void *   g_timer;
-    void            (*m_old_handler)(int);
-    void *          m_old_timer;
     timer_t         m_timerid;
 #else
     // Other
@@ -128,8 +125,9 @@ struct scoped_timer::imp {
         return st;
     }
 #elif defined(_LINUX_) || defined(_FREEBSD_)
-    static void sig_handler(int) {
-       static_cast<imp*>(g_timer)->m_eh->operator()();
+    static void sig_handler(union sigval s) {
+        void * ptr = s.sival_ptr;
+        static_cast<imp*>(ptr)->m_eh->operator()();
     }
 #else
     // Other
@@ -156,23 +154,11 @@ struct scoped_timer::imp {
             throw default_exception("failed to start timer thread");
 #elif defined(_LINUX_) || defined(_FREEBSD_)
 	// Linux & FreeBSD
-        if (omp_in_parallel()) {
-            // It doesn't work in with more than one thread.
-            // SIGEV_SIGNAL: the event is handled by the process not by the thread that installed the handler.
-            // SIGEV_THREAD: the event is handled by a new thread (Z3 crashes with this configuration).
-            // 
-            // It seems the way to go is SIGEV_SIGNAL, but I have to find a way to identify the thread the event is meant to.
-            return;
-        }
-	m_old_timer   = g_timer;
-	g_timer       = this;
-	m_old_handler = signal(SIG, sig_handler);
-
 	struct sigevent sev;
         memset(&sev, 0, sizeof(sigevent));
-	sev.sigev_notify = SIGEV_SIGNAL;
-	sev.sigev_signo  = SIG;
-	sev.sigev_value.sival_ptr = &m_timerid;
+	sev.sigev_notify = SIGEV_THREAD;
+        sev.sigev_value.sival_ptr = this;
+        sev.sigev_notify_function = sig_handler;
 	if (timer_create(CLOCKID, &sev, &m_timerid) == -1)
 	    throw default_exception("failed to create timer");
 
@@ -182,6 +168,7 @@ struct scoped_timer::imp {
 	its.it_value.tv_nsec = nano % 1000000000ull;
 	its.it_interval.tv_sec  = 0; // timer experies once
 	its.it_interval.tv_nsec = 0;
+        
 	if (timer_settime(m_timerid, 0, &its, NULL) == -1)
 	    throw default_exception("failed to set timer");
 #else
@@ -203,12 +190,7 @@ struct scoped_timer::imp {
             throw default_exception("failed to destroy pthread attributes object");
 #elif defined(_LINUX_) || defined(_FREEBSD_)
 	// Linux & FreeBSD
-        if (omp_in_parallel())
-            return; // see comments in the constructor.
 	timer_delete(m_timerid);
-	if (m_old_handler != SIG_ERR)
-	    signal(SIG, m_old_handler);
-	g_timer = m_old_timer;
 #else
 	// Other Platforms
 #endif
@@ -216,16 +198,6 @@ struct scoped_timer::imp {
 
 };
 
-#if defined(_WINDOWS) || defined(_CYGWIN)
-#elif defined(__APPLE__) && defined(__MACH__)
-// Mac OS X
-#elif defined(_LINUX_) || defined(_FREEBSD_)
-// Linux & FreeBSD
-void * scoped_timer::imp::g_timer = 0;
-#else
-// Other platforms
-#endif
-
 scoped_timer::scoped_timer(unsigned ms, event_handler * eh) {
     if (ms != UINT_MAX)
         m_imp = alloc(imp, ms, eh);