diff --git a/examples/ml/ml_example.ml b/examples/ml/ml_example.ml
index 5b1c05069..bab0ba2fc 100644
--- a/examples/ml/ml_example.ml
+++ b/examples/ml/ml_example.ml
@@ -190,9 +190,10 @@ let basic_tests ( ctx : context ) =
   (* Error handling test. *)
   try (
     let i = Integer.mk_numeral_s ctx "1/2" in
-    raise (TestFailedException (numeral_to_string i)) (* unreachable *)
+    Printf.printf "%s\n" (Expr.to_string i) ;
+    raise (TestFailedException "check")
   )
-  with Z3native.Exception(_) -> (
+  with Z3.Error(_) -> (
     Printf.printf "Exception caught, OK.\n" 
   )
 
@@ -342,7 +343,7 @@ let _ =
       );
     Printf.printf "Exiting.\n" ;
     exit 0
-  ) with Z3native.Exception(msg) -> (
+  ) with Error(msg) -> (
     Printf.printf "Z3 EXCEPTION: %s\n" msg ;
     exit 1
   )    
diff --git a/scripts/mk_make.py b/scripts/mk_make.py
index 813cd3a66..8cd9f3a7d 100644
--- a/scripts/mk_make.py
+++ b/scripts/mk_make.py
@@ -19,5 +19,3 @@ mk_bindings(API_files)
 mk_vs_proj('z3', ['shell'])
 mk_vs_proj_dll('libz3', ['api_dll'])
 mk_makefile()
-
-
diff --git a/scripts/mk_util.py b/scripts/mk_util.py
index 38bf2a854..a73a0e59c 100644
--- a/scripts/mk_util.py
+++ b/scripts/mk_util.py
@@ -69,6 +69,7 @@ IS_LINUX=False
 IS_OSX=False
 IS_FREEBSD=False
 IS_OPENBSD=False
+IS_CYGWIN=False
 VERBOSE=True
 DEBUG_MODE=False
 SHOW_CPPS = True
@@ -139,6 +140,9 @@ def is_openbsd():
 def is_osx():
     return IS_OSX
 
+def is_cygwin():
+    return IS_CYGWIN
+
 def norm_path(p):
     # We use '/' on mk_project for convenience
     return os.path.join(*(p.split('/')))
@@ -591,6 +595,8 @@ elif os.name == 'posix':
         IS_FREEBSD=True
     elif os.uname()[0] == 'OpenBSD':
         IS_OPENBSD=True
+    elif os.uname()[0][:6] == 'CYGWIN':
+        IS_CYGWIN=True
 
 def display_help(exit_code):
     print("mk_make.py: Z3 Makefile generator\n")
@@ -1691,6 +1697,8 @@ class JavaDLLComponent(Component):
                 t = t.replace('PLATFORM', 'freebsd')
             elif IS_OPENBSD:
                 t = t.replace('PLATFORM', 'openbsd')
+            elif IS_CYGWIN:
+                t = t.replace('PLATFORM', 'cygwin')
             else:
                 t = t.replace('PLATFORM', 'win32')
             out.write(t)
@@ -1808,6 +1816,16 @@ class MLComponent(Component):
 
     def mk_makefile(self, out):
         if is_ml_enabled():
+            CP_CMD = 'cp'
+            if IS_WINDOWS:
+                CP_CMD='copy'
+
+            OCAML_FLAGS = ''
+            if DEBUG_MODE:             
+                OCAML_FLAGS += '-g'
+            OCAMLCF = OCAMLC + ' ' + OCAML_FLAGS
+            OCAMLOPTF = OCAMLOPT + ' ' + OCAML_FLAGS
+
             src_dir = self.to_src_dir
             mk_dir(os.path.join(BUILD_DIR, self.sub_dir))
             api_src = get_component(API_COMPONENT).to_src_dir
@@ -1824,51 +1842,52 @@ class MLComponent(Component):
                            os.path.join(BUILD_DIR, self.sub_dir, 'META'),
                            substitutions)
 
-            mlis = ''
-            for m in self.modules:
-                mlis = os.path.join(src_dir, m) + '.mli ' + mlis
-
             stubsc = os.path.join(src_dir, self.stubs + '.c')
             stubso = os.path.join(self.sub_dir, self.stubs) + '$(OBJ_EXT)'
             z3dllso = get_component(Z3_DLL_COMPONENT).dll_name + '$(SO_EXT)'
             out.write('%s: %s %s\n' % (stubso, stubsc, z3dllso))
             out.write('\t%s -ccopt "$(CXXFLAGS_OCAML) -I %s -I %s -I %s $(CXX_OUT_FLAG)%s" -c %s\n' %
-                      (OCAMLC, OCAML_LIB, api_src, src_dir, stubso, stubsc))
-
-            cmis = ''
-            for m in self.modules:
-                ff = os.path.join(src_dir, m + '.mli')
-                ft = os.path.join(self.sub_dir, m + '.cmi')
-                out.write('%s: %s\n' % (ft, cmis))
-                out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLC, self.sub_dir, ft, ff))
-                cmis = cmis + ' ' + ft
+                      (OCAMLCF, OCAML_LIB, api_src, src_dir, stubso, stubsc))
 
             cmos = ''
             for m in self.modules:
-                ff = os.path.join(src_dir, m + '.ml')
-                ft = os.path.join(self.sub_dir, m + '.cmo')
-                fd = os.path.join(self.sub_dir, m + '.cmi')
-                out.write('%s: %s %s\n' % (ft, ff, fd))
-                out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLC, self.sub_dir, ft, ff))
-                cmos = cmos + ' ' + ft
+                ml = os.path.join(src_dir, m + '.ml')
+                cmo = os.path.join(self.sub_dir, m + '.cmo')
+                existing_mli = os.path.join(src_dir, m + '.mli')
+                mli = os.path.join(self.sub_dir, m + '.mli')
+                cmi = os.path.join(self.sub_dir, m + '.cmi')
+                out.write('%s: %s %s\n' % (cmo, ml, cmos))
+                if (os.path.exists(existing_mli[3:])):
+                    out.write('\t%s %s %s\n' % (CP_CMD, existing_mli, mli))
+                else:
+                    out.write('\t%s -i -I %s -c %s > %s\n' % (OCAMLCF, self.sub_dir, ml, mli))
+                out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLCF, self.sub_dir, cmi, mli))
+                out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLCF, self.sub_dir, cmo, ml))
+                cmos = cmos + cmo + ' '
 
             cmxs = ''
             for m in self.modules:
                 ff = os.path.join(src_dir, m + '.ml')
                 ft = os.path.join(self.sub_dir, m + '.cmx')
-                fd = os.path.join(self.sub_dir, m + '.cmi')
-                out.write('%s: %s %s\n' % (ft, ff, fd))
-                out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLOPT, self.sub_dir, ft, ff))
+                out.write('%s: %s %s\n' % (ft, ff, cmos))
+                out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLOPTF, self.sub_dir, ft, ff))
                 cmxs = cmxs + ' ' + ft
 
 
+            OCAMLMKLIB = 'ocamlmklib'
+            LIBZ3 = '-L. -lz3'
+            if is_cygwin():
+                # Some ocamlmklib's don't like -g; observed on cygwin, but may be others as well.
+                LIBZ3 = 'libz3.dll'
+            elif DEBUG_MODE:
+                OCAMLMKLIB += ' -g'
             z3mls = os.path.join(self.sub_dir, 'z3ml')
             out.write('%s.cma: %s %s %s\n' % (z3mls, cmos, stubso, z3dllso))
-            out.write('\tocamlmklib -o %s -I %s %s %s -L. -lz3\n' % (z3mls, self.sub_dir, stubso, cmos))
+            out.write('\t%s -o %s -I %s %s %s %s\n' % (OCAMLMKLIB, z3mls, self.sub_dir, stubso, cmos, LIBZ3))
             out.write('%s.cmxa: %s %s %s\n' % (z3mls, cmxs, stubso, z3dllso))
-            out.write('\tocamlmklib -o %s -I %s %s %s -L. -lz3\n' % (z3mls, self.sub_dir, stubso, cmxs))
+            out.write('\t%s -o %s -I %s %s %s %s\n' % (OCAMLMKLIB, z3mls, self.sub_dir, stubso, cmxs, LIBZ3))
             out.write('%s.cmxs: %s.cmxa\n' % (z3mls, z3mls))
-            out.write('\t%s -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPT, z3mls, self.sub_dir, z3mls))
+            out.write('\t%s -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPTF, z3mls, self.sub_dir, z3mls))
 
             out.write('\n')
             out.write('ml: %s.cma %s.cmxa %s.cmxs\n' % (z3mls, z3mls, z3mls))
@@ -1911,7 +1930,11 @@ class MLComponent(Component):
                 metafile=os.path.join(self.sub_dir, 'META')))
 
             for m in self.modules:
-                out.write(' ' + os.path.join(self.to_src_dir, m) + '.mli')
+                mli = os.path.join(self.src_dir, m) + '.mli'
+                if os.path.exists(mli):
+                    out.write(' ' + os.path.join(self.to_src_dir, m) + '.mli')
+                else:
+                    out.write(' ' + os.path.join(self.sub_dir, m) + '.mli')
                 out.write(' ' + os.path.join(self.sub_dir, m) + '.cmi')
                 out.write(' ' + os.path.join(self.sub_dir, m) + '.cmx')
             out.write(' %s' % ((os.path.join(self.sub_dir, 'libz3ml$(LIB_EXT)'))))
@@ -2863,78 +2886,78 @@ def mk_z3consts_ml(api_files):
     efile.close()
     if VERBOSE:
         print ('Generated "%s/z3enums.ml"' % ('%s' % gendir))
-    efile  = open('%s.mli' % os.path.join(gendir, "z3enums"), 'w')
-    efile.write('(* Automatically generated file *)\n\n')
-    efile.write('(** The enumeration types of Z3. *)\n\n')
-    for api_file in api_files:
-        api_file_c = ml.find_file(api_file, ml.name)
-        api_file   = os.path.join(api_file_c.src_dir, api_file)
+    # efile  = open('%s.mli' % os.path.join(gendir, "z3enums"), 'w')
+    # efile.write('(* Automatically generated file *)\n\n')
+    # efile.write('(** The enumeration types of Z3. *)\n\n')
+    # for api_file in api_files:
+    #     api_file_c = ml.find_file(api_file, ml.name)
+    #     api_file   = os.path.join(api_file_c.src_dir, api_file)
 
-        api = open(api_file, 'r')
+    #     api = open(api_file, 'r')
 
-        SEARCHING  = 0
-        FOUND_ENUM = 1
-        IN_ENUM    = 2
+    #     SEARCHING  = 0
+    #     FOUND_ENUM = 1
+    #     IN_ENUM    = 2
 
-        mode    = SEARCHING
-        decls   = {}
-        idx     = 0
+    #     mode    = SEARCHING
+    #     decls   = {}
+    #     idx     = 0
 
-        linenum = 1
-        for line in api:
-            m1 = blank_pat.match(line)
-            m2 = comment_pat.match(line)
-            if m1 or m2:
-                # skip blank lines and comments
-                linenum = linenum + 1
-            elif mode == SEARCHING:
-                m = typedef_pat.match(line)
-                if m:
-                    mode = FOUND_ENUM
-                m = typedef2_pat.match(line)
-                if m:
-                    mode = IN_ENUM
-                    decls = {}
-                    idx   = 0
-            elif mode == FOUND_ENUM:
-                m = openbrace_pat.match(line)
-                if m:
-                    mode  = IN_ENUM
-                    decls = {}
-                    idx   = 0
-                else:
-                    assert False, "Invalid %s, line: %s" % (api_file, linenum)
-            else:
-                assert mode == IN_ENUM
-                words = re.split('[^\-a-zA-Z0-9_]+', line)
-                m = closebrace_pat.match(line)
-                if m:
-                    name = words[1]
-                    if name not in DeprecatedEnums:
-                        efile.write('(** %s *)\n' % name[3:])
-                        efile.write('type %s =\n' % name[3:]) # strip Z3_
-                        for k, i in decls.items():
-                            efile.write('  | %s \n' % k[3:]) # strip Z3_
-                        efile.write('\n')
-                        efile.write('(** Convert %s to int*)\n' % name[3:])
-                        efile.write('val int_of_%s : %s -> int\n' % (name[3:], name[3:])) # strip Z3_
-                        efile.write('(** Convert int to %s*)\n' % name[3:])
-                        efile.write('val %s_of_int : int -> %s\n' % (name[3:],name[3:])) # strip Z3_
-                        efile.write('\n')
-                    mode = SEARCHING
-                else:
-                    if words[2] != '':
-                        if len(words[2]) > 1 and words[2][1] == 'x':
-                            idx = int(words[2], 16)
-                        else:
-                            idx = int(words[2])
-                    decls[words[1]] = idx
-                    idx = idx + 1
-            linenum = linenum + 1
-        api.close()
-    efile.close()
-    if VERBOSE:
-        print ('Generated "%s/z3enums.mli"' % ('%s' % gendir))
+    #     linenum = 1
+    #     for line in api:
+    #         m1 = blank_pat.match(line)
+    #         m2 = comment_pat.match(line)
+    #         if m1 or m2:
+    #             # skip blank lines and comments
+    #             linenum = linenum + 1
+    #         elif mode == SEARCHING:
+    #             m = typedef_pat.match(line)
+    #             if m:
+    #                 mode = FOUND_ENUM
+    #             m = typedef2_pat.match(line)
+    #             if m:
+    #                 mode = IN_ENUM
+    #                 decls = {}
+    #                 idx   = 0
+    #         elif mode == FOUND_ENUM:
+    #             m = openbrace_pat.match(line)
+    #             if m:
+    #                 mode  = IN_ENUM
+    #                 decls = {}
+    #                 idx   = 0
+    #             else:
+    #                 assert False, "Invalid %s, line: %s" % (api_file, linenum)
+    #         else:
+    #             assert mode == IN_ENUM
+    #             words = re.split('[^\-a-zA-Z0-9_]+', line)
+    #             m = closebrace_pat.match(line)
+    #             if m:
+    #                 name = words[1]
+    #                 if name not in DeprecatedEnums:
+    #                     efile.write('(** %s *)\n' % name[3:])
+    #                     efile.write('type %s =\n' % name[3:]) # strip Z3_
+    #                     for k, i in decls.items():
+    #                         efile.write('  | %s \n' % k[3:]) # strip Z3_
+    #                     efile.write('\n')
+    #                     efile.write('(** Convert %s to int*)\n' % name[3:])
+    #                     efile.write('val int_of_%s : %s -> int\n' % (name[3:], name[3:])) # strip Z3_
+    #                     efile.write('(** Convert int to %s*)\n' % name[3:])
+    #                     efile.write('val %s_of_int : int -> %s\n' % (name[3:],name[3:])) # strip Z3_
+    #                     efile.write('\n')
+    #                 mode = SEARCHING
+    #             else:
+    #                 if words[2] != '':
+    #                     if len(words[2]) > 1 and words[2][1] == 'x':
+    #                         idx = int(words[2], 16)
+    #                     else:
+    #                         idx = int(words[2])
+    #                 decls[words[1]] = idx
+    #                 idx = idx + 1
+    #         linenum = linenum + 1
+    #     api.close()
+    # efile.close()
+    # if VERBOSE:
+    #     print ('Generated "%s/z3enums.mli"' % ('%s' % gendir))
 
 def mk_gui_str(id):
     return '4D2F40D8-E5F9-473B-B548-%012d' % id
diff --git a/scripts/update_api.py b/scripts/update_api.py
index 7603817eb..a06f1fbb1 100755
--- a/scripts/update_api.py
+++ b/scripts/update_api.py
@@ -78,7 +78,7 @@ Type2Dotnet = { VOID : 'void', VOID_PTR : 'IntPtr', INT : 'int', UINT : 'uint',
 
 # Mapping to Java types
 Type2Java = { VOID : 'void', VOID_PTR : 'long', INT : 'int', UINT : 'int', INT64 : 'long', UINT64 : 'long', DOUBLE : 'double',
-              FLOAT : 'float', STRING : 'String', STRING_PTR : 'StringPtr', 
+              FLOAT : 'float', STRING : 'String', STRING_PTR : 'StringPtr',
               BOOL : 'boolean', SYMBOL : 'long', PRINT_MODE : 'int', ERROR_CODE : 'int'}
 
 Type2JavaW = { VOID : 'void', VOID_PTR : 'jlong', INT : 'jint', UINT : 'jint', INT64 : 'jlong', UINT64 : 'jlong', DOUBLE : 'jdouble',
@@ -87,7 +87,7 @@ Type2JavaW = { VOID : 'void', VOID_PTR : 'jlong', INT : 'jint', UINT : 'jint', I
 
 # Mapping to ML types
 Type2ML = { VOID : 'unit', VOID_PTR : 'VOIDP', INT : 'int', UINT : 'int', INT64 : 'int', UINT64 : 'int', DOUBLE : 'float',
-            FLOAT : 'float', STRING : 'string', STRING_PTR : 'char**', 
+            FLOAT : 'float', STRING : 'string', STRING_PTR : 'char**',
             BOOL : 'bool', SYMBOL : 'z3_symbol', PRINT_MODE : 'int', ERROR_CODE : 'int' }
 
 next_type_id = FIRST_OBJ_ID
@@ -95,7 +95,7 @@ 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), globals())
-    Type2Str[next_type_id]   = c_type
+    Type2Str[next_type_id] = c_type
     Type2PyStr[next_type_id] = py_type
     next_type_id    = next_type_id + 1
 
@@ -141,7 +141,11 @@ def type2javaw(ty):
 
 def type2ml(ty):
     global Type2ML
-    return Type2ML[ty]
+    q = Type2ML[ty]
+    if q[0:3] == 'z3_':
+        return q[3:]
+    else:
+        return q;
 
 def _in(ty):
     return (IN, ty)
@@ -261,9 +265,9 @@ def param2ml(p):
         else:
             return "ptr"
     elif k == IN_ARRAY or k == INOUT_ARRAY or k == OUT_ARRAY:
-        return "%s array" % type2ml(param_type(p))
+        return "%s list" % type2ml(param_type(p))
     elif k == OUT_MANAGED_ARRAY:
-        return "%s array" % type2ml(param_type(p))
+        return "%s list" % type2ml(param_type(p))
     else:
         return type2ml(param_type(p))
 
@@ -385,7 +389,7 @@ def mk_dotnet(dotnet):
     dotnet.write('        }\n')
 
 
-NULLWrapped = [ 'Z3_mk_context', 'Z3_mk_context_rc' ]
+NULLWrapped = [ 'Z3_mk_context', 'Z3_mk_context_rc', 'Z3_mk_interpolation_context' ]
 Unwrapped = [ 'Z3_del_context', 'Z3_get_error_code' ]
 
 def mk_dotnet_wrappers(dotnet):
@@ -633,18 +637,18 @@ def mk_java(java_dir, package_name):
             elif k == IN_ARRAY or k == INOUT_ARRAY:
                 if param_type(param) == INT or param_type(param) == UINT:
                     java_wrapper.write('  %s * _a%s = (%s*) jenv->GetIntArrayElements(a%s, NULL);\n' % (type2str(param_type(param)), i, type2str(param_type(param)), i))
-                else:                    
+                else:
                     java_wrapper.write('  GETLONGAELEMS(%s, a%s, _a%s);\n' % (type2str(param_type(param)), i, i))
             elif k == OUT_ARRAY:
-                java_wrapper.write('  %s * _a%s = (%s *) malloc(((unsigned)a%s) * sizeof(%s));\n' % (type2str(param_type(param)), 
-                                                                                                     i, 
-                                                                                                     type2str(param_type(param)), 
-                                                                                                     param_array_capacity_pos(param), 
+                java_wrapper.write('  %s * _a%s = (%s *) malloc(((unsigned)a%s) * sizeof(%s));\n' % (type2str(param_type(param)),
+                                                                                                     i,
+                                                                                                     type2str(param_type(param)),
+                                                                                                     param_array_capacity_pos(param),
                                                                                                      type2str(param_type(param))))
                 if param_type(param) == INT or param_type(param) == UINT:
                     java_wrapper.write('  jenv->GetIntArrayRegion(a%s, 0, (jsize)a%s, (jint*)_a%s);\n' % (i, param_array_capacity_pos(param), i))
                 else:
-                    java_wrapper.write('  GETLONGAREGION(%s, a%s, 0, a%s, _a%s);\n' % (type2str(param_type(param)), i, param_array_capacity_pos(param), i))    
+                    java_wrapper.write('  GETLONGAREGION(%s, a%s, 0, a%s, _a%s);\n' % (type2str(param_type(param)), i, param_array_capacity_pos(param), i))
             elif k == IN and param_type(param) == STRING:
                 java_wrapper.write('  Z3_string _a%s = (Z3_string) jenv->GetStringUTFChars(a%s, NULL);\n' % (i, i))
             elif k == OUT_MANAGED_ARRAY:
@@ -675,7 +679,7 @@ def mk_java(java_dir, package_name):
                 java_wrapper.write('(%s)a%i' % (param2str(param), i))
             i = i + 1
         java_wrapper.write(');\n')
-        # cleanup 
+        # cleanup
         i = 0
         for param in params:
             k = param_kind(param)
@@ -711,7 +715,7 @@ def mk_java(java_dir, package_name):
         if result == STRING:
             java_wrapper.write('  return jenv->NewStringUTF(result);\n')
         elif result != VOID:
-            java_wrapper.write('  return (%s) result;\n' % type2javaw(result))        
+            java_wrapper.write('  return (%s) result;\n' % type2javaw(result))
         java_wrapper.write('}\n')
     java_wrapper.write('#ifdef __cplusplus\n')
     java_wrapper.write('}\n')
@@ -941,7 +945,7 @@ def def_API(name, result, params):
                 error ("unsupported parameter for %s, %s" % (ty, name, p))
         elif kind == OUT_ARRAY:
             sz   = param_array_capacity_pos(p)
-            sz_p = params[sz]            
+            sz_p = params[sz]
             sz_p_k = param_kind(sz_p)
             tstr = type2str(ty)
             if sz_p_k == OUT or sz_p_k == INOUT:
@@ -1039,11 +1043,115 @@ def arrayparams(params):
             op.append(param)
     return op
 
+def ml_plus_type(ts):
+    if ts == 'Z3_context':
+        return 'Z3_context_plus'
+    elif ts == 'Z3_ast' or ts == 'Z3_sort' or ts == 'Z3_func_decl' or ts == 'Z3_app' or ts == 'Z3_pattern':
+        return 'Z3_ast_plus'
+    elif ts == 'Z3_symbol':
+        return 'Z3_symbol_plus'
+    elif ts == 'Z3_constructor':
+        return 'Z3_constructor_plus'
+    elif ts == 'Z3_constructor_list':
+        return 'Z3_constructor_list_plus'
+    elif ts == 'Z3_rcf_num':
+        return 'Z3_rcf_num_plus'
+    elif ts == 'Z3_params':
+        return 'Z3_params_plus'
+    elif ts == 'Z3_param_descrs':
+        return 'Z3_param_descrs_plus'
+    elif ts == 'Z3_model':
+        return 'Z3_model_plus'
+    elif ts == 'Z3_func_interp':
+        return 'Z3_func_interp_plus'
+    elif ts == 'Z3_func_entry':
+        return 'Z3_func_entry_plus'
+    elif ts == 'Z3_goal':
+        return 'Z3_goal_plus'
+    elif ts == 'Z3_tactic':
+        return 'Z3_tactic_plus'
+    elif ts == 'Z3_probe':
+        return 'Z3_probe_plus'
+    elif ts == 'Z3_apply_result':
+        return 'Z3_apply_result_plus'
+    elif ts == 'Z3_solver':
+        return 'Z3_solver_plus'
+    elif ts == 'Z3_stats':
+        return 'Z3_stats_plus'
+    elif ts == 'Z3_ast_vector':
+        return 'Z3_ast_vector_plus'
+    elif ts == 'Z3_ast_map':
+        return 'Z3_ast_map_plus'
+    elif ts == 'Z3_fixedpoint':
+        return 'Z3_fixedpoint_plus'
+    elif ts == 'Z3_optimize':
+        return 'Z3_optimize_plus'
+    else:
+        return ts
+
+def ml_minus_type(ts):
+    if ts == 'Z3_ast' or ts == 'Z3_sort' or ts == 'Z3_func_decl' or ts == 'Z3_app' or ts == 'Z3_pattern':
+        return 'Z3_ast'
+    if ts == 'Z3_ast_plus' or ts == 'Z3_sort_plus' or ts == 'Z3_func_decl_plus' or ts == 'Z3_app_plus' or ts == 'Z3_pattern_plus':
+        return 'Z3_ast'
+    elif ts == 'Z3_constructor_plus':
+        return 'Z3_constructor'
+    elif ts == 'Z3_constructor_list_plus':
+        return 'Z3_constructor_list'
+    elif ts == 'Z3_rcf_num_plus':
+        return 'Z3_rcf_num'
+    elif ts == 'Z3_params_plus':
+        return 'Z3_params'
+    elif ts == 'Z3_param_descrs_plus':
+        return 'Z3_param_descrs'
+    elif ts == 'Z3_model_plus':
+        return 'Z3_model'
+    elif ts == 'Z3_func_interp_plus':
+        return 'Z3_func_interp'
+    elif ts == 'Z3_func_entry_plus':
+        return 'Z3_func_entry'
+    elif ts == 'Z3_goal_plus':
+        return 'Z3_goal'
+    elif ts == 'Z3_tactic_plus':
+        return 'Z3_tactic'
+    elif ts == 'Z3_probe_plus':
+        return 'Z3_probe'
+    elif ts == 'Z3_apply_result_plus':
+        return 'Z3_apply_result'
+    elif ts == 'Z3_solver_plus':
+        return 'Z3_solver'
+    elif ts == 'Z3_stats_plus':
+        return 'Z3_stats'
+    elif ts == 'Z3_ast_vector_plus':
+        return 'Z3_ast_vector'
+    elif ts == 'Z3_ast_map_plus':
+        return 'Z3_ast_map'
+    elif ts == 'Z3_fixedpoint_plus':
+        return 'Z3_fixedpoint'
+    elif ts == 'Z3_optimize_plus':
+        return 'Z3_optimize'
+    else:
+        return ts
+
+def ml_plus_type_raw(ts):
+    if ml_has_plus_type(ts):
+        return ml_plus_type(ts) + '_raw';
+    else:
+        return ts
+
+def ml_plus_ops_type(ts):
+    if ml_has_plus_type(ts):
+        return ml_plus_type(ts) + '_custom_ops'
+    else:
+        return 'default_custom_ops'
+
+def ml_has_plus_type(ts):
+    return ts != ml_plus_type(ts)
 
 def ml_unwrap(t, ts, s):
     if t == STRING:
         return '(' + ts + ') String_val(' + s + ')'
-    elif t == BOOL:
+    elif t == BOOL or (type2str(t) == 'Z3_bool'):
         return '(' + ts + ') Bool_val(' + s + ')'
     elif t == INT or t == PRINT_MODE or t == ERROR_CODE:
         return '(' + ts + ') Int_val(' + s + ')'
@@ -1055,232 +1163,105 @@ def ml_unwrap(t, ts, s):
         return '(' + ts + ') Unsigned_long_val(' + s + ')'
     elif t == DOUBLE:
         return '(' + ts + ') Double_val(' + s + ')'
+    elif ml_has_plus_type(ts):
+        pts = ml_plus_type(ts)
+        return '(' + ts + ') ' + ml_plus_type_raw(ts) + '((' + pts + '*) Data_custom_val(' + s + '))'
     else:
-        return '* (' + ts + '*) Data_custom_val(' + s + ')'
+        return '* ((' + ts + '*) Data_custom_val(' + s + '))'
 
 def ml_set_wrap(t, d, n):
     if t == VOID:
         return d + ' = Val_unit;'
-    elif t == BOOL:
+    elif t == BOOL or (type2str(t) == 'Z3_bool'):
         return d + ' = Val_bool(' + n + ');'
     elif t == INT or t == UINT or t == PRINT_MODE or t == ERROR_CODE:
         return d + ' = Val_int(' + n + ');'
     elif t == INT64 or t == UINT64:
         return d + ' = Val_long(' + n + ');'
     elif t == DOUBLE:
-        return 'Store_double_val(' + d + ', ' + n + ');'
+        return d + '= caml_copy_double(' + n + ');'
     elif t == STRING:
         return d + ' = caml_copy_string((const char*) ' + n + ');'
     else:
-        ts = type2str(t)
-        return d + ' = caml_alloc_custom(&default_custom_ops, sizeof(' + ts + '), 0, 1); memcpy( Data_custom_val(' + d + '), &' + n + ', sizeof(' + ts + '));'
+        pts = ml_plus_type(type2str(t))
+        return '*(' + pts + '*)Data_custom_val(' + d + ') = ' + n + ';'
+
+def ml_alloc_and_store(t, lhs, rhs):
+    if t == VOID or t == BOOL or t == INT or t == UINT or t == PRINT_MODE or t == ERROR_CODE or t == INT64 or t == UINT64 or t == DOUBLE or t == STRING or (type2str(t) == 'Z3_bool'):
+        return ml_set_wrap(t, lhs, rhs)
+    else:
+        pts = ml_plus_type(type2str(t))
+        pops = ml_plus_ops_type(type2str(t))
+        alloc_str = '%s = caml_alloc_custom(&%s, sizeof(%s), 0, 1); ' % (lhs, pops, pts)
+        return alloc_str + ml_set_wrap(t, lhs, rhs)
 
 def mk_ml(ml_dir):
     global Type2Str
     ml_nativef  = os.path.join(ml_dir, 'z3native.ml')
-    ml_nativefi = os.path.join(ml_dir, 'z3native.mli')
-    ml_wrapperf = os.path.join(ml_dir, 'z3native_stubs.c')
     ml_native   = open(ml_nativef, 'w')
-    ml_i        = open(ml_nativefi, 'w')
     ml_native.write('(* Automatically generated file *)\n\n')
-    ml_native.write('(** The native (raw) interface to the dynamic Z3 library. *)\n\n')
-    ml_i.write('(* Automatically generated file *)\n\n')
-    ml_i.write('(** The native (raw) interface to the dynamic Z3 library. *)\n\n')
-    ml_i.write('(**/**)\n\n')
-    ml_native.write('open Z3enums\n\n')
-    ml_native.write('(**/**)\n')
-    ml_native.write('type ptr\n')
-    ml_i.write('type ptr\n')
-    ml_native.write('and z3_symbol = ptr\n')
-    ml_i.write('and z3_symbol = ptr\n')
-    for k, v in Type2Str.items():
-        if is_obj(k):
-            ml_native.write('and %s = ptr\n' % v.lower())
-            ml_i.write('and %s = ptr\n' % v.lower())
-    ml_native.write('\n')
-    ml_i.write('\n')
-    ml_native.write('external is_null : ptr -> bool\n  = "n_is_null"\n\n')
-    ml_native.write('external mk_null : unit -> ptr\n  = "n_mk_null"\n\n')
-    ml_native.write('external set_internal_error_handler : ptr -> unit\n  = "n_set_internal_error_handler"\n\n')
-    ml_native.write('exception Exception of string\n\n')
-    ml_i.write('val is_null : ptr -> bool\n')
-    ml_i.write('val mk_null : unit -> ptr\n')
-    ml_i.write('val set_internal_error_handler : ptr -> unit\n\n')
-    ml_i.write('exception Exception of string\n\n')
 
-    # ML declarations
-    ml_native.write('module ML2C = struct\n\n')
+    ml_pref = open(os.path.join(ml_dir, 'z3native.ml.pre'), 'r')
+    for s in ml_pref:
+        ml_native.write(s);
+    ml_pref.close()
+
+    ml_native.write('\n')
     for name, result, params in _dotnet_decls:
-        ml_native.write('    external n_%s : ' % ml_method_name(name))
-        ml_i.write('val %s : ' % ml_method_name(name))
+        ml_native.write('external %s : ' % ml_method_name(name))
         ip = inparams(params)
         op = outparams(params)
         if len(ip) == 0:
             ml_native.write(' unit -> ')
-            ml_i.write(' unit -> ')
         for p in ip:
             ml_native.write('%s -> ' % param2ml(p))
-            ml_i.write('%s -> ' % param2ml(p))
         if len(op) > 0:
             ml_native.write('(')
-            ml_i.write('(')
         first = True
         if result != VOID or len(op) == 0:
             ml_native.write('%s' % type2ml(result))
-            ml_i.write('%s' % type2ml(result))
             first = False
         for p in op:
             if first:
                 first = False
             else:
                 ml_native.write(' * ')
-                ml_i.write(' * ')
             ml_native.write('%s' % param2ml(p))
-            ml_i.write('%s' % param2ml(p))
         if len(op) > 0:
             ml_native.write(')')
-            ml_i.write(')')
-        ml_native.write('\n')
-        ml_i.write('\n')
         if len(ip) > 5:
-            ml_native.write('      = "n_%s_bytecode"\n' % ml_method_name(name))
-            ml_native.write('        "n_%s"\n' % ml_method_name(name))
+            ml_native.write('  = "n_%s_bytecode" "n_%s"\n' % (ml_method_name(name), ml_method_name(name)))
         else:
-            ml_native.write('      = "n_%s"\n' % ml_method_name(name))
+            ml_native.write('  = "n_%s"\n' % ml_method_name(name))
         ml_native.write('\n')
-    ml_native.write('  end\n\n')
-    ml_i.write('\n(**/**)\n')
 
-    # Exception wrappers
-    for name, result, params in _dotnet_decls:
-        ip = inparams(params)
-        op = outparams(params)
-        ml_native.write('  let %s ' % ml_method_name(name))
+    # null pointer helpers
+    for type_id in Type2Str:
+        type_name = Type2Str[type_id]
+        if ml_has_plus_type(type_name) and not type_name in ['Z3_context', 'Z3_sort', 'Z3_func_decl', 'Z3_app', 'Z3_pattern']:
+            ml_name = type2ml(type_id)
+            ml_native.write('external context_of_%s : %s -> context = "n_context_of_%s"\n' % (ml_name, ml_name, ml_name))
+            ml_native.write('external is_null_%s : %s -> bool = "n_is_null_%s"\n' % (ml_name, ml_name, ml_name))
+            ml_native.write('external mk_null_%s : context -> %s = "n_mk_null_%s"\n\n' % (ml_name, ml_name, ml_name))
 
-        first = True
-        i = 0
-        for p in params:
-            if is_in_param(p):
-                if first:
-                    first = False
-                else:
-                    ml_native.write(' ')
-                ml_native.write('a%d' % i)
-            i = i + 1
-        if len(ip) == 0:
-            ml_native.write('()')
-        ml_native.write(' = \n')
-        ml_native.write('    ')
-        if result == VOID and len(op) == 0:
-            ml_native.write('let _ = ')
-        else:
-            ml_native.write('let res = ')
-        ml_native.write('(ML2C.n_%s' % (ml_method_name(name)))
-        if len(ip) == 0:
-            ml_native.write(' ()')
-        first = True
-        i = 0
-        for p in params:
-            if is_in_param(p):
-                ml_native.write(' a%d' % i)
-            i = i + 1
-        ml_native.write(') in\n')
-        if name not in Unwrapped and len(params) > 0 and param_type(params[0]) == CONTEXT:
-            ml_native.write('    let err = (error_code_of_int (ML2C.n_get_error_code a0)) in \n')
-            ml_native.write('      if err <> OK then\n')
-            ml_native.write('        raise (Exception (ML2C.n_get_error_msg a0 (int_of_error_code err)))\n')
-            ml_native.write('      else\n')
-        if result == VOID and len(op) == 0:
-            ml_native.write('        ()\n')
-        else:
-            ml_native.write('        res\n')
-        ml_native.write('\n')
     ml_native.write('(**/**)\n')
+    ml_native.close()
 
-    # C interface
+    if mk_util.is_verbose():
+        print ('Generated "%s"' % ml_nativef)
+
+    mk_z3native_stubs_c(ml_dir)
+
+def mk_z3native_stubs_c(ml_dir): # C interface
+    ml_wrapperf = os.path.join(ml_dir, 'z3native_stubs.c')
     ml_wrapper = open(ml_wrapperf, 'w')
     ml_wrapper.write('// Automatically generated file\n\n')
-    ml_wrapper.write('#include <stddef.h>\n')
-    ml_wrapper.write('#include <string.h>\n\n')
-    ml_wrapper.write('#ifdef __cplusplus\n')
-    ml_wrapper.write('extern "C" {\n')
-    ml_wrapper.write('#endif\n')
-    ml_wrapper.write('#include <caml/mlvalues.h>\n')
-    ml_wrapper.write('#include <caml/memory.h>\n')
-    ml_wrapper.write('#include <caml/alloc.h>\n')
-    ml_wrapper.write('#include <caml/fail.h>\n')
-    ml_wrapper.write('#include <caml/callback.h>\n')
-    ml_wrapper.write('#ifdef Custom_tag\n')
-    ml_wrapper.write('#include <caml/custom.h>\n')
-    ml_wrapper.write('#include <caml/bigarray.h>\n')
-    ml_wrapper.write('#endif\n')
-    ml_wrapper.write('#ifdef __cplusplus\n')
-    ml_wrapper.write('}\n')
-    ml_wrapper.write('#endif\n\n')
-    ml_wrapper.write('#include <z3.h>\n')
-    ml_wrapper.write('#include <z3native_stubs.h>\n\n')
-    ml_wrapper.write('#define CAMLlocal6(X1,X2,X3,X4,X5,X6)                               \\\n')
-    ml_wrapper.write('  CAMLlocal5(X1,X2,X3,X4,X5);                                       \\\n')
-    ml_wrapper.write('  CAMLlocal1(X6)                                                      \n')
-    ml_wrapper.write('#define CAMLlocal7(X1,X2,X3,X4,X5,X6,X7)                            \\\n')
-    ml_wrapper.write('  CAMLlocal5(X1,X2,X3,X4,X5);                                       \\\n')
-    ml_wrapper.write('  CAMLlocal2(X6,X7)                                                   \n')
-    ml_wrapper.write('#define CAMLlocal8(X1,X2,X3,X4,X5,X6,X7,X8)                         \\\n')
-    ml_wrapper.write('  CAMLlocal5(X1,X2,X3,X4,X5);                                       \\\n')
-    ml_wrapper.write('  CAMLlocal3(X6,X7,X8)                                                \n')
-    ml_wrapper.write('\n')
-    ml_wrapper.write('#define CAMLparam7(X1,X2,X3,X4,X5,X6,X7)                            \\\n')
-    ml_wrapper.write('  CAMLparam5(X1,X2,X3,X4,X5);                                       \\\n')
-    ml_wrapper.write('  CAMLxparam2(X6,X7)                                                  \n')
-    ml_wrapper.write('#define CAMLparam8(X1,X2,X3,X4,X5,X6,X7,X8)                         \\\n')
-    ml_wrapper.write('  CAMLparam5(X1,X2,X3,X4,X5);                                       \\\n')
-    ml_wrapper.write('  CAMLxparam3(X6,X7,X8)                                               \n')
-    ml_wrapper.write('#define CAMLparam9(X1,X2,X3,X4,X5,X6,X7,X8,X9)                      \\\n')
-    ml_wrapper.write('  CAMLparam5(X1,X2,X3,X4,X5);                                       \\\n')
-    ml_wrapper.write('  CAMLxparam4(X6,X7,X8,X9)                                            \n')
-    ml_wrapper.write('#define CAMLparam12(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12)         \\\n')
-    ml_wrapper.write('  CAMLparam5(X1,X2,X3,X4,X5);                                       \\\n')
-    ml_wrapper.write('  CAMLxparam5(X6,X7,X8,X9,X10);                                     \\\n')
-    ml_wrapper.write('  CAMLxparam2(X11,X12)                                                \n')
-    ml_wrapper.write('#define CAMLparam13(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13)     \\\n')
-    ml_wrapper.write('  CAMLparam5(X1,X2,X3,X4,X5);                                       \\\n')
-    ml_wrapper.write('  CAMLxparam5(X6,X7,X8,X9,X10);                                     \\\n')
-    ml_wrapper.write('  CAMLxparam3(X11,X12,X13)                                            \n')
-    ml_wrapper.write('\n\n')
-    ml_wrapper.write('static struct custom_operations default_custom_ops = {\n')
-    ml_wrapper.write('  (char*) "default handling",\n')
-    ml_wrapper.write('  custom_finalize_default,\n')
-    ml_wrapper.write('  custom_compare_default,\n')
-    ml_wrapper.write('  custom_hash_default,\n')
-    ml_wrapper.write('  custom_serialize_default,\n')
-    ml_wrapper.write('  custom_deserialize_default\n')
-    ml_wrapper.write('};\n\n')
-    ml_wrapper.write('#ifdef __cplusplus\n')
-    ml_wrapper.write('extern "C" {\n')
-    ml_wrapper.write('#endif\n\n')
-    ml_wrapper.write('CAMLprim DLL_PUBLIC value n_is_null(value p) {\n')
-    ml_wrapper.write('  void * t = * (void**) Data_custom_val(p);\n')
-    ml_wrapper.write('  return Val_bool(t == 0);\n')
-    ml_wrapper.write('}\n\n')
-    ml_wrapper.write('CAMLprim DLL_PUBLIC value n_mk_null( void ) {\n')
-    ml_wrapper.write('  CAMLparam0();\n')
-    ml_wrapper.write('  CAMLlocal1(result);\n')
-    ml_wrapper.write('  void * z3_result = 0;\n')
-    ml_wrapper.write('  result = caml_alloc_custom(&default_custom_ops, sizeof(void*), 0, 1);\n')
-    ml_wrapper.write('  memcpy( Data_custom_val(result), &z3_result, sizeof(void*));\n')
-    ml_wrapper.write('  CAMLreturn (result);\n')
-    ml_wrapper.write('}\n\n')
-    ml_wrapper.write('void MLErrorHandler(Z3_context c, Z3_error_code e)\n')
-    ml_wrapper.write('{\n')
-    ml_wrapper.write('  // Internal do-nothing error handler. This is required to avoid that Z3 calls exit()\n')
-    ml_wrapper.write('  // upon errors, but the actual error handling is done by throwing exceptions in the\n')
-    ml_wrapper.write('  // wrappers below.\n')
-    ml_wrapper.write('}\n\n')
-    ml_wrapper.write('void DLL_PUBLIC n_set_internal_error_handler(value a0)\n')
-    ml_wrapper.write('{\n')
-    ml_wrapper.write('  Z3_context _a0 = * (Z3_context*) Data_custom_val(a0);\n')
-    ml_wrapper.write('  Z3_set_error_handler(_a0, MLErrorHandler);\n')
-    ml_wrapper.write('}\n\n')
+
+    ml_pref = open(os.path.join(ml_dir, 'z3native_stubs.c.pre'), 'r')
+    for s in ml_pref:
+        ml_wrapper.write(s);
+    ml_pref.close()
+
     for name, result, params in _dotnet_decls:
         ip = inparams(params)
         op = outparams(params)
@@ -1288,16 +1269,16 @@ def mk_ml(ml_dir):
         ret_size = len(op)
         if result != VOID:
             ret_size = ret_size + 1
-            
+
         # Setup frame
-        ml_wrapper.write('CAMLprim DLL_PUBLIC value n_%s(' % ml_method_name(name)) 
+        ml_wrapper.write('CAMLprim DLL_PUBLIC value n_%s(' % ml_method_name(name))
         first = True
         i = 0
         for p in params:
             if is_in_param(p):
                 if first:
                     first = False
-                else:                
+                else:
                     ml_wrapper.write(', ')
                 ml_wrapper.write('value a%d' % i)
             i = i + 1
@@ -1319,61 +1300,86 @@ def mk_ml(ml_dir):
             ml_wrapper.write('  CAMLlocal1(result);\n')
         else:
             c = 0
+            needs_tmp_value = False
             for p in params:
                 if is_out_param(p) or is_array_param(p):
                     c = c + 1
-            ml_wrapper.write('  CAMLlocal%s(result, res_val' % (c+2))
+                    needs_tmp_value = needs_tmp_value or param_kind(p) == OUT_ARRAY or param_kind(p) == INOUT_ARRAY
+            if needs_tmp_value:
+                c = c + 1
+            if len(ap) > 0:
+                c = c + 1
+            ml_wrapper.write('  CAMLlocal%s(result, z3rv_val' % (c+2))
             for p in params:
                 if is_out_param(p) or is_array_param(p):
                     ml_wrapper.write(', _a%s_val' % i)
                 i = i + 1
+            if needs_tmp_value:
+                ml_wrapper.write(', tmp_val')
+            if len(ap) != 0:
+                ml_wrapper.write(', _iter');
+
             ml_wrapper.write(');\n')
 
-        if len(ap) != 0:
+        if len(ap) > 0:
             ml_wrapper.write('  unsigned _i;\n')
 
         # declare locals, preprocess arrays, strings, in/out arguments
+        have_context = False
         i = 0
         for param in params:
-            k = param_kind(param)
-            if k == OUT_ARRAY:
-                ml_wrapper.write('  %s * _a%s = (%s*) malloc(sizeof(%s) * (_a%s));\n' % (
+            if param_type(param) == CONTEXT and i == 0:
+                ml_wrapper.write('  Z3_context_plus ctx_p = *(Z3_context_plus*) Data_custom_val(a' + str(i) + ');\n')
+                ml_wrapper.write('  Z3_context _a0 = ctx_p->ctx;\n')
+                have_context = True
+            else:
+                k = param_kind(param)
+                if k == OUT_ARRAY:
+                    ml_wrapper.write('  %s * _a%s = (%s*) malloc(sizeof(%s) * (_a%s));\n' % (
                         type2str(param_type(param)),
-                        i, 
+                        i,
                         type2str(param_type(param)),
                         type2str(param_type(param)),
                         param_array_capacity_pos(param)))
-            elif k == OUT_MANAGED_ARRAY:
-                ml_wrapper.write('  %s * _a%s = 0;\n' % (type2str(param_type(param)), i))
-            elif k == IN_ARRAY or k == INOUT_ARRAY:
-                t = param_type(param)
-                ts = type2str(t)
-                ml_wrapper.write('  %s * _a%s = (%s*) malloc(sizeof(%s) * _a%s);\n' % (ts, i, ts, ts, param_array_capacity_pos(param)))                
-            elif k == IN:
-                t = param_type(param)
-                ml_wrapper.write('  %s _a%s = %s;\n' % (type2str(t), i, ml_unwrap(t, type2str(t), 'a' + str(i))))
-            elif k == OUT:
-                ml_wrapper.write('  %s _a%s;\n' % (type2str(param_type(param)), i))
-            elif k == INOUT:
-                ml_wrapper.write('  %s _a%s = a%s;\n' % (type2str(param_type(param)), i, i))                
+                elif k == OUT_MANAGED_ARRAY:
+                    ml_wrapper.write('  %s * _a%s = 0;\n' % (type2str(param_type(param)), i))
+                elif k == IN_ARRAY or k == INOUT_ARRAY:
+                    t = param_type(param)
+                    ts = type2str(t)
+                    ml_wrapper.write('  %s * _a%s = (%s*) malloc(sizeof(%s) * _a%s);\n' % (ts, i, ts, ts, param_array_capacity_pos(param)))
+                elif k == IN:
+                    t = param_type(param)
+                    ml_wrapper.write('  %s _a%s = %s;\n' % (type2str(t), i, ml_unwrap(t, type2str(t), 'a' + str(i))))
+                elif k == OUT:
+                    ml_wrapper.write('  %s _a%s;\n' % (type2str(param_type(param)), i))
+                elif k == INOUT:
+                    ml_wrapper.write('  %s _a%s = a%s;\n' % (type2str(param_type(param)), i, i))
             i = i + 1
 
-        if result != VOID:
-            ml_wrapper.write('  %s z3_result;\n' % type2str(result))
-
         i = 0
         for param in params:
             k = param_kind(param)
             if k == IN_ARRAY or k == INOUT_ARRAY:
                 t = param_type(param)
                 ts = type2str(t)
-                ml_wrapper.write('  for (_i = 0; _i < _a%s; _i++) { _a%s[_i] = %s; }\n' % (param_array_capacity_pos(param), i, ml_unwrap(t, ts, 'Field(a' + str(i) + ', _i)')))
+                ml_wrapper.write('  _iter = a' + str(i) + ';\n')
+                ml_wrapper.write('  for (_i = 0; _i < _a%s; _i++) {\n' % param_array_capacity_pos(param))
+                ml_wrapper.write('    assert(_iter != Val_emptylist);\n')
+                ml_wrapper.write('    _a%s[_i] = %s;\n' % (i, ml_unwrap(t, ts, 'Field(_iter, 0)')))
+                ml_wrapper.write('    _iter = Field(_iter, 1);\n')
+                ml_wrapper.write('  }\n')
+                ml_wrapper.write('  assert(_iter == Val_emptylist);\n\n')
             i = i + 1
 
-        # invoke procedure
-        ml_wrapper.write('  ')
+        ml_wrapper.write('\n  /* invoke Z3 function */\n  ')
         if result != VOID:
-            ml_wrapper.write('z3_result = ')
+            ts = type2str(result)
+            if ml_has_plus_type(ts):
+                ml_wrapper.write('%s z3rv_m = ' % ts)
+            else:
+                ml_wrapper.write('%s z3rv = ' % ts)
+
+        # invoke procedure
         ml_wrapper.write('%s(' % name)
         i = 0
         first = True
@@ -1390,37 +1396,84 @@ def mk_ml(ml_dir):
             i = i + 1
         ml_wrapper.write(');\n')
 
+        if have_context and name not in Unwrapped:
+            ml_wrapper.write('  int ec = Z3_get_error_code(ctx_p->ctx);\n')
+            ml_wrapper.write('  if (ec != 0) {\n')
+            ml_wrapper.write('    const char * msg = Z3_get_error_msg(ctx_p->ctx, ec);\n')
+            ml_wrapper.write('    caml_raise_with_string(*caml_named_value("Z3EXCEPTION"), msg);\n')
+            ml_wrapper.write('  }\n')
+
+        if result != VOID:
+            ts = type2str(result)
+            if ml_has_plus_type(ts):
+                pts = ml_plus_type(ts)
+                if name in NULLWrapped:
+                    ml_wrapper.write('  %s z3rv = %s_mk(z3rv_m);\n' % (pts, pts))
+                else:
+                    ml_wrapper.write('  %s z3rv = %s_mk(ctx_p, (%s) z3rv_m);\n' % (pts, pts, ml_minus_type(ts)))
+
         # convert output params
         if len(op) > 0:
-            if result != VOID:
-                ml_wrapper.write('  %s\n' % ml_set_wrap(result, "res_val", "z3_result"))
+            # we have output parameters (i.e. call-by-reference arguments to the Z3 native
+            # code function). Hence, the value returned by the OCaml native wrapper is a tuple
+            # which contains the Z3 native function's return value (if it is non-void) in its
+            # first and the output parameters in the following components.
+
+            ml_wrapper.write('\n  /* construct return tuple */\n')
+            ml_wrapper.write('  result = caml_alloc(%s, 0);\n' % ret_size)
+
             i = 0
             for p in params:
+                pt = param_type(p)
+                ts = type2str(pt)
                 if param_kind(p) == OUT_ARRAY or param_kind(p) == INOUT_ARRAY:
-                    ml_wrapper.write('  _a%s_val = caml_alloc(_a%s, 0);\n' % (i, param_array_capacity_pos(p)))
-                    ml_wrapper.write('  for (_i = 0; _i < _a%s; _i++) { value t; %s Store_field(_a%s_val, _i, t); }\n' % (param_array_capacity_pos(p), ml_set_wrap(param_type(p), 't', '_a' + str(i) + '[_i]'), i))
+                    # convert a C-array into an OCaml list and return it
+                    ml_wrapper.write('\n  _a%s_val = Val_emptylist;\n' % i)
+                    ml_wrapper.write('  for (_i = _a%s; _i > 0; _i--) {\n' % param_array_capacity_pos(p))
+                    pts = ml_plus_type(ts)
+                    pops = ml_plus_ops_type(ts)
+                    if ml_has_plus_type(ts):
+                        ml_wrapper.write('    %s _a%dp = %s_mk(ctx_p, (%s) _a%d[_i]);\n' % (pts, i, pts, ml_minus_type(ts), i))
+                        ml_wrapper.write('    %s\n' % ml_alloc_and_store(pt, 'tmp_val', '_a%dp' % i))
+                    else:
+                        ml_wrapper.write('    %s\n' % ml_alloc_and_store(pt, 'tmp_val', '_a%d[_i]' % i))
+                    ml_wrapper.write('    _iter = caml_alloc(2,0);\n')
+                    ml_wrapper.write('    Store_field(_iter, 0, tmp_val);\n')
+                    ml_wrapper.write('    Store_field(_iter, 1, _a%s_val);\n' % i)
+                    ml_wrapper.write('    _a%s_val = _iter;\n' % i)
+                    ml_wrapper.write('  }\n\n')
                 elif param_kind(p) == OUT_MANAGED_ARRAY:
-                    ml_wrapper.write('  %s\n' % ml_set_wrap(param_type(p), "_a" + str(i) + "_val", "_a"  + str(i) ))
+                    wrp = ml_set_wrap(pt, '_a%d_val' % i, '_a%d' % i)
+                    wrp = wrp.replace('*)', '**)')
+                    wrp = wrp.replace('_plus', '')
+                    ml_wrapper.write('  %s\n' % wrp)
                 elif is_out_param(p):
-                    ml_wrapper.write('  %s\n' % ml_set_wrap(param_type(p), "_a" + str(i) + "_val", "_a"  + str(i) ))
+                    if ml_has_plus_type(ts):
+                        pts = ml_plus_type(ts)
+                        ml_wrapper.write('  %s _a%dp = %s_mk(ctx_p, (%s) _a%d);\n' % (pts, i, pts, ml_minus_type(ts), i))
+                        ml_wrapper.write('  %s\n' % ml_alloc_and_store(pt, '_a%d_val' % i, '_a%dp' % i))
+                    else:
+                        ml_wrapper.write('  %s\n' % ml_alloc_and_store(pt, '_a%d_val' % i, '_a%d' % i))
                 i = i + 1
 
-        # return tuples                
-        if len(op) == 0:
-            ml_wrapper.write('  %s\n' % ml_set_wrap(result, "result", "z3_result"))
-        else:
-            ml_wrapper.write('  result = caml_alloc(%s, 0);\n' % ret_size)
+            # return tuples
             i = j = 0
             if result != VOID:
-                ml_wrapper.write('  Store_field(result, 0, res_val);\n')
+                ml_wrapper.write('  %s' % ml_alloc_and_store(result, 'z3rv_val', 'z3rv'))
+                ml_wrapper.write('  Store_field(result, 0, z3rv_val);\n')
                 j = j + 1
             for p in params:
                 if is_out_param(p):
                     ml_wrapper.write('  Store_field(result, %s, _a%s_val);\n' % (j, i))
                     j = j + 1
                 i = i + 1
+        else:
+            # As we have no output parameters, we simply return the result
+            ml_wrapper.write('\n  /* construct simple return value */\n')
+            ml_wrapper.write('  %s' % ml_alloc_and_store(result, "result", "z3rv"))
 
         # local array cleanup
+        ml_wrapper.write('\n  /* cleanup and return */\n')
         i = 0
         for p in params:
             k = param_kind(p)
@@ -1432,7 +1485,7 @@ def mk_ml(ml_dir):
         ml_wrapper.write('  CAMLreturn(result);\n')
         ml_wrapper.write('}\n\n')
         if len(ip) > 5:
-            ml_wrapper.write('CAMLprim DLL_PUBLIC value n_%s_bytecode(value * argv, int argn) {\n' % ml_method_name(name)) 
+            ml_wrapper.write('CAMLprim DLL_PUBLIC value n_%s_bytecode(value * argv, int argn) {\n' % ml_method_name(name))
             ml_wrapper.write('  return n_%s(' % ml_method_name(name))
             i = 0
             while i < len(ip):
@@ -1446,8 +1499,9 @@ def mk_ml(ml_dir):
     ml_wrapper.write('#ifdef __cplusplus\n')
     ml_wrapper.write('}\n')
     ml_wrapper.write('#endif\n')
+
     if mk_util.is_verbose():
-        print ('Generated "%s"' % ml_nativef)
+        print ('Generated "%s"' % ml_wrapperf)
 
 # Collect API(...) commands from
 def def_APIs(api_files):
@@ -1636,6 +1690,7 @@ def generate_files(api_files,
 
   if java_output_dir:
     mk_java(java_output_dir, java_package_name)
+
   if ml_output_dir:
     mk_ml(ml_output_dir)
 
diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml
index ccf18a024..bbbb9e74b 100644
--- a/src/api/ml/z3.ml
+++ b/src/api/ml/z3.ml
@@ -7,204 +7,79 @@
 
 open Z3enums
 
-exception Error = Z3native.Exception
+exception Error of string
+let _ = Callback.register_exception "Z3EXCEPTION" (Error "")
 
-(* Some helpers. *)
-let null = Z3native.mk_null()
-let is_null o = (Z3native.is_null o)
+type context = Z3native.context
 
-(* Internal types *)
-type z3_native_context = { m_n_ctx : Z3native.z3_context; m_n_obj_cnt: int; } 
-type context = z3_native_context
-
-type z3_native_object = { 
-  m_ctx : context ; 
-  mutable m_n_obj : Z3native.ptr ; 
-  inc_ref : Z3native.z3_context -> Z3native.ptr -> unit;
-  dec_ref : Z3native.z3_context -> Z3native.ptr -> unit }
-
-(** Internal stuff *)
-module Internal =
+module Log =
 struct
-  let dispose_context ctx = 
-    if ctx.m_n_obj_cnt == 0 then (
-      (Z3native.del_context ctx.m_n_ctx)
-    ) else (
-      Printf.printf "ERROR: NOT DISPOSING CONTEXT (because it still has %d objects alive)\n" ctx.m_n_obj_cnt;
-    )
-
-  let create_context settings =
-    let cfg = Z3native.mk_config () in
-    let f e = (Z3native.set_param_value cfg (fst e) (snd e)) in
-    (List.iter f settings) ;
-    let v = Z3native.mk_context_rc cfg in
-    Z3native.del_config(cfg) ;
-    Z3native.set_ast_print_mode v (int_of_ast_print_mode PRINT_SMTLIB2_COMPLIANT) ;
-    Z3native.set_internal_error_handler v ;
-    let res = { m_n_ctx = v; m_n_obj_cnt = 0 } in
-    let f = fun o -> dispose_context o in
-    Gc.finalise f res;
-    res
-
-  let context_add1 ctx = ignore (ctx.m_n_obj_cnt = ctx.m_n_obj_cnt + 1)
-  let context_sub1 ctx = ignore (ctx.m_n_obj_cnt = ctx.m_n_obj_cnt - 1)
-  let context_gno ctx = ctx.m_n_ctx
-
-
-  let z3obj_gc o = o.m_ctx
-  let z3obj_gnc o = (context_gno o.m_ctx)
-
-  let z3obj_gno o = o.m_n_obj
-  let z3obj_sno o ctx no =
-    (context_add1 ctx) ;
-    o.inc_ref (context_gno ctx) no ;
-    (
-      if not (is_null o.m_n_obj) then
-     o.dec_ref (context_gno ctx) o.m_n_obj ; 
-      (context_sub1 ctx)
-    ) ;
-    o.m_n_obj <- no
-
-  let z3obj_dispose o =
-    if not (is_null o.m_n_obj) then
-      (
-     o.dec_ref (z3obj_gnc o) o.m_n_obj ;
-     (context_sub1 (z3obj_gc o))
-      ) ;
-    o.m_n_obj <- null
-      
-  let z3obj_create o = 
-    let f = fun o -> (z3obj_dispose o) in
-    Gc.finalise f o
-
-  let z3obj_nil_ref x y = ()
-
-  let z3_native_object_of_ast_ptr : context -> Z3native.ptr -> z3_native_object = fun ctx no ->
-    let res : z3_native_object = { m_ctx = ctx ;
-                       m_n_obj = null ;
-                       inc_ref = Z3native.inc_ref ;
-                       dec_ref = Z3native.dec_ref } in
-    (z3obj_sno res ctx no) ;
-    (z3obj_create res) ;
-    res               
- 
-
-end
-
-open Internal
-
-module Log = 
-struct
-  let open_ filename = ((lbool_of_int (Z3native.open_log filename)) == L_TRUE)
+  let open_ filename =
+    lbool_of_int (Z3native.open_log filename) = L_TRUE
   let close = Z3native.close_log
-  let append s = Z3native.append_log s
+  let append = Z3native.append_log
 end
 
 
 module Version =
 struct
-  let major = let (x, _, _, _) = Z3native.get_version () in x
-  let minor = let (_, x, _, _) = Z3native.get_version () in x
-  let build = let (_, _, x, _) = Z3native.get_version () in x
-  let revision = let (_, _, _, x) = Z3native.get_version () in x
-  let to_string = 
-    let (mj, mn, bld, rev) = Z3native.get_version () in
-    string_of_int mj ^ "." ^
-      string_of_int mn ^ "." ^
-      string_of_int bld ^ "." ^
-      string_of_int rev
+  let (major, minor, build, revision) = Z3native.get_version ()
+
+  let to_string =
+    string_of_int major ^ "." ^
+    string_of_int minor ^ "." ^
+    string_of_int build ^ "." ^
+    string_of_int revision
 end
 
-
-let mk_list ( f : int -> 'a ) ( n : int ) =
-  let rec mk_list' ( f : int -> 'a ) ( i : int ) ( n : int )  ( tail : 'a list ) : 'a list =       
-    if (i >= n) then 
-      tail
+let mk_list f n =
+  let rec mk_list' i accu =
+    if i >= n then
+      List.rev accu
     else
-      (f i) :: (mk_list' f (i+1) n tail)
+      mk_list' (i + 1) ((f i)::accu)
   in
-  mk_list' f 0 n []
-
-let list_of_array ( x : _ array ) =
-  let f i = (Array.get x i) in
-  mk_list f (Array.length x)
-
-let mk_context ( cfg : ( string * string ) list ) =
-  create_context cfg
+  mk_list' 0 []
 
+let mk_context (settings:(string * string) list) =
+  let cfg = Z3native.mk_config () in
+  let f e = Z3native.set_param_value cfg (fst e) (snd e) in
+  List.iter f settings;
+  let res = Z3native.mk_context_rc cfg in
+  Z3native.del_config cfg;
+  Z3native.set_ast_print_mode res (Z3enums.int_of_ast_print_mode PRINT_SMTLIB2_COMPLIANT);
+  Z3native.set_internal_error_handler res;
+  res
 
 module Symbol =
 struct
-  type symbol = z3_native_object
+  type symbol = Z3native.symbol
+  let gc = Z3native.context_of_symbol
 
-  let create_i ( ctx : context ) ( no : Z3native.ptr ) = 
-    let res : symbol = { m_ctx = ctx ;
-                m_n_obj = null ;
-                inc_ref = z3obj_nil_ref ;
-                dec_ref = z3obj_nil_ref } in
-    (z3obj_sno res ctx no) ;
-    (z3obj_create res) ;
-    res
-      
-  let create_s ( ctx : context ) ( no : Z3native.ptr ) = 
-    let res : symbol = { m_ctx = ctx ;
-                m_n_obj = null ;
-                inc_ref = z3obj_nil_ref ;
-                dec_ref = z3obj_nil_ref } in
-    (z3obj_sno res ctx no) ;
-    (z3obj_create res) ;
-    res
+  let kind o = symbol_kind_of_int (Z3native.get_symbol_kind (gc o) o)
+  let is_int_symbol o = kind o = INT_SYMBOL
+  let is_string_symbol o = kind o = STRING_SYMBOL
+  let get_int o = Z3native.get_symbol_int (gc o) o
+  let get_string o = Z3native.get_symbol_string (gc o) o
+  let to_string o =
+    match kind o with
+    | INT_SYMBOL -> string_of_int (Z3native.get_symbol_int (gc o) o)
+    | STRING_SYMBOL -> Z3native.get_symbol_string (gc o) o
 
-  let create ( ctx : context ) ( no : Z3native.ptr ) =
-    match (symbol_kind_of_int (Z3native.get_symbol_kind (context_gno ctx) no)) with
-      | INT_SYMBOL -> (create_i ctx no)
-      | STRING_SYMBOL -> (create_s ctx no)     
+  let mk_int = Z3native.mk_int_symbol
+  let mk_string = Z3native.mk_string_symbol
 
-  let gc ( x : symbol ) = (z3obj_gc x)
-  let gnc ( x : symbol ) = (z3obj_gnc x)
-  let gno ( x : symbol ) = (z3obj_gno x)
-
-  let symbol_lton ( a : symbol list ) =
-    let f ( e : symbol ) = (gno e) in 
-    Array.of_list (List.map f a)
-      
-  let kind ( o : symbol ) = (symbol_kind_of_int (Z3native.get_symbol_kind (gnc o) (gno o)))   
-  let is_int_symbol ( o : symbol ) = (kind o) == INT_SYMBOL
-  let is_string_symbol ( o : symbol ) = (kind o) == STRING_SYMBOL
-  let get_int (o : symbol) = Z3native.get_symbol_int (z3obj_gnc o) (z3obj_gno o)
-  let get_string (o : symbol ) = Z3native.get_symbol_string (z3obj_gnc o) (z3obj_gno o)
-  let to_string ( o : symbol ) = 
-    match (kind o) with
-      | INT_SYMBOL -> (string_of_int (Z3native.get_symbol_int (gnc o) (gno o)))
-      | STRING_SYMBOL -> (Z3native.get_symbol_string (gnc o) (gno o))
-
-  let mk_int ( ctx : context ) ( i : int ) = 
-    (create_i ctx (Z3native.mk_int_symbol (context_gno ctx) i))
-      
-  let mk_string ( ctx : context ) ( s : string ) =
-    (create_s ctx (Z3native.mk_string_symbol (context_gno ctx) s))
-
-  let mk_ints ( ctx : context ) ( names : int list ) =
-    let f elem = mk_int ( ctx : context ) elem in
-    (List.map f names)
-
-  let mk_strings ( ctx : context ) ( names : string list ) =
-    let f elem = mk_string ( ctx : context ) elem in
-    (List.map f names)      
+  let mk_ints ctx names = List.map (mk_int ctx) names
+  let mk_strings ctx names = List.map (mk_string ctx) names
 end
 
-
 module rec AST :
 sig
-  type ast = z3_native_object
-  val context_of_ast : ast -> context
-  val nc_of_ast : ast -> Z3native.z3_context
-  val ptr_of_ast : ast -> Z3native.ptr
-  val ast_of_ptr : context -> Z3native.ptr -> ast
+  type ast = Z3native.ast
+  val gc : ast -> context
   module ASTVector :
   sig
-    type ast_vector = z3_native_object
-    val create : context -> Z3native.ptr -> ast_vector
+    type ast_vector = Z3native.ast_vector
     val mk_ast_vector : context -> ast_vector
     val get_size : ast_vector -> int
     val get : ast_vector -> int -> ast
@@ -218,8 +93,7 @@ sig
   end
   module ASTMap :
   sig
-    type ast_map = z3_native_object
-    val create : context -> Z3native.ptr -> ast_map
+    type ast_map = Z3native.ast_map
     val mk_ast_map : context -> ast_map
     val contains : ast_map -> ast -> bool
     val find : ast_map -> ast -> ast
@@ -244,175 +118,94 @@ sig
   val equal : ast -> ast -> bool
   val compare : ast -> ast -> int
   val translate : ast -> context -> ast
-  val unwrap_ast : ast -> Z3native.ptr
-  val wrap_ast : context -> Z3native.z3_ast -> ast
-end = struct    
-  type ast = z3_native_object
+end = struct
+  type ast = Z3native.ast
+  let gc = Z3native.context_of_ast
 
-  let context_of_ast ( x : ast ) = (z3obj_gc x)
-  let nc_of_ast ( x : ast ) = (z3obj_gnc x)
-  let ptr_of_ast ( x : ast ) = (z3obj_gno x)  
-    
-  let rec ast_of_ptr : context -> Z3native.ptr -> ast = fun ctx no -> 
-    match (ast_kind_of_int (Z3native.get_ast_kind (context_gno ctx) no)) with
-      | FUNC_DECL_AST 
-      | SORT_AST 
-      | QUANTIFIER_AST
-      | APP_AST
-      | NUMERAL_AST
-      | VAR_AST -> z3_native_object_of_ast_ptr ctx no
-      | UNKNOWN_AST -> raise (Z3native.Exception "Cannot create asts of type unknown")
-
-  module ASTVector = 
+  module ASTVector =
   struct
-    type ast_vector = z3_native_object
-     
-    let create ( ctx : context ) ( no : Z3native.ptr ) = 
-      let res : ast_vector = { m_ctx = ctx ;
-                                  m_n_obj = null ;
-                                  inc_ref = Z3native.ast_vector_inc_ref ;
-                                  dec_ref = Z3native.ast_vector_dec_ref } in
-      (z3obj_sno res ctx no) ;
-      (z3obj_create res) ;
-      res
-         
-    let mk_ast_vector ( ctx : context ) = (create ctx (Z3native.mk_ast_vector (context_gno ctx)))
-      
-    let get_size ( x : ast_vector ) =
-      Z3native.ast_vector_size (z3obj_gnc x) (z3obj_gno x)
+    type ast_vector = Z3native.ast_vector
+    let gc = Z3native.context_of_ast_vector
 
-    let get ( x : ast_vector ) ( i : int ) =
-      ast_of_ptr (z3obj_gc x) (Z3native.ast_vector_get (z3obj_gnc x) (z3obj_gno x) i)
+    let mk_ast_vector = Z3native.mk_ast_vector
+    let get_size (x:ast_vector) = Z3native.ast_vector_size (gc x) x
+    let get (x:ast_vector) (i:int) = Z3native.ast_vector_get (gc x) x i
+    let set (x:ast_vector) (i:int) (value:ast) = Z3native.ast_vector_set (gc x) x i value
+    let resize (x:ast_vector) (new_size:int) = Z3native.ast_vector_resize (gc x) x new_size
+    let push (x:ast_vector) (a:ast) = Z3native.ast_vector_push (gc x) x a
+    let translate (x:ast_vector) (to_ctx:context) = Z3native.ast_vector_translate (gc x) x to_ctx
 
-    let set ( x : ast_vector ) ( i : int ) ( value : ast ) =
-      Z3native.ast_vector_set (z3obj_gnc x) (z3obj_gno x) i (z3obj_gno value)
-
-    let resize ( x : ast_vector ) ( new_size : int ) =
-      Z3native.ast_vector_resize (z3obj_gnc x) (z3obj_gno x) new_size
-     
-    let push ( x : ast_vector ) ( a : ast )  =
-      Z3native.ast_vector_push (z3obj_gnc x) (z3obj_gno x) (z3obj_gno a)
-     
-    let translate ( x : ast_vector ) ( to_ctx : context ) =
-      create to_ctx (Z3native.ast_vector_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx))
-
-    let to_list ( x : ast_vector ) =
-       let xs = (get_size x) in
-      let f i = (get x i) in
+    let to_list (x:ast_vector) =
+      let xs = get_size x in
+      let f i = get x i in
       mk_list f xs
 
-    let to_expr_list ( x : ast_vector ) =
-       let xs = (get_size x) in
-      let f i = (Expr.expr_of_ptr (z3obj_gc x) (z3obj_gno (get x i))) in
+    let to_expr_list (x:ast_vector) =
+      let xs = get_size x in
+      let f i = get x i in
       mk_list f xs
-     
-    let to_string ( x : ast_vector ) =
-      Z3native.ast_vector_to_string (z3obj_gnc x) (z3obj_gno x)
+
+    let to_string x = Z3native.ast_vector_to_string (gc x) x
   end
 
   module ASTMap =
-  struct     
-    type ast_map = z3_native_object
-     
-    let create ( ctx : context ) ( no : Z3native.ptr ) = 
-      let res : ast_map  = { m_ctx = ctx ;
-                                m_n_obj = null ;
-                                inc_ref = Z3native.ast_map_inc_ref ;
-                                dec_ref = Z3native.ast_map_dec_ref } in
-      (z3obj_sno res ctx no) ;
-      (z3obj_create res) ;
-      res     
-     
-    let mk_ast_map ( ctx : context ) = (create ctx (Z3native.mk_ast_map (context_gno ctx)))
+  struct
+    type ast_map = Z3native.ast_map
+    let gc = Z3native.context_of_ast_map
 
-    let astmap_of_ptr ( ctx : context ) ( no : Z3native.ptr ) = 
-      let res : ast_map = { m_ctx = ctx ;
-                   m_n_obj = null ;
-                   inc_ref = Z3native.ast_map_inc_ref ;
-                   dec_ref = Z3native.ast_map_dec_ref } in
-      (z3obj_sno res ctx no) ;
-      (z3obj_create res) ;
-      res
-     
-    let contains ( x : ast_map ) ( key : ast ) =
-      Z3native.ast_map_contains (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key)
-     
-    let find ( x : ast_map ) ( key : ast ) =
-      ast_of_ptr (z3obj_gc x) (Z3native.ast_map_find (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key))
-     
-    let insert ( x : ast_map ) ( key : ast ) ( value : ast ) =
-      Z3native.ast_map_insert (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key) (z3obj_gno value)
+    let mk_ast_map = Z3native.mk_ast_map
+    let contains (x:ast_map) (key:ast) = Z3native.ast_map_contains (gc x) x key
+    let find (x:ast_map) (key:ast) = Z3native.ast_map_find (gc x) x key
+    let insert (x:ast_map) (key:ast) (value:ast) = Z3native.ast_map_insert (gc x) x key value
+    let erase (x:ast_map) (key:ast) = Z3native.ast_map_erase (gc x) x key
+    let reset (x:ast_map) = Z3native.ast_map_reset (gc x) x
+    let get_size (x:ast_map) = Z3native.ast_map_size (gc x) x
 
-    let erase ( x : ast_map ) ( key : ast ) =
-      Z3native.ast_map_erase (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key)
-     
-    let reset ( x : ast_map ) =
-      Z3native.ast_map_reset (z3obj_gnc x) (z3obj_gno x)
+    let get_keys (x:ast_map) =
+      let av = Z3native.ast_map_keys (gc x) x in
+      ASTVector.to_list av
 
-    let get_size ( x : ast_map ) =
-      Z3native.ast_map_size (z3obj_gnc x) (z3obj_gno x)
-     
-    let get_keys ( x : ast_map ) =
-      let av = ASTVector.create (z3obj_gc x) (Z3native.ast_map_keys (z3obj_gnc x) (z3obj_gno x)) in
-      (ASTVector.to_list av)
-
-    let to_string ( x : ast_map ) =
-      Z3native.ast_map_to_string (z3obj_gnc x) (z3obj_gno x)
+    let to_string (x:ast_map) = Z3native.ast_map_to_string (gc x) x
   end
 
-  let hash ( x : ast ) = Z3native.get_ast_hash (z3obj_gnc x) (z3obj_gno x)
-  let get_id ( x : ast ) = Z3native.get_ast_id (z3obj_gnc x) (z3obj_gno x)
-  let get_ast_kind ( x : ast ) = (ast_kind_of_int (Z3native.get_ast_kind (z3obj_gnc x) (z3obj_gno x)))
-    
-  let is_expr ( x : ast ) = 
-    match get_ast_kind ( x : ast ) with
-      | APP_AST
-      | NUMERAL_AST
-      | QUANTIFIER_AST
-      | VAR_AST -> true
-      | _ -> false
-     
-  let is_app ( x : ast ) = (get_ast_kind x) == APP_AST
-  let is_var ( x : ast ) = (get_ast_kind x) == VAR_AST   
-  let is_quantifier ( x : ast ) = (get_ast_kind x) == QUANTIFIER_AST
-  let is_sort ( x : ast ) = (get_ast_kind x) == SORT_AST
-  let is_func_decl ( x : ast ) = (get_ast_kind x) == FUNC_DECL_AST
+  let hash (x:ast) = Z3native.get_ast_hash (gc x) x
+  let get_id (x:ast) = Z3native.get_ast_id (gc x) x
+  let get_ast_kind (x:ast) = ast_kind_of_int (Z3native.get_ast_kind (gc x) x)
 
-  let to_string ( x : ast ) = Z3native.ast_to_string (z3obj_gnc x) (z3obj_gno x)
-  let to_sexpr ( x : ast ) = Z3native.ast_to_string (z3obj_gnc x) (z3obj_gno x)
+  let is_expr (x:ast) =
+    match get_ast_kind x with
+    | APP_AST
+    | NUMERAL_AST
+    | QUANTIFIER_AST
+    | VAR_AST -> true
+    | _ -> false
 
+  let is_app (x:ast) = get_ast_kind x = APP_AST
+  let is_var (x:ast) = get_ast_kind x = VAR_AST
+  let is_quantifier (x:ast) = get_ast_kind x = QUANTIFIER_AST
+  let is_sort (x:ast) = get_ast_kind x = SORT_AST
+  let is_func_decl (x:ast) = get_ast_kind x = FUNC_DECL_AST
 
-  let equal ( a : ast ) ( b : ast ) = (a == b) ||
-    if (z3obj_gnc a) != (z3obj_gnc b) then 
-      false 
-    else 
-      Z3native.is_eq_ast (z3obj_gnc a) (z3obj_gno a) (z3obj_gno b)
-     
-  let compare a b = 
-    if (get_id a) < (get_id b) then -1 else
-      if (get_id a) > (get_id b) then 1 else
-     0
-       
-  let translate ( x : ast ) ( to_ctx : context ) = 
-    if (z3obj_gnc x) == (context_gno to_ctx) then 
+  let to_string (x:ast) = Z3native.ast_to_string (gc x) x
+  let to_sexpr (x:ast) = Z3native.ast_to_string (gc x) x
+
+  (* The built-in equality uses the custom operations of the C layer *)
+  let equal = (=)
+
+  (* The standard comparison uses the custom operations of the C layer *)
+  let compare = Pervasives.compare
+
+  let translate (x:ast) (to_ctx:context) =
+    if gc x = to_ctx then
       x
     else
-      ast_of_ptr to_ctx (Z3native.translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx))
-
-  let unwrap_ast ( x : ast ) = (z3obj_gno x)
-  let wrap_ast ( ctx : context ) ( ptr : Z3native.ptr ) = ast_of_ptr ctx ptr
+      Z3native.translate (gc x) x to_ctx
 end
 
 and Sort :
 sig
-  type sort = Sort of AST.ast
-  val ast_of_sort : Sort.sort -> AST.ast
-  val sort_of_ptr : context -> Z3native.ptr -> sort
+  type sort = AST.ast
   val gc : sort -> context
-  val gnc : sort -> Z3native.ptr
-  val gno : sort -> Z3native.ptr
-  val sort_lton : sort list -> Z3native.ptr array
-  val sort_option_lton : sort option list -> Z3native.ptr array
   val equal : sort -> sort -> bool
   val get_id : sort -> int
   val get_sort_kind : sort -> Z3enums.sort_kind
@@ -421,82 +214,34 @@ sig
   val mk_uninterpreted : context -> Symbol.symbol -> sort
   val mk_uninterpreted_s : context -> string -> sort
 end = struct
-  type sort = Sort of AST.ast
+  type sort = Z3native.sort
+  let gc = Z3native.context_of_ast
 
-  let sort_of_ptr : context -> Z3native.ptr -> sort = fun ctx no ->
-    if ((Z3enums.ast_kind_of_int (Z3native.get_ast_kind (context_gno ctx) no)) != Z3enums.SORT_AST) then
-      raise (Z3native.Exception "Invalid coercion")
-    else
-      match (sort_kind_of_int (Z3native.get_sort_kind (context_gno ctx) no)) with
-        | ARRAY_SORT
-        | BOOL_SORT
-        | BV_SORT 
-        | DATATYPE_SORT 
-        | INT_SORT 
-        | REAL_SORT 
-        | UNINTERPRETED_SORT 
-        | FINITE_DOMAIN_SORT 
-        | RELATION_SORT 
-        | RE_SORT
-        | SEQ_SORT
-        | FLOATING_POINT_SORT
-        | ROUNDING_MODE_SORT -> Sort(z3_native_object_of_ast_ptr ctx no)
-        | UNKNOWN_SORT -> raise (Z3native.Exception "Unknown sort kind encountered")
+  let equal a b = (a = b) || (gc a = gc b && Z3native.is_eq_sort (gc a) a b)
 
-  let ast_of_sort s = match s with Sort(x) -> x
-    
-  let gc ( x : sort ) = (match x with Sort(a) -> (z3obj_gc a))
-  let gnc ( x : sort ) = (match x with Sort(a) -> (z3obj_gnc a))
-  let gno ( x : sort ) = (match x with Sort(a) -> (z3obj_gno a))
-
-  let sort_lton ( a : sort list ) =
-    let f ( e : sort ) = match e with Sort(a) -> (AST.ptr_of_ast a) in 
-    Array.of_list (List.map f a)
-
-  let sort_option_lton ( a : sort option list ) =
-    let f ( e : sort option ) = match e with None -> null | Some(Sort(a)) -> (AST.ptr_of_ast a) in 
-    Array.of_list (List.map f a)
-      
-  let equal : sort -> sort -> bool = fun a b ->
-    (a == b) ||
-      if (gnc a) != (gnc b) then 
-     false 
-      else 
-     (Z3native.is_eq_sort (gnc a) (gno a) (gno b))
- 
-       
-  let get_id ( x : sort ) = Z3native.get_sort_id (gnc x) (gno x)
-  let get_sort_kind ( x : sort ) = (sort_kind_of_int (Z3native.get_sort_kind (gnc x) (gno x)))
-  let get_name ( x : sort ) = (Symbol.create (gc x) (Z3native.get_sort_name (gnc x) (gno x)))    
-  let to_string ( x : sort ) = Z3native.sort_to_string (gnc x) (gno x)
-
-  let mk_uninterpreted ( ctx : context ) ( s : Symbol.symbol ) =
-    let n = (Z3native.mk_uninterpreted_sort (context_gno ctx) (Symbol.gno s)) in
-    Sort(z3_native_object_of_ast_ptr ctx n)
-
-  let mk_uninterpreted_s ( ctx : context ) ( s : string ) =
-    mk_uninterpreted ctx (Symbol.mk_string ( ctx : context ) s)
-end 
+  let get_id (x:sort) = Z3native.get_sort_id (gc x) x
+  let get_sort_kind (x:sort) = sort_kind_of_int (Z3native.get_sort_kind (gc x) x)
+  let get_name (x:sort) = Z3native.get_sort_name (gc x) x
+  let to_string (x:sort) = Z3native.sort_to_string (gc x) x
+  let mk_uninterpreted = Z3native.mk_uninterpreted_sort
+  let mk_uninterpreted_s (ctx:context) (s:string) = mk_uninterpreted ctx (Symbol.mk_string ctx s)
+end
 
 and FuncDecl :
-sig 
-  type func_decl = FuncDecl of AST.ast
-  val ast_of_func_decl : FuncDecl.func_decl -> AST.ast
-  val func_decl_of_ptr : context -> Z3native.ptr -> func_decl
+sig
+  type func_decl = Z3native.func_decl
   val gc : func_decl -> context
-  val gnc : func_decl -> Z3native.ptr
-  val gno : func_decl -> Z3native.ptr
   module Parameter :
   sig
     type parameter =
-     P_Int of int
+        P_Int of int
       | P_Dbl of float
       | P_Sym of Symbol.symbol
       | P_Srt of Sort.sort
       | P_Ast of AST.ast
       | P_Fdl of func_decl
       | P_Rat of string
-       
+
     val get_kind : parameter -> Z3enums.parameter_kind
     val get_int : parameter -> int
     val get_float : parameter -> float
@@ -525,29 +270,12 @@ sig
   val get_parameters : func_decl -> Parameter.parameter list
   val apply : func_decl -> Expr.expr list -> Expr.expr
 end = struct
-  type func_decl = FuncDecl of AST.ast
-
-  let func_decl_of_ptr : context -> Z3native.ptr -> func_decl = fun ctx no ->
-    if ((Z3enums.ast_kind_of_int (Z3native.get_ast_kind (context_gno ctx) no)) != Z3enums.FUNC_DECL_AST) then
-      raise (Z3native.Exception "Invalid coercion")
-    else
-      FuncDecl(z3_native_object_of_ast_ptr ctx no)
-
-  let ast_of_func_decl f = match f with FuncDecl(x) -> x
-
-  let create_ndr ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort )  = 
-    func_decl_of_ptr ctx (Z3native.mk_func_decl (context_gno ctx) (Symbol.gno name) (List.length domain) (Sort.sort_lton domain) (Sort.gno range))
-      
-  let create_pdr ( ctx : context) ( prefix : string ) ( domain : Sort.sort list ) ( range : Sort.sort ) = 
-    func_decl_of_ptr ctx (Z3native.mk_fresh_func_decl (context_gno ctx) prefix (List.length domain) (Sort.sort_lton domain) (Sort.gno range))
-
-  let gc ( x : func_decl ) = match x with FuncDecl(a) -> (z3obj_gc a)
-  let gnc ( x : func_decl ) = match x with FuncDecl(a) -> (z3obj_gnc a)
-  let gno ( x : func_decl ) = match x with FuncDecl(a) -> (z3obj_gno a)     
+  type func_decl = AST.ast
+  let gc = Z3native.context_of_ast
 
   module Parameter =
-  struct       
-    type parameter = 
+  struct
+    type parameter =
       | P_Int of int
       | P_Dbl of float
       | P_Sym of Symbol.symbol
@@ -555,124 +283,104 @@ end = struct
       | P_Ast of AST.ast
       | P_Fdl of func_decl
       | P_Rat of string
-       
-    let get_kind ( x : parameter ) =
-      (match x with
-     | P_Int(_) -> PARAMETER_INT
-     | P_Dbl(_) -> PARAMETER_DOUBLE
-     | P_Sym(_) -> PARAMETER_SYMBOL
-     | P_Srt(_) -> PARAMETER_SORT
-     | P_Ast(_) -> PARAMETER_AST
-     | P_Fdl(_) -> PARAMETER_FUNC_DECL
-     | P_Rat(_) -> PARAMETER_RATIONAL)
-     
-    let get_int ( x : parameter ) =
-      match x with
-     | P_Int(x) -> x
-     | _ -> raise (Z3native.Exception "parameter is not an int")
-       
-    let get_float ( x : parameter ) = 
-      match x with
-     | P_Dbl(x) -> x
-     | _ -> raise (Z3native.Exception "parameter is not a float")
-          
-    let get_symbol ( x : parameter ) =
-      match x with
-     | P_Sym(x) -> x
-     | _ -> raise (Z3native.Exception "parameter is not a symbol")
-       
-    let get_sort ( x : parameter ) =
-      match x with
-     | P_Srt(x) -> x
-     | _ -> raise (Z3native.Exception "parameter is not a sort")
 
-    let get_ast ( x : parameter ) =
-      match x with
-     | P_Ast(x) -> x
-     | _ -> raise (Z3native.Exception "parameter is not an ast")
+    let get_kind = function
+      | P_Int _ -> PARAMETER_INT
+      | P_Dbl _ -> PARAMETER_DOUBLE
+      | P_Sym _ -> PARAMETER_SYMBOL
+      | P_Srt _ -> PARAMETER_SORT
+      | P_Ast _ -> PARAMETER_AST
+      | P_Fdl _ -> PARAMETER_FUNC_DECL
+      | P_Rat _ -> PARAMETER_RATIONAL
 
-    let get_func_decl ( x : parameter ) =
-      match x with
-     | P_Fdl(x) -> x
-     | _ -> raise (Z3native.Exception "parameter is not a func_decl")
+    let get_int = function
+      | P_Int x -> x
+      | _ -> raise (Error "parameter is not an int")
 
-    let get_rational ( x : parameter ) =
-      match x with
-     | P_Rat(x) -> x
-     | _ -> raise (Z3native.Exception "parameter is not a rational string")
+    let get_float = function
+      | P_Dbl x -> x
+      | _ -> raise (Error "parameter is not a float")
+
+    let get_symbol = function
+      | P_Sym x -> x
+      | _ -> raise (Error "parameter is not a symbol")
+
+    let get_sort = function
+      | P_Srt x -> x
+      | _ -> raise (Error "parameter is not a sort")
+
+    let get_ast = function
+      | P_Ast x -> x
+      | _ -> raise (Error "parameter is not an ast")
+
+    let get_func_decl = function
+      | P_Fdl x -> x
+      | _ -> raise (Error "parameter is not a func_decl")
+
+    let get_rational = function
+      | P_Rat x -> x
+      | _ -> raise (Error "parameter is not a rational string")
   end
 
-  let mk_func_decl ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort ) =
-    create_ndr ctx name domain range
+  let mk_func_decl (ctx:context) (name:Symbol.symbol) (domain:Sort.sort list) (range:Sort.sort) =
+    Z3native.mk_func_decl ctx name (List.length domain) domain range
 
-  let mk_func_decl_s ( ctx : context ) ( name : string ) ( domain : Sort.sort list ) ( range : Sort.sort ) =
+  let mk_func_decl_s (ctx:context) (name:string) (domain:Sort.sort list) (range:Sort.sort) =
     mk_func_decl ctx (Symbol.mk_string ctx name) domain range
 
-  let mk_fresh_func_decl ( ctx : context ) ( prefix : string ) ( domain : Sort.sort list ) ( range : Sort.sort ) =
-    create_pdr ctx prefix domain range
+  let mk_fresh_func_decl (ctx:context) (prefix:string) (domain:Sort.sort list) (range:Sort.sort) =
+    Z3native.mk_fresh_func_decl ctx prefix (List.length domain) domain range
 
-  let mk_const_decl ( ctx : context ) ( name : Symbol.symbol ) ( range : Sort.sort ) =
-    create_ndr ctx name [] range
+  let mk_const_decl (ctx:context) (name:Symbol.symbol) (range:Sort.sort) =
+    Z3native.mk_func_decl ctx name 0 [] range
 
-  let mk_const_decl_s ( ctx : context ) ( name : string ) ( range : Sort.sort ) =
-    create_ndr ctx (Symbol.mk_string ctx name) []  range
+  let mk_const_decl_s (ctx:context) (name:string) (range:Sort.sort) =
+    Z3native.mk_func_decl ctx (Symbol.mk_string ctx name) 0 [] range
 
-  let mk_fresh_const_decl ( ctx : context ) ( prefix : string ) ( range : Sort.sort ) =
-    create_pdr ctx prefix [] range
+  let mk_fresh_const_decl (ctx:context) (prefix:string) (range:Sort.sort) =
+    Z3native.mk_fresh_func_decl ctx prefix 0 [] range
 
+  let equal a b = (a = b) || (gc a = gc b && Z3native.is_eq_func_decl (gc a) a b)
 
-  let equal ( a : func_decl ) ( b : func_decl ) = (a == b) ||
-    if (gnc a) != (gnc b) then 
-      false 
-    else 
-      (Z3native.is_eq_func_decl (gnc a) (gno a) (gno b))
+  let to_string (x:func_decl) = Z3native.func_decl_to_string (gc x) x
+  let get_id (x:func_decl) = Z3native.get_func_decl_id (gc x) x
+  let get_arity (x:func_decl) = Z3native.get_arity (gc x) x
+  let get_domain_size (x:func_decl) = Z3native.get_domain_size (gc x) x
 
-  let to_string ( x : func_decl ) = Z3native.func_decl_to_string (gnc x) (gno x)
-    
-  let get_id ( x : func_decl ) = Z3native.get_func_decl_id (gnc x) (gno x)
-    
-  let get_arity ( x : func_decl ) = Z3native.get_arity (gnc x) (gno x)
-    
-  let get_domain_size ( x : func_decl ) = Z3native.get_domain_size (gnc x) (gno x)
-    
-  let get_domain ( x : func_decl ) = 
-    let n = (get_domain_size x) in
-    let f i = Sort.sort_of_ptr (gc x) (Z3native.get_domain (gnc x) (gno x) i) in
-    mk_list f n
-      
-  let get_range ( x : func_decl ) = 
-    Sort.sort_of_ptr (gc x) (Z3native.get_range (gnc x) (gno x))
-      
-  let get_decl_kind ( x : func_decl ) = (decl_kind_of_int (Z3native.get_decl_kind (gnc x) (gno x)))
-
-  let get_name ( x : func_decl ) = (Symbol.create (gc x) (Z3native.get_decl_name (gnc x) (gno x)))
-
-  let get_num_parameters ( x : func_decl ) = (Z3native.get_decl_num_parameters (gnc x) (gno x))    
-
-  let get_parameters ( x : func_decl ) =
-    let n = (get_num_parameters x) in
-    let f i = (match (parameter_kind_of_int (Z3native.get_decl_parameter_kind (gnc x) (gno x) i)) with
-      | PARAMETER_INT -> Parameter.P_Int (Z3native.get_decl_int_parameter (gnc x) (gno x) i)
-      | PARAMETER_DOUBLE -> Parameter.P_Dbl (Z3native.get_decl_double_parameter (gnc x) (gno x) i)
-      | PARAMETER_SYMBOL-> Parameter.P_Sym (Symbol.create (gc x) (Z3native.get_decl_symbol_parameter (gnc x) (gno x) i))
-      | PARAMETER_SORT -> Parameter.P_Srt (Sort.sort_of_ptr (gc x) (Z3native.get_decl_sort_parameter (gnc x) (gno x) i))
-      | PARAMETER_AST -> Parameter.P_Ast (AST.ast_of_ptr (gc x) (Z3native.get_decl_ast_parameter (gnc x) (gno x) i))
-      | PARAMETER_FUNC_DECL -> Parameter.P_Fdl (func_decl_of_ptr (gc x) (Z3native.get_decl_func_decl_parameter (gnc x) (gno x) i))
-      | PARAMETER_RATIONAL -> Parameter.P_Rat (Z3native.get_decl_rational_parameter (gnc x) (gno x) i)
-    ) in
+  let get_domain (x:func_decl) =
+    let n = get_domain_size x in
+    let f i = Z3native.get_domain (gc x) x i in
     mk_list f n
 
-  let apply ( x : func_decl ) ( args : Expr.expr list ) = Expr.expr_of_func_app (gc x) x args 
+  let get_range (x:func_decl) = Z3native.get_range (gc x) x
+  let get_decl_kind (x:func_decl) = decl_kind_of_int (Z3native.get_decl_kind (gc x) x)
+  let get_name (x:func_decl) = Z3native.get_decl_name (gc x) x
+  let get_num_parameters (x:func_decl) = Z3native.get_decl_num_parameters (gc x) x
+
+  let get_parameters (x:func_decl) =
+    let n = get_num_parameters x in
+    let f i =
+      match parameter_kind_of_int (Z3native.get_decl_parameter_kind (gc x) x i) with
+      | PARAMETER_INT -> Parameter.P_Int (Z3native.get_decl_int_parameter (gc x) x i)
+      | PARAMETER_DOUBLE -> Parameter.P_Dbl (Z3native.get_decl_double_parameter (gc x) x i)
+      | PARAMETER_SYMBOL-> Parameter.P_Sym (Z3native.get_decl_symbol_parameter (gc x) x i)
+      | PARAMETER_SORT -> Parameter.P_Srt (Z3native.get_decl_sort_parameter (gc x) x i)
+      | PARAMETER_AST -> Parameter.P_Ast (Z3native.get_decl_ast_parameter (gc x) x i)
+      | PARAMETER_FUNC_DECL -> Parameter.P_Fdl (Z3native.get_decl_func_decl_parameter (gc x) x i)
+      | PARAMETER_RATIONAL -> Parameter.P_Rat (Z3native.get_decl_rational_parameter (gc x) x i)
+    in
+    mk_list f n
+
+  let apply (x:func_decl) (args:Expr.expr list) = Expr.expr_of_func_app (gc x) x args
 end
 
 
-and Params : 
+and Params:
 sig
-  type params = z3_native_object
+  type params = Z3native.params
   module ParamDescrs :
   sig
-    type param_descrs 
-    val param_descrs_of_ptr : context -> Z3native.ptr -> param_descrs
+    type param_descrs = Z3native.param_descrs
     val validate : param_descrs -> params -> unit
     val get_kind : param_descrs -> Symbol.symbol -> Z3enums.param_kind
     val get_names : param_descrs -> Symbol.symbol list
@@ -689,77 +397,44 @@ sig
   val update_param_value : context -> string -> string -> unit
   val set_print_mode : context -> Z3enums.ast_print_mode -> unit
 end = struct
-  type params = z3_native_object
+  type params = Z3native.params
+  let gc = Z3native.context_of_params
 
-  module ParamDescrs = 
-  struct    
-    type param_descrs = z3_native_object
+  module ParamDescrs =
+  struct
+    type param_descrs = Z3native.param_descrs
+    let gc = Z3native.context_of_param_descrs
 
-    let param_descrs_of_ptr ( ctx : context ) ( no : Z3native.ptr ) = 
-      let res : param_descrs = { m_ctx = ctx ;
-                     m_n_obj = null ;
-                     inc_ref = Z3native.param_descrs_inc_ref ;
-                     dec_ref = Z3native.param_descrs_dec_ref } in
-      (z3obj_sno res ctx no) ;
-      (z3obj_create res) ;
-      res
-     
-    let validate ( x : param_descrs ) ( p : params ) = 
-      Z3native.params_validate (z3obj_gnc x) (z3obj_gno p) (z3obj_gno x)
-     
-    let get_kind ( x : param_descrs ) ( name : Symbol.symbol ) = 
-      (param_kind_of_int (Z3native.param_descrs_get_kind (z3obj_gnc x) (z3obj_gno x) (Symbol.gno name)))
-     
-    let get_names ( x : param_descrs ) =
-      let n = Z3native.param_descrs_size (z3obj_gnc x) (z3obj_gno x) in
-      let f i = Symbol.create (z3obj_gc x) (Z3native.param_descrs_get_name (z3obj_gnc x) (z3obj_gno x) i) in
+    let validate (x:param_descrs) (p:params) = Z3native.params_validate (gc x) p x
+    let get_kind (x:param_descrs) (name:Symbol.symbol) = param_kind_of_int (Z3native.param_descrs_get_kind (gc x) x name)
+
+    let get_names (x:param_descrs) =
+      let n = Z3native.param_descrs_size (gc x) x in
+      let f i = Z3native.param_descrs_get_name (gc x) x i in
       mk_list f n
 
-    let get_size ( x : param_descrs ) = Z3native.param_descrs_size (z3obj_gnc x) (z3obj_gno x)    
-    let to_string ( x : param_descrs ) = Z3native.param_descrs_to_string (z3obj_gnc x) (z3obj_gno x) 
+    let get_size (x:param_descrs) = Z3native.param_descrs_size (gc x) x
+    let to_string (x:param_descrs) = Z3native.param_descrs_to_string (gc x) x
   end
 
-  let add_bool ( x : params ) ( name : Symbol.symbol ) ( value : bool ) =
-    Z3native.params_set_bool (z3obj_gnc x) (z3obj_gno x) (Symbol.gno name) value
-      
-  let add_int ( x : params )  (name : Symbol.symbol ) ( value : int ) =
-    Z3native.params_set_uint (z3obj_gnc x) (z3obj_gno x) (Symbol.gno name) value
-      
-  let add_float ( x : params ) ( name : Symbol.symbol ) ( value : float ) =
-    Z3native.params_set_double (z3obj_gnc x) (z3obj_gno x) (Symbol.gno name) value
+  let add_bool (x:params) (name:Symbol.symbol) (value:bool) = Z3native.params_set_bool (gc x) x name value
+  let add_int (x:params)  (name:Symbol.symbol) (value:int) = Z3native.params_set_uint (gc x) x name value
+  let add_float (x:params) (name:Symbol.symbol) (value:float) = Z3native.params_set_double (gc x) x name value
+  let add_symbol (x:params) (name:Symbol.symbol) (value:Symbol.symbol) = Z3native.params_set_symbol (gc x) x name value
+  let mk_params (ctx:context) = Z3native.mk_params ctx
+  let to_string (x:params) = Z3native.params_to_string (gc x) x
 
-  let add_symbol ( x : params ) ( name : Symbol.symbol ) ( value : Symbol.symbol ) =
-    Z3native.params_set_symbol (z3obj_gnc x) (z3obj_gno x) (Symbol.gno name) (Symbol.gno value)
-
-  let mk_params ( ctx : context ) =
-    let res : params = { m_ctx = ctx ;
-                m_n_obj = null ;
-                inc_ref = Z3native.params_inc_ref ;
-                dec_ref = Z3native.params_dec_ref } in
-    (z3obj_sno res ctx (Z3native.mk_params (context_gno ctx))) ;
-    (z3obj_create res) ;
-    res
-
-  let to_string ( x : params ) = Z3native.params_to_string (z3obj_gnc x) (z3obj_gno x)
-
-  let update_param_value ( ctx : context ) ( id : string) ( value : string )=
-    Z3native.update_param_value (context_gno ctx) id value
-
-  let set_print_mode ( ctx : context ) ( value : ast_print_mode ) =
-    Z3native.set_ast_print_mode (context_gno ctx) (int_of_ast_print_mode value)
+  let update_param_value (ctx:context) (id:string) (value:string) = Z3native.update_param_value ctx id value
+  let set_print_mode (ctx:context) (value:ast_print_mode) = Z3native.set_ast_print_mode ctx (int_of_ast_print_mode value)
 end
 
 (** General expressions (terms) *)
 and Expr :
 sig
-  type expr = Expr of AST.ast
-  val expr_of_ptr : context -> Z3native.ptr -> expr
+  type expr = AST.ast
   val gc : expr -> context
-  val gnc : expr -> Z3native.ptr
-  val gno : expr -> Z3native.ptr
-  val expr_lton : expr list -> Z3native.ptr array
-  val ast_of_expr : expr -> AST.ast
-  val expr_of_ast : AST.ast -> expr
+  val ast_of_expr  :  expr -> AST.ast
+  val expr_of_ast  :  AST.ast -> expr
   val expr_of_func_app : context -> FuncDecl.func_decl -> expr list -> expr
   val simplify : expr -> Params.params option -> expr
   val get_simplify_help : context -> string
@@ -785,2319 +460,1598 @@ sig
   val mk_numeral_string : context -> string -> Sort.sort -> expr
   val mk_numeral_int : context -> int -> Sort.sort -> expr
   val equal : expr -> expr -> bool
-  val apply1 : context -> (Z3native.ptr -> Z3native.ptr -> Z3native.ptr) -> expr -> expr
-  val apply2 : context -> (Z3native.ptr -> Z3native.ptr -> Z3native.ptr -> Z3native.ptr) -> expr -> expr -> expr 
-  val apply3 : context -> (Z3native.ptr -> Z3native.ptr -> Z3native.ptr -> Z3native.ptr -> Z3native.ptr) 
-                  -> expr -> expr -> expr -> expr 
-  val apply4 : context -> (Z3native.ptr -> Z3native.ptr -> Z3native.ptr -> Z3native.ptr -> Z3native.ptr -> Z3native.ptr) 
-                  -> expr -> expr -> expr -> expr -> expr
   val compare : expr -> expr -> int
-end = struct  
-  type expr = Expr of AST.ast
-      
-  let gc e = match e with Expr(a) -> (z3obj_gc a)
-  let gnc e = match e with Expr(a) -> (z3obj_gnc a)
-  let gno e = match e with Expr(a) -> (z3obj_gno a)
+end = struct
+  type expr = AST.ast
+  let gc = Z3native.context_of_ast
 
-  let inc_elist (es : expr list) = 
-      List.iter (fun e -> match e with Expr(o) -> o.inc_ref (gnc e) o.m_n_obj) es
-
-  let dec_elist (es : expr list) = 
-      List.iter (fun e -> match e with Expr(o) -> o.dec_ref (gnc e) o.m_n_obj) es
-
-  let expr_of_ptr : context -> Z3native.ptr -> expr = fun ctx no -> 
-    let e = z3_native_object_of_ast_ptr ctx no in 
-    if ast_kind_of_int (Z3native.get_ast_kind (context_gno ctx) no) == QUANTIFIER_AST then
-      Expr(e)
+  let expr_of_ast a =
+    let q = Z3enums.ast_kind_of_int (Z3native.get_ast_kind (gc a) a) in
+    if q <> Z3enums.APP_AST && q <> VAR_AST && q <> QUANTIFIER_AST && q <> NUMERAL_AST then
+      raise (Error "Invalid coercion")
     else
-      let s = Z3native.get_sort (context_gno ctx) no in
-      let sk = (sort_kind_of_int (Z3native.get_sort_kind (context_gno ctx) s)) in
-      if (Z3native.is_algebraic_number (context_gno ctx) no) then
-         Expr(e)
-      else if (Z3native.is_numeral_ast (context_gno ctx) no) then
-        match sk with
-        | REAL_SORT 
-        | BOOL_SORT 
-        | ARRAY_SORT 
-        | BV_SORT 
-        | ROUNDING_MODE_SORT 
-        | RELATION_SORT 
-        | UNINTERPRETED_SORT 
-        | FLOATING_POINT_SORT 
-        | INT_SORT 
-        | DATATYPE_SORT 
-        | FINITE_DOMAIN_SORT -> Expr(e)
-        | _ -> raise (Z3native.Exception "Unsupported numeral object")
-      else       
-        Expr(e)
+      a
 
-  let expr_of_ast a = 
-    let q = (Z3enums.ast_kind_of_int (Z3native.get_ast_kind (z3obj_gnc a) (z3obj_gno a))) in
-    if (q != Z3enums.APP_AST && q != VAR_AST && q != QUANTIFIER_AST && q != NUMERAL_AST) then
-      raise (Z3native.Exception "Invalid coercion")
+  let ast_of_expr e = e
+
+  let expr_of_func_app ctx f args =
+    Z3native.mk_app ctx f (List.length args) args
+
+  let simplify (x:expr) (p:Params.params option) =
+    match p with
+    | None -> Z3native.simplify (gc x) x
+    | Some pp -> Z3native.simplify_ex (gc x) x pp
+
+  let get_simplify_help = Z3native.simplify_get_help
+  let get_simplify_parameter_descrs = Z3native.simplify_get_param_descrs
+  let get_func_decl (x:expr) = Z3native.get_app_decl (gc x) x
+  let get_num_args (x:expr) = Z3native.get_app_num_args (gc x) x
+  let get_args (x:expr) =
+    let n = get_num_args x in
+    let f i = Z3native.get_app_arg (gc x) x i in
+    mk_list f n
+
+  let update (x:expr) (args:expr list) =
+    if AST.is_app x && List.length args <> get_num_args x then
+      raise (Error "Number of arguments does not match")
     else
-      Expr(a)
+      Z3native.update_term (gc x) x (List.length args) args
 
-  let ast_of_expr e = match e with Expr(a) -> a
-
-  let expr_lton ( a : expr list ) =
-    let f ( e : expr ) = match e with Expr(a) -> (AST.ptr_of_ast a) in 
-    Array.of_list (List.map f a)
-
-  let expr_of_func_app : context -> FuncDecl.func_decl -> expr list -> expr = fun ctx f args ->
-    match f with FuncDecl.FuncDecl(fa) ->
-      let o = Z3native.mk_app (context_gno ctx) (AST.ptr_of_ast fa) (List.length args) (expr_lton args) in
-      expr_of_ptr ctx o
-
-  let apply1 ctx f t = 
-      expr_of_ptr ctx (f (context_gno ctx) (gno t))
-
-  let apply2 ctx f t1 t2 = 
-      expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2))
-
-  let apply3 ctx f t1 t2 t3 = 
-      expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2) (gno t3))
-
-  let apply4 ctx f t1 t2 t3 t4 = 
-      expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2) (gno t3) (gno t4))
-
-  let simplify ( x : expr ) ( p : Params.params option ) = match p with 
-    | None -> expr_of_ptr (Expr.gc x) (Z3native.simplify (gnc x) (gno x))
-    | Some pp -> expr_of_ptr (Expr.gc x) (Z3native.simplify_ex (gnc x) (gno x) (z3obj_gno pp))
-      
-  let get_simplify_help ( ctx : context ) =
-    Z3native.simplify_get_help (context_gno ctx)
-
-  let get_simplify_parameter_descrs ( ctx : context ) = 
-    Params.ParamDescrs.param_descrs_of_ptr ctx (Z3native.simplify_get_param_descrs (context_gno ctx))
-  let get_func_decl ( x : expr ) = FuncDecl.func_decl_of_ptr (Expr.gc x) (Z3native.get_app_decl (gnc x) (gno x))    
-
-  let get_num_args ( x : expr ) = Z3native.get_app_num_args (gnc x) (gno x)
-    
-  let get_args ( x : expr ) = let n = (get_num_args x) in
-                     let f i = expr_of_ptr (Expr.gc x) (Z3native.get_app_arg (gnc x) (gno x) i) in
-                     mk_list f n
-                    
-  let update ( x : expr ) ( args : expr list ) =
-    if ((AST.is_app (ast_of_expr x)) && (List.length args <> (get_num_args x))) then
-      raise (Z3native.Exception "Number of arguments does not match")
+  let substitute (x:expr) (from:expr list) (to_:expr list) =
+    let len = List.length from in
+    if List.length to_ <> len then
+      raise (Error "Argument sizes do not match")
     else
-      (inc_elist args; 
-       let r = expr_of_ptr (Expr.gc x) (Z3native.update_term (gnc x) (gno x) (List.length args) (expr_lton args)) in
-       dec_elist args;
-       r)
-      
-  let substitute ( x : expr ) from to_ = 
-    if (List.length from) <> (List.length to_) then
-      raise (Z3native.Exception "Argument sizes do not match")
-    else
-      (inc_elist from;
-       inc_elist to_;
-       let r = expr_of_ptr (Expr.gc x) (Z3native.substitute (gnc x) (gno x) (List.length from) (expr_lton from) (expr_lton to_)) in
-       dec_elist from;
-       dec_elist to_;
-       r)
-     
-  let substitute_one ( x : expr ) from to_ =
-    substitute ( x : expr ) [ from ] [ to_ ]
-      
-  let substitute_vars ( x : expr ) to_ =
-    (inc_elist to_;
-     let r = expr_of_ptr (Expr.gc x) (Z3native.substitute_vars (gnc x) (gno x) (List.length to_) (expr_lton to_)) in
-     dec_elist to_;
-     r)
-      
-  let translate ( x : expr ) to_ctx =
-    if (Expr.gc x) == to_ctx then
+      Z3native.substitute (gc x) x len from to_
+
+  let substitute_one x from to_ = substitute x [ from ] [ to_ ]
+  let substitute_vars x to_ =
+    Z3native.substitute_vars (gc x) x (List.length to_) to_
+
+  let translate (x:expr) to_ctx =
+    if gc x = to_ctx then
       x
     else
-      expr_of_ptr to_ctx (Z3native.translate (gnc x) (gno x) (context_gno to_ctx)) 
+      Z3native.translate (gc x) x to_ctx
 
-  let to_string ( x : expr ) = Z3native.ast_to_string (gnc x) (gno x)
+  let to_string (x:expr) = Z3native.ast_to_string (gc x) x
+  let is_numeral (x:expr) = Z3native.is_numeral_ast (gc x) x
+  let is_well_sorted (x:expr) = Z3native.is_well_sorted (gc x) x
+  let get_sort (x:expr) = Z3native.get_sort (gc x) x
+  let is_const (x:expr) =
+    AST.is_app x
+    && get_num_args x = 0
+    && FuncDecl.get_domain_size (get_func_decl x) = 0
 
-  let is_numeral ( x : expr ) = (Z3native.is_numeral_ast (gnc x) (gno x))
-    
-  let is_well_sorted ( x : expr ) = Z3native.is_well_sorted (gnc x) (gno x)
-
-  let get_sort ( x : expr ) = Sort.sort_of_ptr (Expr.gc x) (Z3native.get_sort (gnc x) (gno x))
-    
-  let is_const ( x : expr ) = (match x with Expr(a) -> (AST.is_app a)) &&
-    (get_num_args x) == 0 &&
-    (FuncDecl.get_domain_size (get_func_decl x)) == 0
-    
-  let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( range : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_const (context_gno ctx) (Symbol.gno name) (Sort.gno range))
-      
-  let mk_const_s ( ctx : context ) ( name : string ) ( range : Sort.sort ) =
-    mk_const ctx (Symbol.mk_string ctx name) range
-
-  let mk_const_f ( ctx : context ) ( f : FuncDecl.func_decl ) = Expr.expr_of_func_app ctx f []
-
-  let mk_fresh_const ( ctx : context ) ( prefix : string ) ( range : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_fresh_const (context_gno ctx) prefix (Sort.gno range))
-
-  let mk_app ( ctx : context ) ( f : FuncDecl.func_decl ) ( args : expr list ) = expr_of_func_app ctx f args
-
-  let mk_numeral_string ( ctx : context ) ( v : string ) ( ty : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno ty))
-
-  let mk_numeral_int ( ctx : context ) ( v : int ) ( ty : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_int (context_gno ctx) v (Sort.gno ty))
-
-  let equal ( a : expr ) ( b : expr ) = AST.equal (ast_of_expr a) (ast_of_expr b)
-    
-  let compare a b = AST.compare (ast_of_expr a) (ast_of_expr b)
+  let mk_const (ctx:context) (name:Symbol.symbol) (range:Sort.sort) = Z3native.mk_const ctx name range
+  let mk_const_s (ctx:context) (name:string) (range:Sort.sort) = mk_const ctx (Symbol.mk_string ctx name) range
+  let mk_const_f (ctx:context) (f:FuncDecl.func_decl) = expr_of_func_app ctx f []
+  let mk_fresh_const (ctx:context) (prefix:string) (range:Sort.sort) = Z3native.mk_fresh_const ctx prefix range
+  let mk_app (ctx:context) (f:FuncDecl.func_decl) (args:expr list) = expr_of_func_app ctx f args
+  let mk_numeral_string (ctx:context) (v:string) (ty:Sort.sort) = Z3native.mk_numeral ctx v ty
+  let mk_numeral_int (ctx:context) (v:int) (ty:Sort.sort) = Z3native.mk_int ctx v ty
+  let equal (a:expr) (b:expr) = AST.equal a b
+  let compare (a:expr) (b:expr) = AST.compare a b
 end
 
 open FuncDecl
 open Expr
 
-module Boolean = 
-struct      
-  let mk_sort ( ctx : context ) =
-    (Sort.sort_of_ptr ctx (Z3native.mk_bool_sort (context_gno ctx)))
+module Boolean =
+struct
+  let mk_sort = Z3native.mk_bool_sort
+  let mk_const (ctx:context) (name:Symbol.symbol) = Expr.mk_const ctx name (mk_sort ctx)
+  let mk_const_s (ctx:context) (name:string) = mk_const ctx (Symbol.mk_string ctx name)
+  let mk_true = Z3native.mk_true
+  let mk_false = Z3native.mk_false
+  let mk_val (ctx:context) (value:bool) = if value then mk_true ctx else mk_false ctx
+  let mk_not = Z3native.mk_not
+  let mk_ite = Z3native.mk_ite
+  let mk_iff = Z3native.mk_iff
+  let mk_implies = Z3native.mk_implies
+  let mk_xor = Z3native.mk_xor
 
-  let mk_const ( ctx : context ) ( name : Symbol.symbol ) =
-    (Expr.mk_const ctx name (mk_sort ctx))
-      
-  let mk_const_s ( ctx : context ) ( name : string ) =
-    mk_const ctx (Symbol.mk_string ctx name)
+  let mk_and ctx args = Z3native.mk_and ctx (List.length args) args
 
-  let mk_true ( ctx : context ) =
-    expr_of_ptr ctx (Z3native.mk_true (context_gno ctx))
+  let mk_or ctx args = Z3native.mk_or ctx (List.length args) args
 
-  let mk_false ( ctx : context ) =
-    expr_of_ptr ctx (Z3native.mk_false (context_gno ctx))
+  let mk_eq = Z3native.mk_eq
+  let mk_distinct ctx args = Z3native.mk_distinct ctx (List.length args) args
 
-  let mk_val ( ctx : context ) ( value : bool ) =
-    if value then mk_true ctx else mk_false ctx
-      
-  let mk_not ( ctx : context ) ( a : expr ) = apply1 ctx Z3native.mk_not a
+  let get_bool_value x = lbool_of_int (Z3native.get_bool_value (gc x) x)
 
-  let mk_ite ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( t3 : expr ) = 
-    apply3 ctx Z3native.mk_ite t1 t2 t3
-      
-  let mk_iff ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
-    apply2 ctx Z3native.mk_iff t1 t2
+  let is_bool x =
+    AST.is_expr x
+    && Z3native.is_eq_sort (gc x) (Z3native.mk_bool_sort (gc x)) (Z3native.get_sort (gc x) x)
 
-  let mk_implies ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
-    apply2 ctx Z3native.mk_implies t1 t2
-
-  let mk_xor ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
-    apply2 ctx Z3native.mk_xor t1 t2
-
-  let mk_and ( ctx : context ) ( args : expr list ) =
-    let f x = (Expr.gno (x)) in
-    expr_of_ptr ctx (Z3native.mk_and (context_gno ctx) (List.length args) (Array.of_list (List.map f args))) 
-
-  let mk_or ( ctx : context ) ( args : expr list ) =
-    let f x = (Expr.gno (x)) in
-    expr_of_ptr ctx (Z3native.mk_or (context_gno ctx) (List.length args) (Array.of_list(List.map f args))) 
-
-  let mk_eq ( ctx : context ) ( x : expr ) ( y : expr ) =
-    apply2 ctx Z3native.mk_eq x y
-
-  let mk_distinct ( ctx : context ) ( args : expr list ) =
-    expr_of_ptr ctx (Z3native.mk_distinct (context_gno ctx) (List.length args) (expr_lton args)) 
-
-  let get_bool_value ( x : expr ) = lbool_of_int (Z3native.get_bool_value (gnc x) (gno x))
-
-  let is_bool ( x : expr ) = (match x with Expr(a) -> (AST.is_expr a)) &&
-    (Z3native.is_eq_sort (gnc x) 
-       (Z3native.mk_bool_sort (gnc x))
-       (Z3native.get_sort (gnc x) (gno x)))
-
-  let is_true ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_TRUE)
-  let is_false ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_FALSE)
-  let is_eq ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_EQ)
-  let is_distinct ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_DISTINCT)
-  let is_ite ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_ITE)
-  let is_and ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_AND)
-  let is_or ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_OR)
-  let is_iff ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_IFF)
-  let is_xor ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_XOR)
-  let is_not ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_NOT)
-  let is_implies ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (get_func_decl x) == OP_IMPLIES)
+  let is_true x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_TRUE
+  let is_false x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_FALSE
+  let is_eq x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_EQ
+  let is_distinct x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_DISTINCT
+  let is_ite x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_ITE
+  let is_and x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_AND
+  let is_or x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_OR
+  let is_iff x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_IFF
+  let is_xor x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_XOR
+  let is_not x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_NOT
+  let is_implies x = AST.is_app x && FuncDecl.get_decl_kind (get_func_decl x) = OP_IMPLIES
 end
 
 
-module Quantifier = 
-struct 
-  type quantifier = Quantifier of expr
+module Quantifier =
+struct
+  type quantifier = AST.ast
+  let gc = Z3native.context_of_ast
 
-  let expr_of_quantifier e = match e with Quantifier(x) -> x
+  let expr_of_quantifier q = q
 
   let quantifier_of_expr e =
-    match e with Expr.Expr(a) ->
-      let q = (Z3enums.ast_kind_of_int (Z3native.get_ast_kind (z3obj_gnc a) (z3obj_gno a))) in
-      if (q != Z3enums.QUANTIFIER_AST) then
-     raise (Z3native.Exception "Invalid coercion")
-      else
-     Quantifier(e)
-       
-  let gc ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gc e)
-  let gnc ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gnc e)
-  let gno ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gno e)
-    
-  module Pattern = 
+    let q = Z3enums.ast_kind_of_int (Z3native.get_ast_kind (gc e) e) in
+    if q <> Z3enums.QUANTIFIER_AST then
+      raise (Error "Invalid coercion")
+    else
+      e
+
+  module Pattern =
   struct
-    type pattern = Pattern of AST.ast
+    type pattern = Z3native.pattern
+    let gc = Z3native.context_of_ast
 
-    let ast_of_pattern e = match e with Pattern(x) -> x
-      
-    let pattern_of_ast a =
-      (* CMW: Unchecked ok? *)
-      Pattern(a)
+    let get_num_terms x = Z3native.get_pattern_num_terms (gc x) x
 
-    let gc ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gc a)
-    let gnc ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gnc a)
-    let gno ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gno a)
-
-    let get_num_terms ( x : pattern ) =
-      Z3native.get_pattern_num_terms (gnc x) (gno x)
-
-    let get_terms ( x : pattern ) =
-      let n = (get_num_terms x) in
-      let f i = (expr_of_ptr (gc x) (Z3native.get_pattern (gnc x) (gno x) i)) in
+    let get_terms x =
+      let n = get_num_terms x in
+      let f i = Z3native.get_pattern (gc x) x i in
       mk_list f n
 
-    let to_string ( x : pattern ) = Z3native.pattern_to_string (gnc x) (gno x)
+    let to_string x = Z3native.pattern_to_string (gc x) x
   end
 
-  let get_index ( x : expr ) = 
-    if not (AST.is_var (match x with Expr.Expr(a) -> a)) then
-      raise (Z3native.Exception "Term is not a bound variable.")
+  let get_index (x:expr) =
+    if not (AST.is_var x) then
+      raise (Error "Term is not a bound variable.")
     else
-      Z3native.get_index_value (Expr.gnc x) (Expr.gno x)
+      Z3native.get_index_value (gc x) x
 
-  let is_universal ( x : quantifier ) =
-    Z3native.is_quantifier_forall (gnc x) (gno x)
-      
-  let is_existential ( x : quantifier ) = not (is_universal x)
-
-  let get_weight ( x : quantifier ) = Z3native.get_quantifier_weight (gnc x) (gno x)
-    
-  let get_num_patterns ( x : quantifier ) = Z3native.get_quantifier_num_patterns (gnc x) (gno x)
-    
-  let get_patterns ( x : quantifier ) =
-    let n = (get_num_patterns x) in
-    let f i = Pattern.Pattern (z3_native_object_of_ast_ptr (gc x) (Z3native.get_quantifier_pattern_ast (gnc x) (gno x) i)) in
+  let is_universal x = Z3native.is_quantifier_forall (gc x) x
+  let is_existential x = not (is_universal x)
+  let get_weight x = Z3native.get_quantifier_weight (gc x) x
+  let get_num_patterns x = Z3native.get_quantifier_num_patterns (gc x) x
+  let get_patterns x =
+    let n = get_num_patterns x in
+    let f i = Z3native.get_quantifier_pattern_ast (gc x) x i in
     mk_list f n
-      
-  let get_num_no_patterns ( x : quantifier ) = Z3native.get_quantifier_num_no_patterns (gnc x) (gno x)
-    
-  let get_no_patterns ( x : quantifier ) =
-    let n = (get_num_patterns x) in
-    let f i = Pattern.Pattern (z3_native_object_of_ast_ptr (gc x) (Z3native.get_quantifier_no_pattern_ast (gnc x) (gno x) i)) in
+
+  let get_num_no_patterns x = Z3native.get_quantifier_num_no_patterns (gc x) x
+
+  let get_no_patterns x =
+    let n = get_num_patterns x in
+    let f i = Z3native.get_quantifier_no_pattern_ast (gc x) x i in
     mk_list f n
-      
-  let get_num_bound ( x : quantifier ) = Z3native.get_quantifier_num_bound (gnc x) (gno x)
-    
-  let get_bound_variable_names ( x : quantifier ) =
-    let n = (get_num_bound x) in
-    let f i = (Symbol.create (gc x) (Z3native.get_quantifier_bound_name (gnc x) (gno x) i)) in
+
+  let get_num_bound x = Z3native.get_quantifier_num_bound (gc x) x
+
+  let get_bound_variable_names x =
+    let n = get_num_bound x in
+    let f i = Z3native.get_quantifier_bound_name (gc x) x i in
     mk_list f n
-      
-  let get_bound_variable_sorts ( x : quantifier ) =
-    let n = (get_num_bound x) in
-    let f i = (Sort.sort_of_ptr (gc x) (Z3native.get_quantifier_bound_sort (gnc x) (gno x) i)) in
+
+  let get_bound_variable_sorts x =
+    let n = get_num_bound x in
+    let f i = Z3native.get_quantifier_bound_sort (gc x) x i in
     mk_list f n
-      
-  let get_body ( x : quantifier ) =  
-    let ctx = gc x in 
-    expr_of_ptr ctx (Z3native.get_quantifier_body (context_gno ctx) (gno x))
 
-  let mk_bound ( ctx : context ) ( index : int ) ( ty : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_bound (context_gno ctx) index (Sort.gno ty)) 
+  let get_body x = Z3native.get_quantifier_body (gc x) x
+  let mk_bound = Z3native.mk_bound
 
-  let mk_pattern ( ctx : context ) ( terms : expr list ) =
-    if (List.length terms) == 0 then
-      raise (Z3native.Exception "Cannot create a pattern from zero terms")
+  let mk_pattern ctx terms =
+    let len = List.length terms in
+    if len = 0 then
+      raise (Error "Cannot create a pattern from zero terms")
     else
-      Pattern.Pattern(z3_native_object_of_ast_ptr ctx (Z3native.mk_pattern (context_gno ctx) (List.length terms) (expr_lton terms)))
+      Z3native.mk_pattern ctx len terms
 
-  let mk_forall ( ctx : context ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) =
-    if (List.length sorts) != (List.length names) then
-      raise (Z3native.Exception "Number of sorts does not match number of names")
-    else if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then
-      Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier (context_gno ctx) true 
-                                    (match weight with | None -> 1 | Some(x) -> x)
-                                    (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
-                        (List.length sorts) (Sort.sort_lton sorts)
-                        (Symbol.symbol_lton names)
-                        (Expr.gno body)))
+  let _internal_mk_quantifier ~universal ctx sorts names body weight patterns nopatterns quantifier_id skolem_id =
+    let len = List.length sorts in
+    if List.length names <> len then
+      raise (Error "Number of sorts does not match number of names")
     else
-      Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_ex (context_gno ctx) true
-                        (match weight with | None -> 1 | Some(x) -> x)
-                        (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
-                        (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
-                        (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
-                        (List.length nopatterns) (expr_lton nopatterns)
-                        (List.length sorts) (Sort.sort_lton sorts)
-                        (Symbol.symbol_lton names)
-                        (Expr.gno body)))
-     
-  let mk_forall_const ( ctx : context ) ( bound_constants : expr list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) =
-    if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then
-      Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const (context_gno ctx) true
-                        (match weight with | None -> 1 | Some(x) -> x)
-                        (List.length bound_constants) (expr_lton bound_constants)
-                        (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
-                        (Expr.gno body)))
-    else
-      Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const_ex (context_gno ctx) true
-                        (match weight with | None -> 1 | Some(x) -> x)
-                        (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
-                        (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
-                        (List.length bound_constants) (expr_lton bound_constants)
-                        (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
-                        (List.length nopatterns) (expr_lton nopatterns)
-                        (Expr.gno body)))
+      match nopatterns, quantifier_id, skolem_id with
+      | [], None, None ->
+        Z3native.mk_quantifier ctx universal
+          (match weight with | None -> 1 | Some x -> x)
+          (List.length patterns) patterns
+          len sorts
+          names body
+      | _ ->
+        Z3native.mk_quantifier_ex ctx universal
+          (match weight with | None -> 1 | Some x -> x)
+          (match quantifier_id with | None -> Z3native.mk_null_symbol ctx | Some x -> x)
+          (match skolem_id with | None -> Z3native.mk_null_symbol ctx | Some x -> x)
+          (List.length patterns) patterns
+          (List.length nopatterns) nopatterns
+          len sorts
+          names body
 
-  let mk_exists ( ctx : context ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) =
-    if (List.length sorts) != (List.length names) then
-      raise (Z3native.Exception "Number of sorts does not match number of names")
-    else if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then
-      Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier (context_gno ctx) false
-                        (match weight with | None -> 1 | Some(x) -> x)
-                        (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
-                        (List.length sorts) (Sort.sort_lton sorts)
-                        (Symbol.symbol_lton names)
-                        (Expr.gno body)))
-    else
-      Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_ex (context_gno ctx) false
-                        (match weight with | None -> 1 | Some(x) -> x)
-                        (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
-                        (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
-                        (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
-                        (List.length nopatterns) (expr_lton nopatterns)
-                        (List.length sorts) (Sort.sort_lton sorts)
-                        (Symbol.symbol_lton names)
-                        (Expr.gno body)))
-     
-  let mk_exists_const ( ctx : context ) ( bound_constants : expr list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) =
-    if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then
-      Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const (context_gno ctx) false
-                        (match weight with | None -> 1 | Some(x) -> x)
-                        (List.length bound_constants) (expr_lton bound_constants)
-                        (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
-                        (Expr.gno body)))
-    else
-      Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const_ex (context_gno ctx) false
-                        (match weight with | None -> 1 | Some(x) -> x)
-                        (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
-                        (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
-                        (List.length bound_constants) (expr_lton bound_constants)
-                        (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
-                        (List.length nopatterns) (expr_lton nopatterns)
-                        (Expr.gno body)))
+  let _internal_mk_quantifier_const ~universal ctx bound_constants body weight patterns nopatterns quantifier_id skolem_id =
+    match nopatterns, quantifier_id, skolem_id with
+    | [], None, None ->
+      Z3native.mk_quantifier_const ctx universal
+        (match weight with | None -> 1 | Some x -> x)
+        (List.length bound_constants) bound_constants
+        (List.length patterns) patterns
+        body
+    | _ ->
+      Z3native.mk_quantifier_const_ex ctx universal
+        (match weight with | None -> 1 | Some x -> x)
+        (match quantifier_id with | None -> Z3native.mk_null_symbol ctx | Some x -> x)
+        (match skolem_id with | None -> Z3native.mk_null_symbol ctx | Some x -> x)
+        (List.length bound_constants) bound_constants
+        (List.length patterns) patterns
+        (List.length nopatterns) nopatterns
+        body
 
-  let mk_quantifier ( ctx : context ) ( universal : bool ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) =
-    if (universal) then
-      (mk_forall ctx sorts names body weight patterns nopatterns quantifier_id skolem_id)
-    else
-      (mk_exists ctx sorts names body weight patterns nopatterns quantifier_id skolem_id)
+  let mk_forall = _internal_mk_quantifier ~universal:true
+  let mk_forall_const = _internal_mk_quantifier_const ~universal:true
+  let mk_exists = _internal_mk_quantifier ~universal:false
+  let mk_exists_const = _internal_mk_quantifier_const ~universal:false
 
-  let mk_quantifier ( ctx : context ) ( universal : bool ) ( bound_constants : expr list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) =
-    if (universal) then
+  let mk_quantifier (ctx:context) (universal:bool) (sorts:Sort.sort list) (names:Symbol.symbol list) (body:expr) (weight:int option) (patterns:Pattern.pattern list) (nopatterns:expr list) (quantifier_id:Symbol.symbol option) (skolem_id:Symbol.symbol option) =
+    if universal then
+      mk_forall ctx sorts names body weight patterns nopatterns quantifier_id skolem_id
+    else
+      mk_exists ctx sorts names body weight patterns nopatterns quantifier_id skolem_id
+
+  let mk_quantifier (ctx:context) (universal:bool) (bound_constants:expr list) (body:expr) (weight:int option) (patterns:Pattern.pattern list) (nopatterns:expr list) (quantifier_id:Symbol.symbol option) (skolem_id:Symbol.symbol option) =
+    if universal then
       mk_forall_const ctx bound_constants body weight patterns nopatterns quantifier_id skolem_id
     else
       mk_exists_const ctx bound_constants body weight patterns nopatterns quantifier_id skolem_id
 
-  let to_string ( x : quantifier ) = (Expr.to_string (expr_of_quantifier x))
+  let to_string x = Expr.to_string x
 end
 
-
-module Z3Array = 
+module Z3Array =
 struct
-  let mk_sort ( ctx : context ) ( domain : Sort.sort ) ( range : Sort.sort ) =
-    Sort.sort_of_ptr ctx (Z3native.mk_array_sort (context_gno ctx) (Sort.gno domain) (Sort.gno range))
+  let mk_sort = Z3native.mk_array_sort
+  let is_store x = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_STORE
+  let is_select x = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SELECT
+  let is_constant_array x = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_CONST_ARRAY
+  let is_default_array x = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ARRAY_DEFAULT
+  let is_array_map x = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ARRAY_MAP
+  let is_as_array x = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_AS_ARRAY
 
-  let is_store ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_STORE)
-  let is_select ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SELECT)
-  let is_constant_array ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_CONST_ARRAY)
-  let is_default_array ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_ARRAY_DEFAULT)
-  let is_array_map ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_ARRAY_MAP)
-  let is_as_array ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_AS_ARRAY)       
-  let is_array ( x : expr ) =
-    (Z3native.is_app (Expr.gnc x) (Expr.gno x)) &&
-      ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gnc x) (Z3native.get_sort (Expr.gnc x) (Expr.gno x)))) == ARRAY_SORT)      
+  let is_array x =
+    Z3native.is_app (Expr.gc x) x &&
+    sort_kind_of_int (Z3native.get_sort_kind (Expr.gc x) (Z3native.get_sort (Expr.gc x) x)) = ARRAY_SORT
 
-  let get_domain ( x : Sort.sort ) = Sort.sort_of_ptr (Sort.gc x) (Z3native.get_array_sort_domain (Sort.gnc x) (Sort.gno x))
-  let get_range ( x : Sort.sort ) = Sort.sort_of_ptr (Sort.gc x) (Z3native.get_array_sort_range (Sort.gnc x) (Sort.gno x))
+  let get_domain x = Z3native.get_array_sort_domain (Sort.gc x) x
+  let get_range x = Z3native.get_array_sort_range (Sort.gc x) x
 
-  let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort ) ( range : Sort.sort ) = 
-    (Expr.mk_const ctx name (mk_sort ctx domain range))
-      
-  let mk_const_s ( ctx : context ) ( name : string ) ( domain : Sort.sort ) ( range : Sort.sort ) =     
-    mk_const ctx (Symbol.mk_string ctx name) domain range
-      
-  let mk_select ( ctx : context ) ( a : expr ) ( i : expr ) =
-    apply2 ctx Z3native.mk_select a i
+  let mk_const ctx name domain range = Expr.mk_const ctx name (mk_sort ctx domain range)
 
-  let mk_store ( ctx : context ) ( a : expr ) ( i : expr ) ( v : expr ) =
-    apply3 ctx Z3native.mk_store a i v
+  let mk_const_s ctx name domain range = mk_const ctx (Symbol.mk_string ctx name) domain range
 
-  let mk_const_array ( ctx : context ) ( domain : Sort.sort ) ( v : expr ) =
-    expr_of_ptr ctx (Z3native.mk_const_array (context_gno ctx) (Sort.gno domain) (Expr.gno v)) 
+  let mk_select = Z3native.mk_select
+  let mk_store = Z3native.mk_store
+  let mk_const_array = Z3native.mk_const_array
 
-  let mk_map ( ctx : context ) ( f : func_decl ) ( args : expr list ) =
-    let m x = (Expr.gno x) in    
-    expr_of_ptr ctx (Z3native.mk_map (context_gno ctx) (FuncDecl.gno f) (List.length args) (Array.of_list (List.map m args)))
+  let mk_map ctx f args =
+    Z3native.mk_map ctx f (List.length args) args
 
-  let mk_term_array  ( ctx : context ) ( arg : expr ) =
-    apply1 ctx Z3native.mk_array_default arg
-
-  let mk_array_ext ( ctx : context) ( arg1 : expr ) ( arg2 : expr ) =
-    apply2 ctx Z3native.mk_array_ext arg1 arg2
+  let mk_term_array = Z3native.mk_array_default
+  let mk_array_ext = Z3native.mk_array_ext
 end
 
 
-module Set = 
-struct     
-  let mk_sort  ( ctx : context ) ( ty : Sort.sort ) =
-    Sort.sort_of_ptr ctx (Z3native.mk_set_sort (context_gno ctx) (Sort.gno ty))
-
-  let is_union ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SET_UNION)
-  let is_intersect ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SET_INTERSECT)
-  let is_difference ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SET_DIFFERENCE)
-  let is_complement ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SET_COMPLEMENT)
-  let is_subset ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SET_SUBSET)
-
-
-  let mk_empty ( ctx : context ) ( domain : Sort.sort ) =
-    (expr_of_ptr ctx (Z3native.mk_empty_set (context_gno ctx) (Sort.gno domain)))
-      
-  let mk_full ( ctx : context ) ( domain : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_full_set (context_gno ctx) (Sort.gno domain))
-
-  let mk_set_add  ( ctx : context ) ( set : expr ) ( element : expr ) =
-    apply2 ctx Z3native.mk_set_add set element
-      
-  let mk_del  ( ctx : context ) ( set : expr ) ( element : expr ) =
-    apply2 ctx Z3native.mk_set_del set element
-      
-  let mk_union  ( ctx : context ) ( args : expr list ) =
-    expr_of_ptr ctx (Z3native.mk_set_union (context_gno ctx) (List.length args) (expr_lton args)) 
-          
-  let mk_intersection  ( ctx : context ) ( args : expr list ) =
-    expr_of_ptr ctx (Z3native.mk_set_intersect (context_gno ctx) (List.length args) (expr_lton args))
-
-  let mk_difference  ( ctx : context ) ( arg1 : expr ) ( arg2 : expr ) =
-    apply2 ctx Z3native.mk_set_difference arg1 arg2
-
-  let mk_complement  ( ctx : context ) ( arg : expr ) =
-    apply1 ctx Z3native.mk_set_complement arg
-
-  let mk_membership  ( ctx : context ) ( elem : expr ) ( set : expr ) =
-    apply2 ctx Z3native.mk_set_member elem set
-
-  let mk_subset  ( ctx : context ) ( arg1 : expr ) ( arg2 : expr ) =
-    apply2 ctx Z3native.mk_set_subset arg1 arg2
-
-end
-
-
-module FiniteDomain = 
-struct  
-  let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( size : int ) =
-    Sort.sort_of_ptr ctx (Z3native.mk_finite_domain_sort (context_gno ctx) (Symbol.gno name) size)
-      
-  let mk_sort_s ( ctx : context ) ( name : string ) ( size : int ) =
-    mk_sort ctx (Symbol.mk_string ctx name) size
-
-  let is_finite_domain ( x : expr ) =
-    let nc = (Expr.gnc x) in
-    (Z3native.is_app (Expr.gnc x) (Expr.gno x)) &&
-      (sort_kind_of_int (Z3native.get_sort_kind nc (Z3native.get_sort nc (Expr.gno x))) == FINITE_DOMAIN_SORT)
-
-  let is_lt ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FD_LT)
-
-  let get_size ( x : Sort.sort ) = 
-    let (r, v) = (Z3native.get_finite_domain_sort_size (Sort.gnc x) (Sort.gno x)) in
-    if r then v
-    else raise (Z3native.Exception "Conversion failed.")
-end
-
-
-module Relation = 
+module Set =
 struct
-  let is_relation ( x : expr ) =
-    let nc = (Expr.gnc x) in
-    ((Z3native.is_app (Expr.gnc x) (Expr.gno x)) &&
-     (sort_kind_of_int (Z3native.get_sort_kind nc (Z3native.get_sort nc (Expr.gno x))) == RELATION_SORT))
+  let mk_sort = Z3native.mk_set_sort
 
-  let is_store ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_STORE)
-  let is_empty ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_EMPTY)
-  let is_is_empty ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_IS_EMPTY)
-  let is_join ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_JOIN)
-  let is_union ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_UNION)
-  let is_widen ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_WIDEN)
-  let is_project ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_PROJECT)
-  let is_filter ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_FILTER)
-  let is_negation_filter ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_NEGATION_FILTER)
-  let is_rename ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_RENAME)
-  let is_complement ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_COMPLEMENT)
-  let is_select ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_SELECT)
-  let is_clone ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_CLONE)
+  let is_union (x:expr) = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SET_UNION
+  let is_intersect (x:expr) = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SET_INTERSECT
+  let is_difference (x:expr) = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SET_DIFFERENCE
+  let is_complement (x:expr) = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SET_COMPLEMENT
+  let is_subset (x:expr) = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SET_SUBSET
 
-  let get_arity ( x : Sort.sort ) = Z3native.get_relation_arity (Sort.gnc x) (Sort.gno x)
+  let mk_empty = Z3native.mk_empty_set
+  let mk_full = Z3native.mk_full_set
+  let mk_set_add = Z3native.mk_set_add
+  let mk_del = Z3native.mk_set_del
+  let mk_union ctx args =
+    Z3native.mk_set_union ctx (List.length args) args
 
-  let get_column_sorts ( x : Sort.sort ) = 
+  let mk_intersection ctx args =
+    Z3native.mk_set_intersect ctx (List.length args) args
+
+  let mk_difference = Z3native.mk_set_difference
+  let mk_complement = Z3native.mk_set_complement
+  let mk_membership = Z3native.mk_set_member
+  let mk_subset = Z3native.mk_set_subset
+end
+
+
+module FiniteDomain =
+struct
+  let mk_sort = Z3native.mk_finite_domain_sort
+  let mk_sort_s ctx name size = mk_sort ctx (Symbol.mk_string ctx name) size
+
+  let is_finite_domain (x:expr) =
+    let nc = Expr.gc x in
+    Z3native.is_app nc x &&
+    sort_kind_of_int (Z3native.get_sort_kind nc (Z3native.get_sort nc x)) = FINITE_DOMAIN_SORT
+
+  let is_lt (x:expr) = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FD_LT
+
+  let get_size x =
+    match Z3native.get_finite_domain_sort_size (Sort.gc x) x with
+    | true, v -> v
+    | false, _ -> raise (Error "Conversion failed.")
+end
+
+
+module Relation =
+struct
+  let is_relation x =
+    let nc = Expr.gc x in
+    Z3native.is_app nc x
+    && sort_kind_of_int (Z3native.get_sort_kind nc (Z3native.get_sort nc x)) = RELATION_SORT
+
+  let is_store (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_STORE)
+  let is_empty (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_EMPTY)
+  let is_is_empty (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_IS_EMPTY)
+  let is_join (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_JOIN)
+  let is_union (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_UNION)
+  let is_widen (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_WIDEN)
+  let is_project (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_PROJECT)
+  let is_filter (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_FILTER)
+  let is_negation_filter (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_NEGATION_FILTER)
+  let is_rename (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_RENAME)
+  let is_complement (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_COMPLEMENT)
+  let is_select (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_SELECT)
+  let is_clone (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_RA_CLONE)
+
+  let get_arity (x:Sort.sort) = Z3native.get_relation_arity (Sort.gc x) x
+
+  let get_column_sorts (x:Sort.sort) =
     let n = get_arity x in
-    let f i = (Sort.sort_of_ptr (Sort.gc x) (Z3native.get_relation_column (Sort.gnc x) (Sort.gno x) i)) in
+    let f i = Z3native.get_relation_column (Sort.gc x) x i in
     mk_list f n
 end
-  
 
-module Datatype = 
+
+module Datatype =
 struct
-  module Constructor = 
+  module Constructor =
   struct
-    type constructor = z3_native_object
-     
-    module FieldNumTable = Hashtbl.Make(struct 
-      type t = AST.ast
-      let equal x y = AST.compare x y = 0
-      let hash = AST.hash
-    end)
+    type constructor = Z3native.constructor
+
+    module FieldNumTable = Hashtbl.Make(struct
+        type t = AST.ast
+        let equal x y = AST.compare x y = 0
+        let hash = AST.hash
+      end)
 
     let _field_nums = FieldNumTable.create 0
 
-    let create ( ctx : context ) ( name : Symbol.symbol ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : Sort.sort option list ) ( sort_refs : int list ) =
-      let n = (List.length field_names) in
-      if n != (List.length sorts) then
-     raise (Z3native.Exception "Number of field names does not match number of sorts")
+    let create (ctx:context) (name:Symbol.symbol) (recognizer:Symbol.symbol) (field_names:Symbol.symbol list) (sorts:Sort.sort option list) (sort_refs:int list) =
+      let n = List.length field_names in
+      if n <> List.length sorts then
+        raise (Error "Number of field names does not match number of sorts")
       else
-     if n != (List.length sort_refs) then
-       raise (Z3native.Exception "Number of field names does not match number of sort refs")
-     else
-          let ptr = (Z3native.mk_constructor (context_gno ctx) (Symbol.gno name) 
-                 (Symbol.gno recognizer) 
-                 n
-                 (Symbol.symbol_lton field_names)
-                 (Sort.sort_option_lton sorts)
-                 (Array.of_list sort_refs)) in
-       let no : constructor = { m_ctx = ctx ;
-                       m_n_obj = null ;
-                       inc_ref = z3obj_nil_ref ;
-                       dec_ref = z3obj_nil_ref} in
-       (z3obj_sno no ctx ptr) ;
-       (z3obj_create no) ;
-       let f = fun o -> Z3native.del_constructor (z3obj_gnc o) (z3obj_gno o) in
-       Gc.finalise f no ;
-       FieldNumTable.add _field_nums no n ;
-       no           
-         
-    let get_num_fields ( x : constructor ) = FieldNumTable.find _field_nums x
+      if n <> List.length sort_refs then
+        raise (Error "Number of field names does not match number of sort refs")
+      else
+        let no = Z3native.mk_constructor ctx name
+            recognizer
+            n
+            field_names
+            (let f x = match x with None -> Z3native.mk_null_ast ctx | Some s -> s in
+             List.map f sorts)
+            sort_refs in
+        FieldNumTable.add _field_nums no n;
+        no
 
-    let get_constructor_decl ( x : constructor ) = 
-      let (a, _, _) = (Z3native.query_constructor (z3obj_gnc x) (z3obj_gno x) (get_num_fields x)) in
-      func_decl_of_ptr (z3obj_gc x) a
+    let get_num_fields (x:constructor) = FieldNumTable.find _field_nums x
 
-    let get_tester_decl ( x : constructor ) =
-      let (_, b, _) = (Z3native.query_constructor (z3obj_gnc x) (z3obj_gno x) (get_num_fields x)) in
-      func_decl_of_ptr (z3obj_gc x) b     
+    let get_constructor_decl (x:constructor) =
+      let (a, _, _) = (Z3native.query_constructor (gc x) x (get_num_fields x)) in
+      a
 
-    let get_accessor_decls ( x : constructor ) = 
-      let (_, _, c) = (Z3native.query_constructor (z3obj_gnc x) (z3obj_gno x) (get_num_fields x)) in
-      let f i = func_decl_of_ptr (z3obj_gc x) (Array.get c i) in
-      mk_list f (Array.length c)
-     
+    let get_tester_decl (x:constructor) =
+      let (_, b, _) = (Z3native.query_constructor (gc x) x (get_num_fields x)) in
+      b
+
+    let get_accessor_decls (x:constructor) =
+      let (_, _, c) = (Z3native.query_constructor (gc x) x (get_num_fields x)) in
+      c
   end
 
   module ConstructorList =
   struct
-    type constructor_list = z3_native_object 
+    type constructor_list = Z3native.constructor_list
 
-    let create ( ctx : context ) ( c : Constructor.constructor list ) =
-      let res : constructor_list = { m_ctx = ctx ;
-                         m_n_obj = null ;
-                         inc_ref = z3obj_nil_ref ;
-                         dec_ref = z3obj_nil_ref} in
-      let f x =(z3obj_gno x) in 
-      (z3obj_sno res ctx (Z3native.mk_constructor_list (context_gno ctx) (List.length c) (Array.of_list (List.map f c)))) ;
-      (z3obj_create res) ;
-      let f = fun o -> Z3native.del_constructor_list (z3obj_gnc o) (z3obj_gno o) in      
-      Gc.finalise f res;
-      res       
+    let create (ctx:context) (c:Constructor.constructor list) =
+      Z3native.mk_constructor_list ctx (List.length c) c
   end
-    
-  let mk_constructor ( ctx : context ) ( name : Symbol.symbol ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : Sort.sort option list ) ( sort_refs : int list ) =
+
+  let mk_constructor (ctx:context) (name:Symbol.symbol) (recognizer:Symbol.symbol) (field_names:Symbol.symbol list) (sorts:Sort.sort option list) (sort_refs:int list) =
     Constructor.create ctx name recognizer field_names sorts sort_refs
 
-
-  let mk_constructor_s ( ctx : context ) ( name : string ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : Sort.sort option list ) ( sort_refs : int list ) =
+  let mk_constructor_s (ctx:context) (name:string) (recognizer:Symbol.symbol) (field_names:Symbol.symbol list) (sorts:Sort.sort option list) (sort_refs:int list) =
     mk_constructor ctx (Symbol.mk_string ctx name) recognizer field_names sorts sort_refs
 
-  let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( constructors : Constructor.constructor list ) =
-    let f x = (z3obj_gno x) in 
-    let (x,_) = (Z3native.mk_datatype (context_gno ctx) (Symbol.gno name) (List.length constructors) (Array.of_list (List.map f constructors))) in
-    Sort.sort_of_ptr ctx x
+  let mk_sort (ctx:context) (name:Symbol.symbol) (constructors:Constructor.constructor list) =
+    let (x,_) = Z3native.mk_datatype ctx name (List.length constructors) constructors in
+    x
 
-  let mk_sort_s ( ctx : context ) ( name : string ) ( constructors : Constructor.constructor list ) =
+  let mk_sort_s (ctx:context) (name:string) (constructors:Constructor.constructor list) =
     mk_sort ctx (Symbol.mk_string ctx name) constructors
-      
-  let mk_sorts ( ctx : context ) ( names : Symbol.symbol list ) ( c : Constructor.constructor list list ) =
-    let n = (List.length names) in
-    let f e = (AST.ptr_of_ast (ConstructorList.create ctx e)) in
-    let cla = (Array.of_list (List.map f c)) in
-    let (r, a) = (Z3native.mk_datatypes (context_gno ctx) n (Symbol.symbol_lton names) cla) in
-    let g i = (Sort.sort_of_ptr ctx (Array.get r i)) in
-    mk_list g (Array.length r)
 
-  let mk_sorts_s ( ctx : context ) ( names : string list ) ( c : Constructor.constructor list list ) =
-    mk_sorts ctx 
-      ( 
-     let f e = (Symbol.mk_string ctx e) in
-     List.map f names 
-      )
-      c
+  let mk_sorts (ctx:context) (names:Symbol.symbol list) (c:Constructor.constructor list list) =
+    let n = List.length names in
+    let f e = ConstructorList.create ctx e in
+    let cla = List.map f c in
+    let (r, _) = Z3native.mk_datatypes ctx n names cla in
+    r
 
-  let get_num_constructors ( x : Sort.sort ) = Z3native.get_datatype_sort_num_constructors (Sort.gnc x) (Sort.gno x)
+  let mk_sorts_s (ctx:context) (names:string list) (c:Constructor.constructor list list) =
+    mk_sorts ctx (List.map (fun x -> Symbol.mk_string ctx x) names) c
 
-  let get_constructors ( x : Sort.sort ) = 
-    let n = (get_num_constructors x) in
-    let f i = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x) i) in
+  let get_num_constructors (x:Sort.sort) = Z3native.get_datatype_sort_num_constructors (Sort.gc x) x
+
+  let get_constructors (x:Sort.sort) =
+    let n = get_num_constructors x in
+    let f i = Z3native.get_datatype_sort_constructor (Sort.gc x) x i in
     mk_list f n
 
-  let get_recognizers ( x : Sort.sort ) = 
+  let get_recognizers (x:Sort.sort) =
     let n = (get_num_constructors x) in
-    let f i = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_recognizer (Sort.gnc x) (Sort.gno x) i) in
+    let f i = Z3native.get_datatype_sort_recognizer (Sort.gc x) x i in
     mk_list f n
-      
-  let get_accessors ( x : Sort.sort ) =
+
+  let get_accessors (x:Sort.sort) =
     let n = (get_num_constructors x) in
     let f i = (
-      let fd = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x) i) in
-      let ds = Z3native.get_domain_size (FuncDecl.gnc fd) (FuncDecl.gno fd) in
-      let g j = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor_accessor (Sort.gnc x) (Sort.gno x) i j) in
-      mk_list g ds
-    ) in
+      let fd = Z3native.get_datatype_sort_constructor (Sort.gc x) x i in
+      let ds = Z3native.get_domain_size (FuncDecl.gc fd) fd in
+      let g j = Z3native.get_datatype_sort_constructor_accessor (Sort.gc x) x i j in
+      mk_list g ds) in
     mk_list f n
 end
 
 
-module Enumeration = 
-struct 
-  let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( enum_names : Symbol.symbol list ) =
-    let (a, _, _) = (Z3native.mk_enumeration_sort (context_gno ctx) (Symbol.gno name) (List.length enum_names) (Symbol.symbol_lton enum_names)) in
-    Sort.sort_of_ptr ctx a
+module Enumeration =
+struct
+  let mk_sort (ctx:context) (name:Symbol.symbol) (enum_names:Symbol.symbol list) =
+    let (a, _, _) = Z3native.mk_enumeration_sort ctx name (List.length enum_names) enum_names in
+    a
 
-  let mk_sort_s ( ctx : context ) ( name : string ) ( enum_names : string list ) =
+  let mk_sort_s (ctx:context) (name:string) (enum_names:string list) =
     mk_sort ctx (Symbol.mk_string ctx name) (Symbol.mk_strings ctx enum_names)
 
-  let get_const_decls ( x : Sort.sort ) =
-    let n = Z3native.get_datatype_sort_num_constructors (Sort.gnc x) (Sort.gno x)  in
-    let f i = (func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x)  i)) in
+  let get_const_decls (x:Sort.sort) =
+    let n = Z3native.get_datatype_sort_num_constructors (Sort.gc x) x  in
+    let f i = Z3native.get_datatype_sort_constructor (Sort.gc x) x i in
     mk_list f n
 
-  let get_const_decl ( x : Sort.sort ) ( inx : int ) =
-    func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x) inx)
+  let get_const_decl (x:Sort.sort) (inx:int) = Z3native.get_datatype_sort_constructor (Sort.gc x) x inx
 
-  let get_consts ( x : Sort.sort ) =
-    let n = Z3native.get_datatype_sort_num_constructors (Sort.gnc x) (Sort.gno x)  in
-    let f i = (Expr.mk_const_f (Sort.gc x) (get_const_decl x i)) in
+  let get_consts (x:Sort.sort) =
+    let n = Z3native.get_datatype_sort_num_constructors (Sort.gc x) x  in
+    let f i = Expr.mk_const_f (Sort.gc x) (get_const_decl x i) in
     mk_list f n
 
-  let get_const ( x : Sort.sort ) ( inx : int ) =
-    Expr.mk_const_f (Sort.gc x) (get_const_decl x inx)
+  let get_const (x:Sort.sort) (inx:int) = Expr.mk_const_f (Sort.gc x) (get_const_decl x inx)
 
-  let get_tester_decls ( x : Sort.sort ) = 
-    let n = Z3native.get_datatype_sort_num_constructors (Sort.gnc x) (Sort.gno x)  in
-    let f i = (func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_recognizer (Sort.gnc x) (Sort.gno x) i)) in
+  let get_tester_decls (x:Sort.sort) =
+    let n = Z3native.get_datatype_sort_num_constructors (Sort.gc x) x  in
+    let f i = Z3native.get_datatype_sort_recognizer (Sort.gc x) x i in
     mk_list f n
-      
-  let get_tester_decl ( x : Sort.sort ) ( inx : int ) = 
-    func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_recognizer (Sort.gnc x) (Sort.gno x) inx)
+
+  let get_tester_decl (x:Sort.sort) (inx:int) = Z3native.get_datatype_sort_recognizer (Sort.gc x) x inx
 end
 
 
-module Z3List = 
-struct     
-  let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( elem_sort : Sort.sort ) =
-    let (r, _, _, _, _, _, _) = (Z3native.mk_list_sort (context_gno ctx) (Symbol.gno name) (Sort.gno elem_sort)) in
-    Sort.sort_of_ptr ctx r 
-      
-  let mk_list_s ( ctx : context ) ( name : string ) elem_sort =
-    mk_sort ctx (Symbol.mk_string ctx name) elem_sort
-
-  let get_nil_decl ( x : Sort.sort ) = 
-    func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x)  0)
-
-  let get_is_nil_decl ( x : Sort.sort ) = 
-    func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_recognizer (Sort.gnc x) (Sort.gno x)  0)
-
-  let get_cons_decl ( x : Sort.sort ) = 
-    func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x)  1)
-
-  let get_is_cons_decl ( x : Sort.sort ) =
-    func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_recognizer (Sort.gnc x) (Sort.gno x)  1)
-
-  let get_head_decl ( x : Sort.sort )  = 
-    func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor_accessor (Sort.gnc x) (Sort.gno x) 1 0)
-
-  let get_tail_decl ( x : Sort.sort ) =
-    func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor_accessor (Sort.gnc x) (Sort.gno x) 1 1)
-
-  let nil ( x : Sort.sort ) = expr_of_func_app (Sort.gc x) (get_nil_decl x) []
-end
-
-
-module Tuple = 
+module Z3List =
 struct
-  let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( field_sorts : Sort.sort list ) =
-    let (r, _, _) = (Z3native.mk_tuple_sort (context_gno ctx) (Symbol.gno name) (List.length field_names) (Symbol.symbol_lton field_names) (Sort.sort_lton field_sorts)) in 
-    Sort.sort_of_ptr ctx r
+  let mk_sort (ctx:context) (name:Symbol.symbol) (elem_sort:Sort.sort) =
+    let (r, _, _, _, _, _, _) = Z3native.mk_list_sort ctx name elem_sort in
+    r
 
-  let get_mk_decl ( x : Sort.sort ) =
-    func_decl_of_ptr (Sort.gc x) (Z3native.get_tuple_sort_mk_decl (Sort.gnc x) (Sort.gno x))
+  let mk_list_s (ctx:context) (name:string) elem_sort = mk_sort ctx (Symbol.mk_string ctx name) elem_sort
+  let get_nil_decl (x:Sort.sort) = Z3native.get_datatype_sort_constructor (Sort.gc x) x 0
+  let get_is_nil_decl (x:Sort.sort) = Z3native.get_datatype_sort_recognizer (Sort.gc x) x 0
+  let get_cons_decl (x:Sort.sort) = Z3native.get_datatype_sort_constructor (Sort.gc x) x 1
+  let get_is_cons_decl (x:Sort.sort) =Z3native.get_datatype_sort_recognizer (Sort.gc x) x 1
+  let get_head_decl (x:Sort.sort) = Z3native.get_datatype_sort_constructor_accessor (Sort.gc x) x 1 0
+  let get_tail_decl (x:Sort.sort) = Z3native.get_datatype_sort_constructor_accessor (Sort.gc x) x 1 1
+  let nil (x:Sort.sort) = expr_of_func_app (Sort.gc x) (get_nil_decl x) []
+end
 
-  let get_num_fields ( x : Sort.sort ) = Z3native.get_tuple_sort_num_fields (Sort.gnc x) (Sort.gno x)
-    
-  let get_field_decls ( x : Sort.sort ) = 
+
+module Tuple =
+struct
+  let mk_sort (ctx:context) (name:Symbol.symbol) (field_names:Symbol.symbol list) (field_sorts:Sort.sort list) =
+    let (r, _, _) = Z3native.mk_tuple_sort ctx name (List.length field_names) field_names field_sorts in
+    r
+
+  let get_mk_decl (x:Sort.sort) = Z3native.get_tuple_sort_mk_decl (Sort.gc x) x
+  let get_num_fields (x:Sort.sort) = Z3native.get_tuple_sort_num_fields (Sort.gc x) x
+
+  let get_field_decls (x:Sort.sort) =
     let n = get_num_fields x in
-    let f i = func_decl_of_ptr (Sort.gc x) (Z3native.get_tuple_sort_field_decl (Sort.gnc x) (Sort.gno x) i) in
+    let f i =Z3native.get_tuple_sort_field_decl (Sort.gc x) x i in
     mk_list f n
 end
 
 
 module Arithmetic =
 struct
-  let is_int ( x : expr ) =
-      ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gnc x) (Z3native.get_sort (Expr.gnc x) (Expr.gno x)))) == INT_SORT)
-      
-  let is_arithmetic_numeral ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_ANUM)
+  let is_int (x:expr) =
+    ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gc x) (Z3native.get_sort (Expr.gc x) x))) = INT_SORT)
 
-  let is_le ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_LE)
-
-  let is_ge ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_GE)
-
-  let is_lt ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_LT)
-
-  let is_gt ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_GT)
-
-  let is_add ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_ADD)
-
-  let is_sub ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SUB)
-
-  let is_uminus ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_UMINUS)
-
-  let is_mul ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_MUL)
-
-  let is_div ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_DIV)
-
-  let is_idiv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_IDIV)
-
-  let is_remainder ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_REM)
-
-  let is_modulus ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_MOD)
-
-  let is_int2real ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_TO_REAL)
-
-  let is_real2int ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_TO_INT)
-
-  let is_real_is_int ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_IS_INT)
-
-  let is_real ( x : expr ) =
-    ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gnc x) (Z3native.get_sort (Expr.gnc x) (Expr.gno x)))) == REAL_SORT)
-      
-  let is_int_numeral ( x : expr ) = (Expr.is_numeral x) && (is_int x)
-
-  let is_rat_numeral ( x : expr ) = (Expr.is_numeral x) && (is_real x)
-    
-  let is_algebraic_number ( x : expr ) = Z3native.is_algebraic_number (Expr.gnc x) (Expr.gno x)
+  let is_arithmetic_numeral (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ANUM)
+  let is_le (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_LE)
+  let is_ge (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_GE)
+  let is_lt (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_LT)
+  let is_gt (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_GT)
+  let is_add (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ADD)
+  let is_sub (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SUB)
+  let is_uminus (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_UMINUS)
+  let is_mul (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_MUL)
+  let is_div (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_DIV)
+  let is_idiv (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_IDIV)
+  let is_remainder (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_REM)
+  let is_modulus (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_MOD)
+  let is_int2real (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_TO_REAL)
+  let is_real2int (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_TO_INT)
+  let is_real_is_int (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_IS_INT)
+  let is_real (x:expr) = ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gc x) (Z3native.get_sort (Expr.gc x) x))) = REAL_SORT)
+  let is_int_numeral (x:expr) = (Expr.is_numeral x) && (is_int x)
+  let is_rat_numeral (x:expr) = (Expr.is_numeral x) && (is_real x)
+  let is_algebraic_number (x:expr) = Z3native.is_algebraic_number (Expr.gc x) x
 
   module Integer =
-  struct     
-    let mk_sort ( ctx : context ) =
-      Sort.sort_of_ptr ctx (Z3native.mk_int_sort (context_gno ctx))
+  struct
+    let mk_sort = Z3native.mk_int_sort
 
-    let get_int ( x : expr ) = 
-      let (r, v) = Z3native.get_numeral_int (Expr.gnc x) (Expr.gno x) in
-      if r then v
-      else raise (Z3native.Exception "Conversion failed.")
+    let get_int x =
+      match Z3native.get_numeral_int (Expr.gc x) x with
+      | true, v -> v
+      | false, _ -> raise (Error "Conversion failed.")
 
-    let get_big_int ( x : expr ) = 
-      if (is_int_numeral x) then 
-     let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in
-     (Big_int.big_int_of_string s)
-      else raise (Z3native.Exception "Conversion failed.")
-     
-    let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)
+    let get_big_int (x:expr) =
+      if is_int_numeral x then
+        let s = (Z3native.get_numeral_string (Expr.gc x) x) in
+        Big_int.big_int_of_string s
+      else
+        raise (Error "Conversion failed.")
 
-    let mk_const ( ctx : context ) ( name : Symbol.symbol ) =
-      Expr.mk_const ctx name (mk_sort ctx) 
-     
-    let mk_const_s ( ctx : context ) ( name : string )  =
-      mk_const ctx (Symbol.mk_string ctx name)
-     
-    let mk_mod ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =    
-      apply2 ctx Z3native.mk_mod t1 t2
-     
-    let mk_rem ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
-      apply2 ctx Z3native.mk_rem t1 t2
-
-    let mk_numeral_s ( ctx : context ) ( v : string ) =
-      expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx)))
-     
-    let mk_numeral_i ( ctx : context ) ( v : int ) =
-      expr_of_ptr ctx (Z3native.mk_int (context_gno ctx) v (Sort.gno (mk_sort ctx)))
-
-    let mk_int2real ( ctx : context ) ( t : expr ) =
-      apply1 ctx Z3native.mk_int2real t
-
-    let mk_int2bv ( ctx : context ) ( n : int ) ( t : expr ) =
-      (Expr.expr_of_ptr ctx (Z3native.mk_int2bv (context_gno ctx) n (Expr.gno t)))
+    let numeral_to_string (x:expr) = Z3native.get_numeral_string (Expr.gc x) x
+    let mk_const (ctx:context) (name:Symbol.symbol) = Expr.mk_const ctx name (mk_sort ctx)
+    let mk_const_s (ctx:context) (name:string) = mk_const ctx (Symbol.mk_string ctx name)
+    let mk_mod = Z3native.mk_mod
+    let mk_rem = Z3native.mk_rem
+    let mk_numeral_s (ctx:context) (v:string) = Z3native.mk_numeral ctx v (mk_sort ctx)
+    let mk_numeral_i (ctx:context) (v:int) = Z3native.mk_int ctx v (mk_sort ctx)
+    let mk_int2real = Z3native.mk_int2real
+    let mk_int2bv = Z3native.mk_int2bv
   end
 
   module Real =
-  struct  
-    let mk_sort ( ctx : context ) =
-      Sort.sort_of_ptr ctx (Z3native.mk_real_sort (context_gno ctx))     
+  struct
+    let mk_sort = Z3native.mk_real_sort
+    let get_numerator x = Z3native.get_numerator (Expr.gc x) x
+    let get_denominator x = Z3native.get_denominator (Expr.gc x) x
 
-    let get_numerator ( x : expr ) =
-      apply1 (Expr.gc x) Z3native.get_numerator x
-     
-    let get_denominator ( x : expr ) =
-      apply1 (Expr.gc x) Z3native.get_denominator x
-     
-    let get_ratio ( x : expr ) = 
-      if (is_rat_numeral x)  then
-     let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in
-     (Ratio.ratio_of_string s)
-      else raise (Z3native.Exception "Conversion failed.")
+    let get_ratio x =
+      if is_rat_numeral x then
+        let s = Z3native.get_numeral_string (Expr.gc x) x in
+        Ratio.ratio_of_string s
+      else
+        raise (Error "Conversion failed.")
 
-    let to_decimal_string ( x : expr ) ( precision : int ) = 
-      Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision
-     
-    let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)
+    let to_decimal_string (x:expr) (precision:int) = Z3native.get_numeral_decimal_string (Expr.gc x) x precision
+    let numeral_to_string (x:expr) = Z3native.get_numeral_string (Expr.gc x) x
+    let mk_const (ctx:context) (name:Symbol.symbol) = Expr.mk_const ctx name (mk_sort ctx)
+    let mk_const_s (ctx:context) (name:string) = mk_const ctx (Symbol.mk_string ctx name)
+    let mk_numeral_nd (ctx:context) (num:int) (den:int) =
+      if den = 0 then
+        raise (Error "Denominator is zero")
+      else
+        Z3native.mk_real ctx num den
 
-    let mk_const ( ctx : context ) ( name : Symbol.symbol )  =
-      Expr.mk_const ctx name (mk_sort ctx)
-     
-    let mk_const_s ( ctx : context ) ( name : string )  =
-      mk_const ctx (Symbol.mk_string ctx name)
-
-    let mk_numeral_nd ( ctx : context ) ( num : int ) ( den : int ) =
-      if (den == 0) then 
-     raise (Z3native.Exception "Denominator is zero")
-      else      
-     expr_of_ptr ctx (Z3native.mk_real (context_gno ctx) num den)
-       
-    let mk_numeral_s ( ctx : context ) ( v : string ) =
-      expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx)))
-     
-    let mk_numeral_i ( ctx : context ) ( v : int ) =
-      expr_of_ptr ctx (Z3native.mk_int (context_gno ctx) v (Sort.gno (mk_sort ctx)))
-     
-    let mk_is_integer ( ctx : context ) ( t : expr ) =
-      apply1 ctx Z3native.mk_is_int t
-     
-    let mk_real2int ( ctx : context ) ( t : expr ) =
-      apply1 ctx Z3native.mk_real2int t
+    let mk_numeral_s (ctx:context) (v:string) = Z3native.mk_numeral ctx v (mk_sort ctx)
+    let mk_numeral_i (ctx:context) (v:int) = Z3native.mk_int ctx v (mk_sort ctx)
+    let mk_is_integer = Z3native.mk_is_int
+    let mk_real2int = Z3native.mk_real2int
 
     module AlgebraicNumber =
-    struct    
-      let to_upper ( x : expr ) ( precision : int ) =
-         expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_upper (Expr.gnc x) (Expr.gno x) precision)
-           
-      let to_lower ( x : expr ) precision =
-         expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_lower (Expr.gnc x) (Expr.gno x) precision)
-           
-      let to_decimal_string ( x : expr ) ( precision : int ) = 
-         Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision     
-           
-      let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)      
+    struct
+      let to_upper (x:expr) (precision:int) = Z3native.get_algebraic_number_upper (Expr.gc x) x precision
+      let to_lower (x:expr) (precision:int) = Z3native.get_algebraic_number_lower (Expr.gc x) x precision
+      let to_decimal_string (x:expr) (precision:int) = Z3native.get_numeral_decimal_string (Expr.gc x) x precision
+      let numeral_to_string (x:expr) = Z3native.get_numeral_string (Expr.gc x) x
     end
   end
 
-  let mk_add ( ctx : context ) ( t : expr list ) =
-    let f x = (Expr.gno x) in
-    (expr_of_ptr ctx (Z3native.mk_add (context_gno ctx) (List.length t) (Array.of_list (List.map f t))))
+  let mk_add (ctx:context) (t:expr list) =
+    Z3native.mk_add ctx (List.length t) t
 
-  let mk_mul ( ctx : context ) ( t : expr list ) =
-    let f x = (Expr.gno x) in
-    (expr_of_ptr ctx (Z3native.mk_mul (context_gno ctx) (List.length t) (Array.of_list (List.map f t))))
+  let mk_mul (ctx:context) (t:expr list) =
+    Z3native.mk_mul ctx (List.length t) t
 
-  let mk_sub ( ctx : context ) ( t : expr list ) =
-    let f x = (Expr.gno x) in
-    (expr_of_ptr ctx (Z3native.mk_sub (context_gno ctx) (List.length t) (Array.of_list (List.map f t))))
-      
-  let mk_unary_minus ( ctx : context ) ( t : expr ) = apply1 ctx Z3native.mk_unary_minus t
+  let mk_sub (ctx:context) (t:expr list) =
+    Z3native.mk_sub ctx (List.length t) t
 
-  let mk_div ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_div t1 t2
-
-  let mk_power ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_power t1 t2
-
-  let mk_lt ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_lt t1 t2
-
-  let mk_le ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_le t1 t2
-      
-  let mk_gt ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_gt t1 t2
-
-  let mk_ge ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_ge t1 t2
+  let mk_unary_minus = Z3native.mk_unary_minus
+  let mk_div = Z3native.mk_div
+  let mk_power = Z3native.mk_power
+  let mk_lt = Z3native.mk_lt
+  let mk_le = Z3native.mk_le
+  let mk_gt = Z3native.mk_gt
+  let mk_ge = Z3native.mk_ge
 end
 
 
 module BitVector =
-struct  
-  let mk_sort ( ctx : context ) size =
-    Sort.sort_of_ptr ctx (Z3native.mk_bv_sort (context_gno ctx) size)
-  let is_bv ( x : expr ) =
-    ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gnc x) (Z3native.get_sort (Expr.gnc x) (Expr.gno x)))) == BV_SORT)
-  let is_bv_numeral ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BNUM)
-  let is_bv_bit1 ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BIT1)
-  let is_bv_bit0 ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BIT0)
-  let is_bv_uminus ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BNEG)
-  let is_bv_add ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BADD)
-  let is_bv_sub ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BSUB)
-  let is_bv_mul ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BMUL)
-  let is_bv_sdiv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BSDIV)
-  let is_bv_udiv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BUDIV)
-  let is_bv_SRem ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BSREM)
-  let is_bv_urem ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BUREM)
-  let is_bv_smod ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BSMOD)
-  let is_bv_sdiv0 ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BSDIV0)
-  let is_bv_udiv0 ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BUDIV0)
-  let is_bv_srem0 ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BSREM0)
-  let is_bv_urem0 ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BUREM0)
-  let is_bv_smod0 ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BSMOD0)
-  let is_bv_ule ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_ULEQ)
-  let is_bv_sle ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SLEQ)
-  let is_bv_uge ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_UGEQ)
-  let is_bv_sge ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SGEQ)
-  let is_bv_ult ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_ULT)
-  let is_bv_slt ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SLT)
-  let is_bv_ugt ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_UGT)
-  let is_bv_sgt ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SGT)
-  let is_bv_and ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BAND)
-  let is_bv_or ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BOR)
-  let is_bv_not ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BNOT)
-  let is_bv_xor ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BXOR)
-  let is_bv_nand ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BNAND)
-  let is_bv_nor ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BNOR)
-  let is_bv_xnor ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BXNOR)
-  let is_bv_concat ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_CONCAT)
-  let is_bv_signextension ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SIGN_EXT)
-  let is_bv_zeroextension ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_ZERO_EXT)
-  let is_bv_extract ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_EXTRACT)
-  let is_bv_repeat ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_REPEAT)
-  let is_bv_reduceor ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BREDOR)
-  let is_bv_reduceand ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BREDAND)
-  let is_bv_comp ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BCOMP)
-  let is_bv_shiftleft ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BSHL)
-  let is_bv_shiftrightlogical ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BLSHR)
-  let is_bv_shiftrightarithmetic ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BASHR)
-  let is_bv_rotateleft ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_ROTATE_LEFT)
-  let is_bv_rotateright ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_ROTATE_RIGHT)
-  let is_bv_rotateleftextended ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_EXT_ROTATE_LEFT)
-  let is_bv_rotaterightextended ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_EXT_ROTATE_RIGHT) 
-  let is_int2bv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_INT2BV)
-  let is_bv2int ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BV2INT)
-  let is_bv_carry ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_CARRY)
-  let is_bv_xor3 ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_XOR3)
-  let get_size (x : Sort.sort ) = Z3native.get_bv_sort_size (Sort.gnc x) (Sort.gno x)
-  let get_int ( x : expr ) = 
-    let (r, v) = Z3native.get_numeral_int (Expr.gnc x) (Expr.gno x) in
-    if r then v
-    else raise (Z3native.Exception "Conversion failed.")
-  let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)
-  let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( size : int ) =
-    Expr.mk_const ctx name (mk_sort ctx size) 
-  let mk_const_s ( ctx : context ) ( name : string ) ( size : int ) =
+struct
+  let mk_sort (ctx:context) size = Z3native.mk_bv_sort ctx size
+  let is_bv (x:expr) =
+    ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gc x) (Z3native.get_sort (Expr.gc x) x))) = BV_SORT)
+  let is_bv_numeral (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BNUM)
+  let is_bv_bit1 (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BIT1)
+  let is_bv_bit0 (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BIT0)
+  let is_bv_uminus (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BNEG)
+  let is_bv_add (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BADD)
+  let is_bv_sub (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BSUB)
+  let is_bv_mul (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BMUL)
+  let is_bv_sdiv (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BSDIV)
+  let is_bv_udiv (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BUDIV)
+  let is_bv_SRem (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BSREM)
+  let is_bv_urem (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BUREM)
+  let is_bv_smod (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BSMOD)
+  let is_bv_sdiv0 (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BSDIV0)
+  let is_bv_udiv0 (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BUDIV0)
+  let is_bv_srem0 (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BSREM0)
+  let is_bv_urem0 (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BUREM0)
+  let is_bv_smod0 (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BSMOD0)
+  let is_bv_ule (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ULEQ)
+  let is_bv_sle (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SLEQ)
+  let is_bv_uge (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_UGEQ)
+  let is_bv_sge (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SGEQ)
+  let is_bv_ult (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ULT)
+  let is_bv_slt (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SLT)
+  let is_bv_ugt (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_UGT)
+  let is_bv_sgt (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SGT)
+  let is_bv_and (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BAND)
+  let is_bv_or (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BOR)
+  let is_bv_not (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BNOT)
+  let is_bv_xor (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BXOR)
+  let is_bv_nand (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BNAND)
+  let is_bv_nor (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BNOR)
+  let is_bv_xnor (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BXNOR)
+  let is_bv_concat (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_CONCAT)
+  let is_bv_signextension (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SIGN_EXT)
+  let is_bv_zeroextension (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ZERO_EXT)
+  let is_bv_extract (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_EXTRACT)
+  let is_bv_repeat (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_REPEAT)
+  let is_bv_reduceor (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BREDOR)
+  let is_bv_reduceand (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BREDAND)
+  let is_bv_comp (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BCOMP)
+  let is_bv_shiftleft (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BSHL)
+  let is_bv_shiftrightlogical (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BLSHR)
+  let is_bv_shiftrightarithmetic (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BASHR)
+  let is_bv_rotateleft (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ROTATE_LEFT)
+  let is_bv_rotateright (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ROTATE_RIGHT)
+  let is_bv_rotateleftextended (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_EXT_ROTATE_LEFT)
+  let is_bv_rotaterightextended (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_EXT_ROTATE_RIGHT)
+  let is_int2bv (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_INT2BV)
+  let is_bv2int (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BV2INT)
+  let is_bv_carry (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_CARRY)
+  let is_bv_xor3 (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_XOR3)
+  let get_size (x:Sort.sort) = Z3native.get_bv_sort_size (Sort.gc x) x
+
+  let get_int (x:expr) =
+    match Z3native.get_numeral_int (Expr.gc x) x with
+    | true, v -> v
+    | false, _ -> raise (Error "Conversion failed.")
+
+  let numeral_to_string (x:expr) = Z3native.get_numeral_string (Expr.gc x) x
+  let mk_const (ctx:context) (name:Symbol.symbol) (size:int) =
+    Expr.mk_const ctx name (mk_sort ctx size)
+  let mk_const_s (ctx:context) (name:string) (size:int) =
     mk_const ctx (Symbol.mk_string ctx name) size
-  let mk_not  ( ctx : context ) ( t : expr ) = apply1 ctx Z3native.mk_bvnot t
-  let mk_redand  ( ctx : context ) ( t : expr ) = apply1 ctx Z3native.mk_bvredand t
-  let mk_redor  ( ctx : context ) ( t : expr ) = apply1 ctx Z3native.mk_bvredor t
-  let mk_and  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvand t1 t2
-  let mk_or  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvor t1 t2
-  let mk_xor  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvxor t1 t2
-  let mk_nand  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvnand t1 t2
-  let mk_nor  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvnor t1 t2
-  let mk_xnor  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvxnor t1 t2
-  let mk_neg  ( ctx : context ) ( t : expr ) = apply1 ctx Z3native.mk_bvneg t
-  let mk_add  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvadd t1 t2
-  let mk_sub  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvsub t1 t2
-  let mk_mul  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvmul t1 t2
-  let mk_udiv  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvudiv t1 t2
-  let mk_sdiv  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvsdiv t1 t2
-  let mk_urem  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvurem t1 t2
-  let mk_srem  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvsrem t1 t2
-  let mk_smod  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvsmod t1 t2
-  let mk_ult  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvult t1 t2
-  let mk_slt  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvslt t1 t2
-  let mk_ule  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvule t1 t2
-  let mk_sle  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvsle t1 t2
-  let mk_uge  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvuge t1 t2
-  let mk_sge  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvsge t1 t2
-  let mk_ugt  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvugt t1 t2
-  let mk_sgt  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvsgt t1 t2
-  let mk_concat ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_concat t1 t2
-  let mk_extract ( ctx : context ) ( high : int ) ( low : int ) ( t : expr ) =
-    expr_of_ptr ctx (Z3native.mk_extract (context_gno ctx) high low (Expr.gno t))
-  let mk_sign_ext  ( ctx : context ) ( i : int ) ( t : expr ) = 
-    expr_of_ptr ctx (Z3native.mk_sign_ext (context_gno ctx) i (Expr.gno t))
-  let mk_zero_ext  ( ctx : context ) ( i : int ) ( t : expr ) =
-    expr_of_ptr ctx (Z3native.mk_zero_ext (context_gno ctx) i (Expr.gno t))
-  let mk_repeat  ( ctx : context ) ( i : int ) ( t : expr ) =
-    expr_of_ptr ctx (Z3native.mk_repeat (context_gno ctx) i (Expr.gno t))
-  let mk_shl  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvshl t1 t2
-  let mk_lshr  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvlshr t1 t2
-  let mk_ashr  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvashr t1 t2
-  let mk_rotate_left  ( ctx : context ) ( i : int ) ( t : expr ) = 
-    expr_of_ptr ctx (Z3native.mk_rotate_left (context_gno ctx) i (Expr.gno t))
-  let mk_rotate_right ( ctx : context ) ( i : int ) ( t : expr ) =
-    expr_of_ptr ctx (Z3native.mk_rotate_right (context_gno ctx) i (Expr.gno t))
-  let mk_ext_rotate_left ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_ext_rotate_left t1 t2
-  let mk_ext_rotate_right ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_ext_rotate_right t1 t2
-  let mk_bv2int ( ctx : context ) ( t : expr ) ( signed : bool ) =
-    expr_of_ptr ctx (Z3native.mk_bv2int (context_gno ctx) (Expr.gno t) signed)
-  let mk_add_no_overflow  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) =
-    (expr_of_ptr ctx (Z3native.mk_bvadd_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed))
-  let mk_add_no_underflow  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvadd_no_underflow t1 t2
-  let mk_sub_no_overflow  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvsub_no_overflow t1 t2
-  let mk_sub_no_underflow  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) =
-    (expr_of_ptr ctx (Z3native.mk_bvsub_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed))
-  let mk_sdiv_no_overflow  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvsdiv_no_overflow t1 t2
-  let mk_neg_no_overflow  ( ctx : context ) ( t : expr ) = apply1 ctx Z3native.mk_bvneg_no_overflow t
-  let mk_mul_no_overflow  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) =
-    (expr_of_ptr ctx (Z3native.mk_bvmul_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed))
-  let mk_mul_no_underflow  ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_bvmul_no_underflow t1 t2
-  let mk_numeral ( ctx : context ) ( v : string ) ( size : int ) =
-    expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx size)))
+  let mk_not = Z3native.mk_bvnot
+  let mk_redand = Z3native.mk_bvredand
+  let mk_redor = Z3native.mk_bvredor
+  let mk_and = Z3native.mk_bvand
+  let mk_or = Z3native.mk_bvor
+  let mk_xor = Z3native.mk_bvxor
+  let mk_nand = Z3native.mk_bvnand
+  let mk_nor = Z3native.mk_bvnor
+  let mk_xnor = Z3native.mk_bvxnor
+  let mk_neg = Z3native.mk_bvneg
+  let mk_add = Z3native.mk_bvadd
+  let mk_sub = Z3native.mk_bvsub
+  let mk_mul = Z3native.mk_bvmul
+  let mk_udiv = Z3native.mk_bvudiv
+  let mk_sdiv = Z3native.mk_bvsdiv
+  let mk_urem = Z3native.mk_bvurem
+  let mk_srem = Z3native.mk_bvsrem
+  let mk_smod = Z3native.mk_bvsmod
+  let mk_ult = Z3native.mk_bvult
+  let mk_slt = Z3native.mk_bvslt
+  let mk_ule = Z3native.mk_bvule
+  let mk_sle = Z3native.mk_bvsle
+  let mk_uge = Z3native.mk_bvuge
+  let mk_sge = Z3native.mk_bvsge
+  let mk_ugt = Z3native.mk_bvugt
+  let mk_sgt = Z3native.mk_bvsgt
+  let mk_concat = Z3native.mk_concat
+  let mk_extract = Z3native.mk_extract
+  let mk_sign_ext = Z3native.mk_sign_ext
+  let mk_zero_ext = Z3native.mk_zero_ext
+  let mk_repeat = Z3native.mk_repeat
+  let mk_shl = Z3native.mk_bvshl
+  let mk_lshr = Z3native.mk_bvlshr
+  let mk_ashr = Z3native.mk_bvashr
+  let mk_rotate_left = Z3native.mk_rotate_left
+  let mk_rotate_right = Z3native.mk_rotate_right
+  let mk_ext_rotate_left = Z3native.mk_ext_rotate_left
+  let mk_ext_rotate_right = Z3native.mk_ext_rotate_right
+  let mk_bv2int = Z3native.mk_bv2int
+  let mk_add_no_overflow = Z3native.mk_bvadd_no_overflow
+  let mk_add_no_underflow = Z3native.mk_bvadd_no_underflow
+  let mk_sub_no_overflow = Z3native.mk_bvsub_no_overflow
+  let mk_sub_no_underflow = Z3native.mk_bvsub_no_underflow
+  let mk_sdiv_no_overflow = Z3native.mk_bvsdiv_no_overflow
+  let mk_neg_no_overflow = Z3native.mk_bvneg_no_overflow
+  let mk_mul_no_overflow = Z3native.mk_bvmul_no_overflow
+  let mk_mul_no_underflow = Z3native.mk_bvmul_no_underflow
+  let mk_numeral ctx v size = Z3native.mk_numeral ctx v (mk_sort ctx size)
 end
 
 
-module FloatingPoint = 
+module FloatingPoint =
 struct
-  module RoundingMode = 
+  module RoundingMode =
   struct
-     let mk_sort ( ctx : context ) =
-       (Sort.sort_of_ptr ctx (Z3native.mk_fpa_rounding_mode_sort (context_gno ctx)))
-     let is_fprm ( x : expr ) =
-       (Sort.get_sort_kind (Expr.get_sort(x))) == ROUNDING_MODE_SORT
-     let mk_round_nearest_ties_to_even ( ctx : context ) = 
-       (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_even (context_gno ctx)))
-     let mk_rne ( ctx : context ) =
-       (expr_of_ptr ctx (Z3native.mk_fpa_rne (context_gno ctx)))
-     let mk_round_nearest_ties_to_away ( ctx : context ) = 
-       (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_away (context_gno ctx)))
-     let mk_rna ( ctx : context ) =
-       (expr_of_ptr ctx (Z3native.mk_fpa_rna (context_gno ctx)))
-     let mk_round_toward_positive ( ctx : context ) = 
-       (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_positive (context_gno ctx)))
-     let mk_rtp ( ctx : context ) =
-       (expr_of_ptr ctx (Z3native.mk_fpa_rtp (context_gno ctx)))
-     let mk_round_toward_negative ( ctx : context ) = 
-       (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_negative  (context_gno ctx)))
-     let mk_rtn ( ctx : context ) =
-       (expr_of_ptr ctx (Z3native.mk_fpa_rtn (context_gno ctx)))
-     let mk_round_toward_zero ( ctx : context ) = 
-       (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_zero (context_gno ctx)))
-     let mk_rtz ( ctx : context ) =
-       (expr_of_ptr ctx (Z3native.mk_fpa_rtz (context_gno ctx)))          
+    let mk_sort = Z3native.mk_fpa_rounding_mode_sort
+    let is_fprm x = Sort.get_sort_kind (Expr.get_sort x) = ROUNDING_MODE_SORT
+    let mk_round_nearest_ties_to_even = Z3native.mk_fpa_round_nearest_ties_to_even
+    let mk_rne = Z3native.mk_fpa_rne
+    let mk_round_nearest_ties_to_away = Z3native.mk_fpa_round_nearest_ties_to_away
+    let mk_rna = Z3native.mk_fpa_rna
+    let mk_round_toward_positive = Z3native.mk_fpa_round_toward_positive
+    let mk_rtp = Z3native.mk_fpa_rtp
+    let mk_round_toward_negative = Z3native.mk_fpa_round_toward_negative
+    let mk_rtn = Z3native.mk_fpa_rtn
+    let mk_round_toward_zero = Z3native.mk_fpa_round_toward_zero
+    let mk_rtz = Z3native.mk_fpa_rtz
   end
-     
-  let mk_sort ( ctx : context ) ( ebits : int ) ( sbits : int ) =
-     (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort (context_gno ctx) ebits sbits))
-  let mk_sort_half ( ctx : context ) =
-     (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_half (context_gno ctx)))
-  let mk_sort_16 ( ctx : context ) =
-     (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_16 (context_gno ctx)))
-  let mk_sort_single ( ctx : context ) =
-     (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_single (context_gno ctx)))
-  let mk_sort_32 ( ctx : context ) =
-     (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_32 (context_gno ctx)))
-  let mk_sort_double ( ctx : context ) =
-     (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_double (context_gno ctx)))
-  let mk_sort_64 ( ctx : context ) =
-     (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_64 (context_gno ctx)))
-  let mk_sort_quadruple ( ctx : context ) =
-     (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_quadruple (context_gno ctx)))
-  let mk_sort_128 ( ctx : context ) =
-     (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_128 (context_gno ctx)))
 
-  let mk_nan ( ctx : context ) ( s : Sort.sort ) =
-     (expr_of_ptr ctx (Z3native.mk_fpa_nan (context_gno ctx) (Sort.gno s)))
-  let mk_inf ( ctx : context ) ( s : Sort.sort ) ( negative : bool ) =
-     (expr_of_ptr ctx (Z3native.mk_fpa_inf (context_gno ctx) (Sort.gno s) negative))
-  let mk_zero ( ctx : context ) ( s : Sort.sort ) ( negative : bool ) =
-     (expr_of_ptr ctx (Z3native.mk_fpa_zero (context_gno ctx) (Sort.gno s) negative))
+  let mk_sort = Z3native.mk_fpa_sort
+  let mk_sort_half = Z3native.mk_fpa_sort_half
+  let mk_sort_16 = Z3native.mk_fpa_sort_16
+  let mk_sort_single = Z3native.mk_fpa_sort_single
+  let mk_sort_32 = Z3native.mk_fpa_sort_32
+  let mk_sort_double = Z3native.mk_fpa_sort_double
+  let mk_sort_64 = Z3native.mk_fpa_sort_64
+  let mk_sort_quadruple = Z3native.mk_fpa_sort_quadruple
+  let mk_sort_128 = Z3native.mk_fpa_sort_128
 
-  let mk_fp ( ctx : context ) ( sign : expr ) ( exponent : expr ) ( significand : expr ) =
-     apply3 ctx Z3native.mk_fpa_fp sign exponent significand
-  let mk_numeral_f ( ctx : context ) ( value : float ) ( s : Sort.sort ) =
-     (expr_of_ptr ctx (Z3native.mk_fpa_numeral_double (context_gno ctx) value (Sort.gno s)))
-  let mk_numeral_i ( ctx : context ) ( value : int ) ( s : Sort.sort ) =
-     (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int (context_gno ctx) value (Sort.gno s)))
-  let mk_numeral_i_u ( ctx : context ) ( sign : bool ) ( exponent : int ) ( significand : int ) ( s : Sort.sort ) =
-     (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int64_uint64 (context_gno ctx) sign exponent significand (Sort.gno s)))
-  let mk_numeral_s ( ctx : context ) ( v : string ) ( s : Sort.sort ) =
-    (expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno s)))
+  let mk_nan = Z3native.mk_fpa_nan
+  let mk_inf = Z3native.mk_fpa_inf
+  let mk_zero = Z3native.mk_fpa_zero
+  let mk_fp = Z3native.mk_fpa_fp
+  let mk_numeral_f = Z3native.mk_fpa_numeral_double
+  let mk_numeral_i = Z3native.mk_fpa_numeral_int
+  let mk_numeral_i_u = Z3native.mk_fpa_numeral_int64_uint64
+  let mk_numeral_s = Z3native.mk_numeral
 
-  let is_fp ( x : expr ) = (Sort.get_sort_kind (Expr.get_sort x)) == FLOATING_POINT_SORT
-  let is_abs ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_ABS)
-  let is_neg ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_NEG)
-  let is_add ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_ADD)
-  let is_sub ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_SUB)
-  let is_mul ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_MUL)
-  let is_div ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_DIV)
-  let is_fma ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_FMA)
-  let is_sqrt ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_SQRT)
-  let is_rem ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_REM)
-  let is_round_to_integral ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_ROUND_TO_INTEGRAL)
-  let is_min ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_MIN)
-  let is_max ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_MAX)
-  let is_leq ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_LE)
-  let is_lt ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_LT)
-  let is_geq ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_GE)
-  let is_gt ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_GT)
-  let is_eq ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_EQ)
-  let is_is_normal ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_IS_NORMAL)
-  let is_is_subnormal ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_IS_SUBNORMAL)
-  let is_is_zero ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_IS_ZERO)
-  let is_is_infinite ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_IS_INF)
-  let is_is_nan ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_IS_NAN)
-  let is_is_negative ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_IS_NEGATIVE)
-  let is_is_positive ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_IS_POSITIVE)
-  let is_to_fp ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_FP)
-  let is_to_fp_unsigned ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_FP_UNSIGNED)
-  let is_to_ubv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_UBV)
-  let is_to_sbv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_SBV)
-  let is_to_real ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_REAL)
-  let is_to_ieee_bv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_IEEE_BV)
-     
-  let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)
-  let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( s : Sort.sort ) =
-    Expr.mk_const ctx name s
-  let mk_const_s ( ctx : context ) ( name : string ) ( s : Sort.sort ) =
-    mk_const ctx (Symbol.mk_string ctx name) s
+  let is_fp (x:expr) = (Sort.get_sort_kind (Expr.get_sort x)) = FLOATING_POINT_SORT
+  let is_abs (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_ABS)
+  let is_neg (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_NEG)
+  let is_add (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_ADD)
+  let is_sub (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_SUB)
+  let is_mul (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_MUL)
+  let is_div (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_DIV)
+  let is_fma (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_FMA)
+  let is_sqrt (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_SQRT)
+  let is_rem (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_REM)
+  let is_round_to_integral (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_ROUND_TO_INTEGRAL)
+  let is_min (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_MIN)
+  let is_max (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_MAX)
+  let is_leq (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_LE)
+  let is_lt (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_LT)
+  let is_geq (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_GE)
+  let is_gt (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_GT)
+  let is_eq (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_EQ)
+  let is_is_normal (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_IS_NORMAL)
+  let is_is_subnormal (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_IS_SUBNORMAL)
+  let is_is_zero (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_IS_ZERO)
+  let is_is_infinite (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_IS_INF)
+  let is_is_nan (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_IS_NAN)
+  let is_is_negative (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_IS_NEGATIVE)
+  let is_is_positive (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_IS_POSITIVE)
+  let is_to_fp (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_TO_FP)
+  let is_to_fp_unsigned (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_TO_FP_UNSIGNED)
+  let is_to_ubv (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_TO_UBV)
+  let is_to_sbv (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_TO_SBV)
+  let is_to_real (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_TO_REAL)
+  let is_to_ieee_bv (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_FPA_TO_IEEE_BV)
 
-  let mk_abs ( ctx : context ) ( t : expr ) = apply1 ctx Z3native.mk_fpa_abs t
-  let mk_neg ( ctx : context ) ( t : expr ) = apply1 ctx Z3native.mk_fpa_neg t
-  let mk_add ( ctx : context ) ( rm : expr ) ( t1 : expr ) ( t2 : expr ) = apply3 ctx Z3native.mk_fpa_add rm t1 t2
-  let mk_sub ( ctx : context ) ( rm : expr ) ( t1 : expr ) ( t2 : expr ) = apply3 ctx Z3native.mk_fpa_sub rm t1 t2
-  let mk_mul ( ctx : context ) ( rm : expr ) ( t1 : expr ) ( t2 : expr ) = apply3 ctx Z3native.mk_fpa_mul rm t1 t2
-  let mk_div ( ctx : context ) ( rm : expr ) ( t1 : expr ) ( t2 : expr ) = apply3 ctx Z3native.mk_fpa_div rm t1 t2
-  let mk_fma ( ctx : context ) ( rm : expr ) ( t1 : expr ) ( t2 : expr ) ( t3 : expr ) = apply4 ctx Z3native.mk_fpa_fma rm t1 t2 t3
-  let mk_sqrt ( ctx : context ) ( rm : expr ) ( t : expr ) = apply2 ctx Z3native.mk_fpa_sqrt rm t
-  let mk_rem ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_fpa_rem t1 t2
-  let mk_round_to_integral  ( ctx : context ) ( rm : expr ) ( t : expr ) = apply2 ctx Z3native.mk_fpa_round_to_integral rm t
-  let mk_min ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_fpa_min t1 t2
-  let mk_max ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_fpa_max t1 t2
-  let mk_leq ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_fpa_leq t1 t2
-  let mk_lt ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =  apply2 ctx Z3native.mk_fpa_lt t1 t2
-  let mk_geq ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = apply2 ctx Z3native.mk_fpa_geq t1 t2
-  let mk_gt ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =  apply2 ctx Z3native.mk_fpa_gt t1 t2
-  let mk_eq ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =  apply2 ctx Z3native.mk_fpa_eq t1 t2
-  let mk_is_normal ( ctx : context ) ( t : expr ) =          apply1 ctx Z3native.mk_fpa_is_normal t
-  let mk_is_subnormal ( ctx : context ) ( t : expr ) =       apply1 ctx Z3native.mk_fpa_is_subnormal t
-  let mk_is_zero ( ctx : context ) ( t : expr ) =            apply1 ctx Z3native.mk_fpa_is_zero t
-  let mk_is_infinite  ( ctx : context ) ( t : expr ) =       apply1 ctx Z3native.mk_fpa_is_infinite t
-  let mk_is_nan ( ctx : context ) ( t : expr ) =             apply1 ctx Z3native.mk_fpa_is_nan t
-  let mk_is_negative  ( ctx : context ) ( t : expr ) =       apply1 ctx Z3native.mk_fpa_is_negative t
-  let mk_is_positive ( ctx : context ) ( t : expr ) =        apply1 ctx Z3native.mk_fpa_is_positive t
-  let mk_to_fp_bv ( ctx : context ) ( t : expr ) ( s : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_fpa_to_fp_bv (context_gno ctx) (Expr.gno t) (Sort.gno s))
-  let mk_to_fp_float ( ctx : context ) ( rm : expr) ( t : expr ) ( s : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_fpa_to_fp_float (context_gno ctx) (Expr.gno rm) (Expr.gno t) (Sort.gno s))
-  let mk_to_fp_real ( ctx : context ) ( rm : expr ) ( t : expr ) ( s : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_fpa_to_fp_real (context_gno ctx) (Expr.gno rm) (Expr.gno t) (Sort.gno s))
-  let mk_to_fp_signed  ( ctx : context ) ( rm : expr) ( t : expr ) ( s : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_fpa_to_fp_signed (context_gno ctx) (Expr.gno rm) (Expr.gno t) (Sort.gno s))
-  let mk_to_fp_unsigned  ( ctx : context ) ( rm : expr) ( t : expr ) ( s : Sort.sort ) =
-    expr_of_ptr ctx (Z3native.mk_fpa_to_fp_unsigned (context_gno ctx) (Expr.gno rm) (Expr.gno t) (Sort.gno s))
-  let mk_to_ubv ( ctx : context ) ( rm : expr) ( t : expr ) ( size : int ) =
-    expr_of_ptr ctx (Z3native.mk_fpa_to_ubv (context_gno ctx) (Expr.gno rm) (Expr.gno t) size)
-  let mk_to_sbv ( ctx : context ) ( rm : expr) ( t : expr ) ( size : int ) =
-    expr_of_ptr ctx (Z3native.mk_fpa_to_sbv (context_gno ctx) (Expr.gno rm) (Expr.gno t) size)
-  let mk_to_real ( ctx : context ) ( t : expr ) = apply1 ctx Z3native.mk_fpa_to_real t
+  let numeral_to_string (x:expr) = Z3native.get_numeral_string (Expr.gc x) x
 
-  let get_ebits ( ctx : context ) ( s : Sort.sort ) =
-     (Z3native.fpa_get_ebits (context_gno ctx) (Sort.gno s))
-  let get_sbits ( ctx : context ) ( s : Sort.sort ) =
-     (Z3native.fpa_get_sbits (context_gno ctx) (Sort.gno s))
-  let get_numeral_sign ( ctx : context ) ( t : expr ) =
-     (Z3native.fpa_get_numeral_sign (context_gno ctx) (Expr.gno t))
-  let get_numeral_significand_string ( ctx : context ) ( t : expr ) =
-     (Z3native.fpa_get_numeral_significand_string (context_gno ctx) (Expr.gno t))
-  let get_numeral_significand_uint ( ctx : context ) ( t : expr ) =
-     (Z3native.fpa_get_numeral_significand_uint64 (context_gno ctx) (Expr.gno t))
-  let get_numeral_exponent_string ( ctx : context ) ( t : expr ) =
-     (Z3native.fpa_get_numeral_exponent_string (context_gno ctx) (Expr.gno t))
-  let get_numeral_exponent_int ( ctx : context ) ( t : expr ) =
-     (Z3native.fpa_get_numeral_exponent_int64 (context_gno ctx) (Expr.gno t))
+  let mk_const = Expr.mk_const
+  let mk_const_s = Expr.mk_const_s
 
-  let mk_to_ieee_bv ( ctx : context ) ( t : expr ) =
-     (expr_of_ptr ctx (Z3native.mk_fpa_to_ieee_bv (context_gno ctx) (Expr.gno t)))
-  let mk_to_fp_int_real ( ctx : context ) ( rm : expr ) ( exponent : expr ) ( significand : expr ) ( s : Sort.sort ) =
-     (expr_of_ptr ctx (Z3native.mk_fpa_to_fp_int_real (context_gno ctx) (Expr.gno rm) (Expr.gno exponent) (Expr.gno significand) (Sort.gno s)))
-
-  let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)
+  let mk_abs = Z3native.mk_fpa_abs
+  let mk_neg = Z3native.mk_fpa_neg
+  let mk_add = Z3native.mk_fpa_add
+  let mk_sub = Z3native.mk_fpa_sub
+  let mk_mul = Z3native.mk_fpa_mul
+  let mk_div = Z3native.mk_fpa_div
+  let mk_fma = Z3native.mk_fpa_fma
+  let mk_sqrt = Z3native.mk_fpa_sqrt
+  let mk_rem = Z3native.mk_fpa_rem
+  let mk_round_to_integral = Z3native.mk_fpa_round_to_integral
+  let mk_min = Z3native.mk_fpa_min
+  let mk_max = Z3native.mk_fpa_max
+  let mk_leq = Z3native.mk_fpa_leq
+  let mk_lt = Z3native.mk_fpa_lt
+  let mk_geq = Z3native.mk_fpa_geq
+  let mk_gt = Z3native.mk_fpa_gt
+  let mk_eq = Z3native.mk_fpa_eq
+  let mk_is_normal = Z3native.mk_fpa_is_normal
+  let mk_is_subnormal = Z3native.mk_fpa_is_subnormal
+  let mk_is_zero = Z3native.mk_fpa_is_zero
+  let mk_is_infinite = Z3native.mk_fpa_is_infinite
+  let mk_is_nan = Z3native.mk_fpa_is_nan
+  let mk_is_negative = Z3native.mk_fpa_is_negative
+  let mk_is_positive = Z3native.mk_fpa_is_positive
+  let mk_to_fp_bv = Z3native.mk_fpa_to_fp_bv
+  let mk_to_fp_float = Z3native.mk_fpa_to_fp_float
+  let mk_to_fp_real = Z3native.mk_fpa_to_fp_real
+  let mk_to_fp_signed = Z3native.mk_fpa_to_fp_signed
+  let mk_to_fp_unsigned = Z3native.mk_fpa_to_fp_unsigned
+  let mk_to_ubv = Z3native.mk_fpa_to_ubv
+  let mk_to_sbv = Z3native.mk_fpa_to_sbv
+  let mk_to_real = Z3native.mk_fpa_to_real
+  let get_ebits = Z3native.fpa_get_ebits
+  let get_sbits = Z3native.fpa_get_sbits
+  let get_numeral_sign = Z3native.fpa_get_numeral_sign
+  let get_numeral_significand_string = Z3native.fpa_get_numeral_significand_string
+  let get_numeral_significand_uint = Z3native.fpa_get_numeral_significand_uint64
+  let get_numeral_exponent_string = Z3native.fpa_get_numeral_exponent_string
+  let get_numeral_exponent_int = Z3native.fpa_get_numeral_exponent_int64
+  let mk_to_ieee_bv = Z3native.mk_fpa_to_ieee_bv
+  let mk_to_fp_int_real = Z3native.mk_fpa_to_fp_int_real
+  let numeral_to_string x = Z3native.get_numeral_string (Expr.gc x) x
 end
 
 
-module Proof = 
+module Proof =
 struct
-  let is_true ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_TRUE)
-  let is_asserted ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_ASSERTED)
-  let is_goal ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_GOAL)
-  let is_oeq ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_OEQ)
-  let is_modus_ponens ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_MODUS_PONENS)
-  let is_reflexivity ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_REFLEXIVITY)
-  let is_symmetry ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_SYMMETRY)
-  let is_transitivity ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_TRANSITIVITY)
-  let is_Transitivity_star ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_TRANSITIVITY_STAR)
-  let is_monotonicity ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_MONOTONICITY)
-  let is_quant_intro ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_QUANT_INTRO)
-  let is_distributivity ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_DISTRIBUTIVITY)
-  let is_and_elimination ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_AND_ELIM)
-  let is_or_elimination ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_NOT_OR_ELIM)
-  let is_rewrite ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_REWRITE)
-  let is_rewrite_star ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_REWRITE_STAR)
-  let is_pull_quant ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_PULL_QUANT)
-  let is_pull_quant_star ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_PULL_QUANT_STAR)
-  let is_push_quant ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_PUSH_QUANT)
-  let is_elim_unused_vars ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_ELIM_UNUSED_VARS)
-  let is_der ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_DER)
-  let is_quant_inst ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_QUANT_INST)
-  let is_hypothesis ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_HYPOTHESIS)
-  let is_lemma ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_LEMMA)
-  let is_unit_resolution ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_UNIT_RESOLUTION)
-  let is_iff_true ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_IFF_TRUE)
-  let is_iff_false ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_IFF_FALSE)
-  let is_commutativity ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_COMMUTATIVITY) (*  *)
-  let is_def_axiom ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_DEF_AXIOM)
-  let is_def_intro ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_DEF_INTRO)
-  let is_apply_def ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_APPLY_DEF)
-  let is_iff_oeq ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_IFF_OEQ)
-  let is_nnf_pos ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_NNF_POS)
-  let is_nnf_neg ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_NNF_NEG)
-  let is_nnf_star ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_NNF_STAR)
-  let is_cnf_star ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_CNF_STAR)
-  let is_skolemize ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_SKOLEMIZE)
-  let is_modus_ponens_oeq ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_MODUS_PONENS_OEQ)
-  let is_theory_lemma ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_PR_TH_LEMMA)
+  let is_true (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_TRUE)
+  let is_asserted (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_ASSERTED)
+  let is_goal (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_GOAL)
+  let is_oeq (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_OEQ)
+  let is_modus_ponens (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_MODUS_PONENS)
+  let is_reflexivity (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_REFLEXIVITY)
+  let is_symmetry (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_SYMMETRY)
+  let is_transitivity (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_TRANSITIVITY)
+  let is_Transitivity_star (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_TRANSITIVITY_STAR)
+  let is_monotonicity (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_MONOTONICITY)
+  let is_quant_intro (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_QUANT_INTRO)
+  let is_distributivity (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_DISTRIBUTIVITY)
+  let is_and_elimination (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_AND_ELIM)
+  let is_or_elimination (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_NOT_OR_ELIM)
+  let is_rewrite (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_REWRITE)
+  let is_rewrite_star (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_REWRITE_STAR)
+  let is_pull_quant (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_PULL_QUANT)
+  let is_pull_quant_star (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_PULL_QUANT_STAR)
+  let is_push_quant (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_PUSH_QUANT)
+  let is_elim_unused_vars (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_ELIM_UNUSED_VARS)
+  let is_der (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_DER)
+  let is_quant_inst (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_QUANT_INST)
+  let is_hypothesis (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_HYPOTHESIS)
+  let is_lemma (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_LEMMA)
+  let is_unit_resolution (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_UNIT_RESOLUTION)
+  let is_iff_true (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_IFF_TRUE)
+  let is_iff_false (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_IFF_FALSE)
+  let is_commutativity (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_COMMUTATIVITY) (*  *)
+  let is_def_axiom (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_DEF_AXIOM)
+  let is_def_intro (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_DEF_INTRO)
+  let is_apply_def (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_APPLY_DEF)
+  let is_iff_oeq (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_IFF_OEQ)
+  let is_nnf_pos (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_NNF_POS)
+  let is_nnf_neg (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_NNF_NEG)
+  let is_nnf_star (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_NNF_STAR)
+  let is_cnf_star (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_CNF_STAR)
+  let is_skolemize (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_SKOLEMIZE)
+  let is_modus_ponens_oeq (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_MODUS_PONENS_OEQ)
+  let is_theory_lemma (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_TH_LEMMA)
 end
 
 
 module Goal =
-struct      
-  type goal = z3_native_object
+struct
+  type goal = Z3native.goal
+  let gc = Z3native.context_of_goal
 
-  let create ( ctx : context ) ( no : Z3native.ptr ) = 
-    let res : goal = { m_ctx = ctx ;
-                 m_n_obj = null ;
-                 inc_ref = Z3native.goal_inc_ref ;
-                 dec_ref = Z3native.goal_dec_ref } in
-    (z3obj_sno res ctx no) ;
-    (z3obj_create res) ;
-    res
-      
-  let get_precision ( x : goal ) =
-    goal_prec_of_int (Z3native.goal_precision (z3obj_gnc x) (z3obj_gno x))
-      
-  let is_precise ( x : goal ) =
-    (get_precision x) == GOAL_PRECISE
-      
-  let is_underapproximation ( x : goal ) =
-    (get_precision x) == GOAL_UNDER
+  let get_precision (x:goal) = goal_prec_of_int (Z3native.goal_precision (gc x) x)
+  let is_precise (x:goal) = (get_precision x) = GOAL_PRECISE
+  let is_underapproximation (x:goal) = (get_precision x) = GOAL_UNDER
+  let is_overapproximation (x:goal) = (get_precision x) = GOAL_OVER
+  let is_garbage (x:goal) = (get_precision x) = GOAL_UNDER_OVER
 
-  let is_overapproximation ( x : goal ) =
-    (get_precision x) == GOAL_OVER
-      
-  let is_garbage ( x : goal ) = 
-    (get_precision x) == GOAL_UNDER_OVER
-      
-  let add ( x : goal ) ( constraints : expr list ) =
-    let f e = Z3native.goal_assert (z3obj_gnc x) (z3obj_gno x) (Expr.gno e) in
-    ignore (List.map f constraints) ;
-    ()
-      
-  let is_inconsistent ( x : goal ) =
-    Z3native.goal_inconsistent (z3obj_gnc x) (z3obj_gno x)
+  let add x constraints =
+    List.iter (Z3native.goal_assert (gc x) x) constraints
 
-  let get_depth ( x : goal ) = Z3native.goal_depth (z3obj_gnc x) (z3obj_gno x)
-    
-  let reset ( x : goal ) =  Z3native.goal_reset (z3obj_gnc x) (z3obj_gno x)
-    
-  let get_size ( x : goal ) = Z3native.goal_size (z3obj_gnc x) (z3obj_gno x)
+  let is_inconsistent (x:goal) = Z3native.goal_inconsistent (gc x) x
+  let get_depth (x:goal) = Z3native.goal_depth (gc x) x
+  let reset (x:goal) =  Z3native.goal_reset (gc x) x
+  let get_size (x:goal) = Z3native.goal_size (gc x) x
 
-  let get_formulas ( x : goal ) =
-    let n = get_size x in 
-    let f i = ((expr_of_ptr (z3obj_gc x) 
-            (Z3native.goal_formula (z3obj_gnc x) (z3obj_gno x) i))) in
+  let get_formulas (x:goal) =
+    let n = get_size x in
+    let f i = Z3native.goal_formula (gc x) x i in
     mk_list f n
 
-  let get_num_exprs ( x : goal ) =  Z3native.goal_num_exprs (z3obj_gnc x) (z3obj_gno x)
-    
-  let is_decided_sat ( x : goal ) = 
-    Z3native.goal_is_decided_sat (z3obj_gnc x) (z3obj_gno x)
-      
-  let is_decided_unsat ( x : goal ) =
-    Z3native.goal_is_decided_unsat (z3obj_gnc x) (z3obj_gno x)
-      
-  let translate ( x : goal ) ( to_ctx : context ) =
-    create to_ctx (Z3native.goal_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx))
+  let get_num_exprs (x:goal) = Z3native.goal_num_exprs (gc x) x
+  let is_decided_sat (x:goal) = Z3native.goal_is_decided_sat (gc x) x
+  let is_decided_unsat (x:goal) = Z3native.goal_is_decided_unsat (gc x) x
+  let translate (x:goal) (to_ctx:context) = Z3native.goal_translate (gc x) x to_ctx
 
-  let simplify ( x : goal ) ( p : Params.params option ) =
-    let tn = Z3native.mk_tactic (z3obj_gnc x) "simplify" in
-    Z3native.tactic_inc_ref (z3obj_gnc x) tn ;
+  let simplify (x:goal) (p:Params.params option) =
+    let tn = Z3native.mk_tactic (gc x) "simplify" in
+    Z3native.tactic_inc_ref (gc x) tn;
     let arn = match p with
-      | None -> Z3native.tactic_apply (z3obj_gnc x) tn (z3obj_gno x) 
-      | Some(pn) -> Z3native.tactic_apply_ex (z3obj_gnc x) tn (z3obj_gno x) (z3obj_gno pn)
+      | None -> Z3native.tactic_apply (gc x) tn x
+      | Some pn -> Z3native.tactic_apply_ex (gc x) tn x pn
     in
-    Z3native.apply_result_inc_ref (z3obj_gnc x) arn ;
-    let sg = Z3native.apply_result_get_num_subgoals (z3obj_gnc x) arn in
-    let res = if sg == 0 then 
-     raise (Z3native.Exception "No subgoals") 
-      else 
-     Z3native.apply_result_get_subgoal (z3obj_gnc x) arn 0 in
-    Z3native.apply_result_dec_ref (z3obj_gnc x) arn ;
-    Z3native.tactic_dec_ref (z3obj_gnc x) tn ;
-    create (z3obj_gc x) res
+    Z3native.apply_result_inc_ref (gc x) arn;
+    let sg = Z3native.apply_result_get_num_subgoals (gc x) arn in
+    let res = if sg = 0 then
+        raise (Error "No subgoals")
+      else
+        Z3native.apply_result_get_subgoal (gc x) arn 0 in
+    Z3native.apply_result_dec_ref (gc x) arn;
+    Z3native.tactic_dec_ref (gc x) tn;
+    res
 
-  let mk_goal ( ctx : context ) ( models : bool ) ( unsat_cores : bool ) ( proofs : bool ) = 
-    create ctx (Z3native.mk_goal (context_gno ctx) models unsat_cores proofs)
+  let mk_goal = Z3native.mk_goal
 
-  let to_string ( x : goal ) = Z3native.goal_to_string (z3obj_gnc x) (z3obj_gno x)
+  let to_string (x:goal) = Z3native.goal_to_string (gc x) x
 
-  let as_expr ( x : goal ) = 
-     let n = get_size x in
-     if n = 0 then 
-       (Boolean.mk_true (z3obj_gc x)) 
-     else if n = 1 then
-       (List.hd (get_formulas x))
-     else
-       (Boolean.mk_and (z3obj_gc x) (get_formulas x))
-end  
+  let as_expr (x:goal) =
+    match get_size x with
+    | 0 -> Boolean.mk_true (gc x)
+    | 1 -> List.hd (get_formulas x)
+    | _ -> Boolean.mk_and (gc x) (get_formulas x)
+end
 
 
 module Model =
 struct
-  type model = z3_native_object
+  type model = Z3native.model
+  let gc = Z3native.context_of_model
 
-  let create ( ctx : context ) ( no : Z3native.ptr ) = 
-    let res : model = { m_ctx = ctx ;
-               m_n_obj = null ;
-               inc_ref = Z3native.model_inc_ref ;
-               dec_ref = Z3native.model_dec_ref } in
-    (z3obj_sno res ctx no) ;
-    (z3obj_create res) ;
-    res
-      
   module FuncInterp =
   struct
-    type func_interp = z3_native_object
+    type func_interp = Z3native.func_interp
+    let gc = Z3native.context_of_func_interp
 
-    let create ( ctx : context ) ( no : Z3native.ptr ) = 
-      let res : func_interp = { m_ctx = ctx ;
-                    m_n_obj = null ;
-                    inc_ref = Z3native.func_interp_inc_ref ;
-                    dec_ref = Z3native.func_interp_dec_ref } in
-      (z3obj_sno res ctx no) ;
-      (z3obj_create res) ;
-      res
-     
     module FuncEntry =
-    struct       
-      type func_entry = z3_native_object
-       
-      let create ( ctx : context ) ( no : Z3native.ptr ) = 
-     let res : func_entry = { m_ctx = ctx ;
-                     m_n_obj = null ;
-                     inc_ref = Z3native.func_entry_inc_ref ;
-                     dec_ref = Z3native.func_entry_dec_ref } in
-     (z3obj_sno res ctx no) ;
-     (z3obj_create res) ;
-     res
-       
-      let get_value ( x : func_entry ) =
-     expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_value (z3obj_gnc x) (z3obj_gno x))
+    struct
+      type func_entry = Z3native.func_entry
+      let gc = Z3native.context_of_func_entry
 
-      let get_num_args ( x : func_entry ) = Z3native.func_entry_get_num_args (z3obj_gnc x) (z3obj_gno x)
-     
-      let get_args ( x : func_entry ) =
-     let n = (get_num_args x) in
-     let f i = (expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_arg (z3obj_gnc x) (z3obj_gno x) i)) in
-     mk_list f n
-       
-      let to_string ( x : func_entry ) =
-     let a = (get_args x) in
-     let f c p = (p ^ (Expr.to_string c) ^ ", ") in
-     "[" ^ List.fold_right f a ((Expr.to_string (get_value x)) ^ "]")
+      let get_value (x:func_entry) = Z3native.func_entry_get_value (gc x) x
+      let get_num_args (x:func_entry) = Z3native.func_entry_get_num_args (gc x) x
+
+      let get_args (x:func_entry) =
+        let n = get_num_args x in
+        let f i = Z3native.func_entry_get_arg (gc x) x i in
+        mk_list f n
+
+      let to_string (x:func_entry) =
+        let a = get_args x in
+        let f c p = (p ^ (Expr.to_string c) ^ ", ") in
+        "[" ^ List.fold_right f a ((Expr.to_string (get_value x)) ^ "]")
     end
 
-    let get_num_entries ( x: func_interp ) = Z3native.func_interp_get_num_entries (z3obj_gnc x) (z3obj_gno x)
+    let get_num_entries (x:func_interp) = Z3native.func_interp_get_num_entries (gc x) x
 
-    let get_entries ( x : func_interp ) =
-      let n = (get_num_entries x) in
-      let f i = (FuncEntry.create (z3obj_gc x) (Z3native.func_interp_get_entry (z3obj_gnc x) (z3obj_gno x) i)) in
+    let get_entries (x:func_interp) =
+      let n = get_num_entries x in
+      let f i = Z3native.func_interp_get_entry (gc x) x i in
       mk_list f n
 
-    let get_else ( x : func_interp ) = expr_of_ptr (z3obj_gc x) (Z3native.func_interp_get_else (z3obj_gnc x) (z3obj_gno x))
+    let get_else (x:func_interp) = Z3native.func_interp_get_else (gc x) x
 
-    let get_arity ( x : func_interp ) = Z3native.func_interp_get_arity (z3obj_gnc x) (z3obj_gno x)
+    let get_arity (x:func_interp) = Z3native.func_interp_get_arity (gc x) x
 
-    let to_string ( x : func_interp ) =     
+    let to_string (x:func_interp) =
       let f c p = (
-     let n = (FuncEntry.get_num_args c) in
-     p ^ 
-       let g c p = (p ^ (Expr.to_string c) ^ ", ") in
-       (if n > 1 then "[" else "") ^
-         (List.fold_right 
-            g 
-            (FuncEntry.get_args c) 
-            ((if n > 1 then "]" else "") ^ " -> " ^ (Expr.to_string (FuncEntry.get_value c)) ^ ", "))
-      ) in
+        let n = FuncEntry.get_num_args c in
+        p ^
+        let g c p = (p ^ (Expr.to_string c) ^ ", ") in
+        (if n > 1 then "[" else "") ^
+        (List.fold_right
+           g
+           (FuncEntry.get_args c)
+           ((if n > 1 then "]" else "") ^ " -> " ^ (Expr.to_string (FuncEntry.get_value c)) ^ ", "))) in
       List.fold_right f (get_entries x) ("else -> " ^ (Expr.to_string (get_else x)) ^ "]")
   end
-    
-  let get_const_interp ( x : model ) ( f : func_decl ) =
-    if (FuncDecl.get_arity f) != 0 ||
-      (sort_kind_of_int (Z3native.get_sort_kind (FuncDecl.gnc f) (Z3native.get_range (FuncDecl.gnc f) (FuncDecl.gno f)))) == ARRAY_SORT then
-      raise (Z3native.Exception "Non-zero arity functions and arrays have FunctionInterpretations as a model. Use FuncInterp.")
+
+  let get_const_interp (x:model) (f:func_decl) =
+    if FuncDecl.get_arity f <> 0 ||
+       (sort_kind_of_int (Z3native.get_sort_kind (FuncDecl.gc f) (Z3native.get_range (FuncDecl.gc f) f))) = ARRAY_SORT then
+      raise (Error "Non-zero arity functions and arrays have FunctionInterpretations as a model. Use FuncInterp.")
     else
-      let np = Z3native.model_get_const_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f) in
-      if (Z3native.is_null np) then
-     None
+      let np = Z3native.model_get_const_interp (gc x) x f  in
+      if Z3native.is_null_ast np then
+        None
       else
-     Some (expr_of_ptr (z3obj_gc x) np)
+        Some np
 
-  let get_const_interp_e ( x : model ) ( a : expr ) = get_const_interp x (Expr.get_func_decl a)
+  let get_const_interp_e (x:model) (a:expr) = get_const_interp x (Expr.get_func_decl a)
 
-
-  let rec get_func_interp ( x : model ) ( f : func_decl ) =
-    let sk = (sort_kind_of_int (Z3native.get_sort_kind (z3obj_gnc x) (Z3native.get_range (FuncDecl.gnc f) (FuncDecl.gno f)))) in
-    if (FuncDecl.get_arity f) == 0 then
-      let n = Z3native.model_get_const_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f) in      
-      if (Z3native.is_null n) then
-     None 
-      else 
-     match sk with
-       | ARRAY_SORT ->         
-         if not (Z3native.is_as_array (z3obj_gnc x) n) then
-           raise (Z3native.Exception "Argument was not an array constant")
-         else
-           let fd = Z3native.get_as_array_func_decl (z3obj_gnc x) n in
-              get_func_interp x (func_decl_of_ptr (z3obj_gc x) fd)
-       | _ -> raise (Z3native.Exception "Constant functions do not have a function interpretation; use ConstInterp");
+  let rec get_func_interp (x:model) (f:func_decl) =
+    let sk = sort_kind_of_int (Z3native.get_sort_kind (gc x) (Z3native.get_range (FuncDecl.gc f) f)) in
+    if FuncDecl.get_arity f = 0 then
+      let n = Z3native.model_get_const_interp (gc x) x f in
+      if Z3native.is_null_ast n then
+        None
+      else
+        match sk with
+        | ARRAY_SORT ->
+          if not (Z3native.is_as_array (gc x) n) then
+            raise (Error "Argument was not an array constant")
+          else
+            let fd = Z3native.get_as_array_func_decl (gc x) n in
+            get_func_interp x fd
+        | _ -> raise (Error "Constant functions do not have a function interpretation; use ConstInterp");
     else
-      let n = (Z3native.model_get_func_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f)) in
-      if (Z3native.is_null n) then None else Some (FuncInterp.create (z3obj_gc x) n)
-     
+      let n = Z3native.model_get_func_interp (gc x) x f in
+      if Z3native.is_null_func_interp n then None else Some n
+
   (** The number of constants that have an interpretation in the model. *)
-  let get_num_consts ( x : model ) = Z3native.model_get_num_consts (z3obj_gnc x) (z3obj_gno x)
-    
-  let get_const_decls ( x : model ) = 
+  let get_num_consts (x:model) = Z3native.model_get_num_consts (gc x) x
+
+  let get_const_decls (x:model) =
     let n = (get_num_consts x) in
-    let f i = func_decl_of_ptr (z3obj_gc x) (Z3native.model_get_const_decl (z3obj_gnc x) (z3obj_gno x) i) in
+    let f i = Z3native.model_get_const_decl (gc x) x i in
     mk_list f n
-      
-  let get_num_funcs ( x : model ) = Z3native.model_get_num_funcs (z3obj_gnc x) (z3obj_gno x)
-    
-  let get_func_decls ( x : model ) = 
+
+  let get_num_funcs (x:model) = Z3native.model_get_num_funcs (gc x) x
+
+  let get_func_decls (x:model) =
     let n = (get_num_funcs x) in
-    let f i = func_decl_of_ptr (z3obj_gc x) (Z3native.model_get_func_decl (z3obj_gnc x) (z3obj_gno x) i) in
+    let f i = Z3native.model_get_func_decl (gc x) x i in
     mk_list f n
-      
-  let get_decls ( x : model ) =
-    let n_funcs = (get_num_funcs x) in
-    let n_consts = (get_num_consts x ) in
-    let f i = func_decl_of_ptr (z3obj_gc x) (Z3native.model_get_func_decl (z3obj_gnc x) (z3obj_gno x) i) in
-    let g i = func_decl_of_ptr (z3obj_gc x) (Z3native.model_get_const_decl (z3obj_gnc x) (z3obj_gno x) i) in
+
+  let get_decls (x:model) =
+    let n_funcs = get_num_funcs x in
+    let n_consts = get_num_consts x in
+    let f i = Z3native.model_get_func_decl (gc x) x i in
+    let g i = Z3native.model_get_const_decl (gc x) x i in
     (mk_list f n_funcs) @ (mk_list g n_consts)
-      
-  let eval ( x : model ) ( t : expr ) ( completion : bool ) =
-    let (r, v) = (Z3native.model_eval (z3obj_gnc x) (z3obj_gno x) (Expr.gno t) completion) in
-    if not r then
-      None
-    else
-      Some(expr_of_ptr (z3obj_gc x) v)
 
-  let evaluate ( x : model ) ( t : expr ) ( completion : bool ) =
-    eval x t completion
-      
-  let get_num_sorts ( x : model ) = Z3native.model_get_num_sorts (z3obj_gnc x) (z3obj_gno x)
-    
-  let get_sorts ( x : model ) =
-    let n = (get_num_sorts x) in
-    let f i = (Sort.sort_of_ptr (z3obj_gc x) (Z3native.model_get_sort (z3obj_gnc x) (z3obj_gno x) i)) in
+  let eval (x:model) (t:expr) (completion:bool) =
+    match Z3native.model_eval (gc x) x t completion with
+    | (false, _) -> None
+    | (true, v) -> Some v
+
+  let evaluate = eval
+  let get_num_sorts (x:model) = Z3native.model_get_num_sorts (gc x) x
+
+  let get_sorts (x:model) =
+    let n = get_num_sorts x in
+    let f i = Z3native.model_get_sort (gc x) x i in
     mk_list f n
 
-  let sort_universe ( x : model ) ( s : Sort.sort ) =
-    let av = AST.ASTVector.create (z3obj_gc x) (Z3native.model_get_sort_universe (z3obj_gnc x) (z3obj_gno x) (Sort.gno s)) in
-    (AST.ASTVector.to_expr_list av)
+  let sort_universe (x:model) (s:Sort.sort) =
+    let av = Z3native.model_get_sort_universe (gc x) x s in
+    AST.ASTVector.to_expr_list av
 
-  let to_string ( x : model ) = Z3native.model_to_string (z3obj_gnc x) (z3obj_gno x) 
+  let to_string (x:model) = Z3native.model_to_string (gc x) x
 end
 
 
 module Probe =
 struct
-  type probe = z3_native_object     
+  type probe = Z3native.probe
 
-  let create ( ctx : context ) ( no : Z3native.ptr ) = 
-    let res : probe = { m_ctx = ctx ;
-               m_n_obj = null ;
-               inc_ref = Z3native.probe_inc_ref ;
-               dec_ref = Z3native.probe_dec_ref } in
-    (z3obj_sno res ctx no) ;
-    (z3obj_create res) ;
-    res
-      
+  let apply (x:probe) (g:Goal.goal) = Z3native.probe_apply (gc x) x g
+  let get_num_probes = Z3native.get_num_probes
 
-  let apply ( x : probe ) ( g : Goal.goal ) =
-    Z3native.probe_apply (z3obj_gnc x) (z3obj_gno x) (z3obj_gno g)
-
-  let get_num_probes ( ctx : context ) =
-    Z3native.get_num_probes (context_gno ctx)
-
-  let get_probe_names ( ctx : context ) = 
-    let n = (get_num_probes ctx) in
-    let f i = (Z3native.get_probe_name (context_gno ctx) i) in
+  let get_probe_names (ctx:context) =
+    let n = get_num_probes ctx in
+    let f i = Z3native.get_probe_name ctx i in
     mk_list f n
 
-  let get_probe_description ( ctx : context ) ( name : string ) =
-    Z3native.probe_get_descr (context_gno ctx) name
-
-  let mk_probe ( ctx : context ) ( name : string ) =
-    (create ctx (Z3native.mk_probe (context_gno ctx) name))
-
-  let const ( ctx : context ) ( v : float ) = 
-    (create ctx (Z3native.probe_const (context_gno ctx) v))
-
-  let lt ( ctx : context ) ( p1 : probe ) ( p2 : probe ) =
-    (create ctx (Z3native.probe_lt (context_gno ctx) (z3obj_gno p1) (z3obj_gno p2)))
-
-  let gt ( ctx : context ) ( p1 : probe ) ( p2 : probe ) =
-    (create ctx (Z3native.probe_gt (context_gno ctx) (z3obj_gno p1) (z3obj_gno p2)))
-
-  let le ( ctx : context ) ( p1 : probe ) ( p2 : probe ) = 
-    (create ctx (Z3native.probe_le (context_gno ctx) (z3obj_gno p1) (z3obj_gno p2)))
-
-  let ge ( ctx : context ) ( p1 : probe ) ( p2 : probe ) =
-    (create ctx (Z3native.probe_ge (context_gno ctx) (z3obj_gno p1) (z3obj_gno p2)))
-
-  let eq ( ctx : context ) ( p1 : probe ) ( p2 : probe ) =
-    (create ctx (Z3native.probe_eq (context_gno ctx) (z3obj_gno p1) (z3obj_gno p2)))
-
-  let and_ ( ctx : context ) ( p1 : probe ) ( p2 : probe ) =
-    (create ctx (Z3native.probe_and (context_gno ctx) (z3obj_gno p1) (z3obj_gno p2)))
-
-  let or_ ( ctx : context ) ( p1 : probe ) ( p2 : probe ) =
-    (create ctx (Z3native.probe_or (context_gno ctx) (z3obj_gno p1) (z3obj_gno p2)))
-
-  let not_ ( ctx : context ) ( p : probe ) =
-    (create ctx (Z3native.probe_not (context_gno ctx) (z3obj_gno p)))
+  let get_probe_description = Z3native.probe_get_descr
+  let mk_probe = Z3native.mk_probe
+  let const = Z3native.probe_const
+  let lt = Z3native.probe_lt
+  let gt = Z3native.probe_gt
+  let le = Z3native.probe_le
+  let ge = Z3native.probe_ge
+  let eq = Z3native.probe_eq
+  let and_ = Z3native.probe_and
+  let or_ = Z3native.probe_or
+  let not_ = Z3native.probe_not
 end
 
 
 module Tactic =
-struct      
-  type tactic = z3_native_object
+struct
+  type tactic = Z3native.tactic
+  let gc = Z3native.context_of_tactic
 
-  let create ( ctx : context ) ( no : Z3native.ptr ) = 
-    let res : tactic = { m_ctx = ctx ;
-                m_n_obj = null ;
-                inc_ref = Z3native.tactic_inc_ref ;
-                dec_ref = Z3native.tactic_dec_ref } in
-    (z3obj_sno res ctx no) ;
-    (z3obj_create res) ;
-    res
-      
   module ApplyResult =
-  struct 
-    type apply_result = z3_native_object
-     
-    let create ( ctx : context ) ( no : Z3native.ptr ) = 
-      let res : apply_result = { m_ctx = ctx ;
-                     m_n_obj = null ;
-                     inc_ref = Z3native.apply_result_inc_ref ;
-                     dec_ref = Z3native.apply_result_dec_ref } in
-      (z3obj_sno res ctx no) ;
-      (z3obj_create res) ;
-      res
-     
-    let get_num_subgoals ( x : apply_result ) =
-      Z3native.apply_result_get_num_subgoals (z3obj_gnc x) (z3obj_gno x)
-     
-    let get_subgoals ( x : apply_result ) =
-      let n = (get_num_subgoals x) in
-      let f i = Goal.create (z3obj_gc x) (Z3native.apply_result_get_subgoal (z3obj_gnc x) (z3obj_gno x) i) in
+  struct
+    type apply_result = Z3native.apply_result
+    let gc = Z3native.context_of_apply_result
+
+    let get_num_subgoals (x:apply_result) = Z3native.apply_result_get_num_subgoals (gc x) x
+
+    let get_subgoals (x:apply_result) =
+      let n = get_num_subgoals x in
+      let f i = Z3native.apply_result_get_subgoal (gc x) x i in
       mk_list f n
-     
-    let get_subgoal ( x : apply_result ) ( i : int ) =
-      Goal.create (z3obj_gc x) (Z3native.apply_result_get_subgoal (z3obj_gnc x) (z3obj_gno x) i)
-     
-    let convert_model ( x : apply_result ) ( i : int ) ( m : Model.model ) =
-      Model.create (z3obj_gc x) (Z3native.apply_result_convert_model (z3obj_gnc x) (z3obj_gno x) i (z3obj_gno m))
-     
-    let to_string ( x : apply_result ) = Z3native.apply_result_to_string (z3obj_gnc x) (z3obj_gno x)
+
+    let get_subgoal (x:apply_result) (i:int) = Z3native.apply_result_get_subgoal (gc x) x i
+    let convert_model (x:apply_result) (i:int) (m:Model.model) = Z3native.apply_result_convert_model (gc x) x i m
+    let to_string (x:apply_result) = Z3native.apply_result_to_string (gc x) x
   end
 
-  let get_help ( x : tactic ) = Z3native.tactic_get_help (z3obj_gnc x) (z3obj_gno x)
+  let get_help (x:tactic) = Z3native.tactic_get_help (gc x) x
+  let get_param_descrs (x:tactic) = Z3native.tactic_get_param_descrs (gc x) x
 
-  let get_param_descrs ( x : tactic ) =
-    Params.ParamDescrs.param_descrs_of_ptr (z3obj_gc x) (Z3native.tactic_get_param_descrs (z3obj_gnc x) (z3obj_gno x))
-      
-  let apply ( x : tactic ) ( g : Goal.goal ) ( p : Params.params option ) =
-    match p with 
-      | None -> (ApplyResult.create (z3obj_gc x) (Z3native.tactic_apply (z3obj_gnc x) (z3obj_gno x) (z3obj_gno g)))
-      | Some (pn) -> (ApplyResult.create (z3obj_gc x) (Z3native.tactic_apply_ex (z3obj_gnc x) (z3obj_gno x) (z3obj_gno g) (z3obj_gno pn)))
+  let apply (x:tactic) (g:Goal.goal) (p:Params.params option) =
+    match p with
+    | None -> Z3native.tactic_apply (gc x) x g
+    | Some pn -> Z3native.tactic_apply_ex (gc x) x g pn
 
-  let get_num_tactics ( ctx : context ) = Z3native.get_num_tactics (context_gno ctx)
+  let get_num_tactics = Z3native.get_num_tactics
 
-  let get_tactic_names ( ctx : context ) =
-    let n = (get_num_tactics ctx ) in
-    let f i = (Z3native.get_tactic_name (context_gno ctx) i) in
+  let get_tactic_names (ctx:context) =
+    let n = get_num_tactics ctx in
+    let f i = Z3native.get_tactic_name ctx i in
     mk_list f n
 
-  let get_tactic_description ( ctx : context ) ( name : string ) =
-    Z3native.tactic_get_descr (context_gno ctx) name
+  let get_tactic_description = Z3native.tactic_get_descr
+  let mk_tactic = Z3native.mk_tactic
 
-  let mk_tactic ( ctx : context ) ( name : string ) =
-    create ctx (Z3native.mk_tactic (context_gno ctx) name)
-
-  let and_then ( ctx : context ) ( t1 : tactic ) ( t2 : tactic ) ( ts : tactic list ) =
-    let f p c = (match p with 
-      | None -> (Some (z3obj_gno c)) 
-      | Some(x) -> (Some (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno c) x))) in
+  let and_then (ctx:context) (t1:tactic) (t2:tactic) (ts:tactic list) =
+    let f p c = (match p with
+        | None -> Some c
+        | Some(x) -> Some (Z3native.tactic_and_then ctx c x)) in
     match (List.fold_left f None ts) with
-      | None -> 
-     create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2))
-      | Some(x) ->
-     let o = (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t2) x) in
-     create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) o)
+    | None -> Z3native.tactic_and_then ctx t1 t2
+    | Some(x) -> let o = Z3native.tactic_and_then ctx t2 x in
+      Z3native.tactic_and_then ctx t1 o
 
-  let or_else ( ctx : context ) ( t1 : tactic ) ( t2 : tactic ) =
-    create ctx (Z3native.tactic_or_else (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2))
-
-  let try_for ( ctx : context ) ( t : tactic ) ( ms : int ) =
-    create ctx (Z3native.tactic_try_for (context_gno ctx) (z3obj_gno t) ms)
-
-  let when_ ( ctx : context ) ( p : Probe.probe ) ( t : tactic ) =
-    create ctx (Z3native.tactic_when (context_gno ctx) (z3obj_gno p) (z3obj_gno t))
-
-  let cond ( ctx : context ) ( p : Probe.probe ) ( t1 : tactic ) ( t2 : tactic ) =
-    create ctx (Z3native.tactic_cond (context_gno ctx) (z3obj_gno p) (z3obj_gno t1) (z3obj_gno t2))
-
-  let repeat ( ctx : context ) ( t : tactic ) ( max : int ) =
-    create ctx (Z3native.tactic_repeat (context_gno ctx) (z3obj_gno t) max)
-
-  let skip ( ctx : context ) =
-    create ctx (Z3native.tactic_skip (context_gno ctx))
-
-  let fail ( ctx : context ) =
-    create ctx (Z3native.tactic_fail (context_gno ctx))
-
-  let fail_if ( ctx : context ) ( p : Probe.probe ) =
-    create ctx (Z3native.tactic_fail_if (context_gno ctx) (z3obj_gno p))
-
-  let fail_if_not_decided ( ctx : context ) =
-    create ctx (Z3native.tactic_fail_if_not_decided (context_gno ctx))
-
-  let using_params ( ctx : context ) ( t : tactic ) ( p : Params.params ) =
-    create ctx (Z3native.tactic_using_params (context_gno ctx) (z3obj_gno t) (z3obj_gno p))
-
-  let with_ ( ctx : context ) ( t : tactic ) ( p : Params.params ) =
-    using_params ctx t p
-
-  let par_or ( ctx : context ) ( t : tactic list ) =
-    let f e = (z3obj_gno e) in
-    create ctx (Z3native.tactic_par_or (context_gno ctx) (List.length t) (Array.of_list (List.map f t)))
-
-  let par_and_then ( ctx : context ) ( t1 : tactic ) ( t2 : tactic ) =
-    create ctx (Z3native.tactic_par_and_then (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2))
-
-  let interrupt ( ctx : context ) =
-    Z3native.interrupt (context_gno ctx)
+  let or_else = Z3native.tactic_or_else
+  let try_for = Z3native.tactic_try_for
+  let when_ = Z3native.tactic_when
+  let cond = Z3native.tactic_cond
+  let repeat = Z3native.tactic_repeat
+  let skip = Z3native.tactic_skip
+  let fail = Z3native.tactic_fail
+  let fail_if = Z3native.tactic_fail_if
+  let fail_if_not_decided = Z3native.tactic_fail_if_not_decided
+  let using_params = Z3native.tactic_using_params
+  let with_ = using_params
+  let par_or (ctx:context) (t:tactic list) = Z3native.tactic_par_or ctx (List.length t) t
+  let par_and_then = Z3native.tactic_par_and_then
+  let interrupt = Z3native.interrupt
 end
 
 
 module Statistics =
-struct     
-  type statistics = z3_native_object
-
-  let create ( ctx : context ) ( no : Z3native.ptr ) = 
-    let res : statistics = { m_ctx = ctx ;
-                                m_n_obj = null ;
-                                inc_ref = Z3native.stats_inc_ref ;
-                                dec_ref = Z3native.stats_dec_ref } in
-    (z3obj_sno res ctx no) ;
-    (z3obj_create res) ;
-    res
-      
+struct
+  type statistics = Z3native.stats
+  let gc = Z3native.context_of_stats
 
   module Entry =
   struct
-    type statistics_entry = { 
-       mutable m_key : string; 
-       mutable m_is_int : bool ; 
-       mutable m_is_float : bool ; 
-       mutable m_int : int ; 
-       mutable m_float : float }
-         
-    let create_si k v = 
-       let res : statistics_entry = { 
-         m_key = k ;
-         m_is_int = true ;
-         m_is_float = false ;
-         m_int = v ;
-         m_float = 0.0
-       } in
-       res
+    type statistics_entry = {
+      m_key:string;
+      m_is_int:bool;
+      m_is_float:bool;
+      m_int:int;
+      m_float:float }
 
-    let create_sd k v = 
-       let res : statistics_entry = { 
-         m_key = k ;
-         m_is_int = false ;
-         m_is_float = true ;
-         m_int = 0 ;
-         m_float = v
-       } in
-       res
-         
+    let create_si k v =
+      { m_key = k; m_is_int = true; m_is_float = false; m_int = v; m_float = 0.0 }
 
-    let get_key (x : statistics_entry) = x.m_key
-    let get_int (x : statistics_entry) = x.m_int     
-    let get_float (x : statistics_entry) = x.m_float
-    let is_int (x : statistics_entry) = x.m_is_int
-    let is_float (x : statistics_entry) = x.m_is_float
-    let to_string_value (x : statistics_entry) = 
-       if (is_int x) then
-         string_of_int (get_int x)
-       else if (is_float x) then 
-         string_of_float (get_float x)
-       else
-        raise (Z3native.Exception "Unknown statistical entry type")
-    let to_string ( x : statistics_entry ) = (get_key x) ^ ": " ^ (to_string_value x)
+    let create_sd k v =
+      { m_key = k; m_is_int = false; m_is_float = true; m_int = 0; m_float = v }
+
+    let get_key (x:statistics_entry) = x.m_key
+    let get_int (x:statistics_entry) = x.m_int
+    let get_float (x:statistics_entry) = x.m_float
+    let is_int (x:statistics_entry) = x.m_is_int
+    let is_float (x:statistics_entry) = x.m_is_float
+    let to_string_value (x:statistics_entry) =
+      if is_int x then
+        string_of_int (get_int x)
+      else if is_float x then
+        string_of_float (get_float x)
+      else
+        raise (Error "Unknown statistical entry type")
+    let to_string (x:statistics_entry) = (get_key x) ^ ": " ^ (to_string_value x)
   end
 
-  let to_string ( x : statistics ) = Z3native.stats_to_string (z3obj_gnc x) (z3obj_gno x)
-    
-  let get_size ( x : statistics ) = Z3native.stats_size (z3obj_gnc x) (z3obj_gno x)
-    
-  let get_entries ( x : statistics ) =
-    let n = (get_size x ) in
-    let f i = (
-       let k = Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i in
-       if (Z3native.stats_is_uint (z3obj_gnc x) (z3obj_gno x) i) then
-         (Entry.create_si k (Z3native.stats_get_uint_value (z3obj_gnc x) (z3obj_gno x) i))
-       else 
-         (Entry.create_sd k (Z3native.stats_get_double_value (z3obj_gnc x) (z3obj_gno x) i))
-    ) in
+  let to_string (x:statistics) = Z3native.stats_to_string (gc x) x
+  let get_size (x:statistics) = Z3native.stats_size (gc x) x
+
+  let get_entries (x:statistics) =
+    let n = get_size x in
+    let f i =
+      let k = Z3native.stats_get_key (gc x) x i in
+      if Z3native.stats_is_uint (gc x) x i then
+        Entry.create_si k (Z3native.stats_get_uint_value (gc x) x i)
+      else
+        Entry.create_sd k (Z3native.stats_get_double_value (gc x) x i)
+    in
     mk_list f n
 
-  let get_keys ( x : statistics ) =
-    let n = (get_size x) in
-    let f i = (Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i) in
+  let get_keys (x:statistics) =
+    let n = get_size x in
+    let f i = Z3native.stats_get_key (gc x) x i in
     mk_list f n
-       
-  let get ( x : statistics ) ( key : string ) =
-    let f p c = (if ((Entry.get_key c) == key) then (Some c) else p) in
-    List.fold_left f None (get_entries x)
+
+  let get (x:statistics) (key:string) =
+    try Some(List.find (fun c -> Entry.get_key c = key) (get_entries x)) with
+    | Not_found -> None
 end
 
 
 module Solver =
-struct      
-  type solver = z3_native_object
+struct
+  type solver = Z3native.solver
   type status = UNSATISFIABLE | UNKNOWN | SATISFIABLE
+  let gc = Z3native.context_of_solver
 
-  let create ( ctx : context ) ( no : Z3native.ptr ) = 
-    let res : solver = { m_ctx = ctx ;
-                m_n_obj = null ;
-                inc_ref = Z3native.solver_inc_ref ;
-                dec_ref = Z3native.solver_dec_ref } in
-    (z3obj_sno res ctx no) ;
-    (z3obj_create res) ;
-    res
-      
-  let string_of_status ( s : status) = match s with
+  let string_of_status (s:status) = match s with
     | UNSATISFIABLE -> "unsatisfiable"
-    | SATISFIABLE -> "satisfiable" 
+    | SATISFIABLE -> "satisfiable"
     | _ -> "unknown"
 
-  let get_help ( x : solver ) = Z3native.solver_get_help (z3obj_gnc x) (z3obj_gno x)
+  let get_help (x:solver) = Z3native.solver_get_help (gc x) x
+  let set_parameters (x:solver) (p:Params.params) = Z3native.solver_set_params (gc x) x p
+  let get_param_descrs (x:solver) = Z3native.solver_get_param_descrs (gc x) x
+  let get_num_scopes (x:solver) = Z3native.solver_get_num_scopes (gc x) x
+  let push (x:solver) = Z3native.solver_push (gc x) x
+  let pop (x:solver) (n:int) = Z3native.solver_pop (gc x) x n
+  let reset (x:solver) = Z3native.solver_reset (gc x) x
 
-  let set_parameters ( x : solver ) ( p : Params.params )=
-    Z3native.solver_set_params (z3obj_gnc x) (z3obj_gno x) (z3obj_gno p)
+  let add x constraints =
+    List.iter (Z3native.solver_assert (gc x) x) constraints
 
-  let get_param_descrs ( x : solver ) =
-    Params.ParamDescrs.param_descrs_of_ptr (z3obj_gc x) (Z3native.solver_get_param_descrs (z3obj_gnc x) (z3obj_gno x))
+  let assert_and_track_l x cs ps =
+    try List.iter2 (Z3native.solver_assert_and_track (gc x) x) cs ps with
+    | Invalid_argument _ -> raise (Error "Argument size mismatch")
 
-  let get_num_scopes ( x : solver ) = Z3native.solver_get_num_scopes (z3obj_gnc x) (z3obj_gno x)
+  let assert_and_track x = Z3native.solver_assert_and_track (gc x) x
 
-  let push ( x : solver ) = Z3native.solver_push (z3obj_gnc x) (z3obj_gno x)
+  let get_num_assertions x =
+    let a = Z3native.solver_get_assertions (gc x) x in
+    AST.ASTVector.get_size a
 
-  let pop ( x : solver ) ( n : int ) = Z3native.solver_pop (z3obj_gnc x) (z3obj_gno x) n
+  let get_assertions x =
+    let av = Z3native.solver_get_assertions (gc x) x in
+    AST.ASTVector.to_expr_list av
 
-  let reset ( x : solver ) = Z3native.solver_reset (z3obj_gnc x) (z3obj_gno x)
-
-  let add ( x : solver ) ( constraints : expr list ) =
-    let f e = (Z3native.solver_assert (z3obj_gnc x) (z3obj_gno x) (Expr.gno e)) in
-    ignore (List.map f constraints)
-
-  let assert_and_track_l ( x : solver ) ( cs : expr list ) ( ps : expr list ) =
-    if ((List.length cs) != (List.length ps)) then
-      raise (Z3native.Exception "Argument size mismatch")
-    else
-      let f a b = (Z3native.solver_assert_and_track (z3obj_gnc x) (z3obj_gno x) (Expr.gno a) (Expr.gno b)) in
-      ignore (List.iter2 f cs ps)
-     
-  let assert_and_track ( x : solver ) ( c : expr ) ( p : expr ) =    
-    Z3native.solver_assert_and_track (z3obj_gnc x) (z3obj_gno x) (Expr.gno c) (Expr.gno p)
-
-  let get_num_assertions ( x : solver ) =
-    let a = AST.ASTVector.create (z3obj_gc x) (Z3native.solver_get_assertions (z3obj_gnc x) (z3obj_gno x)) in
-    (AST.ASTVector.get_size a)
-
-  let get_assertions ( x : solver ) =
-    let av = AST.ASTVector.create (z3obj_gc x) (Z3native.solver_get_assertions (z3obj_gnc x) (z3obj_gno x)) in
-    (AST.ASTVector.to_expr_list av)
-
-  let check ( x : solver ) ( assumptions : expr list ) =
-    let r = 
-      if ((List.length assumptions) == 0) then
-     lbool_of_int (Z3native.solver_check (z3obj_gnc x) (z3obj_gno x))
-      else
-     let f x = (Expr.gno x) in
-     lbool_of_int (Z3native.solver_check_assumptions (z3obj_gnc x) (z3obj_gno x) (List.length assumptions) (Array.of_list (List.map f assumptions)))
+  let check (x:solver) (assumptions:expr list) =
+    let result =
+      match assumptions with
+      | [] -> Z3native.solver_check (gc x) x
+      | _::_ ->
+        Z3native.solver_check_assumptions (gc x) x (List.length assumptions) assumptions
     in
-    match r with 
-      | L_TRUE -> SATISFIABLE
-      | L_FALSE -> UNSATISFIABLE
-      | _ -> UNKNOWN
-     
-  let get_model ( x : solver ) =
-    let q = Z3native.solver_get_model (z3obj_gnc x) (z3obj_gno x) in
-    if (Z3native.is_null q) then
-      None
-    else 
-      Some (Model.create (z3obj_gc x) q)
-     
-  let get_proof ( x : solver ) =
-    let q = Z3native.solver_get_proof (z3obj_gnc x) (z3obj_gno x) in
-    if (Z3native.is_null q) then
-      None
-    else
-      Some (expr_of_ptr (z3obj_gc x) q)
-     
-  let get_unsat_core ( x : solver ) =
-    let av = AST.ASTVector.create (z3obj_gc x) (Z3native.solver_get_unsat_core (z3obj_gnc x) (z3obj_gno x)) in 
-    (AST.ASTVector.to_expr_list av)
+    match lbool_of_int result with
+    | L_TRUE -> SATISFIABLE
+    | L_FALSE -> UNSATISFIABLE
+    | _ -> UNKNOWN
 
-  let get_reason_unknown ( x : solver ) =  Z3native.solver_get_reason_unknown (z3obj_gnc x) (z3obj_gno x)
+  let get_model x =
+    let q = Z3native.solver_get_model (gc x) x in
+    if Z3native.is_null_model q then None else Some q
 
-  let get_statistics ( x : solver ) =
-    (Statistics.create (z3obj_gc x) (Z3native.solver_get_statistics (z3obj_gnc x) (z3obj_gno x)))
+  let get_proof x =
+    let q = Z3native.solver_get_proof (gc x) x in
+    if Z3native.is_null_ast q then None else Some q
 
-  let mk_solver ( ctx : context ) ( logic : Symbol.symbol option ) =
+  let get_unsat_core x =
+    let av = Z3native.solver_get_unsat_core (gc x) x in
+    AST.ASTVector.to_expr_list av
+
+  let get_reason_unknown x =  Z3native.solver_get_reason_unknown (gc x) x
+  let get_statistics x = Z3native.solver_get_statistics (gc x) x
+
+  let mk_solver ctx logic =
     match logic with
-      | None -> (create ctx (Z3native.mk_solver (context_gno ctx)))
-      | Some (x) -> (create ctx (Z3native.mk_solver_for_logic (context_gno ctx) (Symbol.gno x)))
+    | None -> Z3native.mk_solver ctx
+    | Some x -> Z3native.mk_solver_for_logic ctx x
 
-  let mk_solver_s ( ctx : context ) ( logic : string ) =
-    mk_solver ctx (Some (Symbol.mk_string ctx logic))
-
-  let mk_simple_solver ( ctx : context ) =
-    create ctx (Z3native.mk_simple_solver (context_gno ctx))
-
-  let mk_solver_t ( ctx : context ) ( t : Tactic.tactic ) = 
-    create ctx (Z3native.mk_solver_from_tactic (context_gno ctx) (z3obj_gno t))
-
-  let translate  ( x : solver ) ( to_ctx : context ) =
-     create to_ctx (Z3native.solver_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx))
-
-  let to_string ( x : solver ) = Z3native.solver_to_string (z3obj_gnc x) (z3obj_gno x)
+  let mk_solver_s ctx logic = mk_solver ctx (Some (Symbol.mk_string ctx logic))
+  let mk_simple_solver = Z3native.mk_simple_solver
+  let mk_solver_t = Z3native.mk_solver_from_tactic
+  let translate x = Z3native.solver_translate (gc x) x
+  let to_string x = Z3native.solver_to_string (gc x) x
 end
 
 
 module Fixedpoint =
 struct
-  type fixedpoint = z3_native_object
-      
-  let create ( ctx : context ) = 
-    let res : fixedpoint = { m_ctx = ctx ;
-                    m_n_obj = null ;
-                    inc_ref = Z3native.fixedpoint_inc_ref ;
-                    dec_ref = Z3native.fixedpoint_dec_ref } in
-    (z3obj_sno res ctx (Z3native.mk_fixedpoint (context_gno ctx))) ;
-    (z3obj_create res) ;
-    res
-      
+  type fixedpoint = Z3native.fixedpoint
+  let gc = Z3native.context_of_fixedpoint
 
-  let get_help ( x : fixedpoint ) =
-    Z3native.fixedpoint_get_help (z3obj_gnc x) (z3obj_gno x)
-      
-  let set_parameters ( x : fixedpoint ) ( p : Params.params )=
-    Z3native.fixedpoint_set_params (z3obj_gnc x) (z3obj_gno x) (z3obj_gno p)
-      
-  let get_param_descrs ( x : fixedpoint ) =
-    Params.ParamDescrs.param_descrs_of_ptr (z3obj_gc x) (Z3native.fixedpoint_get_param_descrs (z3obj_gnc x) (z3obj_gno x))
-      
-  let add ( x : fixedpoint ) ( constraints : expr list ) =
-    let f e = (Z3native.fixedpoint_assert (z3obj_gnc x) (z3obj_gno x) (Expr.gno e)) in
-    ignore (List.map f constraints) ;
-    ()
+  let get_help x = Z3native.fixedpoint_get_help (gc x) x
+  let set_parameters x = Z3native.fixedpoint_set_params (gc x) x
+  let get_param_descrs x = Z3native.fixedpoint_get_param_descrs (gc x) x
 
-  let register_relation ( x : fixedpoint ) ( f : func_decl ) =
-    Z3native.fixedpoint_register_relation (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f)
-      
-  let add_rule ( x : fixedpoint ) ( rule : expr ) ( name : Symbol.symbol option ) =
-    match name with 
-      | None -> Z3native.fixedpoint_add_rule (z3obj_gnc x) (z3obj_gno x) (Expr.gno rule) null
-      | Some(y) -> Z3native.fixedpoint_add_rule (z3obj_gnc x) (z3obj_gno x) (Expr.gno rule) (Symbol.gno y)
+  let add x constraints =
+    List.iter (Z3native.fixedpoint_assert (gc x) x) constraints
 
-  let add_fact ( x : fixedpoint ) ( pred : func_decl ) ( args : int list ) =
-    Z3native.fixedpoint_add_fact (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno pred) (List.length args) (Array.of_list args)
+  let register_relation x = Z3native.fixedpoint_register_relation (gc x) x
 
-  let query ( x : fixedpoint ) ( query : expr ) =
-    match (lbool_of_int (Z3native.fixedpoint_query (z3obj_gnc x) (z3obj_gno x) (Expr.gno query))) with
-      | L_TRUE -> Solver.SATISFIABLE
-      | L_FALSE -> Solver.UNSATISFIABLE
-      | _ -> Solver.UNKNOWN
+  let add_rule (x:fixedpoint) (rule:expr) (name:Symbol.symbol option) =
+    match name with
+    | None -> Z3native.fixedpoint_add_rule (gc x) x rule (Z3native.mk_null_symbol (gc x))
+    | Some y -> Z3native.fixedpoint_add_rule (gc x) x rule y
 
-  let query_r ( x : fixedpoint ) ( relations : func_decl list ) =
-    let f x = AST.ptr_of_ast (ast_of_func_decl x) in
-    match (lbool_of_int (Z3native.fixedpoint_query_relations (z3obj_gnc x) (z3obj_gno x) (List.length relations) (Array.of_list (List.map f relations)))) with
-      | L_TRUE -> Solver.SATISFIABLE
-      | L_FALSE -> Solver.UNSATISFIABLE
-      | _ -> Solver.UNKNOWN
-     
-  let push ( x : fixedpoint ) =
-    Z3native.fixedpoint_push (z3obj_gnc x) (z3obj_gno x)
-      
-  let pop ( x : fixedpoint ) =
-    Z3native.fixedpoint_pop (z3obj_gnc x) (z3obj_gno x)
+  let add_fact (x:fixedpoint) (pred:func_decl) (args:int list) =
+    Z3native.fixedpoint_add_fact (gc x) x pred (List.length args) args
 
-  let update_rule ( x : fixedpoint ) ( rule : expr ) ( name : Symbol.symbol ) =
-    Z3native.fixedpoint_update_rule (z3obj_gnc x) (z3obj_gno x) (Expr.gno rule) (Symbol.gno name)
+  let query (x:fixedpoint) (query:expr) =
+    match lbool_of_int (Z3native.fixedpoint_query (gc x) x query) with
+    | L_TRUE -> Solver.SATISFIABLE
+    | L_FALSE -> Solver.UNSATISFIABLE
+    | _ -> Solver.UNKNOWN
 
-  let get_answer ( x : fixedpoint ) =
-    let q = (Z3native.fixedpoint_get_answer (z3obj_gnc x) (z3obj_gno x)) in
-    if (Z3native.is_null q) then
-      None
-    else
-      Some (expr_of_ptr (z3obj_gc x) q)
+  let query_r (x:fixedpoint) (relations:func_decl list) =
+    match lbool_of_int (Z3native.fixedpoint_query_relations (gc x) x (List.length relations) relations) with
+    | L_TRUE -> Solver.SATISFIABLE
+    | L_FALSE -> Solver.UNSATISFIABLE
+    | _ -> Solver.UNKNOWN
 
-  let get_reason_unknown ( x : fixedpoint ) =
-    Z3native.fixedpoint_get_reason_unknown (z3obj_gnc x) (z3obj_gno x)
+  let push x = Z3native.fixedpoint_push (gc x) x
+  let pop x = Z3native.fixedpoint_pop (gc x) x
+  let update_rule x = Z3native.fixedpoint_update_rule (gc x) x
 
-  let get_num_levels ( x : fixedpoint ) ( predicate : func_decl ) =
-    Z3native.fixedpoint_get_num_levels (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno predicate)
+  let get_answer x =
+    let q = Z3native.fixedpoint_get_answer (gc x) x in
+    if Z3native.is_null_ast q then None else Some q
 
-  let get_cover_delta ( x : fixedpoint ) ( level : int ) ( predicate : func_decl ) =
-    let q = (Z3native.fixedpoint_get_cover_delta (z3obj_gnc x) (z3obj_gno x) level (FuncDecl.gno predicate)) in
-    if (Z3native.is_null q) then
-      None
-    else
-      Some (expr_of_ptr (z3obj_gc x) q)
-     
-  let add_cover ( x : fixedpoint ) ( level : int ) ( predicate : func_decl ) ( property : expr ) =
-    Z3native.fixedpoint_add_cover (z3obj_gnc x) (z3obj_gno x) level (FuncDecl.gno predicate) (Expr.gno property)
-      
-  let to_string ( x : fixedpoint ) = Z3native.fixedpoint_to_string (z3obj_gnc x) (z3obj_gno x) 0 [||]
-    
-  let set_predicate_representation ( x : fixedpoint ) ( f : func_decl ) ( kinds : Symbol.symbol list ) =
-    Z3native.fixedpoint_set_predicate_representation (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f) (List.length kinds) (Symbol.symbol_lton kinds)
+  let get_reason_unknown x = Z3native.fixedpoint_get_reason_unknown (gc x) x
+  let get_num_levels x = Z3native.fixedpoint_get_num_levels (gc x) x
 
-  let to_string_q ( x : fixedpoint ) ( queries : expr list ) =
-    let f x = Expr.gno x in
-    Z3native.fixedpoint_to_string (z3obj_gnc x) (z3obj_gno x) (List.length queries) (Array.of_list (List.map f queries))
+  let get_cover_delta (x:fixedpoint) (level:int) (predicate:func_decl) =
+    let q = Z3native.fixedpoint_get_cover_delta (gc x) x level predicate in
+    if Z3native.is_null_ast q then None else Some q
 
-  let get_rules ( x : fixedpoint ) = 
-    let av = (AST.ASTVector.create (z3obj_gc x) (Z3native.fixedpoint_get_rules (z3obj_gnc x) (z3obj_gno x))) in
+  let add_cover (x:fixedpoint) (level:int) (predicate:func_decl) (property:expr) =
+    Z3native.fixedpoint_add_cover (gc x) x level predicate property
+
+  let to_string (x:fixedpoint) = Z3native.fixedpoint_to_string (gc x) x 0 []
+
+  let set_predicate_representation (x:fixedpoint) (f:func_decl) (kinds:Symbol.symbol list) =
+    Z3native.fixedpoint_set_predicate_representation (gc x) x f (List.length kinds) kinds
+
+  let to_string_q (x:fixedpoint) (queries:expr list) =
+    Z3native.fixedpoint_to_string (gc x) x (List.length queries) queries
+
+  let get_rules (x:fixedpoint) =
+    let av = Z3native.fixedpoint_get_rules (gc x) x in
+    AST.ASTVector.to_expr_list av
+
+  let get_assertions (x:fixedpoint) =
+    let av = Z3native.fixedpoint_get_assertions (gc x) x in
     (AST.ASTVector.to_expr_list av)
 
-  let get_assertions ( x : fixedpoint ) = 
-    let av = (AST.ASTVector.create (z3obj_gc x) (Z3native.fixedpoint_get_assertions (z3obj_gnc x) (z3obj_gno x))) in
-    (AST.ASTVector.to_expr_list av)
+  let mk_fixedpoint (ctx:context) = Z3native.mk_fixedpoint ctx
+  let get_statistics (x:fixedpoint) = Z3native.fixedpoint_get_statistics (gc x) x
 
-  let mk_fixedpoint ( ctx : context ) = create ctx
+  let parse_string (x:fixedpoint) (s:string) =
+    let av = Z3native.fixedpoint_from_string (gc x) x s in
+    AST.ASTVector.to_expr_list av
 
-  let get_statistics ( x : fixedpoint ) =
-    let s = Z3native.fixedpoint_get_statistics (z3obj_gnc x) (z3obj_gno x) in
-    (Statistics.create (z3obj_gc x) s)
-
-  let parse_string ( x : fixedpoint ) ( s : string ) =
-    let av = (AST.ASTVector.create (z3obj_gc x) (Z3native.fixedpoint_from_string (z3obj_gnc x) (z3obj_gno x) s)) in
-    (AST.ASTVector.to_expr_list av)
-
-  let parse_file ( x : fixedpoint ) ( filename : string ) =
-    let av = (AST.ASTVector.create (z3obj_gc x) (Z3native.fixedpoint_from_file (z3obj_gnc x) (z3obj_gno x) filename)) in
-    (AST.ASTVector.to_expr_list av)
+  let parse_file (x:fixedpoint) (filename:string) =
+    let av = Z3native.fixedpoint_from_file (gc x) x filename in
+    AST.ASTVector.to_expr_list av
 end
 
 
-module Optimize =  
-struct 
-  type optimize = z3_native_object 
-  type opt = optimize
-  type handle = { opt : opt; h : int } 
- 
- 
-  let mk_handle (x : opt) h = { opt = x; h = h } 
+module Optimize =
+struct
+  type optimize = Z3native.optimize
+  type handle = { opt:optimize; h:int }
 
- 
-  let mk_opt (ctx : context) = 
-      let res : opt = { m_ctx = ctx;  
-                        m_n_obj = null ; 
-                        inc_ref = Z3native.optimize_inc_ref ; 
-                        dec_ref = Z3native.optimize_dec_ref } in 
-      (z3obj_sno res ctx (Z3native.mk_optimize (context_gno ctx))) ; 
-      (z3obj_create res) ; 
-      res 
-      
-  let get_help ( x : opt ) =  
-    Z3native.optimize_get_help (z3obj_gnc x) (z3obj_gno x) 
- 
- 
-  let set_parameters ( x : opt ) ( p : Params.params )= 
-    Z3native.optimize_set_params (z3obj_gnc x) (z3obj_gno x) (z3obj_gno p) 
-        
-  let get_param_descrs ( x : opt ) = 
-    Params.ParamDescrs.param_descrs_of_ptr (z3obj_gc x) (Z3native.optimize_get_param_descrs (z3obj_gnc x) (z3obj_gno x)) 
-        
-  let add ( x : opt ) ( constraints : expr list ) = 
-    let f e = (Z3native.optimize_assert (z3obj_gnc x) (z3obj_gno x) (Expr.gno e)) in 
-    List.iter f constraints  
- 
- 
-  let add_soft ( x : opt ) ( e : Expr.expr) ( w : string ) ( s : Symbol.symbol ) = 
-    mk_handle x (Z3native.optimize_assert_soft (z3obj_gnc x) (z3obj_gno x) (Expr.gno e) w (Symbol.gno s)) 
- 
- 
-  let maximize ( x : opt ) ( e :  Expr.expr ) =  
-    mk_handle x (Z3native.optimize_maximize (z3obj_gnc x) (z3obj_gno x) (Expr.gno e)) 
- 
- 
-  let minimize ( x : opt ) ( e :  Expr.expr ) =  
-    mk_handle x (Z3native.optimize_minimize (z3obj_gnc x) (z3obj_gno x) (Expr.gno e)) 
-    
-  let check  ( x : opt ) =  
-     let r = lbool_of_int (Z3native.optimize_check (z3obj_gnc x) (z3obj_gno x)) in  
-     match r with 
-       | L_TRUE -> Solver.SATISFIABLE 
-       | L_FALSE -> Solver.UNSATISFIABLE 
-       | _ -> Solver.UNKNOWN 
- 
- 
-  let get_model ( x : opt ) =  
-     let q = Z3native.optimize_get_model (z3obj_gnc x) (z3obj_gno x) in 
-     if (Z3native.is_null q) then 
-       None 
-     else  
-       Some (Model.create (z3obj_gc x) q) 
- 
-  let get_lower ( x : handle ) ( idx : int )  = 
-      expr_of_ptr (z3obj_gc x.opt) (Z3native.optimize_get_lower (z3obj_gnc x.opt) (z3obj_gno x.opt) idx) 
- 
-  let get_upper ( x : handle ) ( idx : int ) =  
-      expr_of_ptr (z3obj_gc x.opt) (Z3native.optimize_get_upper (z3obj_gnc x.opt) (z3obj_gno x.opt) idx)  
-  
-  let push ( x : opt ) = Z3native.optimize_push (z3obj_gnc x) (z3obj_gno x)
- 
-  let pop ( x : opt ) = Z3native.optimize_pop (z3obj_gnc x) (z3obj_gno x) 
- 
-  let get_reason_unknown ( x : opt ) =
-    Z3native.optimize_get_reason_unknown (z3obj_gnc x) (z3obj_gno x)
+  let mk_handle opt h = { opt; h }
+
+  let mk_opt (ctx:context) = Z3native.mk_optimize ctx
+  let get_help (x:optimize) = Z3native.optimize_get_help (gc x) x
+  let set_parameters (x:optimize) (p:Params.params) = Z3native.optimize_set_params (gc x) x p
+  let get_param_descrs (x:optimize) = Z3native.optimize_get_param_descrs (gc x) x
+
+  let add x constraints =
+    List.iter (Z3native.optimize_assert (gc x) x) constraints
+
+  let add_soft (x:optimize) (e:Expr.expr) (w:string) (s:Symbol.symbol) =
+    mk_handle x (Z3native.optimize_assert_soft (gc x) x e w s)
+
+  let maximize (x:optimize) (e:Expr.expr) = mk_handle x (Z3native.optimize_maximize (gc x) x e)
+  let minimize (x:optimize) (e:Expr.expr) = mk_handle x (Z3native.optimize_minimize (gc x) x e)
+
+  let check (x:optimize) =
+    let r = lbool_of_int (Z3native.optimize_check (gc x) x) in
+    match r with
+    | L_TRUE -> Solver.SATISFIABLE
+    | L_FALSE -> Solver.UNSATISFIABLE
+    | _ -> Solver.UNKNOWN
+
+  let get_model (x:optimize) =
+    let q = Z3native.optimize_get_model (gc x) x in
+    if Z3native.is_null_model q then None else Some q
+
+  let get_lower (x:handle) (idx:int) = Z3native.optimize_get_lower (gc x.opt) x.opt idx
+  let get_upper (x:handle) (idx:int) = Z3native.optimize_get_upper (gc x.opt) x.opt idx
+  let push (x:optimize) = Z3native.optimize_push (gc x) x
+  let pop (x:optimize) = Z3native.optimize_pop (gc x) x
+  let get_reason_unknown (x:optimize) = Z3native.optimize_get_reason_unknown (gc x) x
+  let to_string (x:optimize) = Z3native.optimize_to_string (gc x) x
+  let get_statistics (x:optimize) = Z3native.optimize_get_statistics (gc x) x
+end
 
-  let to_string ( x : opt ) = Z3native.optimize_to_string (z3obj_gnc x) (z3obj_gno x)  
- 
- 
-  let get_statistics ( x : opt ) = 
-     let s = Z3native.optimize_get_statistics (z3obj_gnc x) (z3obj_gno x) in 
-     (Statistics.create (z3obj_gc x) s) 
- 
- 
-end 
 
 module SMT =
 struct
-  let benchmark_to_smtstring ( ctx : context ) ( name : string ) ( logic : string ) ( status : string ) ( attributes : string ) ( assumptions : expr list ) ( formula : expr ) =
-    Z3native.benchmark_to_smtlib_string (context_gno ctx) name logic status attributes
-      (List.length assumptions) (let f x = Expr.gno (x) in (Array.of_list (List.map f assumptions)))
-      (Expr.gno formula)
+  let benchmark_to_smtstring (ctx:context) (name:string) (logic:string) (status:string) (attributes:string) (assumptions:expr list) (formula:expr) =
+    Z3native.benchmark_to_smtlib_string ctx name logic status attributes
+      (List.length assumptions) assumptions
+      formula
 
-  let parse_smtlib_string ( ctx : context ) ( str : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) =
+  let parse_smtlib_string (ctx:context) (str:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) =
+    let csn = List.length sort_names in
+    let cs = List.length sorts in
+    let cdn = List.length decl_names in
+    let cd = List.length decls in
+    if (csn <> cs || cdn <> cd) then
+      raise (Error "Argument size mismatch")
+    else
+      Z3native.parse_smtlib_string ctx str
+        cs sort_names sorts cd decl_names decls
+
+  let parse_smtlib_file (ctx:context) (file_name:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) =
     let csn = (List.length sort_names) in
     let cs = (List.length sorts) in
     let cdn = (List.length decl_names) in
     let cd = (List.length decls) in
-    if (csn != cs || cdn != cd) then 
-      raise (Z3native.Exception "Argument size mismatch")
+    if (csn <> cs || cdn <> cd) then
+      raise (Error "Argument size mismatch")
     else
-      Z3native.parse_smtlib_string (context_gno ctx) str 
-         cs 
-         (Symbol.symbol_lton sort_names)
-         (Sort.sort_lton sorts)
-         cd 
-         (Symbol.symbol_lton decl_names)
-         (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))
-     
-  let parse_smtlib_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) =
-    let csn = (List.length sort_names) in
-    let cs = (List.length sorts) in
-    let cdn = (List.length decl_names) in
-    let cd = (List.length decls) in
-    if (csn != cs || cdn != cd) then 
-      raise (Z3native.Exception "Argument size mismatch")
-    else
-      Z3native.parse_smtlib_file (context_gno ctx) file_name
-         cs 
-         (Symbol.symbol_lton sort_names)
-         (Sort.sort_lton sorts)
-         cd 
-         (Symbol.symbol_lton decl_names)
-         (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))
-        
-  let get_num_smtlib_formulas ( ctx : context ) = Z3native.get_smtlib_num_formulas (context_gno ctx)
+      Z3native.parse_smtlib_file ctx file_name
+        cs sort_names sorts cd decl_names decls
 
-  let get_smtlib_formulas ( ctx : context ) =
-    let n = (get_num_smtlib_formulas ctx ) in
-    let f i =(expr_of_ptr ctx (Z3native.get_smtlib_formula (context_gno ctx) i)) in
-    mk_list f n 
+  let get_num_smtlib_formulas (ctx:context) = Z3native.get_smtlib_num_formulas ctx
 
-  let get_num_smtlib_assumptions ( ctx : context ) = Z3native.get_smtlib_num_assumptions (context_gno ctx)
-
-  let get_smtlib_assumptions ( ctx : context ) =
-    let n = (get_num_smtlib_assumptions ctx ) in
-    let f i = (expr_of_ptr ctx (Z3native.get_smtlib_assumption (context_gno ctx) i)) in
+  let get_smtlib_formulas (ctx:context) =
+    let n = get_num_smtlib_formulas ctx in
+    let f i = Z3native.get_smtlib_formula ctx i in
     mk_list f n
 
-  let get_num_smtlib_decls ( ctx : context ) = Z3native.get_smtlib_num_decls (context_gno ctx)
+  let get_num_smtlib_assumptions (ctx:context) = Z3native.get_smtlib_num_assumptions ctx
 
-  let get_smtlib_decls ( ctx : context ) = 
-    let n = (get_num_smtlib_decls ctx) in
-    let f i = func_decl_of_ptr ctx (Z3native.get_smtlib_decl (context_gno ctx) i) in
+  let get_smtlib_assumptions (ctx:context) =
+    let n = get_num_smtlib_assumptions ctx in
+    let f i = Z3native.get_smtlib_assumption ctx i in
     mk_list f n
 
-  let get_num_smtlib_sorts ( ctx : context )  = Z3native.get_smtlib_num_sorts (context_gno ctx)
-    
-  let get_smtlib_sorts ( ctx : context ) = 
-    let n = (get_num_smtlib_sorts ctx) in
-    let f i = (Sort.sort_of_ptr ctx (Z3native.get_smtlib_sort (context_gno ctx) i)) in
+  let get_num_smtlib_decls (ctx:context) = Z3native.get_smtlib_num_decls ctx
+
+  let get_smtlib_decls (ctx:context) =
+    let n = get_num_smtlib_decls ctx in
+    let f i = Z3native.get_smtlib_decl ctx i in
     mk_list f n
 
-  let parse_smtlib2_string ( ctx : context ) ( str : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) =
-    let csn = (List.length sort_names) in
-    let cs = (List.length sorts) in
-    let cdn = (List.length decl_names) in
-    let cd = (List.length decls) in
-    if (csn != cs || cdn != cd) then 
-      raise (Z3native.Exception "Argument size mismatch")
+  let get_num_smtlib_sorts (ctx:context)  = Z3native.get_smtlib_num_sorts ctx
+
+  let get_smtlib_sorts (ctx:context) =
+    let n = get_num_smtlib_sorts ctx in
+    let f i = Z3native.get_smtlib_sort ctx i in
+    mk_list f n
+
+  let parse_smtlib2_string (ctx:context) (str:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) =
+    let csn = List.length sort_names in
+    let cs = List.length sorts in
+    let cdn = List.length decl_names in
+    let cd = List.length decls in
+    if csn <> cs || cdn <> cd then
+      raise (Error "Argument size mismatch")
     else
-      (expr_of_ptr ctx (Z3native.parse_smtlib2_string (context_gno ctx) str 
-                             cs 
-                             (Symbol.symbol_lton sort_names)
-                             (Sort.sort_lton sorts)
-                             cd 
-                             (Symbol.symbol_lton decl_names)
-                             (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))))
-         
-  let parse_smtlib2_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) =
-    let csn = (List.length sort_names) in
-    let cs = (List.length sorts) in
-    let cdn = (List.length decl_names) in
-    let cd = (List.length decls) in
-    if (csn != cs || cdn != cd) then 
-      raise (Z3native.Exception "Argument size mismatch")
+      Z3native.parse_smtlib2_string ctx str
+        cs sort_names sorts cd decl_names decls
+
+  let parse_smtlib2_file (ctx:context) (file_name:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) =
+    let csn = List.length sort_names in
+    let cs = List.length sorts in
+    let cdn = List.length decl_names in
+    let cd = List.length decls in
+    if csn <> cs || cdn <> cd then
+      raise (Error "Argument size mismatch")
     else
-      (expr_of_ptr ctx (Z3native.parse_smtlib2_string (context_gno ctx) file_name
-                             cs 
-                             (Symbol.symbol_lton sort_names)
-                             (Sort.sort_lton sorts)
-                             cd 
-                             (Symbol.symbol_lton decl_names)
-                             (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))))
+      Z3native.parse_smtlib2_string ctx file_name
+        cs sort_names sorts cd decl_names decls
 end
 
-module Interpolation = 
+module Interpolation =
 struct
-  let mk_interpolant ( ctx : context ) ( a : expr ) =
-    (expr_of_ptr ctx (Z3native.mk_interpolant (context_gno ctx) (Expr.gno a)))
-    
-  let mk_interpolation_context ( settings : ( string * string ) list ) =
+  let mk_interpolant = Z3native.mk_interpolant
+
+  let mk_interpolation_context (settings:(string * string) list) =
     let cfg = Z3native.mk_config () in
-    let f e = (Z3native.set_param_value cfg (fst e) (snd e)) in
-    (List.iter f settings) ;
-    let v = Z3native.mk_interpolation_context cfg in
-    Z3native.del_config(cfg) ;
-    Z3native.set_ast_print_mode v (int_of_ast_print_mode PRINT_SMTLIB2_COMPLIANT) ;
-    Z3native.set_internal_error_handler v ;
-    let res = { m_n_ctx = v; m_n_obj_cnt = 0 } in
-    let f = fun o -> dispose_context o in
-    Gc.finalise f res;
+    let f e = Z3native.set_param_value cfg (fst e) (snd e) in
+    List.iter f settings;
+    let res = Z3native.mk_interpolation_context cfg in
+    Z3native.del_config cfg;
+    Z3native.set_ast_print_mode res (int_of_ast_print_mode PRINT_SMTLIB2_COMPLIANT);
+    Z3native.set_internal_error_handler res;
     res
 
-  let get_interpolant ( ctx : context ) ( pf : expr ) ( pat: expr ) ( p : Params.params ) =
-    let av = (AST.ASTVector.create ctx (Z3native.get_interpolant (context_gno ctx) (Expr.gno pf) (Expr.gno pat) (z3obj_gno p))) in
+  let get_interpolant (ctx:context) (pf:expr) (pat:expr) (p:Params.params) =
+    let av = Z3native.get_interpolant ctx pf pat p in
     AST.ASTVector.to_expr_list av
-      
-  let compute_interpolant ( ctx : context ) ( pat : expr ) ( p : Params.params ) =
-    let (r, interp, model) = (Z3native.compute_interpolant (context_gno ctx) (Expr.gno pat) (z3obj_gno p)) in
-    let res = (lbool_of_int r) in
-    match res with
-      | L_TRUE -> (res, None, Some(Model.create ctx model))
-      | L_FALSE -> (res, Some((AST.ASTVector.to_expr_list (AST.ASTVector.create ctx interp))), None)
-      | _ -> (res, None, None)
-       
-  let get_interpolation_profile ( ctx : context ) =
-    (Z3native.interpolation_profile (context_gno ctx))
-      
-  let read_interpolation_problem ( ctx : context ) ( filename : string ) =
-    let (r, num, cnsts, parents, error, num_theory, theory) = (Z3native.read_interpolation_problem (context_gno ctx) filename) in
-    match r with 
-      | 0 -> raise (Z3native.Exception "Interpolation problem could not be read.")
-      | _ ->
-     let f1 i = (expr_of_ptr ctx (Array.get cnsts i)) in
-     let f2 i = (Array.get parents i) in
-     let f3 i = (expr_of_ptr ctx (Array.get theory i)) in 
-     ((mk_list f1 num),
-      (mk_list f2 num),
-      (mk_list f3 num_theory))
-          
-  let check_interpolant ( ctx : context ) ( num : int ) ( cnsts : Expr.expr list ) ( parents : int list ) ( interps : Expr.expr list ) ( num_theory : int ) ( theory : Expr.expr list ) =
-    let (r, str) = (Z3native.check_interpolant (context_gno ctx) 
-                num
-                (let f x = Expr.gno x in (Array.of_list (List.map f cnsts)))
-                (Array.of_list parents)
-                (let f x = Expr.gno x in (Array.of_list (List.map f interps)))
-                num_theory
-                (let f x = Expr.gno x in (Array.of_list (List.map f theory)))) in
-    match (lbool_of_int r) with
-      | L_UNDEF -> raise (Z3native.Exception "Interpolant could not be verified.")
-      | L_FALSE -> raise (Z3native.Exception "Interpolant could not be verified.")
-      | _ -> ()
 
-  let write_interpolation_problem ( ctx : context ) ( num : int ) ( cnsts : Expr.expr list ) ( parents : int list ) ( filename : string ) ( num_theory : int ) ( theory : Expr.expr list ) =
-    (Z3native.write_interpolation_problem (context_gno ctx) num (expr_lton cnsts) (Array.of_list parents) filename num_theory (expr_lton theory)) ;
-    ()
+  let compute_interpolant (ctx:context) (pat:expr) (p:Params.params) =
+    let (r, interp, model) = Z3native.compute_interpolant ctx pat p in
+    let res = lbool_of_int r in
+    match res with
+    | L_TRUE -> (res, None, Some model)
+    | L_FALSE -> (res, Some (AST.ASTVector.to_expr_list interp), None)
+    | _ -> (res, None, None)
+
+  let get_interpolation_profile = Z3native.interpolation_profile
+
+  let read_interpolation_problem (ctx:context) (filename:string) =
+    let (r, num, cnsts, parents, error, num_theory, theory) =
+      Z3native.read_interpolation_problem ctx filename
+    in
+    match r with
+    | 0 -> raise (Error "Interpolation problem could not be read.")
+    | _ -> (cnsts, parents, theory)
+
+  let check_interpolant (ctx:context) (num:int) (cnsts:Expr.expr list) (parents:int list) (interps:Expr.expr list) (num_theory:int) (theory:Expr.expr list) =
+    let (r, str) = Z3native.check_interpolant ctx num cnsts parents interps num_theory theory in
+    match (lbool_of_int r) with
+    | L_UNDEF -> raise (Error "Interpolant could not be verified.")
+    | L_FALSE -> raise (Error "Interpolant could not be verified.")
+    | _ -> ()
+
+  let write_interpolation_problem (ctx:context) (num:int) (cnsts:Expr.expr list) (parents:int list) (filename:string) (num_theory:int) (theory:Expr.expr list) =
+    Z3native.write_interpolation_problem ctx num cnsts parents filename num_theory theory
 end
 
-let set_global_param ( id : string ) ( value : string ) =
-  (Z3native.global_param_set id value)
+let set_global_param = Z3native.global_param_set
 
-let get_global_param ( id : string ) =
-  let (r, v) = (Z3native.global_param_get id) in
-  if not r then
-    None
-  else 
-    Some v
+let get_global_param id =
+  match Z3native.global_param_get id with
+  | (false, _) -> None
+  | (true, v) -> Some v
 
-let global_param_reset_all =
-  Z3native.global_param_reset_all
+let global_param_reset_all = Z3native.global_param_reset_all
 
-let toggle_warning_messages ( enabled : bool ) =
-  Z3native.toggle_warning_messages enabled
-
-let enable_trace ( tag : string ) =
-  (Z3native.enable_trace tag)
-
-let disable_trace ( tag : string ) =
-  (Z3native.enable_trace tag)
+let toggle_warning_messages = Z3native.toggle_warning_messages
 
+let enable_trace = Z3native.enable_trace
 
+let disable_trace = Z3native.enable_trace
diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli
index e69f7f576..9104b3080 100644
--- a/src/api/ml/z3.mli
+++ b/src/api/ml/z3.mli
@@ -5,19 +5,19 @@
    @author CM Wintersteiger (cwinter) 2012-12-17
 *)
 
-(** General Z3 exceptions 
+(** General Z3 exceptions
 
     Many functions in this API may throw an exception; if they do, it is this one.*)
 exception Error of string
 
 (** Context objects.
 
-    Most interactions with Z3 are interpreted in some context; many users will only 
-    require one such object, but power users may require more than one. To start using 
-    Z3, do 
+    Most interactions with Z3 are interpreted in some context; many users will only
+    require one such object, but power users may require more than one. To start using
+    Z3, do
 
     <code>
-    let ctx = (mk_context []) in 
+    let ctx = (mk_context []) in
     (...)
     </code>
 
@@ -26,17 +26,17 @@ exception Error of string
 
     <code>
     let cfg = [("model", "true"); ("...", "...")] in
-    let ctx = (mk_context cfg) in 
+    let ctx = (mk_context cfg) in
     (...)
     </code>
 *)
 type context
 
-(** Create a context object 
+(** Create a context object
     The following parameters can be set:
-    
+
     - proof  (Boolean)           Enable proof generation
-    - debug_ref_count (Boolean)  Enable debug support for Z3_ast reference counting 
+    - debug_ref_count (Boolean)  Enable debug support for Z3_ast reference counting
     - trace  (Boolean)           Tracing support for VCC
     - trace_file_name (String)   Trace out file for VCC traces
     - timeout (unsigned)         default timeout (in milliseconds) used for solvers
@@ -44,16 +44,16 @@ type context
     - auto_config                use heuristics to automatically select solver and configure it
     - model                      model generation for solvers, this parameter can be overwritten when creating a solver
     - model_validate             validate models produced by solvers
-    - unsat_core                 unsat-core generation for solvers, this parameter can be overwritten when creating a solver    
+    - unsat_core                 unsat-core generation for solvers, this parameter can be overwritten when creating a solver
 *)
 val mk_context : (string * string) list -> context
 
 (** Interaction logging for Z3
-    Note that this is a global, static log and if multiple Context 
+    Note that this is a global, static log and if multiple Context
     objects are created, it logs the interaction with all of them. *)
 module Log :
 sig
-  (** Open an interaction log file. 
+  (** Open an interaction log file.
       @return True if opening the log file succeeds, false otherwise. *)
   (* CMW: "open" is a reserved keyword. *)
   val open_ : string -> bool
@@ -107,7 +107,7 @@ sig
   (** A string representation of the symbol. *)
   val to_string : symbol -> string
 
-  (** Creates a new symbol using an integer.     
+  (** Creates a new symbol using an integer.
       Not all integers can be passed to this function.
       The legal range of unsigned integers is 0 to 2^30-1. *)
   val mk_int : context -> int -> symbol
@@ -125,21 +125,21 @@ end
 (** The abstract syntax tree (AST) module *)
 module rec AST :
 sig
-  type ast 
+  type ast
 
   (** Vectors of ASTs *)
   module ASTVector :
   sig
-    type ast_vector 
+    type ast_vector
 
     (** Create an empty AST vector *)
     val mk_ast_vector : context -> ast_vector
-      
+
     (** The size of the vector *)
     val get_size : ast_vector -> int
 
     (** Retrieves the i-th object in the vector.
-		@return An AST *)
+                @return An AST *)
     val get : ast_vector -> int -> ast
 
     (** Sets the i-th object in the vector. *)
@@ -149,11 +149,11 @@ sig
     val resize : ast_vector -> int -> unit
 
     (** Add an ast to the back of the vector. The size
-		is increased by 1. *)
+                is increased by 1. *)
     val push : ast_vector -> ast -> unit
 
     (** Translates all ASTs in the vector to another context.
-		@return A new ASTVector *)
+                @return A new ASTVector *)
     val translate : ast_vector -> context -> ast_vector
 
     (** Translates the ASTVector into an (Ast.ast list) *)
@@ -173,13 +173,13 @@ sig
 
     (** Create an empty mapping from AST to AST *)
     val mk_ast_map : context -> ast_map
-      
+
     (** Checks whether the map contains a key.
-		@return True if the key in the map, false otherwise. *)
+                @return True if the key in the map, false otherwise. *)
     val contains : ast_map -> ast -> bool
 
     (** Finds the value associated with the key.
-		This function signs an error when the key is not a key in the map. *)
+                This function signs an error when the key is not a key in the map. *)
     val find : ast_map -> ast -> ast
 
     (**   Stores or replaces a new key/value pair in the map. *)
@@ -208,7 +208,7 @@ sig
   (** A unique identifier for the AST (unique among all ASTs). *)
   val get_id : ast -> int
 
-  (** The kind of the AST.  *)    
+  (** The kind of the AST.  *)
   val get_ast_kind : ast -> Z3enums.ast_kind
 
   (** Indicates whether the AST is an Expr *)
@@ -233,7 +233,7 @@ sig
   val to_sexpr : ast -> string
 
   (** Comparison operator.
-      @return True if the two ast's are from the same context 
+      @return True if the two ast's are from the same context
       and represent the same sort; false otherwise. *)
   val equal : ast -> ast -> bool
 
@@ -244,36 +244,15 @@ sig
   (** Translates (copies) the AST to another context.
       @return A copy of the AST which is associated with the other context.  *)
   val translate : ast -> context -> ast
-
-  (** Unwraps an AST.
-      This function is used for transitions between native and 
-      managed objects. It returns the native pointer to the AST. Note that 
-      AST objects are reference counted and unwrapping an AST disables automatic
-      reference counting, i.e., all references to the IntPtr that is returned 
-      must be handled externally and through native calls (see e.g., 
-      [Z3native.inc_ref]).
-      {!wrap_ast} *)
-  val unwrap_ast : ast -> Z3native.ptr
-
-  (** Wraps an AST.
-
-      This function is used for transitions between native and 
-      managed objects. Note that the native ast that is passed must be a 
-      native object obtained from Z3 (e.g., through {!unwrap_ast})
-      and that it must have a correct reference count (see e.g., 
-      [Z3native.inc_ref]). *)
-  val wrap_ast : context -> Z3native.z3_ast -> ast
 end
 
 (** The Sort module implements type information for ASTs *)
 and Sort :
 sig
-  type sort = Sort of AST.ast
-
-  val ast_of_sort : sort -> AST.ast
+  type sort
 
   (** Comparison operator.
-      @return True if the two sorts are from the same context 
+      @return True if the two sorts are from the same context
       and represent the same sort; false otherwise. *)
   val equal : sort -> sort -> bool
 
@@ -299,23 +278,21 @@ end
 (** Function declarations *)
 and FuncDecl :
 sig
-  type func_decl = FuncDecl of AST.ast
-
-  val ast_of_func_decl : FuncDecl.func_decl -> AST.ast
+  type func_decl
 
   (** Parameters of Func_Decls *)
   module Parameter :
   sig
     (** Parameters of func_decls *)
     type parameter =
-		P_Int of int
+        P_Int of int
       | P_Dbl of float
       | P_Sym of Symbol.symbol
       | P_Srt of Sort.sort
       | P_Ast of AST.ast
       | P_Fdl of func_decl
       | P_Rat of string
-		  
+
     (** The kind of the parameter. *)
     val get_kind : parameter -> Z3enums.parameter_kind
 
@@ -377,10 +354,10 @@ sig
   (** The size of the domain of the function declaration
       {!get_arity} *)
   val get_domain_size : func_decl -> int
-    
+
   (** The domain of the function declaration *)
   val get_domain : func_decl -> Sort.sort list
-    
+
   (** The range of the function declaration *)
   val get_range : func_decl -> Sort.sort
 
@@ -396,7 +373,7 @@ sig
   (** The parameters of the function declaration *)
   val get_parameters : func_decl -> Parameter.parameter list
 
-  (** Create expression that applies function to arguments. *)	   
+  (** Create expression that applies function to arguments. *)
   val apply : func_decl -> Expr.expr list -> Expr.expr
 end
 
@@ -410,7 +387,7 @@ sig
   (** ParamDescrs describe sets of parameters (of Solvers, Tactics, ...) *)
   module ParamDescrs :
   sig
-    type param_descrs 
+    type param_descrs
 
     (** Validate a set of parameters. *)
     val validate : param_descrs -> params -> unit
@@ -447,19 +424,19 @@ sig
   val to_string : params -> string
 
   (** Update a mutable configuration parameter.
-      
+
       The list of all configuration parameters can be obtained using the Z3 executable:
       [z3.exe -p]
       Only a few configuration parameters are mutable once the context is created.
       An exception is thrown when trying to modify an immutable parameter. *)
   val update_param_value : context -> string -> string -> unit
-    
+
   (** Selects the format used for pretty-printing expressions.
-      
+
       The default mode for pretty printing expressions is to produce
-      SMT-LIB style output where common subexpressions are printed 
+      SMT-LIB style output where common subexpressions are printed
       at each occurrence. The mode is called PRINT_SMTLIB_FULL.
-      To print shared common subexpressions only once, 
+      To print shared common subexpressions only once,
       use the PRINT_LOW_LEVEL mode.
       To print in way that conforms to SMT-LIB standards and uses let
       expressions to share common sub-expressions use PRINT_SMTLIB_COMPLIANT.
@@ -473,7 +450,7 @@ end
 (** General Expressions (terms) *)
 and Expr :
 sig
-  type expr = Expr of AST.ast
+  type expr
 
   val ast_of_expr : Expr.expr -> AST.ast
   val expr_of_ast : AST.ast -> Expr.expr
@@ -494,7 +471,7 @@ sig
   (** The number of arguments of the expression. *)
   val get_num_args : Expr.expr -> int
 
-  (** The arguments of the expression. *)        
+  (** The arguments of the expression. *)
   val get_args : Expr.expr -> Expr.expr list
 
   (** Update the arguments of the expression using an array of expressions.
@@ -502,9 +479,9 @@ sig
   val update : Expr.expr -> Expr.expr list -> expr
 
   (** Substitute every occurrence of [from[i]] in the expression with [to[i]], for [i] smaller than [num_exprs].
-      
+
       The result is the new expression. The arrays [from] and [to] must have size [num_exprs].
-      For every [i] smaller than [num_exprs], we must have that 
+      For every [i] smaller than [num_exprs], we must have that
       sort of [from[i]] must be equal to sort of [to[i]]. *)
   val substitute : Expr.expr -> Expr.expr list -> Expr.expr list -> expr
 
@@ -521,14 +498,14 @@ sig
       @return A copy of the term which is associated with the other context *)
   val translate : Expr.expr -> context -> expr
 
-  (** Returns a string representation of the expression. *)    
+  (** Returns a string representation of the expression. *)
   val to_string : Expr.expr -> string
 
   (** Indicates whether the term is a numeral *)
   val is_numeral : Expr.expr -> bool
 
   (** Indicates whether the term is well-sorted.
-      @return True if the term is well-sorted, false otherwise. *)   
+      @return True if the term is well-sorted, false otherwise. *)
   val is_well_sorted : Expr.expr -> bool
 
   (** The Sort of the term. *)
@@ -536,31 +513,31 @@ sig
 
   (** Indicates whether the term represents a constant. *)
   val is_const : Expr.expr -> bool
-    
+
   (** Creates a new constant. *)
   val mk_const : context -> Symbol.symbol -> Sort.sort -> expr
-    
+
   (** Creates a new constant. *)
   val mk_const_s : context -> string -> Sort.sort -> expr
-    
+
   (** Creates a  constant from the func_decl. *)
   val mk_const_f : context -> FuncDecl.func_decl -> expr
-    
+
   (** Creates a fresh constant with a name prefixed with a string. *)
   val mk_fresh_const : context -> string -> Sort.sort -> expr
-    
+
   (** Create a new function application. *)
   val mk_app : context -> FuncDecl.func_decl -> Expr.expr list -> expr
-    
-  (** Create a numeral of a given sort.         
+
+  (** Create a numeral of a given sort.
       @return A Term with the given value and sort *)
   val mk_numeral_string : context -> string -> Sort.sort -> expr
-    
+
   (** Create a numeral of a given sort. This function can be use to create numerals that fit in a machine integer.
-      It is slightly faster than [MakeNumeral] since it is not necessary to parse a string.       
+      It is slightly faster than [MakeNumeral] since it is not necessary to parse a string.
       @return A Term with the given value and sort *)
   val mk_numeral_int : context -> int -> Sort.sort -> expr
-    
+
   (** Comparison operator.
       @return True if the two expr's are equal; false otherwise. *)
   val equal : expr -> expr -> bool
@@ -576,22 +553,22 @@ sig
   (** Create a Boolean sort *)
   val mk_sort : context -> Sort.sort
 
-  (** Create a Boolean constant. *)        
+  (** Create a Boolean constant. *)
   val mk_const : context -> Symbol.symbol -> Expr.expr
 
-  (** Create a Boolean constant. *)        
+  (** Create a Boolean constant. *)
   val mk_const_s : context -> string -> Expr.expr
 
-  (** The true Term. *)    
+  (** The true Term. *)
   val mk_true : context -> Expr.expr
 
-  (** The false Term. *)    
+  (** The false Term. *)
   val mk_false : context -> Expr.expr
 
-  (** Creates a Boolean value. *)        
+  (** Creates a Boolean value. *)
   val mk_val : context -> bool -> Expr.expr
 
-  (** Mk an expression representing [not(a)]. *)    
+  (** Mk an expression representing [not(a)]. *)
   val mk_not : context -> Expr.expr -> Expr.expr
 
   (** Create an expression representing an if-then-else: [ite(t1, t2, t3)]. *)
@@ -662,7 +639,7 @@ end
 (** Quantifier expressions *)
 module Quantifier :
 sig
-  type quantifier = Quantifier of Expr.expr
+  type quantifier
 
   val expr_of_quantifier : quantifier -> Expr.expr
   val quantifier_of_expr : Expr.expr -> quantifier
@@ -674,10 +651,7 @@ sig
       also called a multi-pattern. *)
   module Pattern :
   sig
-    type pattern = Pattern of AST.ast
-
-    val ast_of_pattern : pattern -> AST.ast
-    val pattern_of_ast : AST.ast -> pattern
+    type pattern
 
     (** The number of terms in the pattern. *)
     val get_num_terms : pattern -> int
@@ -691,7 +665,7 @@ sig
 
 
   (** The de-Burijn index of a bound variable.
-      
+
       Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain
       the meaning of de-Bruijn indices by indicating the compilation process from
       non-de-Bruijn formulas to de-Bruijn format.
@@ -722,19 +696,19 @@ sig
 
   (** The patterns. *)
   val get_patterns : quantifier -> Pattern.pattern list
-    
+
   (** The number of no-patterns. *)
   val get_num_no_patterns : quantifier -> int
-    
+
   (** The no-patterns. *)
   val get_no_patterns : quantifier -> Pattern.pattern list
 
   (** The number of bound variables. *)
   val get_num_bound : quantifier -> int
-    
+
   (** The symbols for the bound variables. *)
   val get_bound_variable_names : quantifier -> Symbol.symbol list
-    
+
   (** The sorts of the bound variables. *)
   val get_bound_variable_sorts : quantifier -> Sort.sort list
 
@@ -761,7 +735,7 @@ sig
 
   (** Create a Quantifier. *)
   val mk_quantifier : context -> Sort.sort list -> Symbol.symbol list -> Expr.expr -> int option -> Pattern.pattern list -> Expr.expr list -> Symbol.symbol option -> Symbol.symbol option -> quantifier
-    
+
   (** Create a Quantifier. *)
   val mk_quantifier : context -> bool -> Expr.expr list -> Expr.expr -> int option -> Pattern.pattern list -> Expr.expr list -> Symbol.symbol option -> Symbol.symbol option -> quantifier
 
@@ -775,28 +749,28 @@ sig
   (** Create a new array sort. *)
   val mk_sort : context -> Sort.sort -> Sort.sort -> Sort.sort
 
-  (** Indicates whether the term is an array store.        
-      It satisfies select(store(a,i,v),j) = if i = j then v else select(a,j). 
+  (** Indicates whether the term is an array store.
+      It satisfies select(store(a,i,v),j) = if i = j then v else select(a,j).
       Array store takes at least 3 arguments.  *)
   val is_store : Expr.expr -> bool
 
   (** Indicates whether the term is an array select. *)
   val is_select : Expr.expr -> bool
 
-  (** Indicates whether the term is a constant array.        
+  (** Indicates whether the term is a constant array.
       For example, select(const(v),i) = v holds for every v and i. The function is unary. *)
   val is_constant_array : Expr.expr -> bool
 
-  (** Indicates whether the term is a default array.        
+  (** Indicates whether the term is a default array.
       For example default(const(v)) = v. The function is unary. *)
   val is_default_array : Expr.expr -> bool
 
-  (** Indicates whether the term is an array map.     
+  (** Indicates whether the term is an array map.
       It satisfies map[f](a1,..,a_n)[i] = f(a1[i],...,a_n[i]) for every i. *)
   val is_array_map : Expr.expr -> bool
 
-  (** Indicates whether the term is an as-array term.        
-      An as-array term is n array value that behaves as the function graph of the 
+  (** Indicates whether the term is an as-array term.
+      An as-array term is n array value that behaves as the function graph of the
       function passed as parameter. *)
   val is_as_array : Expr.expr -> bool
 
@@ -805,54 +779,54 @@ sig
 
   (** The domain of the array sort. *)
   val get_domain : Sort.sort -> Sort.sort
-    
+
   (** The range of the array sort. *)
   val get_range : Sort.sort -> Sort.sort
-    
-  (** Create an array constant. *)        
+
+  (** Create an array constant. *)
   val mk_const : context -> Symbol.symbol -> Sort.sort -> Sort.sort -> Expr.expr
-    
-  (** Create an array constant. *)        
+
+  (** Create an array constant. *)
   val mk_const_s : context -> string -> Sort.sort -> Sort.sort -> Expr.expr
-    
-  (** Array read.       
-      
-      The argument [a] is the array and [i] is the index 
-      of the array that gets read.      
-      
-      The node [a] must have an array sort [[domain -> range]], 
+
+  (** Array read.
+
+      The argument [a] is the array and [i] is the index
+      of the array that gets read.
+
+      The node [a] must have an array sort [[domain -> range]],
       and [i] must have the sort [domain].
       The sort of the result is [range].
       {!Z3Array.mk_sort}
       {!mk_store} *)
   val mk_select : context -> Expr.expr -> Expr.expr -> Expr.expr
 
-  (** Array update.       
-      
-      The node [a] must have an array sort [[domain -> range]], 
+  (** Array update.
+
+      The node [a] must have an array sort [[domain -> range]],
       [i] must have sort [domain],
       [v] must have sort range. The sort of the result is [[domain -> range]].
       The semantics of this function is given by the theory of arrays described in the SMT-LIB
       standard. See http://smtlib.org for more details.
-      The result of this function is an array that is equal to [a] 
+      The result of this function is an array that is equal to [a]
       (with respect to [select])
-      on all indices except for [i], where it maps to [v] 
-      (and the [select] of [a] with 
+      on all indices except for [i], where it maps to [v]
+      (and the [select] of [a] with
       respect to [i] may be a different value).
       {!Z3Array.mk_sort}
       {!mk_select} *)
   val mk_store : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Create a constant array.
-      
-      The resulting term is an array, such that a [select]on an arbitrary index 
+
+      The resulting term is an array, such that a [select]on an arbitrary index
       produces the value [v].
       {!Z3Array.mk_sort}
       {!mk_select} *)
   val mk_const_array : context -> Sort.sort -> Expr.expr -> Expr.expr
 
   (** Maps f on the argument arrays.
-      
+
       Eeach element of [args] must be of an array sort [[domain_i -> range_i]].
       The function declaration [f] must have type [ range_1 .. range_n -> range].
       [v] must have sort range. The sort of the result is [[domain_i -> range]].
@@ -862,12 +836,12 @@ sig
   val mk_map : context -> FuncDecl.func_decl -> Expr.expr list -> Expr.expr
 
   (** Access the array default value.
-      
-      Produces the default range value, for arrays that can be represented as 
+
+      Produces the default range value, for arrays that can be represented as
       finite maps with a default range value. *)
   val mk_term_array : context -> Expr.expr -> Expr.expr
 
-  (** Create array extensionality index given two arrays with the same sort. 
+  (** Create array extensionality index given two arrays with the same sort.
 
       The meaning is given by the axiom:
           (=> (= (select A (array-ext A B)) (select B (array-ext A B))) (= A B)) *)
@@ -954,9 +928,9 @@ sig
   val is_relation : Expr.expr -> bool
 
   (** Indicates whether the term is an relation store
-      
+
       Insert a record into a relation.
-      The function takes [n+1] arguments, where the first argument is the relation and the remaining [n] elements 
+      The function takes [n+1] arguments, where the first argument is the relation and the remaining [n] elements
       correspond to the [n] columns of the relation. *)
   val is_store : Expr.expr -> bool
 
@@ -969,7 +943,7 @@ sig
   (** Indicates whether the term is a relational join *)
   val is_join : Expr.expr -> bool
 
-  (** Indicates whether the term is the union or convex hull of two relations. 
+  (** Indicates whether the term is the union or convex hull of two relations.
       The function takes two arguments. *)
   val is_union : Expr.expr -> bool
 
@@ -982,29 +956,29 @@ sig
   val is_project : Expr.expr -> bool
 
   (** Indicates whether the term is a relation filter
-      
+
       Filter (restrict) a relation with respect to a predicate.
-      The first argument is a relation. 
+      The first argument is a relation.
       The second argument is a predicate with free de-Brujin indices
       corresponding to the columns of the relation.
       So the first column in the relation has index 0. *)
   val is_filter : Expr.expr -> bool
 
   (** Indicates whether the term is an intersection of a relation with the negation of another.
-      
+
       Intersect the first relation with respect to negation
       of the second relation (the function takes two arguments).
       Logically, the specification can be described by a function
-      
+
       target = filter_by_negation(pos, neg, columns)
-      
+
       where columns are pairs c1, d1, .., cN, dN of columns from pos and neg, such that
       target are elements in ( x : expr ) in pos, such that there is no y in neg that agrees with
       ( x : expr ) on the columns c1, d1, .., cN, dN. *)
   val is_negation_filter : Expr.expr -> bool
 
   (** Indicates whether the term is the renaming of a column in a relation
-      
+
       The function takes one argument.
       The parameters contain the renaming as a cycle. *)
   val is_rename : Expr.expr -> bool
@@ -1013,18 +987,18 @@ sig
   val is_complement : Expr.expr -> bool
 
   (** Indicates whether the term is a relational select
-      
+
       Check if a record is an element of the relation.
       The function takes [n+1] arguments, where the first argument is a relation,
       and the remaining [n] arguments correspond to a record. *)
   val is_select : Expr.expr -> bool
 
   (** Indicates whether the term is a relational clone (copy)
-      
-      Create a fresh copy (clone) of a relation. 
+
+      Create a fresh copy (clone) of a relation.
       The function is logically the identity, but
-      in the context of a register machine allows 
-      for terms of kind {!is_union} 
+      in the context of a register machine allows
+      for terms of kind {!is_union}
       to perform destructive updates to the first argument. *)
   val is_clone : Expr.expr -> bool
 
@@ -1045,24 +1019,24 @@ sig
 
     (** The number of fields of the constructor. *)
     val get_num_fields : constructor -> int
-      
+
     (** The function declaration of the constructor. *)
     val get_constructor_decl : constructor -> FuncDecl.func_decl
 
     (** The function declaration of the tester. *)
     val get_tester_decl : constructor -> FuncDecl.func_decl
-      
+
     (** The function declarations of the accessors *)
     val get_accessor_decls : constructor -> FuncDecl.func_decl list
   end
 
   (** Create a datatype constructor.
-      if the corresponding sort reference is 0, then the value in sort_refs should be an index 
+      if the corresponding sort reference is 0, then the value in sort_refs should be an index
       referring to one of the recursive datatypes that is declared. *)
   val mk_constructor : context -> Symbol.symbol -> Symbol.symbol -> Symbol.symbol list -> Sort.sort option list -> int list -> Constructor.constructor
 
   (** Create a datatype constructor.
-      if the corresponding sort reference is 0, then the value in sort_refs should be an index 
+      if the corresponding sort reference is 0, then the value in sort_refs should be an index
       referring to one of the recursive datatypes that is declared. *)
   val mk_constructor_s : context -> string -> Symbol.symbol -> Symbol.symbol list -> Sort.sort option list -> int list -> Constructor.constructor
 
@@ -1078,13 +1052,12 @@ sig
   (** Create mutually recursive data-types. *)
   val mk_sorts_s : context -> string list -> Constructor.constructor list list -> Sort.sort list
 
-
   (** The number of constructors of the datatype sort. *)
   val get_num_constructors : Sort.sort -> int
 
   (** The constructors. *)
   val get_constructors : Sort.sort -> FuncDecl.func_decl list
-    
+
   (** The recognizers. *)
   val get_recognizers : Sort.sort -> FuncDecl.func_decl list
 
@@ -1154,7 +1127,7 @@ end
 (** Functions to manipulate Tuple expressions *)
 module Tuple :
 sig
-  (** Create a new tuple sort. *)    
+  (** Create a new tuple sort. *)
   val mk_sort : context -> Symbol.symbol -> Symbol.symbol list -> Sort.sort list -> Sort.sort
 
   (**  The constructor function of the tuple. *)
@@ -1173,7 +1146,7 @@ sig
   (** Integer Arithmetic *)
   module Integer :
   sig
-    (** Create a new integer sort. *)      
+    (** Create a new integer sort. *)
     val mk_sort : context -> Sort.sort
 
     (** Retrieve the int value. *)
@@ -1185,7 +1158,7 @@ sig
     (** Returns a string representation of a numeral. *)
     val numeral_to_string : Expr.expr -> string
 
-    (** Creates an integer constant. *)        
+    (** Creates an integer constant. *)
     val mk_const : context -> Symbol.symbol -> Expr.expr
 
     (** Creates an integer constant. *)
@@ -1206,21 +1179,21 @@ sig
         @return A Term with the given value and sort Integer *)
     val mk_numeral_i : context -> int -> Expr.expr
 
-    (** Coerce an integer to a real.    
-        
+    (** Coerce an integer to a real.
+
         There is also a converse operation exposed. It follows the semantics prescribed by the SMT-LIB standard.
-        
+
         You can take the floor of a real by creating an auxiliary integer Term [k] and
         and asserting [MakeInt2Real(k) <= t1 < MkInt2Real(k)+1].
         The argument must be of integer sort. *)
     val mk_int2real : context -> Expr.expr -> Expr.expr
 
-    (**   Create an n-bit bit-vector from an integer argument.  
-          
-          NB. This function is essentially treated as uninterpreted. 
+    (**   Create an n-bit bit-vector from an integer argument.
+
+          NB. This function is essentially treated as uninterpreted.
           So you cannot expect Z3 to precisely reflect the semantics of this function
           when solving constraints with this function.
-          
+
           The argument must be of integer sort. *)
     val mk_int2bv : context -> int -> Expr.expr -> Expr.expr
   end
@@ -1228,7 +1201,7 @@ sig
   (** Real Arithmetic *)
   module Real :
   sig
-    (** Create a real sort. *)    
+    (** Create a real sort. *)
     val mk_sort : context -> Sort.sort
 
     (** The numerator of a rational numeral. *)
@@ -1240,7 +1213,7 @@ sig
     (** Get a ratio from a real numeral *)
     val get_ratio : Expr.expr -> Ratio.ratio
 
-    (** Returns a string representation in decimal notation. 
+    (** Returns a string representation in decimal notation.
         The result has at most as many decimal places as indicated by the int argument.*)
     val to_decimal_string : Expr.expr-> int -> string
 
@@ -1253,7 +1226,7 @@ sig
     (** Creates a real constant. *)
     val mk_const_s : context -> string -> Expr.expr
 
-    (** Create a real numeral from a fraction.       
+    (** Create a real numeral from a fraction.
         @return A Term with rational value and sort Real
         {!mk_numeral_s} *)
     val mk_numeral_nd : context -> int -> int -> Expr.expr
@@ -1274,26 +1247,26 @@ sig
         The semantics of this function follows the SMT-LIB standard for the function to_int.
         The argument must be of real sort. *)
     val mk_real2int : context -> Expr.expr -> Expr.expr
-      
+
     (** Algebraic Numbers *)
     module AlgebraicNumber :
     sig
-      (** Return a upper bound for a given real algebraic number. 
+      (** Return a upper bound for a given real algebraic number.
           The interval isolating the number is smaller than 1/10^precision.
-          {!is_algebraic_number}   
+          {!is_algebraic_number}
           @return A numeral Expr of sort Real *)
       val to_upper : Expr.expr -> int -> Expr.expr
-        
-      (** Return a lower bound for the given real algebraic number. 
+
+      (** Return a lower bound for the given real algebraic number.
           The interval isolating the number is smaller than 1/10^precision.
           {!is_algebraic_number}
           @return A numeral Expr of sort Real *)
       val to_lower : Expr.expr -> int -> Expr.expr
-        
-      (** Returns a string representation in decimal notation. 
+
+      (** Returns a string representation in decimal notation.
           The result has at most as many decimal places as the int argument provided.*)
       val to_decimal_string : Expr.expr -> int -> string
-        
+
       (** Returns a string representation of a numeral. *)
       val numeral_to_string : Expr.expr -> string
     end
@@ -1362,34 +1335,34 @@ sig
   (** Indicates whether the term is an algebraic number *)
   val is_algebraic_number : Expr.expr -> bool
 
-  (** Create an expression representing [t[0] + t[1] + ...]. *)    
+  (** Create an expression representing [t[0] + t[1] + ...]. *)
   val mk_add : context -> Expr.expr list -> Expr.expr
 
-  (** Create an expression representing [t[0] * t[1] * ...]. *)    
+  (** Create an expression representing [t[0] * t[1] * ...]. *)
   val mk_mul : context -> Expr.expr list -> Expr.expr
 
-  (** Create an expression representing [t[0] - t[1] - ...]. *)    
+  (** Create an expression representing [t[0] - t[1] - ...]. *)
   val mk_sub : context -> Expr.expr list -> Expr.expr
 
-  (** Create an expression representing [-t]. *)    
+  (** Create an expression representing [-t]. *)
   val mk_unary_minus : context -> Expr.expr -> Expr.expr
 
-  (** Create an expression representing [t1 / t2]. *)    
+  (** Create an expression representing [t1 / t2]. *)
   val mk_div : context -> Expr.expr -> Expr.expr -> Expr.expr
 
-  (** Create an expression representing [t1 ^ t2]. *)    
+  (** Create an expression representing [t1 ^ t2]. *)
   val mk_power : context -> Expr.expr -> Expr.expr -> Expr.expr
 
-  (** Create an expression representing [t1 < t2] *)    
+  (** Create an expression representing [t1 < t2] *)
   val mk_lt : context -> Expr.expr -> Expr.expr -> Expr.expr
 
-  (** Create an expression representing [t1 <= t2] *)    
+  (** Create an expression representing [t1 <= t2] *)
   val mk_le : context -> Expr.expr -> Expr.expr -> Expr.expr
 
-  (** Create an expression representing [t1 > t2] *)    
+  (** Create an expression representing [t1 > t2] *)
   val mk_gt : context -> Expr.expr -> Expr.expr -> Expr.expr
 
-  (** Create an expression representing [t1 >= t2] *)    
+  (** Create an expression representing [t1 >= t2] *)
   val mk_ge : context -> Expr.expr -> Expr.expr -> Expr.expr
 end
 
@@ -1544,22 +1517,22 @@ sig
   (** Indicates whether the term is a bit-vector rotate right (extended)
       Similar to Z3_OP_ROTATE_RIGHT, but it is a binary operator instead of a parametric one. *)
   val is_bv_rotaterightextended : Expr.expr -> bool
-    
+
   (** Indicates whether the term is a coercion from bit-vector to integer
-      This function is not supported by the decision procedures. Only the most 
+      This function is not supported by the decision procedures. Only the most
       rudimentary simplification rules are applied to this function. *)
   val is_int2bv : Expr.expr -> bool
 
   (** Indicates whether the term is a coercion from integer to bit-vector
-      This function is not supported by the decision procedures. Only the most 
+      This function is not supported by the decision procedures. Only the most
       rudimentary simplification rules are applied to this function. *)
   val is_bv2int : Expr.expr -> bool
 
   (** Indicates whether the term is a bit-vector carry
-      Compute the carry bit in a full-adder.  The meaning is given by the 
+      Compute the carry bit in a full-adder.  The meaning is given by the
       equivalence (carry l1 l2 l3) <=> (or (and l1 l2) (and l1 l3) (and l2 l3))) *)
   val is_bv_carry : Expr.expr -> bool
-    
+
   (** Indicates whether the term is a bit-vector ternary XOR
       The meaning is given by the equivalence (xor3 l1 l2 l3) <=> (xor (xor l1 l2) l3) *)
   val is_bv_xor3 : Expr.expr -> bool
@@ -1569,7 +1542,7 @@ sig
 
   (**  Retrieve the int value. *)
   val get_int : Expr.expr -> int
-    
+
   (** Returns a string representation of a numeral. *)
   val numeral_to_string : Expr.expr -> string
 
@@ -1632,7 +1605,7 @@ sig
   val mk_mul : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Unsigned division.
-      
+
       It is defined as the floor of [t1/t2] if \c t2 is
       different from zero. If [t2] is zero, then the result
       is undefined.
@@ -1640,7 +1613,7 @@ sig
   val mk_udiv : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Signed division.
-      
+
       It is defined in the following way:
 
       - The \c floor of [t1/t2] if \c t2 is different from zero, and [t1*t2 >= 0].
@@ -1652,14 +1625,14 @@ sig
   val mk_sdiv : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Unsigned remainder.
-      
-      It is defined as [t1 - (t1 /u t2) * t2], where [/u] represents unsigned division.       
+
+      It is defined as [t1 - (t1 /u t2) * t2], where [/u] represents unsigned division.
       If [t2] is zero, then the result is undefined.
       The arguments must have the same bit-vector sort. *)
   val mk_urem : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Signed remainder.
-      
+
       It is defined as [t1 - (t1 /s t2) * t2], where [/s] represents signed division.
       The most significant bit (sign) of the result is equal to the most significant bit of \c t1.
 
@@ -1668,63 +1641,63 @@ sig
   val mk_srem : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Two's complement signed remainder (sign follows divisor).
-      
+
       If [t2] is zero, then the result is undefined.
       The arguments must have the same bit-vector sort. *)
   val mk_smod : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Unsigned less-than
-      
+
       The arguments must have the same bit-vector sort. *)
   val mk_ult : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Two's complement signed less-than
-      
+
       The arguments must have the same bit-vector sort. *)
   val mk_slt : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Unsigned less-than or equal to.
-      
+
       The arguments must have the same bit-vector sort. *)
   val mk_ule : context -> Expr.expr -> Expr.expr -> Expr.expr
-    
+
   (** Two's complement signed less-than or equal to.
-      
+
       The arguments must have the same bit-vector sort. *)
   val mk_sle : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Unsigned greater than or equal to.
-      
+
       The arguments must have the same bit-vector sort. *)
   val mk_uge : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Two's complement signed greater than or equal to.
-      
+
       The arguments must have the same bit-vector sort. *)
   val mk_sge : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Unsigned greater-than.
-      
+
       The arguments must have the same bit-vector sort. *)
   val mk_ugt : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Two's complement signed greater-than.
-      
+
       The arguments must have the same bit-vector sort. *)
   val mk_sgt : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Bit-vector concatenation.
-      
+
       The arguments must have a bit-vector sort.
-      @return 
-      The result is a bit-vector of size [n1+n2], where [n1] ([n2]) 
+      @return
+      The result is a bit-vector of size [n1+n2], where [n1] ([n2])
       is the size of [t1] ([t2]). *)
   val mk_concat : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Bit-vector extraction.
-      
+
       Extract the bits between two limits from a bitvector of
-      size [m] to yield a new bitvector of size [n], where 
+      size [m] to yield a new bitvector of size [n], where
       [n = high - low + 1]. *)
   val mk_extract : context -> int -> int -> Expr.expr -> Expr.expr
 
@@ -1740,38 +1713,38 @@ sig
       bitvector of size [m+i], where \c m is the size of the
       given bit-vector. *)
   val mk_zero_ext : context -> int -> Expr.expr -> Expr.expr
-    
+
   (** Bit-vector repetition. *)
   val mk_repeat : context -> int -> Expr.expr -> Expr.expr
 
   (** Shift left.
 
       It is equivalent to multiplication by [2^x] where \c x is the value of third argument.
-      
-      NB. The semantics of shift operations varies between environments. This 
-      definition does not necessarily capture directly the semantics of the 
+
+      NB. The semantics of shift operations varies between environments. This
+      definition does not necessarily capture directly the semantics of the
       programming language or assembly architecture you are modeling.*)
   val mk_shl : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Logical shift right
-      
+
       It is equivalent to unsigned division by [2^x] where \c x is the value of the third argument.
 
-      NB. The semantics of shift operations varies between environments. This 
-      definition does not necessarily capture directly the semantics of the 
+      NB. The semantics of shift operations varies between environments. This
+      definition does not necessarily capture directly the semantics of the
       programming language or assembly architecture you are modeling.
 
       The arguments must have a bit-vector sort. *)
   val mk_lshr : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Arithmetic shift right
-      
+
       It is like logical shift right except that the most significant
       bits of the result always copy the most significant bit of the
       second argument.
 
-      NB. The semantics of shift operations varies between environments. This 
-      definition does not necessarily capture directly the semantics of the 
+      NB. The semantics of shift operations varies between environments. This
+      definition does not necessarily capture directly the semantics of the
       programming language or assembly architecture you are modeling.
 
       The arguments must have a bit-vector sort. *)
@@ -1781,70 +1754,70 @@ sig
       Rotate bits of \c t to the left \c i times. *)
   val mk_rotate_left : context -> int -> Expr.expr -> Expr.expr
 
-  (** Rotate Right.      
+  (** Rotate Right.
       Rotate bits of \c t to the right \c i times.*)
   val mk_rotate_right : context -> int -> Expr.expr -> Expr.expr
 
-  (** Rotate Left.     
+  (** Rotate Left.
       Rotate bits of the second argument to the left.*)
   val mk_ext_rotate_left : context -> Expr.expr -> Expr.expr -> Expr.expr
 
-  (** Rotate Right.     
+  (** Rotate Right.
       Rotate bits of the second argument to the right. *)
   val mk_ext_rotate_right : context -> Expr.expr -> Expr.expr -> Expr.expr
 
-  (** Create an integer from the bit-vector argument 
-      
-      If \c is_signed is false, then the bit-vector \c t1 is treated as unsigned. 
-      So the result is non-negative and in the range [[0..2^N-1]], where 
+  (** Create an integer from the bit-vector argument
+
+      If \c is_signed is false, then the bit-vector \c t1 is treated as unsigned.
+      So the result is non-negative and in the range [[0..2^N-1]], where
       N are the number of bits in the argument.
       If \c is_signed is true, \c t1 is treated as a signed bit-vector.
-      
-      NB. This function is essentially treated as uninterpreted. 
+
+      NB. This function is essentially treated as uninterpreted.
       So you cannot expect Z3 to precisely reflect the semantics of this function
       when solving constraints with this function.*)
   val mk_bv2int : context -> Expr.expr -> bool -> Expr.expr
-    
+
   (** Create a predicate that checks that the bit-wise addition does not overflow.
-      
+
       The arguments must be of bit-vector sort. *)
   val mk_add_no_overflow : context -> Expr.expr -> Expr.expr -> bool -> Expr.expr
 
   (** Create a predicate that checks that the bit-wise addition does not underflow.
-      
+
       The arguments must be of bit-vector sort. *)
   val mk_add_no_underflow : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Create a predicate that checks that the bit-wise subtraction does not overflow.
-      
+
       The arguments must be of bit-vector sort. *)
   val mk_sub_no_overflow : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Create a predicate that checks that the bit-wise subtraction does not underflow.
-      
+
       The arguments must be of bit-vector sort. *)
   val mk_sub_no_underflow : context -> Expr.expr -> Expr.expr -> bool -> Expr.expr
 
   (** Create a predicate that checks that the bit-wise signed division does not overflow.
-      
+
       The arguments must be of bit-vector sort. *)
   val mk_sdiv_no_overflow : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Create a predicate that checks that the bit-wise negation does not overflow.
-      
-      The arguments must be of bit-vector sort. *)      
+
+      The arguments must be of bit-vector sort. *)
   val mk_neg_no_overflow : context -> Expr.expr -> Expr.expr
 
   (** Create a predicate that checks that the bit-wise multiplication does not overflow.
-      
+
       The arguments must be of bit-vector sort. *)
   val mk_mul_no_overflow : context -> Expr.expr -> Expr.expr -> bool -> Expr.expr
 
   (** Create a predicate that checks that the bit-wise multiplication does not underflow.
-      
+
       The arguments must be of bit-vector sort. *)
   val mk_mul_no_underflow : context -> Expr.expr -> Expr.expr -> Expr.expr
-    
+
   (** Create a bit-vector numeral. *)
   val mk_numeral : context -> string -> int -> Expr.expr
 end
@@ -1853,7 +1826,7 @@ end
 module FloatingPoint :
 sig
 
-  (** Rounding Modes *)    
+  (** Rounding Modes *)
   module RoundingMode :
   sig
     (** Create the RoundingMode sort. *)
@@ -1864,47 +1837,47 @@ sig
 
     (** Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. *)
     val mk_round_nearest_ties_to_even : context -> Expr.expr
-      
+
     (** Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. *)
     val mk_rne : context -> Expr.expr
 
     (** Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. *)
     val mk_round_nearest_ties_to_away : context -> Expr.expr
-      
+
     (** Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. *)
     val mk_rna : context -> Expr.expr
-      
+
     (** Create a numeral of RoundingMode sort which represents the TowardPositive rounding mode. *)
     val mk_round_toward_positive : context -> Expr.expr
-      
+
     (** Create a numeral of RoundingMode sort which represents the TowardPositive rounding mode. *)
     val mk_rtp : context -> Expr.expr
-      
+
     (** Create a numeral of RoundingMode sort which represents the TowardNegative rounding mode. *)
     val mk_round_toward_negative : context -> Expr.expr
-      
+
     (** Create a numeral of RoundingMode sort which represents the TowardNegative rounding mode. *)
     val mk_rtn : context -> Expr.expr
-      
+
     (** Create a numeral of RoundingMode sort which represents the TowardZero rounding mode. *)
     val mk_round_toward_zero : context -> Expr.expr
-      
+
     (** Create a numeral of RoundingMode sort which represents the TowardZero rounding mode. *)
     val mk_rtz : context -> Expr.expr
   end
 
   (** Create a FloatingPoint sort. *)
   val mk_sort : context -> int -> int -> Sort.sort
-    
-  (** Create the half-precision (16-bit) FloatingPoint sort.*) 
+
+  (** Create the half-precision (16-bit) FloatingPoint sort.*)
   val mk_sort_half : context -> Sort.sort
-    
+
   (** Create the half-precision (16-bit) FloatingPoint sort. *)
   val mk_sort_16 : context -> Sort.sort
 
   (** Create the single-precision (32-bit) FloatingPoint sort.*)
   val mk_sort_single : context -> Sort.sort
-    
+
   (** Create the single-precision (32-bit) FloatingPoint sort. *)
   val mk_sort_32 : context -> Sort.sort
 
@@ -1913,7 +1886,7 @@ sig
 
   (** Create the double-precision (64-bit) FloatingPoint sort. *)
   val mk_sort_64 : context -> Sort.sort
-    
+
   (** Create the quadruple-precision (128-bit) FloatingPoint sort. *)
   val mk_sort_quadruple : context -> Sort.sort
 
@@ -1929,11 +1902,11 @@ sig
   (** Create a floating-point zero of a given FloatingPoint sort. *)
   val mk_zero : context -> Sort.sort -> bool -> Expr.expr
 
-  (** Create an expression of FloatingPoint sort from three bit-vector expressions. 
+  (** Create an expression of FloatingPoint sort from three bit-vector expressions.
 
       This is the operator named `fp' in the SMT FP theory definition.
-      Note that \c sign is required to be a bit-vector of size 1. Significand and exponent 
-      are required to be greater than 1 and 2 respectively. The FloatingPoint sort 
+      Note that \c sign is required to be a bit-vector of size 1. Significand and exponent
+      are required to be greater than 1 and 2 respectively. The FloatingPoint sort
       of the resulting expression is automatically determined from the bit-vector sizes
       of the arguments. *)
   val mk_fp : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
@@ -1946,16 +1919,16 @@ sig
 
   (** Create a numeral of FloatingPoint sort from a signed integer. *)
   val mk_numeral_i : context -> int -> Sort.sort -> Expr.expr
-    
+
   (** Create a numeral of FloatingPoint sort from a sign bit and two integers. *)
   val mk_numeral_i_u : context -> bool -> int -> int -> Sort.sort -> Expr.expr
 
   (** Create a numeral of FloatingPoint sort from a string *)
   val mk_numeral_s : context -> string -> Sort.sort -> Expr.expr
-    
+
   (** Indicates whether the terms is of floating-point sort. *)
   val is_fp : Expr.expr -> bool
-    
+
 
   (** Indicates whether an expression is a floating-point abs expression *)
   val is_abs : Expr.expr -> bool
@@ -1965,7 +1938,7 @@ sig
 
   (** Indicates whether an expression is a floating-point add expression *)
   val is_add : Expr.expr -> bool
-    
+
   (** Indicates whether an expression is a floating-point sub expression *)
   val is_sub : Expr.expr -> bool
 
@@ -2022,7 +1995,7 @@ sig
 
   (** Indicates whether an expression is a floating-point is_nan expression *)
   val is_is_nan : Expr.expr -> bool
-    
+
   (** Indicates whether an expression is a floating-point is_negative expression *)
   val is_is_negative : Expr.expr -> bool
 
@@ -2077,16 +2050,16 @@ sig
 
   (** Floating-point fused multiply-add. *)
   val mk_fma : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
-    
+
   (** Floating-point square root *)
   val mk_sqrt : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Floating-point remainder *)
   val mk_rem : context -> Expr.expr -> Expr.expr -> Expr.expr
-    
-  (** Floating-point roundToIntegral. 
 
-      Rounds a floating-point number to the closest integer, 
+  (** Floating-point roundToIntegral.
+
+      Rounds a floating-point number to the closest integer,
       again represented as a floating-point number. *)
   val mk_round_to_integral : context -> Expr.expr -> Expr.expr -> Expr.expr
 
@@ -2095,16 +2068,16 @@ sig
 
   (** Maximum of floating-point numbers. *)
   val mk_max : context -> Expr.expr -> Expr.expr -> Expr.expr
-    
+
   (** Floating-point less than or equal. *)
   val mk_leq : context -> Expr.expr -> Expr.expr -> Expr.expr
-    
+
   (** Floating-point less than. *)
   val mk_lt : context -> Expr.expr -> Expr.expr -> Expr.expr
 
   (** Floating-point greater than or equal. *)
   val mk_geq : context -> Expr.expr -> Expr.expr -> Expr.expr
-    
+
   (** Floating-point greater than. *)
   val mk_gt : context -> Expr.expr -> Expr.expr -> Expr.expr
 
@@ -2149,27 +2122,27 @@ sig
 
   (** C1onversion of a floating-point term into an unsigned bit-vector. *)
   val mk_to_ubv : context -> Expr.expr -> Expr.expr -> int -> Expr.expr
-    
+
   (** Conversion of a floating-point term into a signed bit-vector. *)
   val mk_to_sbv : context -> Expr.expr -> Expr.expr -> int -> Expr.expr
 
   (** Conversion of a floating-point term into a real-numbered term. *)
   val mk_to_real : context -> Expr.expr -> Expr.expr
-    
+
   (** Retrieves the number of bits reserved for the exponent in a FloatingPoint sort. *)
   val get_ebits : context -> Sort.sort -> int
 
   (** Retrieves the number of bits reserved for the significand in a FloatingPoint sort. *)
   val get_sbits : context -> Sort.sort -> int
-    
+
   (** Retrieves the sign of a floating-point literal. *)
   val get_numeral_sign : context -> Expr.expr -> bool * int
 
   (** Return the significand value of a floating-point numeral as a string. *)
   val get_numeral_significand_string : context -> Expr.expr -> string
 
-  (** Return the significand value of a floating-point numeral as a uint64. 
-      Remark: This function extracts the significand bits, without the 
+  (** Return the significand value of a floating-point numeral as a uint64.
+      Remark: This function extracts the significand bits, without the
       hidden bit or normalization. Throws an exception if the
       significand does not fit into a uint64. *)
   val get_numeral_significand_uint : context -> Expr.expr -> bool * int
@@ -2179,7 +2152,7 @@ sig
 
   (** Return the exponent value of a floating-point numeral as a signed integer *)
   val get_numeral_exponent_int : context -> Expr.expr -> bool * int
-    
+
   (** Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format. *)
   val mk_to_ieee_bv : context -> Expr.expr -> Expr.expr
 
@@ -2203,13 +2176,13 @@ sig
   (** Indicates whether the term is a proof for a fact (tagged as goal) asserted by the user. *)
   val is_goal : Expr.expr -> bool
 
-  (** Indicates whether the term is a binary equivalence modulo namings. 
+  (** Indicates whether the term is a binary equivalence modulo namings.
       This binary predicate is used in proof terms.
       It captures equisatisfiability and equivalence modulo renamings. *)
   val is_oeq : Expr.expr -> bool
 
   (** Indicates whether the term is proof via modus ponens
-      
+
       Given a proof for p and a proof for (implies p q), produces a proof for q.
       T1: p
       T2: (implies p q)
@@ -2218,14 +2191,14 @@ sig
   val is_modus_ponens : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for (R t t), where R is a reflexive relation.
-      This proof object has no antecedents. 
-      The only reflexive relations that are used are 
+      This proof object has no antecedents.
+      The only reflexive relations that are used are
       equivalence modulo namings, equality and equivalence.
       That is, R is either '~', '=' or 'iff'. *)
   val is_reflexivity : Expr.expr -> bool
 
   (** Indicates whether the term is proof by symmetricity of a relation
-      
+
       Given an symmetric relation R and a proof for (R t s), produces a proof for (R s t).
       T1: (R t s)
       [symmetry T1]: (R s t)
@@ -2233,51 +2206,51 @@ sig
   val is_symmetry : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by transitivity of a relation
-      
-      Given a transitive relation R, and proofs for (R t s) and (R s u), produces a proof 
-      for (R t u). 
+
+      Given a transitive relation R, and proofs for (R t s) and (R s u), produces a proof
+      for (R t u).
       T1: (R t s)
       T2: (R s u)
       [trans T1 T2]: (R t u) *)
   val is_transitivity : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by condensed transitivity of a relation
-      
+
       Condensed transitivity proof. This proof object is only used if the parameter PROOF_MODE is 1.
-      It combines several symmetry and transitivity proofs. 
+      It combines several symmetry and transitivity proofs.
       Example:
       T1: (R a b)
       T2: (R c b)
       T3: (R c d)
-      [trans* T1 T2 T3]: (R a d)          
+      [trans* T1 T2 T3]: (R a d)
       R must be a symmetric and transitive relation.
-      
+
       Assuming that this proof object is a proof for (R s t), then
       a proof checker must check if it is possible to prove (R s t)
-      using the antecedents, symmetry and transitivity.  That is, 
+      using the antecedents, symmetry and transitivity.  That is,
       if there is a path from s to t, if we view every
       antecedent (R a b) as an edge between a and b. *)
   val is_Transitivity_star : Expr.expr -> bool
 
   (** Indicates whether the term is a monotonicity proof object.
-      
+
       T1: (R t_1 s_1)
       ...
       Tn: (R t_n s_n)
-      [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n))          
+      [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n))
       Remark: if t_i == s_i, then the antecedent Ti is suppressed.
       That is, reflexivity proofs are supressed to save space. *)
   val is_monotonicity : Expr.expr -> bool
 
-  (** Indicates whether the term is a quant-intro proof 
-      
+  (** Indicates whether the term is a quant-intro proof
+
       Given a proof for (~ p q), produces a proof for (~ (forall (x) p) (forall (x) q)).
       T1: (~ p q)
       [quant-intro T1]: (~ (forall (x) p) (forall (x) q)) *)
   val is_quant_intro : Expr.expr -> bool
 
-  (** Indicates whether the term is a distributivity proof object.  
-      
+  (** Indicates whether the term is a distributivity proof object.
+
       Given that f (= or) distributes over g (= and), produces a proof for
       (= (f a (g c d))
       (g (f a c) (f a d)))
@@ -2285,36 +2258,36 @@ sig
       (= (f (g a b) (g c d))
       (g (f a c) (f a d) (f b c) (f b d)))
       where each f and g can have arbitrary number of arguments.
-      
+
       This proof object has no antecedents.
-      Remark. This rule is used by the CNF conversion pass and 
+      Remark. This rule is used by the CNF conversion pass and
       instantiated by f = or, and g = and. *)
   val is_distributivity : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by elimination of AND
-      
+
       Given a proof for (and l_1 ... l_n), produces a proof for l_i
       T1: (and l_1 ... l_n)
       [and-elim T1]: l_i *)
   val is_and_elimination : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by eliminiation of not-or
-      
+
       Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i).
       T1: (not (or l_1 ... l_n))
       [not-or-elim T1]: (not l_i)        *)
   val is_or_elimination : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by rewriting
-      
+
       A proof for a local rewriting step (= t s).
       The head function symbol of t is interpreted.
-      
+
       This proof object has no antecedents.
-      The conclusion of a rewrite rule is either an equality (= t s), 
+      The conclusion of a rewrite rule is either an equality (= t s),
       an equivalence (iff t s), or equi-satisfiability (~ t s).
       Remark: if f is bool, then = is iff.
-      
+
       Examples:
       (= (+ ( x : expr ) 0) x)
       (= (+ ( x : expr ) 1 2) (+ 3 x))
@@ -2322,7 +2295,7 @@ sig
   val is_rewrite : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by rewriting
-      
+
       A proof for rewriting an expression t into an expression s.
       This proof object is used if the parameter PROOF_MODE is 1.
       This proof object can have n antecedents.
@@ -2335,49 +2308,49 @@ sig
   val is_rewrite_star : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for pulling quantifiers out.
-      
+
       A proof for (iff (f (forall (x) q(x)) r) (forall (x) (f (q x) r))). This proof object has no antecedents. *)
   val is_pull_quant : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for pulling quantifiers out.
-      
-      A proof for (iff P Q) where Q is in prenex normal form. 
-      This proof object is only used if the parameter PROOF_MODE is 1.       
+
+      A proof for (iff P Q) where Q is in prenex normal form.
+      This proof object is only used if the parameter PROOF_MODE is 1.
       This proof object has no antecedents *)
   val is_pull_quant_star : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for pushing quantifiers in.
-      
+
       A proof for:
       (iff (forall (x_1 ... x_m) (and p_1[x_1 ... x_m] ... p_n[x_1 ... x_m]))
       (and (forall (x_1 ... x_m) p_1[x_1 ... x_m])
-      ... 
-      (forall (x_1 ... x_m) p_n[x_1 ... x_m])))               
+      ...
+      (forall (x_1 ... x_m) p_n[x_1 ... x_m])))
       This proof object has no antecedents *)
   val is_push_quant : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for elimination of unused variables.
-      
+
       A proof for (iff (forall (x_1 ... x_n y_1 ... y_m) p[x_1 ... x_n])
-      (forall (x_1 ... x_n) p[x_1 ... x_n])) 
-      
+      (forall (x_1 ... x_n) p[x_1 ... x_n]))
+
       It is used to justify the elimination of unused variables.
       This proof object has no antecedents. *)
   val is_elim_unused_vars : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for destructive equality resolution
-      
+
       A proof for destructive equality resolution:
       (iff (forall (x) (or (not (= ( x : expr ) t)) P[x])) P[t])
       if ( x : expr ) does not occur in t.
-      
+
       This proof object has no antecedents.
-      
+
       Several variables can be eliminated simultaneously. *)
   val is_der : Expr.expr -> bool
-    
+
   (** Indicates whether the term is a proof for quantifier instantiation
-      
+
       A proof of (or (not (forall (x) (P x))) (P a)) *)
   val is_quant_inst : Expr.expr -> bool
 
@@ -2386,17 +2359,17 @@ sig
   val is_hypothesis : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by lemma
-      
+
       T1: false
       [lemma T1]: (or (not l_1) ... (not l_n))
-      
+
       This proof object has one antecedent: a hypothetical proof for false.
       It converts the proof in a proof for (or (not l_1) ... (not l_n)),
       when T1 contains the hypotheses: l_1, ..., l_n. *)
   val is_lemma : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by unit resolution
-      
+
       T1:      (or l_1 ... l_n l_1' ... l_m')
       T2:      (not l_1)
       ...
@@ -2405,31 +2378,31 @@ sig
   val is_unit_resolution : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by iff-true
-      
+
       T1: p
       [iff-true T1]: (iff p true) *)
   val is_iff_true : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by iff-false
-      
+
       T1: (not p)
       [iff-false T1]: (iff p false) *)
   val is_iff_false : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by commutativity
-      
+
       [comm]: (= (f a b) (f b a))
-      
+
       f is a commutative operator.
-      
+
       This proof object has no antecedents.
       Remark: if f is bool, then = is iff. *)
   val is_commutativity : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for Tseitin-like axioms
-      
+
       Proof object used to justify Tseitin's like axioms:
-      
+
       (or (not (and p q)) p)
       (or (not (and p q)) q)
       (or (not (and p q r)) p)
@@ -2450,7 +2423,7 @@ sig
       (or (ite a b c) a (not c))
       (or (not (not a)) (not a))
       (or (not a) a)
-      
+
       This proof object has no antecedents.
       Note: all axioms are propositional tautologies.
       Note also that 'and' and 'or' can take multiple arguments.
@@ -2460,56 +2433,56 @@ sig
   val is_def_axiom : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for introduction of a name
-      
+
       Introduces a name for a formula/term.
       Suppose e is an expression with free variables x, and def-intro
       introduces the name n(x). The possible cases are:
-      
+
       When e is of Boolean type:
       [def-intro]: (and (or n (not e)) (or (not n) e))
-      
+
       or:
       [def-intro]: (or (not n) e)
       when e only occurs positively.
-      
+
       When e is of the form (ite cond th el):
       [def-intro]: (and (or (not cond) (= n th)) (or cond (= n el)))
-      
+
       Otherwise:
       [def-intro]: (= n e)        *)
   val is_def_intro : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for application of a definition
-      
+
       [apply-def T1]: F ~ n
       F is 'equivalent' to n, given that T1 is a proof that
       n is a name for F. *)
   val is_apply_def : Expr.expr -> bool
 
   (** Indicates whether the term is a proof iff-oeq
-      
+
       T1: (iff p q)
       [iff~ T1]: (~ p q) *)
   val is_iff_oeq : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for a positive NNF step
-      
+
       Proof for a (positive) NNF step. Example:
-      
+
       T1: (not s_1) ~ r_1
       T2: (not s_2) ~ r_2
       T3: s_1 ~ r_1'
       T4: s_2 ~ r_2'
       [nnf-pos T1 T2 T3 T4]: (~ (iff s_1 s_2)
       (and (or r_1 r_2') (or r_1' r_2)))
-      
+
       The negation normal form steps NNF_POS and NNF_NEG are used in the following cases:
       (a) When creating the NNF of a positive force quantifier.
       The quantifier is retained (unless the bound variables are eliminated).
       Example
-      T1: q ~ q_new 
+      T1: q ~ q_new
       [nnf-pos T1]: (~ (forall (x T) q) (forall (x T) q_new))
-      
+
       (b) When recursively creating NNF over Boolean formulas, where the top-level
       connective is changed during NNF conversion. The relevant Boolean connectives
       for NNF_POS are 'implies', 'iff', 'xor', 'ite'.
@@ -2518,9 +2491,9 @@ sig
   val is_nnf_pos : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for a negative NNF step
-      
+
       Proof for a (negative) NNF step. Examples:
-      
+
       T1: (not s_1) ~ r_1
       ...
       Tn: (not s_n) ~ r_n
@@ -2540,33 +2513,33 @@ sig
   val is_nnf_neg : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for (~ P Q) here Q is in negation normal form.
-      
+
       A proof for (~ P Q) where Q is in negation normal form.
-      
-      This proof object is only used if the parameter PROOF_MODE is 1.       
-      
+
+      This proof object is only used if the parameter PROOF_MODE is 1.
+
       This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. *)
   val is_nnf_star : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for (~ P Q) where Q is in conjunctive normal form.
-      
+
       A proof for (~ P Q) where Q is in conjunctive normal form.
-      This proof object is only used if the parameter PROOF_MODE is 1.       
+      This proof object is only used if the parameter PROOF_MODE is 1.
       This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO.           *)
   val is_cnf_star : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for a Skolemization step
-      
-      Proof for: 
-      
+
+      Proof for:
+
       [sk]: (~ (not (forall ( x : expr ) (p ( x : expr ) y))) (not (p (sk y) y)))
       [sk]: (~ (exists ( x : expr ) (p ( x : expr ) y)) (p (sk y) y))
-      
+
       This proof object has no antecedents. *)
   val is_skolemize : Expr.expr -> bool
 
   (** Indicates whether the term is a proof by modus ponens for equi-satisfiability.
-      
+
       Modus ponens style rule for equi-satisfiability.
       T1: p
       T2: (~ p q)
@@ -2574,32 +2547,32 @@ sig
   val is_modus_ponens_oeq : Expr.expr -> bool
 
   (** Indicates whether the term is a proof for theory lemma
-      
+
       Generic proof for theory lemmas.
-      
+
       The theory lemma function comes with one or more parameters.
       The first parameter indicates the name of the theory.
       For the theory of arithmetic, additional parameters provide hints for
-      checking the theory lemma. 
+      checking the theory lemma.
       The hints for arithmetic are:
       - farkas - followed by rational coefficients. Multiply the coefficients to the
       inequalities in the lemma, add the (negated) inequalities and obtain a contradiction.
-      - triangle-eq - Indicates a lemma related to the equivalence:        
+      - triangle-eq - Indicates a lemma related to the equivalence:
       (iff (= t1 t2) (and (<= t1 t2) (<= t2 t1)))
       - gcd-test - Indicates an integer linear arithmetic lemma that uses a gcd test. *)
   val is_theory_lemma : Expr.expr -> bool
 end
 
-(** Goals 
+(** Goals
 
-    A goal (aka problem). A goal is essentially a 
+    A goal (aka problem). A goal is essentially a
     of formulas, that can be solved and/or transformed using
     tactics and solvers. *)
 module Goal :
 sig
-  type goal 
+  type goal
 
-  (** The precision of the goal. 
+  (** The precision of the goal.
 
       Goals can be transformed using over and under approximations.
       An under approximation is applied when the objective is to find a model for a given goal.
@@ -2620,11 +2593,11 @@ sig
 
   (** Adds the constraints to the given goal. *)
   val add : goal -> Expr.expr list -> unit
-    
+
   (** Indicates whether the goal contains `false'. *)
   val is_inconsistent : goal -> bool
-    
-  (** The depth of the goal.      
+
+  (** The depth of the goal.
       This tracks how many transformations were applied to it. *)
   val get_depth : goal -> int
 
@@ -2653,8 +2626,8 @@ sig
   val simplify : goal -> Params.params option -> goal
 
   (** Creates a new Goal.
-      
-      Note that the Context must have been created with proof generation support if 
+
+      Note that the Context must have been created with proof generation support if
       the fourth argument is set to true here. *)
   val mk_goal : context -> bool -> bool -> bool -> goal
 
@@ -2670,25 +2643,25 @@ end
     A Model contains interpretations (assignments) of constants and functions. *)
 module Model :
 sig
-  type model 
+  type model
 
-  (** Function interpretations 
+  (** Function interpretations
 
       A function interpretation is represented as a finite map and an 'else'.
-      Each entry in the finite map represents the value of a function given a set of arguments.   *)    
+      Each entry in the finite map represents the value of a function given a set of arguments.   *)
   module FuncInterp :
   sig
-    type func_interp 
-      
-    (** Function interpretations entries 
+    type func_interp
 
-        An Entry object represents an element in the finite map used to a function interpretation. *)  
+    (** Function interpretations entries
+
+        An Entry object represents an element in the finite map used to a function interpretation. *)
     module FuncEntry :
     sig
-      type func_entry 
+      type func_entry
 
       (** Return the (symbolic) value of this entry.
-      *)    
+      *)
       val get_value : func_entry -> Expr.expr
 
       (** The number of arguments of the entry.
@@ -2716,26 +2689,26 @@ sig
     (**   The arity of the function interpretation *)
     val get_arity : func_interp -> int
 
-    (**   A string representation of the function interpretation. *)    
+    (**   A string representation of the function interpretation. *)
     val to_string : func_interp -> string
   end
 
-  (** Retrieves the interpretation (the assignment) of a func_decl in the model. 
+  (** Retrieves the interpretation (the assignment) of a func_decl in the model.
       @return An expression if the function has an interpretation in the model, null otherwise. *)
   val get_const_interp : model -> FuncDecl.func_decl -> Expr.expr option
 
-  (** Retrieves the interpretation (the assignment) of an expression in the model. 
+  (** Retrieves the interpretation (the assignment) of an expression in the model.
       @return An expression if the constant has an interpretation in the model, null otherwise. *)
   val get_const_interp_e : model -> Expr.expr -> Expr.expr option
 
-  (** Retrieves the interpretation (the assignment) of a non-constant func_decl in the model. 
+  (** Retrieves the interpretation (the assignment) of a non-constant func_decl in the model.
       @return A FunctionInterpretation if the function has an interpretation in the model, null otherwise. *)
   val get_func_interp : model -> FuncDecl.func_decl -> FuncInterp.func_interp option
 
   (** The number of constant interpretations in the model. *)
   val get_num_consts : model -> int
 
-  (** The function declarations of the constants in the model. *)  
+  (** The function declarations of the constants in the model. *)
   val get_const_decls : model -> FuncDecl.func_decl list
 
   (** The number of function interpretations in the model. *)
@@ -2748,8 +2721,8 @@ sig
   val get_decls : model -> FuncDecl.func_decl list
 
   (** Evaluates an expression in the current model.
-      
-      This function may fail if the argument contains quantifiers, 
+
+      This function may fail if the argument contains quantifiers,
       is partial (MODEL_PARTIAL enabled), or if it is not well-sorted.
       In this case a [ModelEvaluationFailedException] is thrown.
   *)
@@ -2761,8 +2734,8 @@ sig
   (** The number of uninterpreted sorts that the model has an interpretation for. *)
   val get_num_sorts : model -> int
 
-  (** The uninterpreted sorts that the model has an interpretation for. 
-      
+  (** The uninterpreted sorts that the model has an interpretation for.
+
       Z3 also provides an intepretation for uninterpreted sorts used in a formula.
       The interpretation for a sort is a finite set of distinct values. We say this finite set is
       the "universe" of the sort.
@@ -2770,17 +2743,17 @@ sig
       {!sort_universe} *)
   val get_sorts : model -> Sort.sort list
 
-  (** The finite set of distinct values that represent the interpretation of a sort. 
+  (** The finite set of distinct values that represent the interpretation of a sort.
       {!get_sorts}
       @return A list of expressions, where each is an element of the universe of the sort *)
   val sort_universe : model -> Sort.sort -> Expr.expr list
-    
-  (** Conversion of models to strings. 
+
+  (** Conversion of models to strings.
       @return A string representation of the model. *)
   val to_string : model -> string
 end
 
-(** Probes 
+(** Probes
 
     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.
@@ -2790,9 +2763,9 @@ end
 *)
 module Probe :
 sig
-  type probe 
+  type probe
 
-  (** Execute the probe over the goal. 
+  (** Execute the probe over the goal.
       @return A probe always produce a float value.
       "Boolean" probes return 0.0 for false, and a value different from 0.0 for true. *)
   val apply : probe -> Goal.goal -> float
@@ -2806,7 +2779,7 @@ sig
   (** Returns a string containing a description of the probe with the given name. *)
   val get_probe_description : context -> string -> string
 
-  (** Creates a new Probe. *) 
+  (** Creates a new Probe. *)
   val mk_probe : context -> string -> probe
 
   (** Create a probe that always evaluates to a float value. *)
@@ -2846,21 +2819,21 @@ end
 (** Tactics
 
     Tactics are the basic building block for creating custom solvers for specific problem domains.
-    The complete list of tactics may be obtained using [Context.get_num_tactics] 
+    The complete list of tactics may be obtained using [Context.get_num_tactics]
     and [Context.get_tactic_names].
     It may also be obtained using the command [(help-tactic)] in the SMT 2.0 front-end.
 *)
 module Tactic :
 sig
-  type tactic 
+  type tactic
 
-  (** Tactic application results 
-      
-      ApplyResult objects represent the result of an application of a 
+  (** Tactic application results
+
+      ApplyResult objects represent the result of an application of a
       tactic to a goal. It contains the subgoals that were produced. *)
   module ApplyResult :
   sig
-    type apply_result 
+    type apply_result
 
     (** The number of Subgoals. *)
     val get_num_subgoals : apply_result -> int
@@ -2871,8 +2844,8 @@ sig
     (** Retrieves a subgoal from the apply_result. *)
     val get_subgoal : apply_result -> int -> Goal.goal
 
-    (** Convert a model for a subgoal into a model for the original 
-        goal [g], that the ApplyResult was obtained from. 
+    (** Convert a model for a subgoal into a model for the original
+        goal [g], that the ApplyResult was obtained from.
         #return A model for [g] *)
     val convert_model : apply_result -> int -> Model.model -> Model.model
 
@@ -2898,7 +2871,7 @@ sig
   (** Returns a string containing a description of the tactic with the given name. *)
   val get_tactic_description : context -> string -> string
 
-  (** Creates a new Tactic. *)    
+  (** Creates a new Tactic. *)
   val mk_tactic : context -> string -> tactic
 
   (** Create a tactic that applies one tactic to a Goal and
@@ -2909,22 +2882,22 @@ sig
       if it fails then returns the result of another tactic applied to the Goal. *)
   val or_else : context -> tactic -> tactic -> tactic
 
-  (** Create a tactic that applies one tactic to a goal for some time (in milliseconds).    
-      
+  (** Create a tactic that applies one tactic to a goal for some time (in milliseconds).
+
       If the tactic does not terminate within the timeout, then it fails. *)
   val try_for : context -> tactic -> int -> tactic
 
-  (** Create a tactic that applies one tactic to a given goal if the probe 
-      evaluates to true. 
-      
+  (** Create a tactic that applies one tactic to a given goal if the probe
+      evaluates to true.
+
       If the probe evaluates to false, then the new tactic behaves like the [skip] tactic.  *)
   val when_ : context -> Probe.probe -> tactic -> tactic
 
-  (** Create a tactic that applies a tactic to a given goal if the probe 
+  (** Create a tactic that applies a tactic to a given goal if the probe
       evaluates to true and another tactic otherwise. *)
   val cond : context -> Probe.probe -> tactic -> tactic -> tactic
 
-  (** Create a tactic that keeps applying one tactic until the goal is not 
+  (** Create a tactic that keeps applying one tactic until the goal is not
       modified anymore or the maximum number of iterations is reached. *)
   val repeat : context -> tactic -> int -> tactic
 
@@ -2955,7 +2928,7 @@ sig
       to every subgoal produced by the first one. The subgoals are processed in parallel. *)
   val par_and_then : context -> tactic -> tactic -> tactic
 
-  (** Interrupt the execution of a Z3 procedure.        
+  (** Interrupt the execution of a Z3 procedure.
       This procedure can be used to interrupt: solvers, simplifiers and tactics. *)
   val interrupt : context -> unit
 end
@@ -2963,37 +2936,37 @@ end
 (** Objects that track statistical information. *)
 module Statistics :
 sig
-  type statistics 
-    
+  type statistics
+
   (** Statistical data is organized into pairs of \[Key, Entry\], where every
       Entry is either a floating point or integer value. *)
   module Entry :
   sig
     type statistics_entry
-      
+
     (** The key of the entry. *)
     val get_key : statistics_entry -> string
-      
+
     (** The int-value of the entry. *)
     val get_int : statistics_entry -> int
-      
+
     (** The float-value of the entry. *)
     val get_float : statistics_entry -> float
-      
+
     (** True if the entry is uint-valued. *)
     val is_int : statistics_entry -> bool
-      
+
     (** True if the entry is float-valued. *)
     val is_float : statistics_entry -> bool
-      
+
     (** The string representation of the the entry's value. *)
     val to_string_value : statistics_entry -> string
-      
+
     (** The string representation of the entry (key and value) *)
     val to_string : statistics_entry -> string
   end
 
-  (** A string representation of the statistical data. *)    
+  (** A string representation of the statistical data. *)
   val to_string : statistics -> string
 
   (** The number of statistical data. *)
@@ -3005,16 +2978,16 @@ sig
   (**   The statistical counters. *)
   val get_keys : statistics -> string list
 
-  (** The value of a particular statistical counter. *)        
+  (** The value of a particular statistical counter. *)
   val get : statistics -> string -> Entry.statistics_entry option
 end
 
 (** Solvers *)
 module Solver :
 sig
-  type solver 
+  type solver
   type status = UNSATISFIABLE | UNKNOWN | SATISFIABLE
-      
+
   val string_of_status : status -> string
 
   (** A string that describes all available solver parameters. *)
@@ -3044,7 +3017,7 @@ sig
       This removes all assertions from the solver. *)
   val reset : solver -> unit
 
-  (** Assert a constraint (or multiple) into the solver. *)        
+  (** Assert a constraint (or multiple) into the solver. *)
   val add : solver -> Expr.expr list -> unit
 
   (** * Assert multiple constraints (cs) into the solver, and track them (in the
@@ -3062,7 +3035,7 @@ sig
 
   (** * Assert a constraint (c) into the solver, and track it (in the unsat) core
       * using the Boolean constant p.
-      * 
+      *
       * This API is an alternative to {!check} with assumptions for
       * extracting unsat cores.
       * Both APIs can be used in the same solver. The unsat core will contain a
@@ -3079,26 +3052,26 @@ sig
   val get_assertions : solver -> Expr.expr list
 
   (** Checks whether the assertions in the solver are consistent or not.
-      
+
       {!Model}
       {!get_unsat_core}
       {!Proof}     *)
   val check : solver -> Expr.expr list -> status
 
   (** The model of the last [Check].
-      
+
       The result is [None] if [Check] was not invoked before,
       if its results was not [SATISFIABLE], or if model production is not enabled. *)
   val get_model : solver -> Model.model option
 
   (** The proof of the last [Check].
-      
+
       The result is [null] if [Check] was not invoked before,
       if its results was not [UNSATISFIABLE], or if proof production is disabled. *)
   val get_proof : solver -> Expr.expr option
 
   (** The unsat core of the last [Check].
-      
+
       The unsat core is a subset of [Assertions]
       The result is empty if [Check] was not invoked before,
       if its results was not [UNSATISFIABLE], or if core production is disabled. *)
@@ -3110,26 +3083,26 @@ sig
   (** Solver statistics. *)
   val get_statistics : solver -> Statistics.statistics
 
-  (** Creates a new (incremental) solver. 
-      
-      This solver also uses a set of builtin tactics for handling the first 
-      check-sat command, and check-sat commands that take more than a given 
-      number of milliseconds to be solved.  *)    
+  (** Creates a new (incremental) solver.
+
+      This solver also uses a set of builtin tactics for handling the first
+      check-sat command, and check-sat commands that take more than a given
+      number of milliseconds to be solved.  *)
   val mk_solver : context -> Symbol.symbol option -> solver
 
   (** Creates a new (incremental) solver.
-      {!mk_solver} *)        
+      {!mk_solver} *)
   val mk_solver_s : context -> string -> solver
 
   (** Creates a new (incremental) solver.  *)
   val mk_simple_solver : context -> solver
 
   (** Creates a solver that is implemented using the given tactic.
-      
+
       The solver supports the commands [Push] and [Pop], but it
       will always solve each check from scratch. *)
   val mk_solver_t : context -> Tactic.tactic -> solver
-        
+
   (** Create a clone of the current solver with respect to a context. *)
   val translate : solver -> context -> solver
 
@@ -3140,8 +3113,8 @@ end
 (** Fixedpoint solving *)
 module Fixedpoint :
 sig
-  type fixedpoint 
-    
+  type fixedpoint
+
   (** A string that describes all available fixedpoint solver parameters. *)
   val get_help : fixedpoint -> string
 
@@ -3151,28 +3124,28 @@ sig
   (** Retrieves parameter descriptions for Fixedpoint solver. *)
   val get_param_descrs : fixedpoint -> Params.ParamDescrs.param_descrs
 
-  (** Assert a constraints into the fixedpoint solver. *)        
+  (** Assert a constraints into the fixedpoint solver. *)
   val add : fixedpoint -> Expr.expr list -> unit
 
-  (** Register predicate as recursive relation. *)       
+  (** Register predicate as recursive relation. *)
   val register_relation : fixedpoint -> FuncDecl.func_decl -> unit
 
-  (** Add rule into the fixedpoint solver. *)        
+  (** Add rule into the fixedpoint solver. *)
   val add_rule : fixedpoint -> Expr.expr -> Symbol.symbol option -> unit
 
-  (** Add table fact to the fixedpoint solver. *)        
+  (** Add table fact to the fixedpoint solver. *)
   val add_fact : fixedpoint -> FuncDecl.func_decl -> int list -> unit
 
   (** Query the fixedpoint solver.
       A query is a conjunction of constraints. The constraints may include the recursively defined relations.
       The query is satisfiable if there is an instance of the query variables and a derivation for it.
-      The query is unsatisfiable if there are no derivations satisfying the query variables.  *)        
+      The query is unsatisfiable if there are no derivations satisfying the query variables.  *)
   val query : fixedpoint -> Expr.expr -> Solver.status
 
   (** Query the fixedpoint solver.
       A query is an array of relations.
       The query is satisfiable if there is an instance of some relation that is non-empty.
-      The query is unsatisfiable if there are no derivations satisfying any of the relations. *)        
+      The query is unsatisfiable if there are no derivations satisfying any of the relations. *)
   val query_r : fixedpoint -> FuncDecl.func_decl list -> Solver.status
 
   (** Creates a backtracking point.
@@ -3185,39 +3158,39 @@ sig
       {!push} *)
   val pop : fixedpoint -> unit
 
-  (** Update named rule into in the fixedpoint solver. *)        
+  (** Update named rule into in the fixedpoint solver. *)
   val update_rule : fixedpoint -> Expr.expr -> Symbol.symbol -> unit
 
-  (** Retrieve satisfying instance or instances of solver, 
-      or definitions for the recursive predicates that show unsatisfiability. *)                
+  (** Retrieve satisfying instance or instances of solver,
+      or definitions for the recursive predicates that show unsatisfiability. *)
   val get_answer : fixedpoint -> Expr.expr option
 
-  (** Retrieve explanation why fixedpoint engine returned status Unknown. *)                
+  (** Retrieve explanation why fixedpoint engine returned status Unknown. *)
   val get_reason_unknown : fixedpoint -> string
 
-  (** Retrieve the number of levels explored for a given predicate. *)                
+  (** Retrieve the number of levels explored for a given predicate. *)
   val get_num_levels : fixedpoint -> FuncDecl.func_decl -> int
 
-  (** Retrieve the cover of a predicate. *)                
+  (** Retrieve the cover of a predicate. *)
   val get_cover_delta : fixedpoint -> int -> FuncDecl.func_decl -> Expr.expr option
 
   (** Add <tt>property</tt> about the <tt>predicate</tt>.
-      The property is added at <tt>level</tt>. *)                
+      The property is added at <tt>level</tt>. *)
   val add_cover : fixedpoint -> int -> FuncDecl.func_decl -> Expr.expr -> unit
 
   (** Retrieve internal string representation of fixedpoint object. *)
   val to_string : fixedpoint -> string
 
-  (** Instrument the Datalog engine on which table representation to use for recursive predicate. *)                
+  (** Instrument the Datalog engine on which table representation to use for recursive predicate. *)
   val set_predicate_representation : fixedpoint -> FuncDecl.func_decl -> Symbol.symbol list -> unit
 
-  (** Convert benchmark given as set of axioms, rules and queries to a string. *)                
+  (** Convert benchmark given as set of axioms, rules and queries to a string. *)
   val to_string_q : fixedpoint -> Expr.expr list -> string
 
-  (** Retrieve set of rules added to fixedpoint context. *)                
+  (** Retrieve set of rules added to fixedpoint context. *)
   val get_rules : fixedpoint -> Expr.expr list
 
-  (** Retrieve set of assertions added to fixedpoint context. *)                
+  (** Retrieve set of assertions added to fixedpoint context. *)
   val get_assertions : fixedpoint -> Expr.expr list
 
   (** Create a Fixedpoint context. *)
@@ -3226,98 +3199,83 @@ sig
   (** Retrieve statistics information from the last call to #Z3_fixedpoint_query. *)
   val get_statistics : fixedpoint -> Statistics.statistics
 
-  (** Parse an SMT-LIB2 string with fixedpoint rules. 
-      Add the rules to the current fixedpoint context. 
+  (** Parse an SMT-LIB2 string with fixedpoint rules.
+      Add the rules to the current fixedpoint context.
       Return the set of queries in the string. *)
   val parse_string : fixedpoint -> string -> Expr.expr list
 
-  (** Parse an SMT-LIB2 file with fixedpoint rules. 
-      Add the rules to the current fixedpoint context. 
+  (** Parse an SMT-LIB2 file with fixedpoint rules.
+      Add the rules to the current fixedpoint context.
       Return the set of queries in the file. *)
   val parse_file : fixedpoint -> string -> Expr.expr list
 end
 
-(** Optimization *) 
-module Optimize : 
-sig 
-  type optimize  
-  type handle 
- 
- 
-  (** Create a Optimize context. *) 
-  val mk_opt : context -> optimize 
-      
-  (** A string that describes all available optimize solver parameters. *) 
-  val get_help : optimize -> string 
- 
- 
-  (** Sets the optimize solver parameters. *) 
-  val set_parameters : optimize -> Params.params -> unit 
- 
- 
-  (** Retrieves parameter descriptions for Optimize solver. *) 
-  val get_param_descrs : optimize -> Params.ParamDescrs.param_descrs 
- 
- 
-  (** Assert a constraints into the optimize solver. *)         
-  val add : optimize -> Expr.expr list -> unit 
- 
- 
-  (** Asssert a soft constraint.  
-     Supply integer weight and string that identifies a group 
-      of soft constraints.  
-   *) 
-  val add_soft : optimize -> Expr.expr -> string -> Symbol.symbol -> handle 
- 
- 
-  (** Add maximization objective. 
-   *)  
-  val maximize : optimize -> Expr.expr -> handle 
- 
- 
-  (** Add minimization objective. 
-   *)  
-  val minimize : optimize -> Expr.expr -> handle 
-    
-  (** Checks whether the assertions in the context are satisfiable and solves objectives. 
-   *)         
-  val check : optimize -> Solver.status 
- 
- 
-  (** Retrieve model from satisfiable context *) 
+(** Optimization *)
+module Optimize :
+sig
+  type optimize
+  type handle
+
+  (** Create a Optimize context. *)
+  val mk_opt : context -> optimize
+
+  (** A string that describes all available optimize solver parameters. *)
+  val get_help : optimize -> string
+
+  (** Sets the optimize solver parameters. *)
+  val set_parameters : optimize -> Params.params -> unit
+
+  (** Retrieves parameter descriptions for Optimize solver. *)
+  val get_param_descrs : optimize -> Params.ParamDescrs.param_descrs
+
+  (** Assert a constraints into the optimize solver. *)
+  val add : optimize -> Expr.expr list -> unit
+
+  (** Asssert a soft constraint.
+      Supply integer weight and string that identifies a group
+      of soft constraints.
+  *)
+  val add_soft : optimize -> Expr.expr -> string -> Symbol.symbol -> handle
+
+  (** Add maximization objective.
+  *)
+  val maximize : optimize -> Expr.expr -> handle
+
+  (** Add minimization objective.
+  *)
+  val minimize : optimize -> Expr.expr -> handle
+
+  (** Checks whether the assertions in the context are satisfiable and solves objectives.
+  *)
+  val check : optimize -> Solver.status
+
+  (** Retrieve model from satisfiable context *)
   val get_model : optimize -> Model.model option
- 
- 
-  (** Retrieve lower bound in current model for handle *) 
-  val get_lower : handle -> int -> Expr.expr 
- 
- 
-  (** Retrieve upper bound in current model for handle *) 
-  val get_upper : handle -> int -> Expr.expr 
 
- 
-  (** Creates a backtracking point. 
-      {!pop} *) 
-  val push : optimize -> unit 
+  (** Retrieve lower bound in current model for handle *)
+  val get_lower : handle -> int -> Expr.expr
 
+  (** Retrieve upper bound in current model for handle *)
+  val get_upper : handle -> int -> Expr.expr
 
-  (** Backtrack one backtracking point. 
-      Note that an exception is thrown if Pop is called without a corresponding [Push] 
-      {!push} *) 
-  val pop : optimize -> unit 
+  (** Creates a backtracking point.
+      {!pop} *)
+  val push : optimize -> unit
 
- 
-  (** Retrieve explanation why optimize engine returned status Unknown. *)                 
-  val get_reason_unknown : optimize -> string 
+  (** Backtrack one backtracking point.
+      Note that an exception is thrown if Pop is called without a corresponding [Push]
+      {!push} *)
+  val pop : optimize -> unit
 
- 
-  (** Retrieve SMT-LIB string representation of optimize object. *) 
-  val to_string : optimize -> string 
- 
- 
-  (** Retrieve statistics information from the last call to check *) 
-  val get_statistics : optimize -> Statistics.statistics 
-end 
+  (** Retrieve explanation why optimize engine returned status Unknown. *)
+  val get_reason_unknown : optimize -> string
+
+  (** Retrieve SMT-LIB string representation of optimize object. *)
+  val to_string : optimize -> string
+
+  (** Retrieve statistics information from the last call to check *)
+  val get_statistics : optimize -> Statistics.statistics
+end
 
 
 (** Functions for handling SMT and SMT2 expressions and files *)
@@ -3328,16 +3286,16 @@ sig
       @return A string representation of the benchmark. *)
   val benchmark_to_smtstring : context -> string -> string -> string -> string -> Expr.expr list -> Expr.expr -> string
 
-  (** Parse the given string using the SMT-LIB parser. 
-      
-      The symbol table of the parser can be initialized using the given sorts and declarations. 
-      The symbols in the arrays in the third and fifth argument 
-      don't need to match the names of the sorts and declarations in the arrays in the fourth 
-      and sixth argument. This is a useful feature since we can use arbitrary names to 
+  (** Parse the given string using the SMT-LIB parser.
+
+      The symbol table of the parser can be initialized using the given sorts and declarations.
+      The symbols in the arrays in the third and fifth argument
+      don't need to match the names of the sorts and declarations in the arrays in the fourth
+      and sixth argument. This is a useful feature since we can use arbitrary names to
       reference sorts and declarations. *)
   val parse_smtlib_string : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> unit
 
-  (** Parse the given file using the SMT-LIB parser. 
+  (** Parse the given file using the SMT-LIB parser.
       {!parse_smtlib_string} *)
   val parse_smtlib_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> unit
 
@@ -3365,13 +3323,13 @@ sig
   (** The sort declarations parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *)
   val get_smtlib_sorts : context -> Sort.sort list
 
-  (** Parse the given string using the SMT-LIB2 parser. 
+  (** Parse the given string using the SMT-LIB2 parser.
 
       {!parse_smtlib_string}
       @return A conjunction of assertions in the scope (up to push/pop) at the end of the string. *)
   val parse_smtlib2_string : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr
 
-  (** Parse the given file using the SMT-LIB2 parser. 
+  (** Parse the given file using the SMT-LIB2 parser.
       {!parse_smtlib2_string} *)
   val parse_smtlib2_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr
 end
@@ -3383,7 +3341,7 @@ sig
   (** Create an AST node marking a formula position for interpolation.
       The expression must have Boolean sort. *)
   val mk_interpolant : context -> Expr.expr -> Expr.expr
-    
+
   (** The interpolation context is suitable for generation of interpolants.
       For more information on interpolation please refer
       too the C/C++ API, which is well documented. *)
@@ -3403,12 +3361,12 @@ sig
       For more information on interpolation please refer
       too the C/C++ API, which is well documented. *)
   val get_interpolation_profile : context -> string
-    
+
   (** Read an interpolation problem from file.
       For more information on interpolation please refer
       too the C/C++ API, which is well documented. *)
   val read_interpolation_problem : context -> string -> (Expr.expr list * int list * Expr.expr list)
-    
+
   (** Check the correctness of an interpolant.
       For more information on interpolation please refer
       too the C/C++ API, which is well documented. *)
@@ -3423,10 +3381,10 @@ sig
 end
 
 (** Set a global (or module) parameter, which is shared by all Z3 contexts.
-    
+
     When a Z3 module is initialized it will use the value of these parameters
     when Z3_params objects are not provided.
-    The name of parameter can be composed of characters [a-z][A-Z], digits [0-9], '-' and '_'. 
+    The name of parameter can be composed of characters [a-z][A-Z], digits [0-9], '-' and '_'.
     The character '.' is a delimiter (more later).
     The parameter names are case-insensitive. The character '-' should be viewed as an "alias" for '_'.
     Thus, the following parameter names are considered equivalent: "pp.decimal-precision"  and "PP.DECIMAL_PRECISION".
@@ -3439,7 +3397,7 @@ end
 val set_global_param : string -> string -> unit
 
 (** Get a global (or module) parameter.
-    
+
     Returns None if the parameter does not exist.
     The caller must invoke #Z3_global_param_del_value to delete the value returned at param_value.
     This function cannot be invoked simultaneously from different threads without synchronization.
@@ -3448,32 +3406,29 @@ val set_global_param : string -> string -> unit
 val get_global_param : string -> string option
 
 (** Restore the value of all global (and module) parameters.
-    
+
     This command will not affect already created objects (such as tactics and solvers)
     {!set_global_param}
 *)
 
 val global_param_reset_all : unit -> unit
-  
+
 (** Enable/disable printing of warning messages to the console.
-    
-    Note that this function is static and effects the behaviour of 
+
+    Note that this function is static and effects the behaviour of
     all contexts globally. *)
 val toggle_warning_messages : bool -> unit
 
 (**
    Enable tracing messages tagged as `tag' when Z3 is compiled in debug mode.
-   
-   Remarks: It is a NOOP otherwise. 
+
+   Remarks: It is a NOOP otherwise.
 *)
 val enable_trace : string -> unit
 
 (**
-   Disable tracing messages tagged as `tag' when Z3 is compiled in debug mode.        
+   Disable tracing messages tagged as `tag' when Z3 is compiled in debug mode.
 
    Remarks: It is a NOOP otherwise.
 *)
 val disable_trace : string -> unit
-
-
-
diff --git a/src/api/ml/z3native.ml.pre b/src/api/ml/z3native.ml.pre
new file mode 100644
index 000000000..87a069df9
--- /dev/null
+++ b/src/api/ml/z3native.ml.pre
@@ -0,0 +1,36 @@
+(** The native (raw) interface to the dynamic Z3 library. *)
+
+open Z3enums
+
+(**/**)
+type ptr
+and symbol = ptr
+and config = ptr
+and context = ptr
+and ast = ptr
+and app = ast
+and sort = ast
+and func_decl = ast
+and pattern = ast
+and model = ptr
+and literals = ptr
+and constructor = ptr
+and constructor_list = ptr
+and solver = ptr
+and goal = ptr
+and tactic = ptr
+and params = ptr
+and probe = ptr
+and stats = ptr
+and ast_vector = ptr
+and ast_map = ptr
+and apply_result = ptr
+and func_interp = ptr
+and func_entry = ptr
+and fixedpoint = ptr
+and optimize = ptr
+and param_descrs = ptr
+and rcf_num = ptr
+
+external set_internal_error_handler : ptr -> unit
+  = "n_set_internal_error_handler"
diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre
new file mode 100644
index 000000000..d6b2cdab4
--- /dev/null
+++ b/src/api/ml/z3native_stubs.c.pre
@@ -0,0 +1,445 @@
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <caml/mlvalues.h>
+#include <caml/memory.h>
+#include <caml/alloc.h>
+#include <caml/fail.h>
+#include <caml/callback.h>
+
+#ifdef Custom_tag
+#include <caml/custom.h>
+#include <caml/bigarray.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <z3.h>
+#include <z3native_stubs.h>
+
+#define CAMLlocal6(X1,X2,X3,X4,X5,X6)                                   \
+  CAMLlocal5(X1,X2,X3,X4,X5);                                       	\
+  CAMLlocal1(X6)
+#define CAMLlocal7(X1,X2,X3,X4,X5,X6,X7)				\
+  CAMLlocal5(X1,X2,X3,X4,X5);                                       	\
+  CAMLlocal2(X6,X7)
+#define CAMLlocal8(X1,X2,X3,X4,X5,X6,X7,X8)				\
+  CAMLlocal5(X1,X2,X3,X4,X5);                                       	\
+  CAMLlocal3(X6,X7,X8)
+
+#define CAMLparam7(X1,X2,X3,X4,X5,X6,X7)				\
+  CAMLparam5(X1,X2,X3,X4,X5);                                       	\
+  CAMLxparam2(X6,X7)
+#define CAMLparam8(X1,X2,X3,X4,X5,X6,X7,X8)				\
+  CAMLparam5(X1,X2,X3,X4,X5);                                       	\
+  CAMLxparam3(X6,X7,X8)
+#define CAMLparam9(X1,X2,X3,X4,X5,X6,X7,X8,X9)				\
+  CAMLparam5(X1,X2,X3,X4,X5);                                       	\
+  CAMLxparam4(X6,X7,X8,X9)
+#define CAMLparam12(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12)		\
+  CAMLparam5(X1,X2,X3,X4,X5);                                   	\
+  CAMLxparam5(X6,X7,X8,X9,X10);                                 	\
+  CAMLxparam2(X11,X12)
+#define CAMLparam13(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13)		\
+  CAMLparam5(X1,X2,X3,X4,X5);                                   	\
+  CAMLxparam5(X6,X7,X8,X9,X10);                                 	\
+  CAMLxparam3(X11,X12,X13)
+
+
+static struct custom_operations default_custom_ops = {
+  (char*) "default handling",
+  custom_finalize_default,
+  custom_compare_default,
+  custom_hash_default,
+  custom_serialize_default,
+  custom_deserialize_default,
+  custom_compare_ext_default,
+};
+
+int compare_pointers(void* pt1, void* pt2) {
+  if (pt1 == pt2)
+    return 0;
+  else if ((intnat)pt1 < (intnat)pt2)
+    return -1;
+  else
+    return +1;
+}
+
+#define MK_CTX_OF(X)                                                    \
+  CAMLprim DLL_PUBLIC value n_context_of_ ## X(value v) {               \
+    CAMLparam1(v);                                                      \
+    CAMLlocal1(result);                                                 \
+    Z3_context_plus cp;                                                 \
+    Z3_ ## X ## _plus * p = (Z3_ ## X ## _plus *) Data_custom_val(v);   \
+    cp = p->cp;                                                         \
+    result = caml_alloc_custom(&Z3_context_plus_custom_ops, sizeof(Z3_context_plus), 0, 1); \
+    *(Z3_context_plus *)Data_custom_val(result) = cp;                   \
+    /* We increment the usage counter of the context, as we just        \
+       created a second custom block holding that context        */     \
+    cp->obj_count++;                                                    \
+    CAMLreturn(result);                                                 \
+  }                                                                     \
+                                                                        \
+  CAMLprim value DLL_PUBLIC n_is_null_ ## X (value v) {                 \
+    CAMLparam1(v);                                                      \
+    Z3_ ## X ## _plus* pp = (Z3_ ## X ## _plus*)Data_custom_val(v);     \
+    CAMLreturn(Val_bool(pp->p == NULL));                                \
+  }                                                                     \
+                                                                        \
+  CAMLprim value DLL_PUBLIC n_mk_null_ ## X (value v) {                 \
+    CAMLparam1(v);                                                      \
+    CAMLlocal1(result);                                                 \
+    Z3_context_plus cp = *(Z3_context_plus*)(Data_custom_val(v));       \
+    Z3_ ## X ## _plus a = Z3_ ## X ## _plus_mk(cp, NULL);               \
+    result = caml_alloc_custom(&Z3_ ## X ## _plus_custom_ops, sizeof(Z3_ ## X ## _plus), 0, 1); \
+    *(Z3_ ## X ## _plus*)(Data_custom_val(result)) = a;                 \
+    CAMLreturn(result);                                                 \
+  }
+
+
+/* Context objects */
+
+/* The Z3context_plus_data exists exactly once for each context,
+   no matter how many custom blocks for that context exist.
+   Each custom block only stores a pointer to the corresponding
+   Z3_context_plus_data. This ensures that the reference counting
+   is performed at exactly one place and not within the custom
+   blocks that get copied. */
+typedef struct {
+  Z3_context ctx;
+  unsigned long obj_count;
+} Z3_context_plus_data;
+
+/* A context is wrapped to an OCaml value by storing a pointer
+   to its associated Z3_context_plus_data instance.
+   This instance gets created in mk_context and is deleted
+   together with the Z3 context instance in try_to_delete_context
+   whenever the obj_count field is zero. */
+typedef Z3_context_plus_data* Z3_context_plus;
+
+Z3_context_plus Z3_context_plus_mk(Z3_context c) {
+  Z3_context_plus r = (Z3_context_plus)malloc(sizeof(Z3_context_plus_data));
+  r->ctx = c;
+  /* The context created here will be wrapped into a custom block.
+     We regard custom blocks that point to a Z3_context_plus structure
+     as a usage of this structure. Hence, we assign it a counter of one. */
+  r->obj_count = 1;
+  return r;
+}
+
+Z3_context Z3_context_plus_raw(Z3_context_plus * cp) {
+  return (*cp)->ctx;
+}
+
+void try_to_delete_context(Z3_context_plus cp) {
+  if (cp->obj_count == 0) {
+    /* printf("try_to_delete_context: Deleting context %p(%p) with cnt=0.\n", cp, cp->ctx); */
+    Z3_del_context(cp->ctx);
+    free(cp);
+  }
+  /*
+  else if (cp->obj_count > 0)
+    printf("try_to_delete_context: Not deleting context %p(%p) with cnt=%lu.\n", cp, cp->ctx, cp->obj_count);
+  else if (cp->obj_count < 0)
+    printf("try_to_delete_context: ERROR, found context %p(%p) with negative cnt=%lu.\n", cp, cp->ctx, cp->obj_count);
+  */
+}
+
+void Z3_context_finalize(value v) {
+  Z3_context_plus cp = *(Z3_context_plus*)Data_custom_val(v);
+  cp->obj_count--;
+  try_to_delete_context(cp);
+}
+
+int Z3_context_compare(value v1, value v2) {
+  /* As each context created within the OCaml bindings has a unique
+     Z3_context_plus_data allocated to store the handle and the ref counters,
+     we can just compare pointers here. This suffices to test for (in)equality
+     and induces an arbitrary (but fixed) ordering. */
+  Z3_context_plus cp1 = *(Z3_context_plus*)Data_custom_val(v1);
+  Z3_context_plus cp2 = *(Z3_context_plus*)Data_custom_val(v2);
+  return compare_pointers(cp1, cp2);
+}
+
+int Z3_context_compare_ext(value v1, value v2) {
+  Z3_context_plus cp = *(Z3_context_plus*)Data_custom_val(v1);
+  return compare_pointers(cp, (void*)Val_int(v2));
+}
+
+/* We use the pointer to the Z3_context_plus_data structure as
+   a hash value; it is unique, at least. */
+intnat Z3_context_hash(value v) {
+  /* We use the address of the context's Z3_context_plus_data structure
+     as a hash value */
+  Z3_context_plus cp = *(Z3_context_plus*)Data_custom_val(v);
+  return (intnat)cp;
+}
+
+static struct custom_operations Z3_context_plus_custom_ops = {
+  (char*) "Z3_context ops",
+  Z3_context_finalize,
+  Z3_context_compare,
+  Z3_context_hash,
+  custom_serialize_default,
+  custom_deserialize_default,
+  Z3_context_compare_ext
+};
+
+
+/* AST objects */
+
+typedef struct {
+  Z3_context_plus cp;
+  Z3_ast p;
+} Z3_ast_plus;
+
+Z3_ast_plus Z3_ast_plus_mk(Z3_context_plus cp, Z3_ast p) {
+  Z3_ast_plus r;
+  r.cp = cp;
+  r.p = p;
+  /* printf("++\n"); */
+  cp->obj_count++;
+  if (p != NULL)
+    Z3_inc_ref(cp->ctx, p);
+  return r;
+}
+
+Z3_ast Z3_ast_plus_raw(Z3_ast_plus * ap) {
+  return ap->p;
+}
+
+void Z3_ast_finalize(value v) {
+  /* printf("--\n"); */
+  Z3_ast_plus * ap = (Z3_ast_plus*)(Data_custom_val(v));
+  if (ap->p != NULL)
+    Z3_dec_ref(ap->cp->ctx, ap->p);
+  ap->cp->obj_count--;
+  try_to_delete_context(ap->cp);
+}
+
+int Z3_ast_compare(value v1, value v2) {
+  Z3_ast_plus * a1 = (Z3_ast_plus*)Data_custom_val(v1);
+  Z3_ast_plus * a2 = (Z3_ast_plus*)Data_custom_val(v2);
+
+  /* if the two ASTs belong to different contexts, we take
+     their contexts' addresses to order them (arbitrarily, but fixed) */
+  if (a1->cp->ctx != a2->cp->ctx)
+     return compare_pointers(a1->cp->ctx, a2->cp->ctx);
+
+  /* handling of NULL pointers */
+  if (a1->p == NULL && a2->p == NULL)
+    return 0;
+  if (a1->p == NULL)
+    return -1;
+  if (a2->p == NULL)
+    return +1;
+
+  /* Comparison according to AST ids. */
+  unsigned id1 = Z3_get_ast_id(a1->cp->ctx, a1->p);
+  unsigned id2 = Z3_get_ast_id(a2->cp->ctx, a2->p);
+  if (id1 == id2)
+    return 0;
+  else if (id1 < id2)
+    return -1;
+  else
+    return +1;
+}
+
+int Z3_ast_compare_ext(value v1, value v2) {
+  Z3_ast_plus * a1 = (Z3_ast_plus*)Data_custom_val(v1);
+  unsigned id1;
+  int id2 = Val_int(v2);
+  if (a1->p == NULL && id2 == 0)
+    return 0;
+  if (a1->p == NULL)
+    return -1;
+  if (id2 == 0)
+    return +1;
+  id1 = Z3_get_ast_id(a1->cp->ctx, a1->p);
+  if (id1 == id2)
+    return 0;
+  else if (id1 < id2)
+    return -1;
+  else
+    return +1;
+}
+
+intnat Z3_ast_hash(value v) {
+  Z3_ast_plus * ap = (Z3_ast_plus*)Data_custom_val(v);
+  if (ap->p == NULL)
+    return 0;
+  else
+    return Z3_get_ast_hash(ap->cp->ctx, ap->p);
+}
+
+static struct custom_operations Z3_ast_plus_custom_ops = {
+  (char*) "Z3_ast ops",
+  Z3_ast_finalize,
+  Z3_ast_compare,
+  Z3_ast_hash,
+  custom_serialize_default,
+  custom_deserialize_default,
+  Z3_ast_compare_ext
+};
+
+MK_CTX_OF(ast)
+
+#define MK_PLUS_OBJ_NO_REF(X)                                           \
+  typedef struct {                                                      \
+    Z3_context_plus cp;                                                 \
+    Z3_ ## X p;                                                         \
+  } Z3_ ## X ## _plus;                                                  \
+                                                                        \
+  Z3_ ## X ## _plus Z3_ ## X ## _plus_mk(Z3_context_plus cp, Z3_ ## X p) { \
+    Z3_ ## X ## _plus  r;                                               \
+      r.cp = cp;                                                        \
+      r.p = p;                                                          \
+      r.cp->obj_count++;                                                \
+      return r;                                                         \
+  }                                                                     \
+                                                                        \
+  Z3_ ## X Z3_ ## X ## _plus_raw(Z3_ ## X ## _plus * pp) {              \
+    return pp->p;                                                       \
+  }                                                                     \
+                                                                        \
+  void Z3_ ## X ## _finalize(value v) {                                 \
+    Z3_ ## X ## _plus * pp = (Z3_ ## X ## _plus*)Data_custom_val(v);    \
+    pp->cp->obj_count--;                                                \
+    try_to_delete_context(pp->cp);                                      \
+  }                                                                     \
+                                                                        \
+  int Z3_ ## X ## _compare(value v1, value v2) {                        \
+    Z3_ ## X ## _plus * pp1 = (Z3_ ## X ## _plus*)Data_custom_val(v1);  \
+    Z3_ ## X ## _plus * pp2 = (Z3_ ## X ## _plus*)Data_custom_val(v2);  \
+    if (pp1->cp != pp2->cp)                                             \
+      return compare_pointers(pp1->cp, pp2->cp);                        \
+    else                                                                \
+      return compare_pointers(pp1->p, pp2->p);                          \
+  }                                                                     \
+                                                                        \
+  intnat Z3_ ## X ## _hash(value v) {                                   \
+    Z3_ ## X ## _plus * pp = (Z3_ ## X ## _plus*)Data_custom_val(v);    \
+    return (intnat)pp->p;                                               \
+  }                                                                     \
+                                                                        \
+  int Z3_ ## X ## _compare_ext(value v1, value v2) {                    \
+    Z3_ ## X ## _plus * pp = (Z3_ ## X ## _plus*)Data_custom_val(v1);   \
+    return compare_pointers(pp->p, (void*)Val_int(v2));                 \
+  }                                                                     \
+                                                                        \
+  static struct custom_operations Z3_ ## X ## _plus_custom_ops = {      \
+    (char*) "Z3_" #X " ops",                                            \
+    Z3_ ## X ## _finalize,                                              \
+    Z3_ ## X ## _compare,                                               \
+    Z3_ ## X ## _hash,                                                  \
+    custom_serialize_default,                                           \
+    custom_deserialize_default,                                         \
+    Z3_ ## X ## _compare_ext                                            \
+  };                                                                    \
+                                                                        \
+  MK_CTX_OF(X)
+
+#define MK_PLUS_OBJ(X)                                                  \
+  typedef struct {                                                      \
+    Z3_context_plus cp;                                                 \
+    Z3_ ## X p;                                                         \
+  } Z3_ ## X ## _plus;                                                  \
+                                                                        \
+  Z3_ ## X ## _plus Z3_ ## X ## _plus_mk(Z3_context_plus cp, Z3_ ## X p) { \
+    Z3_ ## X ## _plus  r;                                               \
+      r.cp = cp;                                                        \
+      r.p = p;                                                          \
+      r.cp->obj_count++;                                                \
+      if (p != NULL)                                                    \
+        Z3_ ## X ## _inc_ref(cp->ctx, p);                               \
+      return r;                                                         \
+  }                                                                     \
+                                                                        \
+  Z3_ ## X Z3_ ## X ## _plus_raw(Z3_ ## X ## _plus * pp) {              \
+    return pp->p;                                                       \
+  }                                                                     \
+                                                                        \
+  void Z3_ ## X ## _finalize(value v) {                                 \
+    Z3_ ## X ## _plus * pp = (Z3_ ## X ## _plus*)Data_custom_val(v);    \
+    if (pp->p != NULL)                                                  \
+      Z3_ ## X ## _dec_ref(pp->cp->ctx, pp->p);                         \
+    pp->cp->obj_count--;                                                \
+    try_to_delete_context(pp->cp);                                      \
+  }                                                                     \
+                                                                        \
+  int Z3_ ## X ## _compare(value v1, value v2) {                        \
+    Z3_ ## X ## _plus * pp1 = (Z3_ ## X ## _plus*)Data_custom_val(v1);  \
+    Z3_ ## X ## _plus * pp2 = (Z3_ ## X ## _plus*)Data_custom_val(v2);  \
+    if (pp1->cp != pp2->cp)                                             \
+      return compare_pointers(pp1->cp, pp2->cp);                        \
+    else                                                                \
+      return compare_pointers(pp1->p, pp2->p);                          \
+  }                                                                     \
+                                                                        \
+  intnat Z3_ ## X ## _hash(value v) {                                   \
+    Z3_ ## X ## _plus * pp = (Z3_ ## X ## _plus*)Data_custom_val(v);    \
+    return (intnat)pp->p;                                               \
+  }                                                                     \
+                                                                        \
+  int Z3_ ## X ## _compare_ext(value v1, value v2) {                    \
+    Z3_ ## X ## _plus * pp = (Z3_ ## X ## _plus*)Data_custom_val(v1);   \
+    return compare_pointers(pp->p, (void*)Val_int(v2));                 \
+  }                                                                     \
+                                                                        \
+  static struct custom_operations Z3_ ## X ## _plus_custom_ops = {      \
+    (char*) "Z3_" #X " ops",                                            \
+    Z3_ ## X ## _finalize,                                              \
+    Z3_ ## X ## _compare,                                               \
+    Z3_ ## X ## _hash,                                                  \
+    custom_serialize_default,                                           \
+    custom_deserialize_default,                                         \
+    Z3_ ## X ## _compare_ext                                            \
+  };                                                                    \
+                                                                        \
+  MK_CTX_OF(X)
+
+MK_PLUS_OBJ_NO_REF(symbol)
+MK_PLUS_OBJ_NO_REF(constructor)
+MK_PLUS_OBJ_NO_REF(constructor_list)
+MK_PLUS_OBJ_NO_REF(rcf_num)
+MK_PLUS_OBJ(params)
+MK_PLUS_OBJ(param_descrs)
+MK_PLUS_OBJ(model)
+MK_PLUS_OBJ(func_interp)
+MK_PLUS_OBJ(func_entry)
+MK_PLUS_OBJ(goal)
+MK_PLUS_OBJ(tactic)
+MK_PLUS_OBJ(probe)
+MK_PLUS_OBJ(apply_result)
+MK_PLUS_OBJ(solver)
+MK_PLUS_OBJ(stats)
+MK_PLUS_OBJ(ast_map)
+MK_PLUS_OBJ(ast_vector)
+MK_PLUS_OBJ(fixedpoint)
+MK_PLUS_OBJ(optimize)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void MLErrorHandler(Z3_context c, Z3_error_code e)
+{
+  /* Internal do-nothing error handler. This is required to avoid that Z3 calls exit()
+     upon errors, but the actual error handling is done by throwing exceptions in the
+     n_* wrapper functions. */
+}
+
+CAMLprim value DLL_PUBLIC n_set_internal_error_handler(value ctx_v)
+{
+  CAMLparam1(ctx_v);
+  Z3_context_plus ctx_p = *(Z3_context_plus*) Data_custom_val(ctx_v);
+  Z3_set_error_handler(ctx_p->ctx, MLErrorHandler);
+  CAMLreturn(Val_unit);
+}