diff --git a/drivers/beagle.drv b/drivers/beagle.drv
index 9c5dbe6c19141e9d4c8ad95bce92bca524c1cda3..707e0832185d0ee42e947b4710ca872ea3123478 100644
--- a/drivers/beagle.drv
+++ b/drivers/beagle.drv
@@ -1,7 +1,7 @@
 (* Why3 driver for beagle
    see http://users.cecs.anu.edu.au/~baumgart/systems/beagle/ *)
 
-printer "tptp-tff"
+printer "tptp-tff0"
 filename "%f-%t-%g.p"
 
 valid   "Proof found"
@@ -34,8 +34,10 @@ transformation "eliminate_algebraic"
 transformation "eliminate_let"
 transformation "eliminate_if"
 
+transformation "discriminate"
 transformation "encoding_smt"
-transformation "encoding_sort"
+
+import "discrimination.gen"
 
 theory BuiltIn
   syntax predicate (=)  "(%1 = %2)"
@@ -45,11 +47,6 @@ theory BuiltIn
   meta "encoding : kept" type int
   meta "encoding : kept" type real
   meta "eliminate_algebraic" "no_index"
-
-  meta "select_inst" "all"
-  meta "select_lskept" "all"
-  meta "select_lsinst" "all"
-  meta "select_kept" "all"
 end
 
 theory int.Int
diff --git a/drivers/princess.drv b/drivers/princess.drv
index 54ebd9e2a4b11b6a46ecc660cee5de82084d9d19..1827bfc25515d98de47faa1bee381b7a9a03f998 100644
--- a/drivers/princess.drv
+++ b/drivers/princess.drv
@@ -1,7 +1,7 @@
 (* Why3 driver for princess
    see http://www.philipp.ruemmer.org/princess.shtml *)
 
-printer "tptp-tff"
+printer "tptp-tff0"
 filename "%f-%t-%g.p"
 
 valid   "Proof found"
@@ -36,7 +36,8 @@ transformation "eliminate_if"
 
 transformation "discriminate"
 transformation "encoding_smt"
-transformation "encoding_sort"
+
+import "discrimination.gen"
 
 theory BuiltIn
   syntax predicate (=)  "(%1 = %2)"
@@ -46,11 +47,6 @@ theory BuiltIn
   meta "encoding : kept" type int
   meta "encoding : kept" type real
   meta "eliminate_algebraic" "no_index"
-
-  meta "select_inst" "all"
-  meta "select_lskept" "all"
-  meta "select_lsinst" "all"
-  meta "select_kept" "all"
 end
 
 theory int.Int
diff --git a/drivers/simplify.drv b/drivers/simplify.drv
index b76b897a0b2e06232c89cba3abc8b0d0c4ae704c..b3c2dddbf903718f1e73e73c79e42091d0ec1ccd 100644
--- a/drivers/simplify.drv
+++ b/drivers/simplify.drv
@@ -28,18 +28,12 @@ trigger they can't appear since = can't appear *)
 (*transformation "filter_trigger_builtin"*)
 
 (* this is sound as long as int is the only kept type *)
-transformation "encoding_smt"
+transformation "encoding_tptp"
 
 theory BuiltIn
   syntax predicate (=)  "(EQ %1 %2)"
 
-  meta "encoding : kept" type int
-
-  (* no symbol discrimination, no kept types *)
-  meta "select_inst" "none"
-  meta "select_lskept" "none"
-  meta "select_lsinst" "none"
-  meta "select_kept" "none"
+  meta "encoding : base" type int
 end
 
 theory int.Int
diff --git a/drivers/tptp-tff.drv b/drivers/tptp-tff0.drv
similarity index 97%
rename from drivers/tptp-tff.drv
rename to drivers/tptp-tff0.drv
index 3e52c1f54a8fc384f45c17e9c3939aab63036364..224bc7d1723b83649dd4e5f7cb5bf84082b6fcf1 100644
--- a/drivers/tptp-tff.drv
+++ b/drivers/tptp-tff0.drv
@@ -1,6 +1,6 @@
 (* Why driver for first-order tptp provers supporting TFF0 *)
 
-printer "tptp-tff"
+printer "tptp-tff0"
 filename "%f-%t-%g.p"
 
 valid   "Proof found"
@@ -29,8 +29,10 @@ transformation "eliminate_definition"
 transformation "eliminate_inductive"
 transformation "eliminate_algebraic"
 
+transformation "discriminate"
 transformation "encoding_smt"
-transformation "encoding_sort"
+
+import "discrimination.gen"
 
 theory BuiltIn
   syntax predicate (=)  "(%1 = %2)"
@@ -40,11 +42,6 @@ theory BuiltIn
   meta "encoding : kept" type int
   meta "encoding : kept" type real
   meta "eliminate_algebraic" "no_index"
-
-  meta "select_inst" "all"
-  meta "select_lskept" "all"
-  meta "select_lsinst" "all"
-  meta "select_kept" "all"
 end
 
 theory int.Int
diff --git a/drivers/tptp-tff1.drv b/drivers/tptp-tff1.drv
new file mode 100644
index 0000000000000000000000000000000000000000..351e7aedf84427e199164a7ea4b1dc8b871d5d02
--- /dev/null
+++ b/drivers/tptp-tff1.drv
@@ -0,0 +1,279 @@
+(* Why driver for first-order tptp provers supporting TFF1 *)
+
+printer "tptp-tff1"
+filename "%f-%t-%g.p"
+
+valid   "Proof found"
+invalid "Completion found"
+valid   "^% SZS status Theorem"
+valid   "^% SZS status Unsatisfiable"
+unknown "^% SZS status CounterSatisfiable" ""
+unknown "^% SZS status Satisfiable" ""
+timeout "^% SZS status Timeout"
+unknown "^% SZS status GaveUp" ""
+fail    "^% SZS status Error" ""
+timeout "Ran out of time"
+timeout "CPU time limit exceeded"
+outofmemory "Out of Memory"
+unknown "No Proof Found"            ""
+fail    "Failure.*"                   "\"\\0\""
+time "why3cpulimit time : %s s"
+
+
+(* to be improved *)
+
+transformation "inline_trivial"
+
+transformation "eliminate_builtin"
+transformation "eliminate_definition"
+transformation "eliminate_inductive"
+transformation "eliminate_algebraic"
+
+theory BuiltIn
+  syntax predicate (=)  "(%1 = %2)"
+  syntax type int  "$int"
+  syntax type real "$real"
+
+  meta "eliminate_algebraic" "no_index"
+end
+
+theory int.Int
+  syntax function zero "0"
+  syntax function one  "1"
+
+  syntax function (+)  "$sum(%1,%2)"
+  syntax function (-)  "$difference(%1,%2)"
+  syntax function (*)  "$product(%1,%2)"
+  syntax function (-_) "$uminus(%1)"
+
+  syntax predicate (<=) "$lesseq(%1,%2)"
+  syntax predicate (<)  "$less(%1,%2)"
+  syntax predicate (>=) "$greatereq(%1,%2)"
+  syntax predicate (>)  "$greater(%1,%2)"
+
+  remove prop CommutativeGroup.Comm.Comm
+  remove prop CommutativeGroup.Assoc
+  remove prop CommutativeGroup.Unit_def_l
+  remove prop CommutativeGroup.Unit_def_r
+  remove prop CommutativeGroup.Inv_def_l
+  remove prop CommutativeGroup.Inv_def_r
+  remove prop Assoc.Assoc
+  remove prop Mul_distr_l
+  remove prop Mul_distr_r
+  remove prop Comm.Comm
+  remove prop Unitary
+  remove prop Refl
+  remove prop Trans
+  remove prop Antisymm
+  remove prop Total
+  remove prop NonTrivialRing
+  remove prop CompatOrderAdd
+  remove prop ZeroLessOne
+end
+
+theory real.Real
+  syntax function zero "0.0"
+  syntax function one  "1.0"
+
+  syntax function (+)  "$sum(%1,%2)"
+  syntax function (-)  "$difference(%1,%2)"
+  syntax function (*)  "$product(%1,%2)"
+  syntax function (-_) "$uminus(%1)"
+
+  syntax function (/)  "$quotient(%1,%2)"
+  syntax function inv  "$quotient(1.0,%1)"
+
+  syntax predicate (<=) "$lesseq(%1,%2)"
+  syntax predicate (<)  "$less(%1,%2)"
+  syntax predicate (>=) "$greatereq(%1,%2)"
+  syntax predicate (>)  "$greater(%1,%2)"
+
+  remove prop CommutativeGroup.Comm.Comm
+  remove prop CommutativeGroup.Assoc
+  remove prop CommutativeGroup.Unit_def_l
+  remove prop CommutativeGroup.Unit_def_r
+  remove prop CommutativeGroup.Inv_def_l
+  remove prop CommutativeGroup.Inv_def_r
+  remove prop Assoc.Assoc
+  remove prop Mul_distr_l
+  remove prop Mul_distr_r
+  remove prop Comm.Comm
+  remove prop Unitary
+  remove prop Inverse
+  remove prop Refl
+  remove prop Trans
+  remove prop Antisymm
+  remove prop Total
+  remove prop NonTrivialRing
+  remove prop CompatOrderAdd
+  remove prop ZeroLessOne
+end
+
+theory int.EuclideanDivision
+  syntax function div "$quotient_e(%1,%2)"
+  syntax function mod "$remainder_e(%1,%2)"
+
+  remove prop Div_mod
+  remove prop Div_bound
+  remove prop Mod_bound
+  remove prop Mod_1
+  remove prop Div_1
+  remove prop Div_inf
+  remove prop Div_inf_neg
+  remove prop Mod_0
+  remove prop Div_1_left
+  remove prop Div_minus1_left
+  remove prop Mod_1_left
+  remove prop Mod_minus1_left
+end
+
+theory tptp.Univ
+  syntax type iType "$i"
+end
+
+theory tptp.IntTrunc
+  syntax function floor    "$floor(%1)"
+  syntax function ceil     "$ceil(%1)"
+  syntax function truncate "$truncate(%1)"
+  syntax function round    "$round(%1)"
+
+  syntax function to_int   "$to_int(%1)"
+
+  syntax predicate is_int  "$is_int(%1)"
+  syntax predicate is_rat  "$is_rat(%1)"
+end
+
+theory tptp.IntDivT
+  syntax function div_t "$quotient_t(%1,%2)"
+  syntax function mod_t "$remainder_t(%1,%2)"
+end
+
+theory tptp.IntDivF
+  syntax function div_f "$quotient_f(%1,%2)"
+  syntax function mod_f "$remainder_f(%1,%2)"
+end
+
+theory tptp.Rat
+  syntax type rat "$rat"
+
+  syntax function zero "0/1"
+  syntax function one  "1/1"
+
+  syntax function (+)  "$sum(%1,%2)"
+  syntax function (-)  "$difference(%1,%2)"
+  syntax function (*)  "$product(%1,%2)"
+  syntax function (-_) "$uminus(%1)"
+
+  syntax function (/)  "$quotient(%1,%2)"
+  syntax function inv  "$quotient(1.0,%1)"
+
+  syntax predicate (<=) "$lesseq(%1,%2)"
+  syntax predicate (<)  "$less(%1,%2)"
+  syntax predicate (>=) "$greatereq(%1,%2)"
+  syntax predicate (>)  "$greater(%1,%2)"
+
+  syntax function to_rat   "$to_rat(%1)"
+
+  syntax predicate is_int  "$is_int(%1)"
+  syntax predicate is_rat  "$is_rat(%1)"
+
+  remove prop CommutativeGroup.Comm.Comm
+  remove prop CommutativeGroup.Assoc
+  remove prop CommutativeGroup.Unit_def_l
+  remove prop CommutativeGroup.Unit_def_r
+  remove prop CommutativeGroup.Inv_def_l
+  remove prop CommutativeGroup.Inv_def_r
+  remove prop Assoc.Assoc
+  remove prop Mul_distr_l
+  remove prop Mul_distr_r
+  remove prop Comm.Comm
+  remove prop Unitary
+  remove prop Refl
+  remove prop Trans
+  remove prop Antisymm
+  remove prop Total
+  remove prop NonTrivialRing
+  remove prop CompatOrderAdd
+  remove prop ZeroLessOne
+end
+
+theory tptp.RatTrunc
+  syntax function floor    "$floor(%1)"
+  syntax function ceil     "$ceil(%1)"
+  syntax function truncate "$truncate(%1)"
+  syntax function round    "$round(%1)"
+
+  syntax function to_int   "$to_int(%1)"
+end
+
+theory tptp.RatDivE
+  syntax function div "$quotient_e(%1,%2)"
+  syntax function mod "$remainder_e(%1,%2)"
+end
+
+theory tptp.RatDivT
+  syntax function div_t "$quotient_t(%1,%2)"
+  syntax function mod_t "$remainder_t(%1,%2)"
+end
+
+theory tptp.RatDivF
+  syntax function div_f "$quotient_f(%1,%2)"
+  syntax function mod_f "$remainder_f(%1,%2)"
+end
+
+theory tptp.Real
+  syntax function to_real "$to_real(%1)"
+end
+
+theory real.Truncate
+  syntax function floor    "$floor(%1)"
+  syntax function ceil     "$ceil(%1)"
+  syntax function truncate "$truncate(%1)"
+end
+
+theory tptp.RealTrunc
+  syntax function round    "$round(%1)"
+
+  syntax function to_int   "$to_int(%1)"
+
+  syntax predicate is_int  "$is_int(%1)"
+  syntax predicate is_rat  "$is_rat(%1)"
+end
+
+theory tptp.RealDivE
+  syntax function div "$quotient_e(%1,%2)"
+  syntax function mod "$remainder_e(%1,%2)"
+end
+
+theory tptp.RealDivT
+  syntax function div_t "$quotient_t(%1,%2)"
+  syntax function mod_t "$remainder_t(%1,%2)"
+end
+
+theory tptp.RealDivF
+  syntax function div_f "$quotient_f(%1,%2)"
+  syntax function mod_f "$remainder_f(%1,%2)"
+end
+
+theory tptp.IntToRat
+  syntax function to_rat   "$to_rat(%1)"
+end
+
+theory tptp.IntToReal
+  syntax function to_real "$to_real(%1)"
+end
+
+theory tptp.RealToRat
+  syntax function to_rat   "$to_rat(%1)"
+end
+
+theory tptp.RatToReal
+  syntax function to_real "$to_real(%1)"
+end
+
+(*
+Local Variables:
+mode: why
+compile-command: "unset LANG; make -C .. bench"
+End:
+*)
diff --git a/drivers/z3_smtv1.drv b/drivers/z3_smtv1.drv
index f6d5fd31c23429daef9159e1f36a6f71c325dcf6..d2acd89c73fc07c1c839623b97fcffb601f2ddc8 100644
--- a/drivers/z3_smtv1.drv
+++ b/drivers/z3_smtv1.drv
@@ -22,7 +22,6 @@ transformation "simplify_formula"
 (*transformation "simplify_trivial_quantification"*)
 
 transformation "encoding_smt"
-transformation "encoding_sort"
 
 theory BuiltIn
   syntax type int   "Int"
diff --git a/plugins/tptp/tptp_printer.ml b/plugins/tptp/tptp_printer.ml
index 6937a21dea076dde37a82ecf3d3ae2498a77f9c4..e2f7718c11ceca17f5ed885182f1282093cd86a8 100644
--- a/plugins/tptp/tptp_printer.ml
+++ b/plugins/tptp/tptp_printer.ml
@@ -45,22 +45,46 @@ let print_pr fmt pr =
 let forget_var v = forget_id ident_printer v.vs_name
 let forget_tvar v = forget_id ident_printer v.tv_name
 
+type tptp_format = FOF | TFF0 | TFF1
+
 type info = {
   info_syn : syntax_map;
-  info_fof : bool;
+  info_fmt : tptp_format;
+  info_srt : ty Mty.t ref;
+  info_urg : string list ref;
 }
 
+let complex_type = Wty.memoize 3 (fun ty ->
+  let s = Pp.string_of_wnl Pretty.print_ty ty in
+  create_tysymbol (id_fresh s) [] None)
+
 let rec print_type info fmt ty = match ty.ty_node with
+  | Tyvar _ when info.info_fmt = TFF0 ->
+      unsupported "TFF0 does not support polymorphic types"
   | Tyvar tv -> print_tvar fmt tv
-  | Tyapp (ts, tl) -> begin match query_syntax info.info_syn ts.ts_name with
-      | Some s -> syntax_arguments s (print_type info) fmt tl
-      | None -> begin match tl with
-          | [] -> print_symbol fmt ts.ts_name
-          | _ -> fprintf fmt "@[%a(%a)@]" print_symbol ts.ts_name
-              (print_list comma (print_type info)) tl
+  | Tyapp (ts, tl) ->
+      begin match query_syntax info.info_syn ts.ts_name, tl with
+      | Some s, _ -> syntax_arguments s (print_type info) fmt tl
+      | None, [] -> print_symbol fmt ts.ts_name
+      | None, _ when info.info_fmt = TFF0 ->
+          begin match Mty.find_opt ty !(info.info_srt) with
+          | Some ty -> print_type info fmt ty
+          | None ->
+              let ts = complex_type ty in let cty = ty_app ts [] in
+              let us = sprintf "@[<hov 2>tff(%s, type,@ %a:@ $tType).@]@\n@\n"
+                (id_unique pr_printer ts.ts_name) print_symbol ts.ts_name in
+              info.info_srt := Mty.add ty cty !(info.info_srt);
+              info.info_urg := us :: !(info.info_urg);
+              print_type info fmt cty
           end
+      | None, tl ->
+          fprintf fmt "@[%a(%a)@]" print_symbol ts.ts_name
+            (print_list comma (print_type info)) tl
       end
 
+let print_type info fmt ty = try print_type info fmt ty
+  with Unsupported s -> raise (UnsupportedType (ty,s))
+
 let number_format = {
   Number.long_int_support = true;
   Number.extra_leading_zeros_support = false;
@@ -73,8 +97,7 @@ let number_format = {
   Number.hex_real_support = Number.Number_unsupported;
   Number.frac_real_support = Number.Number_custom
     (Number.PrintFracReal ("%s", "(%s * %s)", "(%s / %s)"));
-  Number.def_real_support = Number.Number_unsupported
-  ;
+  Number.def_real_support = Number.Number_unsupported;
 }
 
 let rec print_app info fmt ls tl oty =
@@ -131,7 +154,7 @@ and print_fmla info fmt f = match f.t_node with
       let q = match q with Tforall -> "!" | Texists -> "?" in
       let vl, _tl, f = t_open_quant fq in
       let print_vsty fmt vs =
-        if info.info_fof then fprintf fmt "%a" print_var vs
+        if info.info_fmt = FOF then fprintf fmt "%a" print_var vs
         else fprintf fmt "%a:@,%a" print_var vs (print_type info) vs.vs_ty in
       fprintf fmt "%s[%a]:@ %a" q
         (print_list comma print_vsty) vl (print_fmla info) f;
@@ -160,8 +183,9 @@ let print_fmla info fmt f =
   Stv.iter forget_tvar tvs
 
 let print_decl info fmt d = match d.d_node with
-  | Dtype _ when info.info_fof -> ()
+  | Dtype _ when info.info_fmt = FOF -> ()
   | Dtype { ts_def = Some _ } -> ()
+  | Dtype { ts_args = _::_ } when info.info_fmt = TFF0 -> ()
   | Dtype ts when query_syntax info.info_syn ts.ts_name <> None -> ()
   | Dtype ts ->
       let print_arg fmt _ = fprintf fmt "$tType" in
@@ -173,7 +197,7 @@ let print_decl info fmt d = match d.d_node with
       fprintf fmt "@[<hov 2>tff(%s, type,@ %a:@ %a).@]@\n@\n"
         (id_unique pr_printer ts.ts_name)
         print_symbol ts.ts_name print_sig ts
-  | Dparam _ when info.info_fof -> ()
+  | Dparam _ when info.info_fmt = FOF -> ()
   | Dparam ls when query_syntax info.info_syn ls.ls_name <> None -> ()
   | Dparam ls ->
       let print_type = print_type info in
@@ -208,30 +232,43 @@ let print_decl info fmt d = match d.d_node with
       "TPTP does not support inductive predicates, use eliminate_inductive"
   | Dprop (Paxiom, pr, _) when Mid.mem pr.pr_name info.info_syn -> ()
   | Dprop (Paxiom, pr, f) ->
-      let head = if info.info_fof then "fof" else "tff" in
+      let head = if info.info_fmt = FOF then "fof" else "tff" in
       fprintf fmt "@[<hov 2>%s(%a, axiom,@ %a).@]@\n@\n"
         head print_pr pr (print_fmla info) f
   | Dprop (Pgoal, pr, f) ->
-      let head = if info.info_fof then "fof" else "tff" in
+      let head = if info.info_fmt = FOF then "fof" else "tff" in
       fprintf fmt "@[<hov 2>%s(%a, conjecture,@ %a).@]@\n"
         head print_pr pr (print_fmla info) f
   | Dprop ((Plemma|Pskip), _, _) -> assert false
 
-let print_decl info fmt = catch_unsupportedDecl (print_decl info fmt)
-
-let print_task fof _env pr thpr _blacklist ?old:_ fmt task =
-  forget_all ident_printer;
-  forget_all pr_printer;
-  print_prelude fmt pr;
-  print_th_prelude task fmt thpr;
-  let info = { info_syn = get_syntax_map task; info_fof = fof } in
-  fprintf fmt "@[%a@]@."
-    (print_list nothing (print_decl info)) (Task.task_decls task)
-
-let () = register_printer "tptp-tff" (print_task false) ~desc:"TPTP TFF format"
-let () = register_printer "tptp-fof" (print_task true) ~desc:"TPTP FOF format"
-
-
+let print_decls fm =
+  let print_decl (sm,fm,ct) fmt d =
+    let info = { info_syn = sm;     info_fmt = fm;
+                 info_srt = ref ct; info_urg = ref [] } in
+    try print_decl info fmt d;
+        (sm,fm,!(info.info_srt)), !(info.info_urg)
+    with Unsupported s -> raise (UnsupportedDecl (d,s)) in
+  let print_decl = Printer.sprint_decl print_decl in
+  let print_decl task acc = print_decl task.Task.task_decl acc in
+  Discriminate.on_syntax_map (fun sm ->
+    Trans.fold print_decl ((sm,fm,Mty.empty),[]))
+
+let print_task fm =
+  let print_decls = print_decls fm in
+  fun _env pr thpr _blacklist ?old:_ fmt task ->
+    (* In trans-based p-printing [forget_all] is a no-no *)
+    (* forget_all ident_printer; *)
+    print_prelude fmt pr;
+    print_th_prelude task fmt thpr;
+    let rec print = function
+      | x :: r -> print r; Pp.string fmt x
+      | [] -> () in
+    print (snd (Trans.apply print_decls task));
+    pp_print_flush fmt ()
+
+let () = register_printer "tptp-tff0" (print_task TFF0) ~desc:"TPTP TFF0 format"
+let () = register_printer "tptp-tff1" (print_task TFF1) ~desc:"TPTP TFF1 format"
+let () = register_printer "tptp-fof"  (print_task FOF)  ~desc:"TPTP FOF format"
 
 (** DFG input format for SPASS >= 3.8
     (with the help of Daniel Wand)
@@ -364,7 +401,11 @@ let print_dfg _env pr thpr _blacklist ?old:_ fmt task =
   fprintf fmt
     "name({**}). author({**}). status(unknown). description({**}).@\n";
   fprintf fmt "end_of_list.@\n@\n";
-  let info = { info_syn = get_syntax_map task; info_fof = true } in
+  let info = {
+    info_syn = get_syntax_map task;
+    info_fmt = FOF;
+    info_urg = ref [];
+    info_srt = ref Mty.empty } in
   let dl = Task.task_decls task in
   let tl = List.filter (is_type info) dl in
   let fl = List.filter (is_function info) dl in
diff --git a/plugins/tptp/tptp_typing.ml b/plugins/tptp/tptp_typing.ml
index 7f2cf25ed5e466605a25d95c5aaa2741be9ad6a8..96edbd20218bfaabf448662db342bf68e2a1fdd2 100644
--- a/plugins/tptp/tptp_typing.ml
+++ b/plugins/tptp/tptp_typing.ml
@@ -649,7 +649,7 @@ let typecheck lib path ast =
         let f,_ = fmla denv env impl (Some pol) [] e in
         let f = if strict then f else
           let q = if pol then Texists else Tforall in
-          let vl = Mvs.keys f.t_vars in
+          let vl = Mvs.keys (t_vars f) in
           t_quant_close q vl [] f in
         let env,uc = flush_impl ~strict env uc impl in
 
diff --git a/src/core/decl.ml b/src/core/decl.ml
index 04d0042e08f795060d369242acaade9525d9b735..927b4fbc49a2e757992785f2aa2bcd839a8671d1 100644
--- a/src/core/decl.ml
+++ b/src/core/decl.ml
@@ -30,7 +30,7 @@ type logic_decl = lsymbol * ls_defn
 exception UnboundVar of vsymbol
 
 let check_fvs f =
-  Mvs.iter (fun vs _ -> raise (UnboundVar vs)) f.t_vars;
+  t_v_fold (fun _ vs -> raise (UnboundVar vs)) () f;
   t_prop f
 
 let check_vl ty v = ty_equal_check ty v.vs_ty
diff --git a/src/core/dterm.ml b/src/core/dterm.ml
index e1c6570ccd2c4ac347ca91b27720267d605e408e..2647b958f00b1f0b1b8982001f85f7bd421aa968 100644
--- a/src/core/dterm.ml
+++ b/src/core/dterm.ml
@@ -356,8 +356,8 @@ let quant_vars ~strict env vl =
   let acc, vl = Lists.map_fold_left add Mstr.empty vl in
   Mstr.set_union acc env, vl
 
-let check_used_var vars vs =
-  if not (Mvs.mem vs vars) then
+let check_used_var t vs =
+  if t_v_occurs vs t = 0 then
   let s = vs.vs_name.id_string in
   if not (String.length s > 0 && s.[0] = '_') then
   Warning.emit ?loc:vs.vs_name.id_loc "unused variable %s" s
@@ -389,26 +389,26 @@ let term ~strict ~keep_loc env dt =
         let v = create_vsymbol id (t_type t) in
         let env = Mstr.add (preid_name id) v env in
         let f = get uloc env df in
-        check_used_var f.t_vars v;
+        check_used_var f v;
         t_let_close v t f
     | DTcase (dt,bl) ->
         let branch (dp,df) =
           let env, p = pattern ~strict env dp in
           let f = get uloc env df in
-          Svs.iter (check_used_var f.t_vars) p.pat_vars;
+          Svs.iter (check_used_var f) p.pat_vars;
           t_close_branch p f in
         t_case (get uloc env dt) (List.map branch bl)
     | DTeps (id,dty,df) ->
         let v = create_vsymbol id (ty_of_dty ~strict dty) in
         let env = Mstr.add (preid_name id) v env in
         let f = get uloc env df in
-        check_used_var f.t_vars v;
+        check_used_var f v;
         t_eps_close v f
     | DTquant (q,vl,dll,df) ->
         let env, vl = quant_vars ~strict env vl in
         let trl = List.map (List.map (get uloc env)) dll in
         let f = get uloc env df in
-        List.iter (check_used_var f.t_vars) vl;
+        List.iter (check_used_var f) vl;
         check_exists_implies q f;
         t_quant_close q vl trl f
     | DTbinop (op,df1,df2) ->
diff --git a/src/core/ident.ml b/src/core/ident.ml
index 6dd2e8b09eeab408cd55f501da5ad10dc9a1f573..ab7c8d1e42d8ec578949e5cbd5e6854dd97f2611 100644
--- a/src/core/ident.ml
+++ b/src/core/ident.ml
@@ -39,8 +39,8 @@ let create_label s = Hslab.hashcons {
 }
 
 let lab_equal : label -> label -> bool = (==)
-
-let lab_hash (lab : label) = lab.lab_tag
+let lab_hash lab = lab.lab_tag
+let lab_compare l1 l2 = Pervasives.compare l1.lab_tag l2.lab_tag
 
 (** Identifiers *)
 
@@ -64,8 +64,8 @@ module Wid = Id.W
 type preid = ident
 
 let id_equal : ident -> ident -> bool = (==)
-
 let id_hash id = Weakhtbl.tag_hash id.id_tag
+let id_compare id1 id2 = Pervasives.compare (id_hash id1) (id_hash id2)
 
 (* constructors *)
 
diff --git a/src/core/ident.mli b/src/core/ident.mli
index f989e5f68f11d40a37a20c537cea5733cd645e85..ac2716a4fc54ac6ec9b127ce18a26853e401efca 100644
--- a/src/core/ident.mli
+++ b/src/core/ident.mli
@@ -23,8 +23,9 @@ type label = private {
 module Mlab : Extmap.S with type key = label
 module Slab : Extset.S with module M = Mlab
 
+val lab_compare : label -> label -> int
 val lab_equal : label -> label -> bool
-val lab_hash  : label -> int
+val lab_hash : label -> int
 
 val create_label : string -> label
 
@@ -42,8 +43,8 @@ module Sid : Extset.S with module M = Mid
 module Hid : Exthtbl.S with type key = ident
 module Wid : Weakhtbl.S with type key = ident
 
+val id_compare : ident -> ident -> int
 val id_equal : ident -> ident -> bool
-
 val id_hash : ident -> int
 
 (* a user-created type of unregistered identifiers *)
diff --git a/src/core/printer.ml b/src/core/printer.ml
index e2f1d36992d9161d267cf5c8acafe7a2e61e527c..64e4d0cf3b236bf9281c4a832f22c199ec3619a9 100644
--- a/src/core/printer.ml
+++ b/src/core/printer.ml
@@ -266,7 +266,7 @@ let add_syntax_map td sm = match td.td_node with
 
 let query_syntax sm id = Mid.find_opt id sm
 
-let fold_tdecls fn acc =
+let on_syntax_map fn =
   Trans.on_meta meta_syntax_type (fun sts ->
   Trans.on_meta meta_syntax_logic (fun sls ->
   Trans.on_meta meta_remove_prop (fun spr ->
@@ -274,27 +274,27 @@ let fold_tdecls fn acc =
     let sm = List.fold_left sm_add_ts sm sts in
     let sm = List.fold_left sm_add_ls sm sls in
     let sm = List.fold_left sm_add_pr sm spr in
-    Trans.fold (fun t -> fn sm t.task_decl) acc)))
+    fn sm)))
 
-let sprint_tdecls (fn : syntax_map -> tdecl pp) =
-  let buf = Buffer.create 512 in
+let sprint_tdecl (fn : 'a -> Format.formatter -> tdecl -> 'a * string list) =
+  let buf = Buffer.create 2048 in
   let fmt = Format.formatter_of_buffer buf in
-  let print sm td acc =
+  fun td (acc,strl) ->
     Buffer.reset buf;
-    Format.fprintf fmt "%a@?" (fn sm) td;
-    Buffer.contents buf :: acc in
-  fold_tdecls print []
+    let acc, urg = fn acc fmt td in
+    Format.pp_print_flush fmt ();
+    acc, Buffer.contents buf :: List.rev_append urg strl
 
-let sprint_decls (fn : syntax_map -> decl pp) =
-  let buf = Buffer.create 512 in
+let sprint_decl (fn : 'a -> Format.formatter -> decl -> 'a * string list) =
+  let buf = Buffer.create 2048 in
   let fmt = Format.formatter_of_buffer buf in
-  let print sm td acc = match td.td_node with
+  fun td (acc,strl) -> match td.td_node with
     | Decl d ->
         Buffer.reset buf;
-        Format.fprintf fmt "%a@?" (fn sm) d;
-        Buffer.contents buf :: acc
-    | _ -> acc in
-  fold_tdecls print []
+        let acc, urg = fn acc fmt d in
+        Format.pp_print_flush fmt ();
+        acc, Buffer.contents buf :: List.rev_append urg strl
+    | _ -> acc, strl
 
 (** {2 exceptions to use in transformations and printers} *)
 
diff --git a/src/core/printer.mli b/src/core/printer.mli
index 8426dc46f5984bddb5943f6e6799a4efccac6d71..59df559bc5774ae32c9e52759de8732a5bfa95fc 100644
--- a/src/core/printer.mli
+++ b/src/core/printer.mli
@@ -72,10 +72,15 @@ val syntax_arguments_typed :
 
 (** {2 pretty-printing transformations (useful for caching)} *)
 
-val fold_tdecls : (syntax_map -> tdecl -> 'a -> 'a) -> 'a -> 'a Trans.trans
+val on_syntax_map : (syntax_map -> 'a Trans.trans) -> 'a Trans.trans
 
-val sprint_tdecls : (syntax_map -> tdecl pp) -> string list Trans.trans
-val sprint_decls  : (syntax_map -> decl  pp) -> string list Trans.trans
+val sprint_tdecl :
+  ('a -> Format.formatter -> Theory.tdecl -> 'a * string list) ->
+    Theory.tdecl -> 'a * string list -> 'a * string list
+
+val sprint_decl :
+  ('a -> Format.formatter -> Decl.decl -> 'a * string list) ->
+    Theory.tdecl -> 'a * string list -> 'a * string list
 
 (** {2 exceptions to use in transformations and printers} *)
 
diff --git a/src/core/term.ml b/src/core/term.ml
index 8f93b7d6071b3264102c8d69b634060df871e8d8..8c3ba32f04eb56f8a5fc24c4dadbe06df9da2c7c 100644
--- a/src/core/term.ml
+++ b/src/core/term.ml
@@ -31,8 +31,8 @@ module Hvs = Vsym.H
 module Wvs = Vsym.W
 
 let vs_equal : vsymbol -> vsymbol -> bool = (==)
-
 let vs_hash vs = id_hash vs.vs_name
+let vs_compare vs1 vs2 = id_compare vs1.vs_name vs2.vs_name
 
 let create_vsymbol name ty = {
   vs_name = id_register name;
@@ -60,8 +60,8 @@ module Hls = Lsym.H
 module Wls = Lsym.W
 
 let ls_equal : lsymbol -> lsymbol -> bool = (==)
-
 let ls_hash ls = id_hash ls.ls_name
+let ls_compare ls1 ls2 = id_compare ls1.ls_name ls2.ls_name
 
 let check_opaque opaque args value =
   if Stv.is_empty opaque then opaque else
@@ -94,7 +94,6 @@ type pattern = {
   pat_node : pattern_node;
   pat_vars : Svs.t;
   pat_ty   : ty;
-  pat_tag  : int;
 }
 
 and pattern_node =
@@ -104,55 +103,12 @@ and pattern_node =
   | Por  of pattern * pattern
   | Pas  of pattern * vsymbol
 
-let pat_equal : pattern -> pattern -> bool = (==)
-
-let pat_hash p = p.pat_tag
-
-module Hspat = Hashcons.Make (struct
-  type t = pattern
-
-  let equal_node p1 p2 = match p1, p2 with
-    | Pwild, Pwild -> true
-    | Pvar v1, Pvar v2 -> vs_equal v1 v2
-    | Papp (s1, l1), Papp (s2, l2) ->
-        ls_equal s1 s2 && List.for_all2 pat_equal l1 l2
-    | Por (p1, q1), Por (p2, q2) ->
-        pat_equal p1 p2 && pat_equal q1 q2
-    | Pas (p1, n1), Pas (p2, n2) ->
-        pat_equal p1 p2 && vs_equal n1 n2
-    | _ -> false
-
-  let equal p1 p2 =
-    equal_node p1.pat_node p2.pat_node && ty_equal p1.pat_ty p2.pat_ty
-
-  let hash_node = function
-    | Pwild -> 0
-    | Pvar v -> vs_hash v
-    | Papp (s, pl) -> Hashcons.combine_list pat_hash (ls_hash s) pl
-    | Por (p, q) -> Hashcons.combine (pat_hash p) (pat_hash q)
-    | Pas (p, v) -> Hashcons.combine (pat_hash p) (vs_hash v)
-
-  let hash p = Hashcons.combine (hash_node p.pat_node) (ty_hash p.pat_ty)
-
-  let tag n p = { p with pat_tag = n }
-end)
-
-module Pat = MakeMSH (struct
-  type t = pattern
-  let tag pat = pat.pat_tag
-end)
-
-module Spat = Pat.S
-module Mpat = Pat.M
-module Hpat = Pat.H
-
 (* h-consing constructors for patterns *)
 
-let mk_pattern n vs ty = Hspat.hashcons {
+let mk_pattern n vs ty = {
   pat_node = n;
   pat_vars = vs;
   pat_ty   = ty;
-  pat_tag  = -1
 }
 
 exception UncoveredVar of vsymbol
@@ -271,8 +227,6 @@ type term = {
   t_ty    : ty option;
   t_label : Slab.t;
   t_loc   : Loc.position option;
-  t_vars  : int Mvs.t;
-  t_tag   : int;
 }
 
 and term_node =
@@ -300,10 +254,248 @@ and bind_info = {
   bv_subst : term Mvs.t   (* deferred substitution *)
 }
 
-(* term equality and hash *)
-
-let t_equal : term -> term -> bool = (==)
-let t_hash t = t.t_tag
+(* term equality modulo alpha-equivalence and location *)
+
+exception CompLT
+exception CompGT
+
+type frame = int Mvs.t * term Mvs.t
+
+type term_or_bound =
+  | Trm of term * frame list
+  | Bnd of int
+
+let rec descend vml t = match t.t_node with
+  | Tvar vs ->
+      let rec find vs = function
+        | (bv,vm)::vml ->
+            begin match Mvs.find_opt vs bv with
+            | Some i -> Bnd i
+            | None ->
+                begin match Mvs.find_opt vs vm with
+                | Some t -> descend vml t
+                | None   -> find vs vml
+                end
+            end
+        | [] -> Trm (t, [])
+      in
+      find vs vml
+  | _ -> Trm (t, vml)
+
+let t_compare t1 t2 =
+  let comp_raise c =
+    if c < 0 then raise CompLT else if c > 0 then raise CompGT in
+  let perv_compare h1 h2 = comp_raise (Pervasives.compare h1 h2) in
+  let rec pat_compare (bnd,bv1,bv2 as state) p1 p2 =
+    match p1.pat_node, p2.pat_node with
+    | Pwild, Pwild ->
+        bnd, bv1, bv2
+    | Pvar v1, Pvar v2 ->
+        bnd + 1, Mvs.add v1 bnd bv1, Mvs.add v2 bnd bv2
+    | Papp (s1, l1), Papp (s2, l2) ->
+        comp_raise (ls_compare s1 s2);
+        List.fold_left2 pat_compare state l1 l2
+    | Por (p1, q1), Por (p2, q2) ->
+        let (_,bv1,bv2 as res) = pat_compare state p1 p2 in
+        let rec or_cmp q1 q2 = match q1.pat_node, q2.pat_node with
+          | Pwild, Pwild -> ()
+          | Pvar v1, Pvar v2 ->
+              perv_compare (Mvs.find v1 bv1) (Mvs.find v2 bv2)
+          | Papp (s1, l1), Papp (s2, l2) ->
+              comp_raise (ls_compare s1 s2);
+              List.iter2 or_cmp l1 l2
+          | Por (p1, q1), Por (p2, q2) ->
+              or_cmp p1 p2; or_cmp q1 q2
+          | Pas (p1, v1), Pas (p2, v2) ->
+              or_cmp p1 p2;
+              perv_compare (Mvs.find v1 bv1) (Mvs.find v2 bv2)
+          | Pwild,  _ -> raise CompLT | _, Pwild  -> raise CompGT
+          | Pvar _, _ -> raise CompLT | _, Pvar _ -> raise CompGT
+          | Papp _, _ -> raise CompLT | _, Papp _ -> raise CompGT
+          | Por _,  _ -> raise CompLT | _, Por _  -> raise CompGT
+        in
+        or_cmp q1 q2;
+        res
+    | Pas (p1, v1), Pas (p2, v2) ->
+        let bnd, bv1, bv2 = pat_compare state p1 p2 in
+        bnd + 1, Mvs.add v1 bnd bv1, Mvs.add v2 bnd bv2
+    | Pwild, _  -> raise CompLT | _, Pwild  -> raise CompGT
+    | Pvar _, _ -> raise CompLT | _, Pvar _ -> raise CompGT
+    | Papp _, _ -> raise CompLT | _, Papp _ -> raise CompGT
+    | Por _, _  -> raise CompLT | _, Por _  -> raise CompGT
+  in
+  let rec t_compare bnd vml1 vml2 t1 t2 =
+    if t1 != t2 || vml1 <> [] || vml2 <> [] then begin
+      comp_raise (oty_compare t1.t_ty t2.t_ty);
+      comp_raise (Slab.compare t1.t_label t2.t_label);
+      match descend vml1 t1, descend vml2 t2 with
+      | Bnd i1, Bnd i2 -> perv_compare i1 i2
+      | Bnd _, Trm _ -> raise CompLT
+      | Trm _, Bnd _ -> raise CompGT
+      | Trm (t1,vml1), Trm (t2,vml2) ->
+          begin match t1.t_node, t2.t_node with
+          | Tvar v1, Tvar v2 ->
+              comp_raise (vs_compare v1 v2)
+          | Tconst c1, Tconst c2 ->
+              perv_compare c1 c2
+          | Tapp (s1,l1), Tapp (s2,l2) ->
+              comp_raise (ls_compare s1 s2);
+              List.iter2 (t_compare bnd vml1 vml2) l1 l2
+          | Tif (f1,t1,e1), Tif (f2,t2,e2) ->
+              t_compare bnd vml1 vml2 f1 f2;
+              t_compare bnd vml1 vml2 t1 t2;
+              t_compare bnd vml1 vml2 e1 e2
+          | Tlet (t1,(v1,b1,e1)), Tlet (t2,(v2,b2,e2)) ->
+              t_compare bnd vml1 vml2 t1 t2;
+              let vml1 = (Mvs.singleton v1 bnd, b1.bv_subst) :: vml1 in
+              let vml2 = (Mvs.singleton v2 bnd, b2.bv_subst) :: vml2 in
+              t_compare (bnd + 1) vml1 vml2 e1 e2
+          | Tcase (t1,bl1), Tcase (t2,bl2) ->
+              t_compare bnd vml1 vml2 t1 t2;
+              let b_compare (p1,b1,t1) (p2,b2,t2) =
+                let bnd,bv1,bv2 = pat_compare (bnd,Mvs.empty,Mvs.empty) p1 p2 in
+                let vml1 = (bv1, b1.bv_subst) :: vml1 in
+                let vml2 = (bv2, b2.bv_subst) :: vml2 in
+                t_compare bnd vml1 vml2 t1 t2; 0 in
+              comp_raise (Lists.compare b_compare bl1 bl2)
+          | Teps (v1,b1,e1), Teps (v2,b2,e2) ->
+              let vml1 = (Mvs.singleton v1 bnd, b1.bv_subst) :: vml1 in
+              let vml2 = (Mvs.singleton v2 bnd, b2.bv_subst) :: vml2 in
+              t_compare (bnd + 1) vml1 vml2 e1 e2
+          | Tquant (q1,(vl1,b1,tr1,f1)), Tquant (q2,(vl2,b2,tr2,f2)) ->
+              perv_compare q1 q2;
+              let rec add bnd bv1 bv2 vl1 vl2 = match vl1, vl2 with
+                | (v1::vl1), (v2::vl2) ->
+                    let bv1 = Mvs.add v1 bnd bv1 in
+                    let bv2 = Mvs.add v2 bnd bv2 in
+                    add (bnd + 1) bv1 bv2 vl1 vl2
+                | [], (_::_) -> raise CompLT
+                | (_::_), [] -> raise CompGT
+                | [], [] -> bnd, bv1, bv2 in
+              let bnd, bv1, bv2 = add bnd Mvs.empty Mvs.empty vl1 vl2 in
+              let vml1 = (bv1, b1.bv_subst) :: vml1 in
+              let vml2 = (bv2, b2.bv_subst) :: vml2 in
+              let tr_cmp t1 t2 = t_compare bnd vml1 vml2 t1 t2; 0 in
+              comp_raise (Lists.compare (Lists.compare tr_cmp) tr1 tr2);
+              t_compare bnd vml1 vml2 f1 f2
+          | Tbinop (op1,f1,g1), Tbinop (op2,f2,g2) ->
+              perv_compare op1 op2;
+              t_compare bnd vml1 vml2 f1 f2;
+              t_compare bnd vml1 vml2 g1 g2
+          | Tnot f1, Tnot f2 ->
+              t_compare bnd vml1 vml2 f1 f2
+          | Ttrue, Ttrue -> ()
+          | Tfalse, Tfalse -> ()
+          | Tvar _, _   -> raise CompLT | _, Tvar _   -> raise CompGT
+          | Tconst _, _ -> raise CompLT | _, Tconst _ -> raise CompGT
+          | Tapp _, _   -> raise CompLT | _, Tapp _   -> raise CompGT
+          | Tif _, _    -> raise CompLT | _, Tif _    -> raise CompGT
+          | Tlet _, _   -> raise CompLT | _, Tlet _   -> raise CompGT
+          | Tcase _, _  -> raise CompLT | _, Tcase _  -> raise CompGT
+          | Teps _, _   -> raise CompLT | _, Teps _   -> raise CompGT
+          | Tquant _, _ -> raise CompLT | _, Tquant _ -> raise CompGT
+          | Tbinop _, _ -> raise CompLT | _, Tbinop _ -> raise CompGT
+          | Tnot _, _   -> raise CompLT | _, Tnot _   -> raise CompGT
+          | Ttrue, _    -> raise CompLT | _, Ttrue    -> raise CompGT
+          end
+    end in
+  try t_compare 0 [] [] t1 t2; 0
+  with CompLT -> -1 | CompGT -> 1
+
+let t_equal t1 t2 = (t_compare t1 t2 = 0)
+
+let t_similar t1 t2 =
+  oty_equal t1.t_ty t2.t_ty &&
+  match t1.t_node, t2.t_node with
+    | Tvar v1, Tvar v2 -> vs_equal v1 v2
+    | Tconst c1, Tconst c2 -> c1 = c2
+    | Tapp (s1,l1), Tapp (s2,l2) -> ls_equal s1 s2 && Lists.equal (==) l1 l2
+    | Tif (f1,t1,e1), Tif (f2,t2,e2) -> f1 == f2 && t1 == t2 && e1 == e2
+    | Tlet (t1,bv1), Tlet (t2,bv2) -> t1 == t2 && bv1 == bv2
+    | Tcase (t1,bl1), Tcase (t2,bl2) -> t1 == t2 && Lists.equal (==) bl1 bl2
+    | Teps bv1, Teps bv2 -> bv1 == bv2
+    | Tquant (q1,bv1), Tquant (q2,bv2) -> q1 = q2 && bv1 == bv2
+    | Tbinop (o1,f1,g1), Tbinop (o2,f2,g2) -> o1 = o2 && f1 == f2 && g1 == g2
+    | Tnot f1, Tnot f2 -> f1 == f2
+    | Ttrue, Ttrue | Tfalse, Tfalse -> true
+    | _, _ -> false
+
+let t_hash t =
+  let rec pat_hash bnd bv p = match p.pat_node with
+    | Pwild -> bnd, bv, 0
+    | Pvar v -> bnd + 1, Mvs.add v bnd bv, bnd + 1
+    | Papp (s,l) ->
+        let hash (bnd,bv,h) p =
+          let bnd,bv,hp = pat_hash bnd bv p in
+          bnd, bv, Hashcons.combine h hp in
+        List.fold_left hash (bnd,bv,ls_hash s) l
+    | Por (p,q) ->
+        let bnd,bv,hp = pat_hash bnd bv p in
+        let rec or_hash q = match q.pat_node with
+          | Pwild -> 0
+          | Pvar v -> Mvs.find v bv + 1
+          | Papp (s,l) -> Hashcons.combine_list or_hash (ls_hash s) l
+          | Por (p,q) -> Hashcons.combine (or_hash p) (or_hash q)
+          | Pas (p,v) -> Hashcons.combine (or_hash p) (Mvs.find v bv + 1)
+        in
+        bnd, bv, Hashcons.combine hp (or_hash q)
+    | Pas (p,v) ->
+        let bnd,bv,hp = pat_hash bnd bv p in
+        bnd + 1, Mvs.add v bnd bv, Hashcons.combine hp (bnd + 1)
+  in
+  let rec t_hash bnd vml t =
+    let comb l h = Hashcons.combine (lab_hash l) h in
+    let h = Slab.fold comb t.t_label (oty_hash t.t_ty) in
+    Hashcons.combine h
+      begin match descend vml t with
+      | Bnd i -> i + 1
+      | Trm (t,vml) ->
+          begin match t.t_node with
+          | Tvar v -> vs_hash v
+          | Tconst c -> Hashtbl.hash c
+          | Tapp (s,l) ->
+              Hashcons.combine_list (t_hash bnd vml) (ls_hash s) l
+          | Tif (f,t,e) ->
+              let hf = t_hash bnd vml f in
+              let ht = t_hash bnd vml t in
+              let he = t_hash bnd vml e in
+              Hashcons.combine2 hf ht he
+          | Tlet (t,(v,b,e)) ->
+              let h = t_hash bnd vml t in
+              let vml = (Mvs.singleton v bnd, b.bv_subst) :: vml in
+              Hashcons.combine h (t_hash (bnd + 1) vml e)
+          | Tcase (t,bl) ->
+              let h = t_hash bnd vml t in
+              let b_hash (p,b,t) =
+                let bnd,bv,hp = pat_hash bnd Mvs.empty p in
+                let vml = (bv, b.bv_subst) :: vml in
+                Hashcons.combine hp (t_hash bnd vml t) in
+              Hashcons.combine_list b_hash h bl
+          | Teps (v,b,e) ->
+              let vml = (Mvs.singleton v bnd, b.bv_subst) :: vml in
+              t_hash (bnd + 1) vml e
+          | Tquant (q,(vl,b,tr,f)) ->
+              let h = Hashtbl.hash q in
+              let rec add bnd bv vl = match vl with
+                | v::vl -> add (bnd + 1) (Mvs.add v bnd bv) vl
+                | [] -> bnd, bv in
+              let bnd, bv = add bnd Mvs.empty vl in
+              let vml = (bv, b.bv_subst) :: vml in
+              let h = List.fold_left
+                (Hashcons.combine_list (t_hash bnd vml)) h tr in
+              Hashcons.combine h (t_hash bnd vml f)
+          | Tbinop (op,f,g) ->
+              let ho = Hashtbl.hash op in
+              let hf = t_hash bnd vml f in
+              let hg = t_hash bnd vml g in
+              Hashcons.combine2 ho hf hg
+          | Tnot f ->
+              Hashcons.combine 1 (t_hash bnd vml f)
+          | Ttrue -> 2
+          | Tfalse -> 3
+          end
+    end in
+  t_hash 0 [] t
 
 (* type checking *)
 
@@ -335,12 +527,6 @@ let tr_map_fold fn = Lists.map_fold_left (Lists.map_fold_left fn)
 
 (* bind_info equality, hash, and traversal *)
 
-let bnd_equal b1 b2 = Mvs.equal t_equal b1.bv_subst b2.bv_subst
-
-let bnd_hash bv =
-  let comb v t acc = Hashcons.combine2 (vs_hash v) (t_hash t) acc in
-  Mvs.fold comb bv.bv_subst
-
 let bnd_map fn bv = { bv with bv_subst = Mvs.map fn bv.bv_subst }
 
 let bnd_fold fn acc bv = Mvs.fold (fun _ t a -> fn a t) bv.bv_subst acc
@@ -351,119 +537,46 @@ let bnd_map_fold fn acc bv =
 
 (* hash-consing for terms and formulas *)
 
-let some_plus _ m n = Some (m + n)
-let add_t_vars s t = Mvs.union some_plus s t.t_vars
-let add_b_vars s (_,b,_) = Mvs.union some_plus s b.bv_vars
-let add_nt_vars _ n t s = Mvs.union some_plus s
-  (if n = 1 then t.t_vars else Mvs.map (( * ) n) t.t_vars)
-
-module Hsterm = Hashcons.Make (struct
+let vars_union s1 s2 = Mvs.union (fun _ m n -> Some (m + n)) s1 s2
 
-  type t = term
+let add_b_vars s (_,b,_) = vars_union s b.bv_vars
 
-  let t_eq_bound (v1,b1,t1) (v2,b2,t2) =
-    vs_equal v1 v2 && bnd_equal b1 b2 && t_equal t1 t2
+let rec t_vars t = match t.t_node with
+  | Tvar v -> Mvs.singleton v 1
+  | Tconst _ -> Mvs.empty
+  | Tapp (_,tl) -> List.fold_left add_t_vars Mvs.empty tl
+  | Tif (f,t,e) -> add_t_vars (add_t_vars (t_vars f) t) e
+  | Tlet (t,bt) -> add_b_vars (t_vars t) bt
+  | Tcase (t,bl) -> List.fold_left add_b_vars (t_vars t) bl
+  | Teps (_,b,_) -> b.bv_vars
+  | Tquant (_,(_,b,_,_)) -> b.bv_vars
+  | Tbinop (_,f1,f2) -> add_t_vars (t_vars f1) f2
+  | Tnot f -> t_vars f
+  | Ttrue | Tfalse -> Mvs.empty
 
-  let t_eq_branch (p1,b1,t1) (p2,b2,t2) =
-    pat_equal p1 p2 && bnd_equal b1 b2 && t_equal t1 t2
+and add_t_vars s t = vars_union s (t_vars t)
 
-  let t_eq_quant (vl1,b1,tl1,f1) (vl2,b2,tl2,f2) =
-    t_equal f1 f2 && Lists.equal vs_equal vl1 vl2 &&
-    bnd_equal b1 b2 && tr_equal tl1 tl2
-
-  let t_equal_node t1 t2 = match t1,t2 with
-    | Tvar v1, Tvar v2 -> vs_equal v1 v2
-    | Tconst c1, Tconst c2 -> c1 = c2
-    | Tapp (s1,l1), Tapp (s2,l2) ->
-        ls_equal s1 s2 && List.for_all2 t_equal l1 l2
-    | Tif (f1,t1,e1), Tif (f2,t2,e2) ->
-        t_equal f1 f2 && t_equal t1 t2 && t_equal e1 e2
-    | Tlet (t1,b1), Tlet (t2,b2) ->
-        t_equal t1 t2 && t_eq_bound b1 b2
-    | Tcase (t1,bl1), Tcase (t2,bl2) ->
-        t_equal t1 t2 && Lists.equal t_eq_branch bl1 bl2
-    | Teps f1, Teps f2 -> t_eq_bound f1 f2
-    | Tquant (q1,b1), Tquant (q2,b2) ->
-        q1 = q2 && t_eq_quant b1 b2
-    | Tbinop (op1,f1,g1), Tbinop (op2,f2,g2) ->
-        op1 = op2 && t_equal f1 f2 && t_equal g1 g2
-    | Tnot f1, Tnot f2 -> t_equal f1 f2
-    | Ttrue, Ttrue | Tfalse, Tfalse -> true
-    | _ -> false
-
-  let equal t1 t2 =
-    oty_equal t1.t_ty t2.t_ty &&
-    t_equal_node t1.t_node t2.t_node &&
-    Slab.equal t1.t_label t2.t_label &&
-    Opt.equal Loc.equal t1.t_loc t2.t_loc
-
-  let t_hash_bound (v,b,t) =
-    Hashcons.combine (vs_hash v) (bnd_hash b (t_hash t))
-
-  let t_hash_branch (p,b,t) =
-    Hashcons.combine (pat_hash p) (bnd_hash b (t_hash t))
-
-  let t_hash_quant (vl,b,tl,f) =
-    let h = bnd_hash b (t_hash f) in
-    let h = Hashcons.combine_list vs_hash h vl in
-    List.fold_left (fun acc t -> Hashcons.combine_list t_hash acc t) h tl
-
-  let t_hash_node = function
-    | Tvar v -> vs_hash v
-    | Tconst c -> Hashtbl.hash c
-    | Tapp (f,tl) -> Hashcons.combine_list t_hash (ls_hash f) tl
-    | Tif (f,t,e) -> Hashcons.combine2 (t_hash f) (t_hash t) (t_hash e)
-    | Tlet (t,bt) -> Hashcons.combine (t_hash t) (t_hash_bound bt)
-    | Tcase (t,bl) -> Hashcons.combine_list t_hash_branch (t_hash t) bl
-    | Teps f -> t_hash_bound f
-    | Tquant (q,bf) -> Hashcons.combine (Hashtbl.hash q) (t_hash_quant bf)
-    | Tbinop (op,f1,f2) ->
-        Hashcons.combine2 (Hashtbl.hash op) (t_hash f1) (t_hash f2)
-    | Tnot f -> Hashcons.combine 1 (t_hash f)
-    | Ttrue -> 0
-    | Tfalse -> 1
-
-  let hash t =
-    let comb l = Hashcons.combine (lab_hash l) in
-    Hashcons.combine2 (t_hash_node t.t_node)
-      (Hashcons.combine_option Loc.hash t.t_loc)
-      (Slab.fold comb t.t_label (oty_hash t.t_ty))
-
-  let t_vars_node = function
-    | Tvar v -> Mvs.singleton v 1
-    | Tconst _ -> Mvs.empty
-    | Tapp (_,tl) -> List.fold_left add_t_vars Mvs.empty tl
-    | Tif (f,t,e) -> add_t_vars (add_t_vars f.t_vars t) e
-    | Tlet (t,bt) -> add_b_vars t.t_vars bt
-    | Tcase (t,bl) -> List.fold_left add_b_vars t.t_vars bl
-    | Teps (_,b,_) -> b.bv_vars
-    | Tquant (_,(_,b,_,_)) -> b.bv_vars
-    | Tbinop (_,f1,f2) -> add_t_vars f1.t_vars f2
-    | Tnot f -> f.t_vars
-    | Ttrue | Tfalse -> Mvs.empty
-
-  let tag n t = { t with t_tag = n ; t_vars = t_vars_node t.t_node }
-
-end)
+let add_nt_vars _ n t s = vars_union s
+  (if n = 1 then t_vars t else Mvs.map (( * ) n) (t_vars t))
 
-module Term = MakeMSH (struct
+module TermOHT = struct
   type t = term
-  let tag term = term.t_tag
-end)
+  let hash = t_hash
+  let equal = t_equal
+  let compare = t_compare
+end
 
-module Sterm = Term.S
-module Mterm = Term.M
-module Hterm = Term.H
+module Mterm = Extmap.Make(TermOHT)
+module Sterm = Extset.MakeOfMap(Mterm)
+module Hterm = Exthtbl.Make(TermOHT)
 
 (* hash-consing constructors for terms *)
 
-let mk_term n ty = Hsterm.hashcons {
+let mk_term n ty = {
   t_node  = n;
   t_label = Slab.empty;
   t_loc   = None;
-  t_vars  = Mvs.empty;
   t_ty    = ty;
-  t_tag   = -1
 }
 
 let t_var v         = mk_term (Tvar v) (Some v.vs_ty)
@@ -479,20 +592,18 @@ let t_not f         = mk_term (Tnot f) None
 let t_true          = mk_term (Ttrue) None
 let t_false         = mk_term (Tfalse) None
 
-let t_label ?loc l t =
-  Hsterm.hashcons { t with t_label = l; t_loc = loc }
+let t_label ?loc l t = { t with t_label = l; t_loc = loc }
 
-let t_label_add l t =
-  Hsterm.hashcons { t with t_label = Slab.add l t.t_label }
+let t_label_add l t = { t with t_label = Slab.add l t.t_label }
 
-let t_label_remove l t =
-  Hsterm.hashcons { t with t_label = Slab.remove l t.t_label }
+let t_label_remove l t = { t with t_label = Slab.remove l t.t_label }
 
 let t_label_copy s t =
-  if t_equal s t then s else
+  if s == t then s else
+  if t_similar s t && Slab.is_empty t.t_label && t.t_loc = None then s else
   let lab = Slab.union s.t_label t.t_label in
   let loc = if t.t_loc = None then s.t_loc else t.t_loc in
-  Hsterm.hashcons { t with t_label = lab; t_loc = loc }
+  { t with t_label = lab; t_loc = loc }
 
 (* unsafe map *)
 
@@ -500,30 +611,14 @@ let bound_map fn (u,b,e) = (u, bnd_map fn b, fn e)
 
 let t_map_unsafe fn t = t_label_copy t (match t.t_node with
   | Tvar _ | Tconst _ -> t
-  | Tapp (f,tl) ->
-      let sl = List.map fn tl in
-      if List.for_all2 t_equal sl tl then t else
-      t_app f sl t.t_ty
-  | Tif (f,t1,t2) ->
-      let g = fn f and s1 = fn t1 and s2 = fn t2 in
-      if t_equal g f && t_equal s1 t1 && t_equal s2 t2 then t else
-      t_if g s1 s2
-  | Tlet (e,b) ->
-      t_let (fn e) (bound_map fn b) t.t_ty
-  | Tcase (e,bl) ->
-      t_case (fn e) (List.map (bound_map fn) bl) t.t_ty
-  | Teps b ->
-      t_eps (bound_map fn b) t.t_ty
-  | Tquant (q,(vl,b,tl,f1)) ->
-      t_quant q (vl, bnd_map fn b, tr_map fn tl, fn f1)
-  | Tbinop (op,f1,f2) ->
-      let g1 = fn f1 and g2 = fn f2 in
-      if t_equal g1 f1 && t_equal g2 f2 then t else
-      t_binary op g1 g2
-  | Tnot f1 ->
-      let g1 = fn f1 in
-      if t_equal g1 f1 then t else
-      t_not g1
+  | Tapp (f,tl) -> t_app f (List.map fn tl) t.t_ty
+  | Tif (f,t1,t2) -> t_if (fn f) (fn t1) (fn t2)
+  | Tlet (e,b) -> t_let (fn e) (bound_map fn b) t.t_ty
+  | Tcase (e,bl) -> t_case (fn e) (List.map (bound_map fn) bl) t.t_ty
+  | Teps b -> t_eps (bound_map fn b) t.t_ty
+  | Tquant (q,(vl,b,tl,f)) -> t_quant q (vl, bnd_map fn b, tr_map fn tl, fn f)
+  | Tbinop (op,f1,f2) -> t_binary op (fn f1) (fn f2)
+  | Tnot f1 -> t_not (fn f1)
   | Ttrue | Tfalse -> t)
 
 (* unsafe fold *)
@@ -554,13 +649,11 @@ let t_map_fold_unsafe fn acc t = match t.t_node with
       acc, t
   | Tapp (f,tl) ->
       let acc,sl = Lists.map_fold_left fn acc tl in
-      if List.for_all2 t_equal sl tl then acc,t else
       acc, t_label_copy t (t_app f sl t.t_ty)
   | Tif (f,t1,t2) ->
       let acc, g  = fn acc f in
       let acc, s1 = fn acc t1 in
       let acc, s2 = fn acc t2 in
-      if t_equal g f && t_equal s1 t1 && t_equal s2 t2 then acc,t else
       acc, t_label_copy t (t_if g s1 s2)
   | Tlet (e,b) ->
       let acc, e = fn acc e in
@@ -581,11 +674,9 @@ let t_map_fold_unsafe fn acc t = match t.t_node with
   | Tbinop (op,f1,f2) ->
       let acc, g1 = fn acc f1 in
       let acc, g2 = fn acc f2 in
-      if t_equal g1 f1 && t_equal g2 f2 then acc,t else
       acc, t_label_copy t (t_binary op g1 g2)
   | Tnot f1 ->
       let acc, g1 = fn acc f1 in
-      if t_equal g1 f1 then acc,t else
       acc, t_label_copy t (t_not g1)
   | Ttrue | Tfalse ->
       acc, t
@@ -594,27 +685,26 @@ let t_map_fold_unsafe fn acc t = match t.t_node with
 
 let rec t_subst_unsafe m t =
   let t_subst t = t_subst_unsafe m t in
-  let b_subst (u,b,e) = (u, bv_subst_unsafe m b, e) in
-  let nosubst (_,b,_) = Mvs.set_disjoint m b.bv_vars in
+  let b_subst (u,b,e as bv) =
+    if Mvs.set_disjoint m b.bv_vars then bv else
+    (u, bv_subst_unsafe m b, e) in
   match t.t_node with
   | Tvar u ->
       Mvs.find_def t u m
   | Tlet (e, bt) ->
       let d = t_subst e in
-      if t_equal d e && nosubst bt then t else
       t_label_copy t (t_let d (b_subst bt) t.t_ty)
   | Tcase (e, bl) ->
       let d = t_subst e in
-      if t_equal d e && List.for_all nosubst bl then t else
       let bl = List.map b_subst bl in
       t_label_copy t (t_case d bl t.t_ty)
   | Teps bf ->
-      if nosubst bf then t else
       t_label_copy t (t_eps (b_subst bf) t.t_ty)
-  | Tquant (q, (vl,b,tl,f1)) ->
-      if Mvs.set_disjoint m b.bv_vars then t else
-      let b = bv_subst_unsafe m b in
-      t_label_copy t (t_quant q (vl,b,tl,f1))
+  | Tquant (q, (vl,b,tl,f1 as bq)) ->
+      let bq =
+        if Mvs.set_disjoint m b.bv_vars then bq else
+        (vl,bv_subst_unsafe m b,tl,f1) in
+      t_label_copy t (t_quant q bq)
   | _ ->
       t_map_unsafe t_subst t
 
@@ -641,13 +731,13 @@ let t_subst_unsafe m t =
 
 let bnd_new s = { bv_vars = s ; bv_subst = Mvs.empty }
 
-let t_close_bound v t = (v, bnd_new (Mvs.remove v t.t_vars), t)
+let t_close_bound v t = (v, bnd_new (Mvs.remove v (t_vars t)), t)
 
-let t_close_branch p t = (p, bnd_new (Mvs.set_diff t.t_vars p.pat_vars), t)
+let t_close_branch p t = (p, bnd_new (Mvs.set_diff (t_vars t) p.pat_vars), t)
 
 let t_close_quant vl tl f =
   let del_v s v = Mvs.remove v s in
-  let s = tr_fold add_t_vars f.t_vars tl in
+  let s = tr_fold add_t_vars (t_vars f) tl in
   let s = List.fold_left del_v s vl in
   (vl, bnd_new s, tl, t_prop f)
 
@@ -687,21 +777,23 @@ let t_open_quant (vl,b,tl,f) =
 let t_open_bound_cb tb =
   let v, t = t_open_bound tb in
   let close v' t' =
-    if t_equal t t' && vs_equal v v' then tb else t_close_bound v' t'
+    if t == t' && vs_equal v v' then tb else t_close_bound v' t'
   in
   v, t, close
 
 let t_open_branch_cb tbr =
   let p, t = t_open_branch tbr in
   let close p' t' =
-    if t_equal t t' && pat_equal p p' then tbr else t_close_branch p' t'
+    if t == t' && p == p' then tbr else t_close_branch p' t'
   in
   p, t, close
 
 let t_open_quant_cb fq =
   let vl, tl, f = t_open_quant fq in
   let close vl' tl' f' =
-    if t_equal f f' && tr_equal tl tl' && Lists.equal vs_equal vl vl'
+    if f == f' &&
+      Lists.equal (Lists.equal ((==) : term -> term -> bool)) tl tl' &&
+      Lists.equal vs_equal vl vl'
     then fq else t_close_quant vl' tl' f'
   in
   vl, tl, f, close
@@ -926,13 +1018,13 @@ let t_gen_map fnT fnL mapV t = t_gen_map (Wty.memoize 17 fnT) fnL mapV t
 
 let gen_mapV fnT = Mvs.mapi (fun v _ -> gen_fresh_vsymbol fnT v)
 
-let t_s_map fnT fnL t = t_gen_map fnT fnL (gen_mapV fnT t.t_vars) t
+let t_s_map fnT fnL t = t_gen_map fnT fnL (gen_mapV fnT (t_vars t)) t
 
 (* simultaneous substitution into types and terms *)
 
 let t_ty_subst mapT mapV t =
   let fnT = ty_inst mapT in
-  let m = gen_mapV fnT t.t_vars in
+  let m = gen_mapV fnT (t_vars t) in
   let t = t_gen_map fnT (fun ls -> ls) m t in
   let add _ v t m = vs_check v t; Mvs.add v t m in
   let m = Mvs.fold2_inter add m mapV Mvs.empty in
@@ -1001,8 +1093,8 @@ let t_map fn t = match t.t_node with
   | Tlet (t1, b) ->
       let u,t2 = t_open_bound b in
       let s1 = fn t1 and s2 = fn t2 in
-      if t_equal s2 t2
-        then if t_equal s1 t1 then t
+      if s2 == t2
+        then if s1 == t1 then t
           else t_label_copy t (t_let s1 b)
         else t_label_copy t (t_let_close u s1 s2)
   | Tcase (t1, bl) ->
@@ -1010,21 +1102,21 @@ let t_map fn t = match t.t_node with
       let brn same b =
         let p,t = t_open_branch b in
         let s = fn t in
-        if t_equal s t then same, b
+        if s == t then same, b
           else false, t_close_branch p s
       in
       let same, bl = Lists.map_fold_left brn true bl in
-      if t_equal s1 t1 && same then t
+      if s1 == t1 && same then t
         else t_label_copy t (t_case s1 bl)
   | Teps b ->
       let u,t1 = t_open_bound b in
       let s1 = fn t1 in
-      if t_equal s1 t1 then t
+      if s1 == t1 then t
         else t_label_copy t (t_eps_close u s1)
   | Tquant (q, b) ->
       let vl,tl,f1 = t_open_quant b in
       let g1 = fn f1 and sl = tr_map fn tl in
-      if t_equal g1 f1 && List.for_all2 (List.for_all2 t_equal) sl tl then t
+      if g1 == f1 && List.for_all2 (List.for_all2 (==)) sl tl then t
         else t_label_copy t (t_quant_close q vl sl g1)
   | _ ->
       t_map_unsafe fn t
@@ -1056,8 +1148,8 @@ let t_map_fold fn acc t = match t.t_node with
       let acc, s1 = fn acc t1 in
       let u,t2 = t_open_bound b in
       let acc, s2 = fn acc t2 in
-      acc, if t_equal s2 t2
-        then if t_equal s1 t1 then t
+      acc, if s2 == t2
+        then if s1 == t1 then t
           else t_label_copy t (t_let s1 b)
         else t_label_copy t (t_let_close u s1 s2)
   | Tcase (t1, bl) ->
@@ -1065,22 +1157,22 @@ let t_map_fold fn acc t = match t.t_node with
       let brn (acc,same) b =
         let p,t = t_open_branch b in
         let acc, s = fn acc t in
-        if t_equal s t then (acc,same), b
+        if s == t then (acc,same), b
           else (acc,false), t_close_branch p s
       in
       let (acc,same), bl = Lists.map_fold_left brn (acc,true) bl in
-      acc, if t_equal s1 t1 && same then t
+      acc, if s1 == t1 && same then t
         else t_label_copy t (t_case s1 bl)
   | Teps b ->
       let u,t1 = t_open_bound b in
       let acc, s1 = fn acc t1 in
-      acc, if t_equal s1 t1 then t
+      acc, if s1 == t1 then t
         else t_label_copy t (t_eps_close u s1)
   | Tquant (q, b) ->
       let vl,tl,f1 = t_open_quant b in
       let acc, sl = tr_map_fold fn acc tl in
       let acc, g1 = fn acc f1 in
-      acc, if t_equal g1 f1 && List.for_all2 (List.for_all2 t_equal) sl tl
+      acc, if g1 == f1 && List.for_all2 (List.for_all2 (==)) sl tl
         then t else t_label_copy t (t_quant_close q vl sl g1)
   | _ -> t_map_fold_unsafe fn acc t
 
@@ -1171,204 +1263,58 @@ let t_map_cont fn = t_map_cont (fun cont t ->
 
 let t_v_map fn t =
   let fn v _ = let res = fn v in vs_check v res; res in
-  t_subst_unsafe (Mvs.mapi fn t.t_vars) t
+  t_subst_unsafe (Mvs.mapi fn (t_vars t)) t
 
-let t_v_fold fn acc t = Mvs.fold (fun v _ a -> fn a v) t.t_vars acc
+let bnd_v_fold fn acc b = Mvs.fold (fun v _ acc -> fn acc v) b.bv_vars acc
 
-let t_v_all pr t = Mvs.for_all (fun v _ -> pr v) t.t_vars
-let t_v_any pr t = Mvs.exists  (fun v _ -> pr v) t.t_vars
+let bound_v_fold fn acc (_,b,_) = bnd_v_fold fn acc b
 
-(* replaces variables with terms in term [t] using map [m] *)
+let rec t_v_fold fn acc t = match t.t_node with
+  | Tvar v -> fn acc v
+  | Tlet (e,b) -> bound_v_fold fn (t_v_fold fn acc e) b
+  | Tcase (e,bl) -> List.fold_left (bound_v_fold fn) (t_v_fold fn acc e) bl
+  | Teps b -> bound_v_fold fn acc b
+  | Tquant (_,(_,b,_,_)) -> bnd_v_fold fn acc b
+  | _ -> t_fold_unsafe (t_v_fold fn) acc t
 
-let t_subst m t = Mvs.iter vs_check m; t_subst_unsafe m t
+let t_v_all pr t =
+  try t_v_fold (Util.all_fn pr) true t with Util.FoldSkip -> false
 
-let t_subst_single v t1 t = t_subst (Mvs.singleton v t1) t
+let t_v_any pr t =
+  try t_v_fold (Util.any_fn pr) false t with Util.FoldSkip -> true
 
-(* set of free variables *)
+let t_closed t = t_v_all (fun _ -> false) t
 
-let t_freevars = add_t_vars
+let bnd_v_count fn acc b = Mvs.fold (fun v n acc -> fn acc v n) b.bv_vars acc
 
-(* alpha-equality *)
+let bound_v_count fn acc (_,b,_) = bnd_v_count fn acc b
 
-let vs_rename_alpha c h vs = incr c; Mvs.add vs !c h
+let rec t_v_count fn acc t = match t.t_node with
+  | Tvar v -> fn acc v 1
+  | Tlet (e,b) -> bound_v_count fn (t_v_count fn acc e) b
+  | Tcase (e,bl) -> List.fold_left (bound_v_count fn) (t_v_count fn acc e) bl
+  | Teps b -> bound_v_count fn acc b
+  | Tquant (_,(_,b,_,_)) -> bnd_v_count fn acc b
+  | _ -> t_fold_unsafe (t_v_count fn) acc t
 
-let vl_rename_alpha c h vl = List.fold_left (vs_rename_alpha c) h vl
+let t_v_occurs v t =
+  t_v_count (fun c u n -> if vs_equal u v then c + n else c) 0 t
 
-let rec pat_rename_alpha c h p = match p.pat_node with
-  | Pvar v -> vs_rename_alpha c h v
-  | Pas (p, v) -> pat_rename_alpha c (vs_rename_alpha c h v) p
-  | Por (p, _) -> pat_rename_alpha c h p
-  | _ -> pat_fold (pat_rename_alpha c) h p
-
-let rec pat_equal_alpha p1 p2 =
-  pat_equal p1 p2 ||
-  ty_equal p1.pat_ty p2.pat_ty &&
-  match p1.pat_node, p2.pat_node with
-  | Pwild, Pwild | Pvar _, Pvar _ -> true
-  | Papp (f1, l1), Papp (f2, l2) ->
-      ls_equal f1 f2 && List.for_all2 pat_equal_alpha l1 l2
-  | Pas (p1, _), Pas (p2, _) -> pat_equal_alpha p1 p2
-  | Por (p1, q1), Por (p2, q2) ->
-      pat_equal_alpha p1 p2 && pat_equal_alpha q1 q2
-  | _ -> false
+(* replaces variables with terms in term [t] using map [m] *)
 
-let rec t_equal_alpha c1 c2 m1 m2 t1 t2 =
-  t_equal t1 t2 || oty_equal t1.t_ty t2.t_ty &&
-  let t_eq = t_equal_alpha c1 c2 m1 m2 in
-  match t1.t_node, t2.t_node with
-    | Tvar v1, Tvar v2 when Mvs.mem v1 m1 ->
-        Mvs.mem v2 m2 && Mvs.find v1 m1 = Mvs.find v2 m2
-    | Tvar v1, Tvar v2 when not (Mvs.mem v2 m2) ->
-        vs_equal v1 v2
-    | Tconst c1, Tconst c2 ->
-        c1 = c2
-    | Tapp (s1,l1), Tapp (s2,l2) ->
-        ls_equal s1 s2 && List.for_all2 t_eq l1 l2
-    | Tif (f1,t1,e1), Tif (f2,t2,e2) ->
-        t_eq f1 f2 && t_eq t1 t2 && t_eq e1 e2
-    | Tlet (t1,b1), Tlet (t2,b2) ->
-        t_eq t1 t2 &&
-        let u1,e1 = t_open_bound b1 in
-        let u2,e2 = t_open_bound b2 in
-        let m1 = vs_rename_alpha c1 m1 u1 in
-        let m2 = vs_rename_alpha c2 m2 u2 in
-        t_equal_alpha c1 c2 m1 m2 e1 e2
-    | Tcase (t1,bl1), Tcase (t2,bl2) ->
-        t_eq t1 t2 &&
-        let br_eq ((p1,_,_) as b1) ((p2,_,_) as b2) =
-          pat_equal_alpha p1 p2 &&
-          let p1,e1 = t_open_branch b1 in
-          let p2,e2 = t_open_branch b2 in
-          let m1 = pat_rename_alpha c1 m1 p1 in
-          let m2 = pat_rename_alpha c2 m2 p2 in
-          t_equal_alpha c1 c2 m1 m2 e1 e2
-        in
-        Lists.equal br_eq bl1 bl2
-    | Teps b1, Teps b2 ->
-        let u1,e1 = t_open_bound b1 in
-        let u2,e2 = t_open_bound b2 in
-        let m1 = vs_rename_alpha c1 m1 u1 in
-        let m2 = vs_rename_alpha c2 m2 u2 in
-        t_equal_alpha c1 c2 m1 m2 e1 e2
-    | Tquant (q1,((vl1,_,_,_) as b1)), Tquant (q2,((vl2,_,_,_) as b2)) ->
-        q1 = q2 &&
-        Lists.equal (fun v1 v2 -> ty_equal v1.vs_ty v2.vs_ty) vl1 vl2 &&
-        let vl1,_,e1 = t_open_quant b1 in
-        let vl2,_,e2 = t_open_quant b2 in
-        let m1 = vl_rename_alpha c1 m1 vl1 in
-        let m2 = vl_rename_alpha c2 m2 vl2 in
-        t_equal_alpha c1 c2 m1 m2 e1 e2
-    | Tbinop (a,f1,g1), Tbinop (b,f2,g2) ->
-        a = b && t_eq f1 f2 && t_eq g1 g2
-    | Tnot f1, Tnot f2 ->
-        t_eq f1 f2
-    | Ttrue, Ttrue | Tfalse, Tfalse ->
-        true
-    | _ -> false
-
-let t_equal_alpha = t_equal_alpha (ref (-1)) (ref (-1)) Mvs.empty Mvs.empty
-
-(* hash modulo alpha *)
-
-(* dead code
-let rec pat_hash_alpha p =
-  match p.pat_node with
-  | Pwild -> 0
-  | Pvar _ -> 1
-  | Papp (f, l) ->
-      let acc = Hashcons.combine 2 (ls_hash f) in
-      Hashcons.combine_list pat_hash_alpha acc l
-  | Pas (p, _) -> Hashcons.combine 3 (pat_hash_alpha p)
-  | Por (p, q) ->
-      Hashcons.combine
-        (Hashcons.combine 4 (pat_hash_alpha p)) (pat_hash_alpha q)
-*)
-
-let rec t_hash_alpha c m t =
-  let fn = t_hash_alpha c m in
-  match t.t_node with
-  | Tvar v ->
-      Hashcons.combine 0 (Mvs.find_def (vs_hash v) v m)
-  | Tconst c ->
-      Hashcons.combine 1 (Hashtbl.hash c)
-  | Tapp (s,l) ->
-      let acc = Hashcons.combine 2 (ls_hash s) in
-      Hashcons.combine_list fn acc l
-  | Tif (f,t1,t2) ->
-      Hashcons.combine3 3 (fn f) (fn t1) (fn t2)
-  | Tlet (t1,b) ->
-      let u,t2 = t_open_bound b in
-      let m = vs_rename_alpha c m u in
-      Hashcons.combine2 4 (fn t1) (t_hash_alpha c m t2)
-  | Tcase (t1,bl) ->
-      let hash_br b =
-        let p,t2 = t_open_branch b in
-        let m = pat_rename_alpha c m p in
-        t_hash_alpha c m t2
-      in
-      let acc = Hashcons.combine 5 (fn t1) in
-      Hashcons.combine_list hash_br acc bl
-  | Teps b ->
-      let u,f = t_open_bound b in
-      let m = vs_rename_alpha c m u in
-      Hashcons.combine 6 (t_hash_alpha c m f)
-  | Tquant (q,b) ->
-      let vl,_,f1 = t_open_quant b in
-      let m = vl_rename_alpha c m vl in
-      let hq = match q with Tforall -> 1 | Texists -> 2 in
-      Hashcons.combine2 1 hq (t_hash_alpha c m f1)
-  | Tbinop (o,f,g) ->
-      let ho = match o with
-        | Tand -> 3 | Tor -> 4 | Timplies -> 5 | Tiff -> 7
-      in
-      Hashcons.combine3 2 ho (fn f) (fn g)
-  | Tnot f ->
-      Hashcons.combine 3 (fn f)
-  | Ttrue -> 4
-  | Tfalse -> 5
+let t_subst m t = Mvs.iter vs_check m; t_subst_unsafe m t
 
-let t_hash_alpha = t_hash_alpha (ref (-1)) Mvs.empty
+let t_subst_single v t1 t = t_subst (Mvs.singleton v t1) t
 
-module Hterm_alpha = Exthtbl.Make (struct
-  type t = term
-  let equal = t_equal_alpha
-  let hash = t_hash_alpha
-end)
+(* set of free variables *)
 
-(* binder-free term/formula matching *)
-
-(* exception NoMatch *)
-
-(* let rec t_match s t1 t2 = *)
-(*   if not (oty_equal t1.t_ty t2.t_ty) then raise NoMatch else *)
-(*   match t1.t_node, t2.t_node with *)
-(*     | Tconst c1, Tconst c2 when c1 = c2 -> s *)
-(*     | Tvar v1, _ -> *)
-(*         Mvs.change v1 (function *)
-(*           | None -> Some t2 *)
-(*           | Some t1 as r when t_equal t1 t2 -> r *)
-(*           | _ -> raise NoMatch) s *)
-(*     | Tapp (s1,l1), Tapp (s2,l2) when ls_equal s1 s2 -> *)
-(*         List.fold_left2 t_match s l1 l2 *)
-(*     | Tif (f1,t1,e1), Tif (f2,t2,e2) -> *)
-(*         t_match (t_match (t_match s f1 f2) t1 t2) e1 e2 *)
-(*     | Tbinop (op1,f1,g1), Tbinop (op2,f2,g2) when op1 = op2 -> *)
-(*         t_match (t_match s f1 f2) g1 g2 *)
-(*     | Tnot f1, Tnot f2 -> *)
-(*         t_match s f1 f2 *)
-(*     | Ttrue, Ttrue *)
-(*     | Tfalse, Tfalse -> *)
-(*         s *)
-(*     | _ -> raise NoMatch *)
+let t_freevars = add_t_vars
 
 (* occurrence check *)
 
 let rec t_occurs r t =
   t_equal r t || t_any (t_occurs r) t
 
-let rec t_occurs_alpha r t =
-  t_equal_alpha r t || t_any (t_occurs_alpha r) t
-
 (* substitutes term [t2] for term [t1] in term [t] *)
 
 let rec t_replace t1 t2 t =
@@ -1378,13 +1324,6 @@ let t_replace t1 t2 t =
   t_ty_check t2 t1.t_ty;
   t_replace t1 t2 t
 
-let rec t_replace_alpha t1 t2 t =
-  if t_equal_alpha t t1 then t2 else t_map (t_replace_alpha t1 t2) t
-
-let t_replace_alpha t1 t2 t =
-  t_ty_check t2 t1.t_ty;
-  t_replace_alpha t1 t2 t
-
 (* constructors with propositional simplification *)
 
 let keep_on_simp_label = create_label "keep_on_simp"
@@ -1474,7 +1413,7 @@ let small t = match t.t_node with
   | _ -> false
 
 let t_let_simp e ((v,b,t) as bt) =
-  let n = Mvs.find_def 0 v t.t_vars in
+  let n = t_v_occurs v t in
   if n = 0 && can_simp e then
     t_subst_unsafe b.bv_subst t else
   if n = 1 || small e then begin
@@ -1484,7 +1423,7 @@ let t_let_simp e ((v,b,t) as bt) =
     t_let e bt
 
 let t_let_close_simp v e t =
-  let n = Mvs.find_def 0 v t.t_vars in
+  let n = t_v_occurs v t in
   if n = 0 && can_simp e then t else
   if n = 1 || small e then
     t_subst_single v e t
@@ -1503,7 +1442,7 @@ let t_case_simp t bl =
     | Ttrue when can_simp e -> e0_true
     | Tfalse when can_simp e -> e0_false
     | _ -> t_equal e e0 in
-  if can_simp t && Mvs.is_empty e0.t_vars && List.for_all is_e0 tl then e0
+  if can_simp t && t_closed e0 && List.for_all is_e0 tl then e0
   else t_case t bl
 
 let t_case_close_simp t bl =
@@ -1518,29 +1457,31 @@ let t_case_close_simp t bl =
     | Ttrue when can_simp e -> e0_true
     | Tfalse when can_simp e -> e0_false
     | _ -> t_equal e e0 in
-  if can_simp t && Mvs.is_empty e0.t_vars && List.for_all is_e0 tl then e0
+  if can_simp t && t_closed e0 && List.for_all is_e0 tl then e0
   else t_case_close t bl
 
-let v_occurs f v = Mvs.mem v f.t_vars
-let v_subset f e = Mvs.set_submap e.t_vars f.t_vars
-
-let vl_filter f vl = List.filter (v_occurs f) vl
-let tr_filter f tl = List.filter (List.for_all (v_subset f)) tl
-
 let t_quant_simp q ((vl,_,_,f) as qf) =
-  if List.for_all (v_occurs f) vl then
+  let fvs = t_vars f in
+  let check v = Mvs.mem v fvs in
+  if List.for_all check vl then
     t_quant q qf
   else
     let vl,tl,f = t_open_quant qf in
-    let vl = vl_filter f vl in
-    if vl = [] then f else t_quant_close q vl (tr_filter f tl) f
+    let fvs = t_vars f in
+    let check v = Mvs.mem v fvs in
+    let vl = List.filter check vl in
+    if vl = [] then f
+    else t_quant_close q vl (List.filter (List.for_all (t_v_all check)) tl) f
 
 let t_quant_close_simp q vl tl f =
-  if List.for_all (v_occurs f) vl then
+  let fvs = t_vars f in
+  let check v = Mvs.mem v fvs in
+  if List.for_all check vl then
     t_quant_close q vl tl f
   else
-    let vl = vl_filter f vl in
-    if vl = [] then f else t_quant_close q vl (tr_filter f tl) f
+    let vl = List.filter check vl in
+    if vl = [] then f
+    else t_quant_close q vl (List.filter (List.for_all (t_v_all check)) tl) f
 
 let t_forall_simp = t_quant_simp Tforall
 let t_exists_simp = t_quant_simp Texists
diff --git a/src/core/term.mli b/src/core/term.mli
index b10a85d86da6884a4960149063b3dcba5cfe35f8..6eb7d1660f6ff4cdd96c5ea807550abcbe1b1ff5 100644
--- a/src/core/term.mli
+++ b/src/core/term.mli
@@ -27,6 +27,7 @@ module Svs : Extset.S with module M = Mvs
 module Hvs : Exthtbl.S with type key = vsymbol
 module Wvs : Weakhtbl.S with type key = vsymbol
 
+val vs_compare : vsymbol -> vsymbol -> int
 val vs_equal : vsymbol -> vsymbol -> bool
 val vs_hash : vsymbol -> int
 
@@ -47,6 +48,7 @@ module Sls : Extset.S with module M = Mls
 module Hls : Exthtbl.S with type key = lsymbol
 module Wls : Weakhtbl.S with type key = lsymbol
 
+val ls_compare : lsymbol -> lsymbol -> int
 val ls_equal : lsymbol -> lsymbol -> bool
 val ls_hash : lsymbol -> int
 
@@ -77,7 +79,6 @@ type pattern = private {
   pat_node : pattern_node;
   pat_vars : Svs.t;
   pat_ty   : ty;
-  pat_tag  : int;
 }
 
 and pattern_node = private
@@ -87,9 +88,6 @@ and pattern_node = private
   | Por  of pattern * pattern
   | Pas  of pattern * vsymbol
 
-val pat_equal : pattern -> pattern -> bool
-val pat_hash : pattern -> int
-
 (** Smart constructors for patterns *)
 
 val pat_wild : ty -> pattern
@@ -122,8 +120,6 @@ type term = private {
   t_ty    : ty option;
   t_label : Slab.t;
   t_loc   : Loc.position option;
-  t_vars  : int Mvs.t;
-  t_tag   : int;
 }
 
 and term_node = private
@@ -150,6 +146,7 @@ module Mterm : Extmap.S with type key = term
 module Sterm : Extset.S with module M = Mterm
 module Hterm : Exthtbl.S with type key = term
 
+val t_compare : term -> term -> int
 val t_equal : term -> term -> bool
 val t_hash : term -> int
 
@@ -383,6 +380,10 @@ val t_v_fold : ('a -> vsymbol -> 'a) -> 'a -> term -> 'a
 val t_v_all : (vsymbol -> bool) -> term -> bool
 val t_v_any : (vsymbol -> bool) -> term -> bool
 
+val t_v_count : ('a -> vsymbol -> int -> 'a) -> 'a -> term -> 'a
+
+val t_v_occurs : vsymbol -> term -> int
+
 (** Variable substitution *)
 
 val t_subst : term Mvs.t -> term -> term
@@ -392,7 +393,12 @@ val t_ty_subst : ty Mtv.t -> term Mvs.t -> term -> term
 
 (** Find free variables and type variables *)
 
-val t_freevars    : int Mvs.t -> term -> int Mvs.t
+val t_closed : term -> bool
+
+val t_vars : term -> int Mvs.t
+
+val t_freevars : int Mvs.t -> term -> int Mvs.t
+
 val t_ty_freevars : Stv.t -> term -> Stv.t
 
 (** Map/fold over types and logical symbols in terms and patterns *)
@@ -417,17 +423,7 @@ val t_app_map :
 val t_app_fold :
   ('a -> lsymbol -> ty list -> ty option -> 'a) -> 'a -> term -> 'a
 
-(** Equality modulo alpha *)
-
-val t_equal_alpha : term -> term -> bool
-
-module Hterm_alpha : Exthtbl.S with type key = term
-
 (** Subterm occurrence check and replacement *)
 
-val t_occurs : term -> term -> bool
-val t_occurs_alpha : term -> term -> bool
-
+val t_occurs  : term -> term -> bool
 val t_replace : term -> term -> term -> term
-val t_replace_alpha : term -> term -> term -> term
-
diff --git a/src/core/trans.ml b/src/core/trans.ml
index 8b2bc7baf2c3835d8779c5d19bb55d19a55c6831..6d21d7892bf2dbdeb510fe0707f14b8d5957a654 100644
--- a/src/core/trans.ml
+++ b/src/core/trans.ml
@@ -47,7 +47,9 @@ module Wtask = Weakhtbl.Make (struct
   let tag t = t.task_tag
 end)
 
-let store fn = Wtask.memoize_option 63 fn
+let store fn = let tr = Wtask.memoize_option 63 fn in fun t -> match t with
+  | Some {task_decl = {td_node = Decl {d_node = Dprop (Pgoal,_,_)}}} -> fn t
+  | _ -> tr t
 
 let bind f g = store (fun task -> g (f task) task)
 
@@ -60,8 +62,9 @@ let fold fn v =
     | Use _  -> 'U' | Meta _  -> 'M') (task.task_decl.td_tag);
 *)
     let acc = fn task acc in
-    Wtask.set h task acc;
-    acc
+    match task.task_decl.td_node with
+    | Decl {d_node = Dprop (Pgoal,_,_)} -> acc
+    | _ -> Wtask.set h task acc; acc
   in
   let current task =
     try Some (Wtask.find h task)
@@ -82,8 +85,12 @@ let fold_map   fn v t = conv_res snd            (fold   fn (v, t))
 let fold_map_l fn v t = conv_res (List.map snd) (fold_l fn (v, t))
 (* we use List.map instead of List.map_rev to preserve the order *)
 
+let store_decl fn = let tr = Wdecl.memoize 63 fn in function
+  | {d_node = Dprop (Pgoal,_,_)} as d -> fn d
+  | d -> tr d
+
 let gen_decl add fn =
-  let fn = Wdecl.memoize 63 fn in
+  let fn = store_decl fn in
   let fn task acc = match task.task_decl.td_node with
     | Decl d -> List.fold_left add acc (fn d)
     | _ -> add_tdecl acc task.task_decl
@@ -91,7 +98,7 @@ let gen_decl add fn =
   fold fn
 
 let gen_decl_l add fn =
-  let fn = Wdecl.memoize 63 fn in
+  let fn = store_decl fn in
   let fn task acc = match task.task_decl.td_node with
     | Decl d -> List.map (List.fold_left add acc) (fn d)
     | _ -> [add_tdecl acc task.task_decl]
@@ -107,17 +114,15 @@ let apply_to_goal fn d = match d.d_node with
   | Dprop (Pgoal,pr,f) -> fn pr f
   | _ -> assert false
 
-let gen_goal add fn =
-  let fn = Wdecl.memoize 5 (apply_to_goal fn) in store (function
-    | Some { task_decl = { td_node = Decl d }; task_prev = prev } ->
-        List.fold_left add prev (fn d)
-    | _ -> assert false)
-
-let gen_goal_l add fn =
-  let fn = Wdecl.memoize 5 (apply_to_goal fn) in store (function
-    | Some { task_decl = { td_node = Decl d }; task_prev = prev } ->
-        List.map (List.fold_left add prev) (fn d)
-    | _ -> assert false)
+let gen_goal add fn = function
+  | Some { task_decl = { td_node = Decl d }; task_prev = prev } ->
+      List.fold_left add prev (apply_to_goal fn d)
+  | _ -> assert false
+
+let gen_goal_l add fn = function
+  | Some { task_decl = { td_node = Decl d }; task_prev = prev } ->
+      List.map (List.fold_left add prev) (apply_to_goal fn d)
+  | _ -> assert false
 
 let goal    = gen_goal   add_decl
 let goal_l  = gen_goal_l add_decl
diff --git a/src/core/ty.ml b/src/core/ty.ml
index c9a7c066a56713d2a6e9d4842ad70ccb8a82900e..58932485f99ba135e534998c7953e9f3008eb3c8 100644
--- a/src/core/ty.ml
+++ b/src/core/ty.ml
@@ -28,8 +28,8 @@ module Mtv = Tvar.M
 module Htv = Tvar.H
 
 let tv_equal : tvsymbol -> tvsymbol -> bool = (==)
-
 let tv_hash tv = id_hash tv.tv_name
+let tv_compare tv1 tv2 = id_compare tv1.tv_name tv2.tv_name
 
 let create_tvsymbol n = { tv_name = id_register n }
 
@@ -66,6 +66,9 @@ let ty_equal : ty       -> ty       -> bool = (==)
 let ts_hash ts = id_hash ts.ts_name
 let ty_hash ty = Weakhtbl.tag_hash ty.ty_tag
 
+let ts_compare ts1 ts2 = id_compare ts1.ts_name ts2.ts_name
+let ty_compare ty1 ty2 = Pervasives.compare (ty_hash ty1) (ty_hash ty2)
+
 let mk_ts name args def = {
   ts_name = id_register name;
   ts_args = args;
@@ -252,6 +255,8 @@ let oty_type = function Some ty -> ty | None -> raise UnexpectedProp
 let oty_equal = Opt.equal ty_equal
 let oty_hash = Opt.fold (fun _ -> ty_hash) 1
 
+let oty_compare o1 o2 = Opt.compare ty_compare o1 o2
+
 let oty_match m o1 o2 = match o1,o2 with
   | Some ty1, Some ty2 -> ty_match m ty1 ty2
   | None, None -> m
diff --git a/src/core/ty.mli b/src/core/ty.mli
index ba7b6878d02d29584122f8850af4fa17e0250f62..65a6363267dd2e91d9db3d180a930d33560346de 100644
--- a/src/core/ty.mli
+++ b/src/core/ty.mli
@@ -55,6 +55,9 @@ module Sty : Extset.S with module M = Mty
 module Hty : Exthtbl.S with type key = ty
 module Wty : Weakhtbl.S with type key = ty
 
+val ts_compare : tysymbol -> tysymbol -> int
+val ty_compare : ty -> ty -> int
+
 val ts_equal : tysymbol -> tysymbol -> bool
 val ty_equal : ty -> ty -> bool
 
@@ -127,6 +130,7 @@ val is_ts_tuple_id : ident -> int option
 
 exception UnexpectedProp
 
+val oty_compare : ty option -> ty option -> int
 val oty_equal : ty option -> ty option -> bool
 val oty_hash  : ty option -> int
 
diff --git a/src/driver/driver.ml b/src/driver/driver.ml
index bbffcd4e3d5edc81cd9cb70f5438110a84ce8bb4..1f3021121663fb770a09bda66287dea3436d1743 100644
--- a/src/driver/driver.ml
+++ b/src/driver/driver.ml
@@ -248,36 +248,26 @@ let call_on_buffer ~command ?timelimit ?memlimit ?inplace ~filename drv buffer =
 
 exception NoPrinter
 
-let update_task drv task_orig =
-  (** task_orig is the task for looking for theories
-      task      is the task for adding new metas
-      goal      is the last decl that we want to keep at the end (goal or clone)
-  *)
-  let task, goal = match task_orig with
-    | Some { task_decl = g ; task_prev = t } -> t,g
-    | None -> raise Task.GoalNotFound
-  in
-  let task =
+let update_task = let ht = Hint.create 5 in fun drv ->
+  let update task0 =
     Mid.fold (fun _ (th,s) task ->
       Task.on_theory th (fun task sm ->
         Stdecl.fold (fun tdm task ->
           add_tdecl task (clone_meta tdm sm)
         ) s task
-      ) task task_orig
-    ) drv.drv_meta task
+      ) task task0
+    ) drv.drv_meta task0
   in
-  add_tdecl task goal
-
-let update_task =
-  let h = Hint.create 5 in
-  fun drv ->
-    let update = try Hint.find h drv.drv_tag with
-      | Not_found ->
-          let upd = Trans.store (update_task drv) in
-          Hint.add h drv.drv_tag upd;
-          upd
-    in
-    Trans.apply update
+  function
+  | Some {task_decl = {td_node = Decl {d_node = Dprop (Pgoal,_,_)}} as goal;
+          task_prev = task} ->
+      (* we cannot add metas nor memoize after goal *)
+      let update = try Hint.find ht drv.drv_tag with Not_found ->
+        let upd = Trans.store update in
+        Hint.add ht drv.drv_tag upd; upd in
+      let task = Trans.apply update task in
+      add_tdecl task goal
+  | task -> update task
 
 let prepare_task drv task =
   let lookup_transform t = lookup_transform t drv.drv_env in
diff --git a/src/parser/denv.ml b/src/parser/denv.ml
index 232d5647dbb9f82ed3ab34c658fda089702d6d8f..76189510b75b3c3ec5749088d1fc1c76da03bc70 100644
--- a/src/parser/denv.ml
+++ b/src/parser/denv.ml
@@ -192,14 +192,14 @@ and dtrigger =
 
 let allowed_unused s = String.length s > 0 && s.[0] = '_'
 
-let check_used_var vars v =
-  if not (Mvs.mem v vars) then
+let check_used_var t v =
+  if t_v_occurs v t = 0 then
     let s = v.vs_name.id_string in
     if not (allowed_unused s) then
       Warning.emit ?loc:v.vs_name.Ident.id_loc "unused variable %s" s
 
-let check_used_vars vars =
-  List.iter (check_used_var vars)
+let check_used_vars t vl =
+  List.iter (check_used_var t) vl
 
 let check_exists_implies q f =
   match q,f.t_node with
@@ -224,7 +224,7 @@ let rec term env t = match t.dt_node with
       let v = create_user_vs id (t_type e1) in
       let env = Mstr.add id.id v env in
       let e2 = term env e2 in
-      check_used_var e2.t_vars v;
+      check_used_var e2 v;
       t_let_close v e1 e2
   | Tmatch (t1, bl) ->
       let branch (p,e) =
@@ -267,7 +267,7 @@ and fmla env = function
       in
       let trl = List.map (List.map trigger) trl in
       let f = fmla env f1 in
-      check_used_vars f.Term.t_vars vl;
+      check_used_vars f vl;
       check_exists_implies q f;
       t_quant_close q vl trl f
   | Fapp (s, tl) ->
@@ -277,7 +277,7 @@ and fmla env = function
       let v = create_user_vs id (t_type e1) in
       let env = Mstr.add id.id v env in
       let f2 = fmla env f2 in
-      check_used_var f2.t_vars v;
+      check_used_var f2 v;
       t_let_close v e1 f2
   | Fmatch (t, bl) ->
       let branch (p,e) =
diff --git a/src/printer/alt_ergo.ml b/src/printer/alt_ergo.ml
index d6f21c11d1b0acc17b600bc16dd9ef5c4983950b..44ffdaf85cd5768a90e037e7adfddc3245b075fa 100644
--- a/src/printer/alt_ergo.ml
+++ b/src/printer/alt_ergo.ml
@@ -251,6 +251,7 @@ let print_enum_decl fmt ts csl =
     (print_list alt2 print_cs) csl
 
 let print_ty_decl info fmt ts =
+  if ts.ts_def <> None then () else
   if Mid.mem ts.ts_name info.info_syn then () else
   (fprintf fmt "%a@\n@\n" print_type_decl ts; forget_tvs ())
 
@@ -333,8 +334,6 @@ let print_decl info fmt d = match d.d_node with
       "alt-ergo: inductive definitions are not supported"
   | Dprop (k,pr,f) -> print_prop_decl info fmt k pr f
 
-let print_decl info fmt = catch_unsupportedDecl (print_decl info fmt)
-
 let add_projection (csm,pjs,axs) = function
   | [Theory.MAls ls; Theory.MAls cs; Theory.MAint ind; Theory.MApr pr] ->
       let csm = try Array.set (Mls.find cs csm) ind ls; csm
@@ -353,66 +352,41 @@ let check_typecasts acc = function
   | [Theory.MAstr _] -> acc
   | _ -> assert false
 
-(*
-let print_task_old pr thpr fmt task =
-  print_prelude fmt pr;
-  print_th_prelude task fmt thpr;
-  let csm,pjs,axs = Task.on_meta Eliminate_algebraic.meta_proj
-    add_projection (Mls.empty,Sls.empty,Spr.empty) task in
-  let info = {
-    info_syn = get_syntax_map task;
-    info_ac  = Task.on_tagged_ls meta_ac task;
-    info_show_labels =
-      Task.on_meta meta_printer_option check_showlabels false task;
-    info_csm = Mls.map Array.to_list csm;
-    info_pjs = pjs;
-    info_axs = axs;
-  } in
-  let decls = Task.task_decls task in
-  fprintf fmt "%a@." (print_list nothing (print_decl info)) decls
-
-let () = register_printer "alt-ergo-old"
-  (fun _env pr thpr ?old:_ fmt task ->
-     forget_all ident_printer;
-     print_task_old pr thpr fmt task)
-*)
-
 let print_decls =
-  let print inv_trig ac sl tc csm pjs axs sm fmt d =
+  let print_decl info fmt d =
+    try print_decl info fmt d; info, []
+    with Unsupported s -> raise (UnsupportedDecl (d,s)) in
+  let print_decl = Printer.sprint_decl print_decl in
+  let print_decl task acc = print_decl task.Task.task_decl acc in
+  Discriminate.on_syntax_map (fun sm ->
+  Trans.on_tagged_ls meta_ac (fun ac ->
+  Trans.on_meta meta_printer_option (fun args ->
+  Trans.on_meta Eliminate_algebraic.meta_proj (fun mal ->
+  Trans.on_tagged_ls meta_invalid_trigger (fun inv_trig ->
+    let csm,pjs,axs =
+      List.fold_left add_projection (Mls.empty,Sls.empty,Spr.empty) mal in
     let info = {
       info_syn = sm;
       info_ac  = ac;
-      info_show_labels = sl;
-      info_type_casts = tc;
+      info_show_labels = List.fold_left check_showlabels false args;
+      info_type_casts = List.fold_left check_typecasts true args;
       info_csm = Mls.map Array.to_list csm;
       info_pjs = pjs;
       info_axs = axs;
       info_inv_trig = Sls.add ps_equ inv_trig;
     } in
-    print_decl info fmt d in
-  Trans.on_tagged_ls meta_invalid_trigger (fun inv_trig ->
-  Trans.on_tagged_ls meta_ac (fun ac ->
-  Trans.on_meta meta_printer_option (fun args ->
-    let sl = List.fold_left check_showlabels false args in
-    let tc = List.fold_left check_typecasts  true  args in
-  Trans.on_meta Eliminate_algebraic.meta_proj (fun mal ->
-    let csm,pjs,axs = List.fold_left
-      add_projection (Mls.empty,Sls.empty,Spr.empty) mal in
-    Printer.sprint_decls (print inv_trig ac sl tc csm pjs axs)))))
+    Trans.fold print_decl (info,[]))))))
 
 let print_task _env pr thpr _blacklist ?old:_ fmt task =
   (* In trans-based p-printing [forget_all] is a no-no *)
   (* forget_all ident_printer; *)
   print_prelude fmt pr;
   print_th_prelude task fmt thpr;
-  fprintf fmt "%a@." (print_list nothing string)
-    (List.rev (Trans.apply print_decls task))
+  let rec print = function
+    | x :: r -> print r; Pp.string fmt x
+    | [] -> () in
+  print (snd (Trans.apply print_decls task));
+  pp_print_flush fmt ()
 
 let () = register_printer "alt-ergo" print_task
   ~desc:"Printer for the Alt-Ergo theorem prover."
-(*
-let print_goal info fmt (id, f, task) =
-  print_task info fmt task;
-  fprintf fmt "@\n@[<hov 2>goal %a : %a@]@\n" print_ident id (print_fmla info) f
-*)
-
diff --git a/src/printer/cvc3.ml b/src/printer/cvc3.ml
index 377eecc99d626f5bea291c2675208fd9f93cd5dd..4955de0548f0c05bfe89f49d709dc8bd8ab7cd33 100644
--- a/src/printer/cvc3.ml
+++ b/src/printer/cvc3.ml
@@ -47,56 +47,37 @@ let ident_printer =
 let print_ident fmt id =
   fprintf fmt "%s" (id_unique ident_printer id)
 
-(** type *)
 type info = {
-  info_syn : syntax_map;
-  complex_type : ty Hty.t;
+  info_syn     : syntax_map;
+  complex_type : ty Mty.t ref;
+  urg_output   : string list ref;
 }
 
-let rec print_type info fmt ty = match ty.ty_node with
-  | Tyvar _ -> unsupported "cvc3 : you must encode the polymorphism"
-  | Tyapp (ts, []) -> begin match query_syntax info.info_syn ts.ts_name with
-      | Some s -> syntax_arguments s (print_type info) fmt []
-      | None -> fprintf fmt "%a" print_ident ts.ts_name
-  end
-  | Tyapp (ts, l) ->
-     begin match query_syntax info.info_syn ts.ts_name with
-      | Some s -> syntax_arguments s (print_type info) fmt l
-      | None -> print_type info fmt (Hty.find info.complex_type ty)
-     end
-
-(* and print_tyapp info fmt = function *)
-(*   | [] -> () *)
-(*   | [ty] -> fprintf fmt "%a " (print_type info) ty *)
-(*   | tl -> fprintf fmt "(%a) " (print_list comma (print_type info)) tl *)
+(** type *)
+let complex_type = Wty.memoize 3 (fun ty ->
+  let s = Pp.string_of_wnl Pretty.print_ty ty in
+  create_tysymbol (id_fresh s) [] None)
 
-let rec iter_complex_type info fmt () ty = match ty.ty_node with
-  | Tyvar _ -> unsupported "cvc3 : you must encode the polymorphism"
-  | Tyapp (_, []) -> ()
+let rec print_type info fmt ty = match ty.ty_node with
+  | Tyvar _ -> unsupported "cvc3: you must encode the polymorphism"
   | Tyapp (ts, l) ->
-    begin match query_syntax info.info_syn ts.ts_name with
-      | Some _ -> List.iter (iter_complex_type info fmt ()) l
-      | None when not (Hty.mem info.complex_type ty) ->
-        let id = id_fresh (Pp.string_of_wnl Pretty.print_ty ty) in
-        let ts = create_tysymbol id [] None in
-        let cty = ty_app ts [] in
-        fprintf fmt "%a: TYPE;@."
-          print_ident ts.ts_name;
-        Hty.add info.complex_type ty cty
-      | None -> ()
-    end
-
-let find_complex_type info fmt f =
-  t_ty_fold (iter_complex_type info fmt) () f
+      begin match query_syntax info.info_syn ts.ts_name, l with
+      | Some s, _ -> syntax_arguments s (print_type info) fmt l
+      | None, [] -> fprintf fmt "%a" print_ident ts.ts_name
+      | None, _ ->
+          begin match Mty.find_opt ty !(info.complex_type) with
+          | Some ty -> print_type info fmt ty
+          | None ->
+              let ts = complex_type ty in let cty = ty_app ts [] in
+              let us = sprintf "%a: TYPE;@\n@\n" print_ident ts.ts_name in
+              info.complex_type := Mty.add ty cty !(info.complex_type);
+              info.urg_output := us :: !(info.urg_output);
+              print_type info fmt cty
+          end
+      end
 
-let find_complex_type_expr info fmt f =
-  TermTF.t_selecti
-    (t_ty_fold (iter_complex_type info fmt))
-    (t_ty_fold (iter_complex_type info fmt))
-    () f
-
-let print_type info fmt =
-  catch_unsupportedType (print_type info fmt)
+let print_type info fmt ty = try print_type info fmt ty
+  with Unsupported s -> raise (UnsupportedType (ty,s))
 
 let print_type_value info fmt = function
   | None -> fprintf fmt "BOOLEAN"
@@ -221,42 +202,28 @@ and print_triggers info fmt = function
     (print_list comma (print_expr info)) a
     (print_triggers info) l
 
-let _print_logic_binder info fmt v =
-  fprintf fmt "%a: %a" print_ident v.vs_name
-    (print_type info) v.vs_ty
-
 let print_type_decl info fmt ts =
-  if Mid.mem ts.ts_name info.info_syn then false else
-  if ts.ts_args = [] then
-  (fprintf fmt "%a : TYPE;" print_ident ts.ts_name; true)
-  else false
+  if ts.ts_args = [] && ts.ts_def = None then
+  if not (Mid.mem ts.ts_name info.info_syn) then
+  fprintf fmt "%a : TYPE;@\n@\n" print_ident ts.ts_name
+
+let print_lsargs info fmt = function
+  | [] -> ()
+  | l  -> fprintf fmt "(%a) -> " (print_list comma (print_type info)) l
 
 let print_param_decl info fmt ls =
-  let print_lsargs info fmt = function
-    | [] -> ()
-    | l ->  fprintf fmt "(%a) -> "
-      (print_list comma (print_type info)) l in
-  List.iter (iter_complex_type info fmt ()) ls.ls_args;
-  Opt.iter (iter_complex_type info fmt ()) ls.ls_value;
-  fprintf fmt "@[<hov 2>%a: %a%a;@]@\n"
+  fprintf fmt "@[<hov 2>%a: %a%a;@]@\n@\n"
     print_ident ls.ls_name
     (print_lsargs info) ls.ls_args
     (print_type_value info) ls.ls_value
 
 let print_param_decl info fmt ls =
-  if Mid.mem ls.ls_name info.info_syn then
-    false else (print_param_decl info fmt ls; true)
+  if not (Mid.mem ls.ls_name info.info_syn)
+  then print_param_decl info fmt ls
 
 let print_logic_decl info fmt (ls,def) =
-  let print_lsargs info fmt = function
-    | [] -> ()
-    | l ->  fprintf fmt "(%a) -> "
-      (print_list comma (print_type info)) l in
-  List.iter (iter_complex_type info fmt ()) ls.ls_args;
-  Opt.iter (iter_complex_type info fmt ()) ls.ls_value;
   let vsl,expr = Decl.open_ls_defn def in
-  find_complex_type_expr info fmt expr;
-  fprintf fmt "@[<hov 2>%a: %a%a = LAMBDA (%a): %a;@]@\n"
+  fprintf fmt "@[<hov 2>%a: %a%a = LAMBDA (%a): %a;@]@\n@\n"
     print_ident ls.ls_name
     (print_lsargs info) ls.ls_args
     (print_type_value info) ls.ls_value
@@ -265,8 +232,8 @@ let print_logic_decl info fmt (ls,def) =
   List.iter forget_var vsl
 
 let print_logic_decl info fmt d =
-  if Mid.mem (fst d).ls_name info.info_syn then
-    false else (print_logic_decl info fmt d; true)
+  if not (Mid.mem (fst d).ls_name info.info_syn)
+  then print_logic_decl info fmt d
 
 let print_decl info fmt d = match d.d_node with
   | Dtype ts ->
@@ -276,59 +243,42 @@ let print_decl info fmt d = match d.d_node with
   | Dparam ls ->
       print_param_decl info fmt ls
   | Dlogic dl ->
-      print_list_opt newline (print_logic_decl info) fmt dl
+      print_list nothing (print_logic_decl info) fmt dl
   | Dind _ -> unsupportedDecl d
       "cvc3 : inductive definition are not supported"
-  | Dprop (Paxiom, pr, _) when Mid.mem pr.pr_name info.info_syn -> false
+  | Dprop (Paxiom, pr, _) when Mid.mem pr.pr_name info.info_syn -> ()
   | Dprop (Paxiom, pr, f) ->
-    find_complex_type info fmt f;
-      fprintf fmt "@[<hov 2>%% %s@\nASSERT@ %a;@]@\n"
-        pr.pr_name.id_string
-        (print_fmla info) f; true
+      fprintf fmt "@[<hov 2>%% %s@\nASSERT@ %a;@]@\n@\n"
+        pr.pr_name.id_string (print_fmla info) f
   | Dprop (Pgoal, pr, f) ->
-    find_complex_type info fmt f;
       fprintf fmt "@[QUERY@\n";
       fprintf fmt "@[%% %a@]@\n" print_ident pr.pr_name;
       (match pr.pr_name.id_loc with
-        | None -> ()
-        | Some loc -> fprintf fmt " @[%% %a@]@\n"
-            Loc.gen_report_position loc);
-      fprintf fmt "  @[%a;@]@]" (print_fmla info) f;
-      true
+        | Some loc -> fprintf fmt " @[%% %a@]@\n" Loc.gen_report_position loc
+        | None -> ());
+      fprintf fmt "  @[%a;@]@]@\n" (print_fmla info) f
   | Dprop ((Plemma|Pskip), _, _) -> assert false
 
-let print_decl info fmt = catch_unsupportedDecl (print_decl info fmt)
-
-let distingued =
-  let dist_syntax mls = function
-    | [MAls ls;MAstr s] -> Mls.add ls s mls
-    | _ -> assert false in
-  let dist_dist syntax mls = function
-    | [MAls ls;MAls lsdis] ->
-      begin try
-              Mid.add lsdis.ls_name (Mls.find ls syntax) mls
-        with Not_found -> mls end
-    | _ -> assert false in
-  Trans.on_meta meta_syntax_logic (fun syntax ->
-    let syntax = List.fold_left dist_syntax Mls.empty syntax in
-    Trans.on_meta Discriminate.meta_lsinst (fun dis ->
-      let dis2 = List.fold_left (dist_dist syntax) Mid.empty dis in
-      Trans.return dis2))
+let print_decls =
+  let print_decl (sm,ct) fmt d =
+    let info = {info_syn = sm; complex_type = ref ct; urg_output = ref []} in
+    try print_decl info fmt d; (sm, !(info.complex_type)), !(info.urg_output)
+    with Unsupported s -> raise (UnsupportedDecl (d,s)) in
+  let print_decl = Printer.sprint_decl print_decl in
+  let print_decl task acc = print_decl task.Task.task_decl acc in
+  Discriminate.on_syntax_map (fun sm ->
+    Trans.fold print_decl ((sm,Mty.empty),[]))
 
-let print_task pr thpr _blacklist fmt task =
+let print_task _env pr thpr _blacklist ?old:_ fmt task =
+  (* In trans-based p-printing [forget_all] is a no-no *)
+  (* forget_all ident_printer; *)
   print_prelude fmt pr;
   print_th_prelude task fmt thpr;
-  let info = {
-    info_syn = Mid.union (fun _ _ s -> Some s)
-      (get_syntax_map task) (Trans.apply distingued task);
-    complex_type = Hty.create 5;
-  }
-  in
-  let decls = Task.task_decls task in
-  ignore (print_list_opt (add_flush newline2) (print_decl info) fmt decls)
+  let rec print = function
+    | x :: r -> print r; Pp.string fmt x
+    | [] -> () in
+  print (snd (Trans.apply print_decls task));
+  pp_print_flush fmt ()
 
-let () = register_printer "cvc3"
-  (fun _env pr thpr blacklist ?old:_ fmt task ->
-     forget_all ident_printer;
-     print_task pr thpr blacklist fmt task)
+let () = register_printer "cvc3" print_task
   ~desc:"Printer@ for@ the@ CVC3@ theorem@ prover."
diff --git a/src/printer/simplify.ml b/src/printer/simplify.ml
index 1a56dcf8076d93d945cc34c782b3a4779309f100..a1fb4dfef6a3057684272d81773d9d6f7e9f00be 100644
--- a/src/printer/simplify.ml
+++ b/src/printer/simplify.ml
@@ -123,46 +123,44 @@ and print_triggers info fmt = function
   | tl -> fprintf fmt "@ (PATS %a)" (print_list space (print_trigger info)) tl
 
 let print_decl info fmt d = match d.d_node with
-  | Dtype _ | Dparam _ ->
-      false
+  | Dtype _ | Dparam _ -> ()
   | Ddata _ ->
       unsupportedDecl d "Algebraic datatypes are not supported"
   | Dlogic _ ->
       unsupportedDecl d "Predicate and function definition aren't supported"
   | Dind _ ->
       unsupportedDecl d "simplify : inductive definition are not supported"
-  | Dprop (Paxiom, pr, _) when Mid.mem pr.pr_name info.info_syn ->
-      false
+  | Dprop (Paxiom, pr, _) when Mid.mem pr.pr_name info.info_syn -> ()
   | Dprop (Paxiom, pr, f) ->
-      fprintf fmt "@[(BG_PUSH@\n ;; axiom %s@\n @[<hov 2>%a@])@]@\n"
-        pr.pr_name.id_string (print_fmla info) f;
-      true
+      fprintf fmt "@[(BG_PUSH@\n ;; axiom %s@\n @[<hov 2>%a@])@]@\n@\n"
+        pr.pr_name.id_string (print_fmla info) f
   | Dprop (Pgoal, pr, f) ->
       fprintf fmt "@[;; %a@]@\n" print_ident pr.pr_name;
-      begin match pr.pr_name.id_loc with
-        | None -> ()
-        | Some loc -> fprintf fmt " @[;; %a@]@\n"
-            Loc.gen_report_position loc
-      end;
-      fprintf fmt "@[<hov 2>%a@]@\n" (print_fmla info) f;
-      true
+      (match pr.pr_name.id_loc with
+        | Some loc -> fprintf fmt " @[;; %a@]@\n" Loc.gen_report_position loc
+        | None -> ());
+      fprintf fmt "@[<hov 2>%a@]@\n" (print_fmla info) f
   | Dprop ((Plemma|Pskip), _, _) ->
       assert false
 
-let print_decl info fmt = catch_unsupportedDecl (print_decl info fmt)
-
-let print_task pr thpr _blacklist fmt task =
+let print_decls =
+  let print_decl sm fmt d =
+    try print_decl {info_syn = sm} fmt d; sm, []
+    with Unsupported s -> raise (UnsupportedDecl (d,s)) in
+  let print_decl = Printer.sprint_decl print_decl in
+  let print_decl task acc = print_decl task.Task.task_decl acc in
+  Discriminate.on_syntax_map (fun sm -> Trans.fold print_decl (sm,[]))
+
+let print_task _env pr thpr _blacklist ?old:_ fmt task =
+  (* In trans-based p-printing [forget_all] is a no-no *)
+  (* forget_all ident_printer; *)
   print_prelude fmt pr;
   print_th_prelude task fmt thpr;
-  let info = {
-    info_syn = get_syntax_map task }
-  in
-  let decls = Task.task_decls task in
-  ignore (print_list_opt (add_flush newline2) (print_decl info) fmt decls)
-
-let () = register_printer "simplify"
-  (fun _env pr thpr blacklist ?old:_ fmt task ->
-     forget_all ident_printer;
-     print_task pr thpr blacklist fmt task)
-  ~desc:"Printer@ for@ the@ Simplify@ theorem@ prover."
+  let rec print = function
+    | x :: r -> print r; Pp.string fmt x
+    | [] -> () in
+  print (snd (Trans.apply print_decls task));
+  pp_print_flush fmt ()
 
+let () = register_printer "simplify" print_task
+  ~desc:"Printer@ for@ the@ Simplify@ theorem@ prover."
diff --git a/src/printer/smtv1.ml b/src/printer/smtv1.ml
index 2cc9d49aa05161b03d087b8aef2b9b2c88c6d18b..f47fcf3dd8b7c0121fa575fa96adbba8124264ae 100644
--- a/src/printer/smtv1.ml
+++ b/src/printer/smtv1.ml
@@ -41,23 +41,36 @@ let print_var fmt {vs_name = id} =
   fprintf fmt "%s" n
 
 type info = {
-  info_syn : syntax_map;
+  info_syn     : syntax_map;
+  complex_type : ty Mty.t ref;
+  urg_output   : string list ref;
 }
 
-let rec print_type info fmt ty = match ty.ty_node with
-  | Tyvar _ -> unsupported "smt : you must encode the polymorphism"
-  | Tyapp (ts, []) -> begin match query_syntax info.info_syn ts.ts_name with
-      | Some s -> syntax_arguments s (print_type info) fmt []
-      | None -> fprintf fmt "%a" print_ident ts.ts_name
-  end
-  | Tyapp (_, _) -> unsupported "smt : you must encode the complexe type"
-
-(* and print_tyapp info fmt = function *)
-(*   | [] -> () *)
-(*   | [ty] -> fprintf fmt "%a " (print_type info) ty *)
-(*   | tl -> fprintf fmt "(%a) " (print_list comma (print_type info)) tl *)
+let complex_type = Wty.memoize 3 (fun ty ->
+  let s = Pp.string_of_wnl Pretty.print_ty ty in
+  create_tysymbol (id_fresh s) [] None)
 
-let print_type info fmt = catch_unsupportedType (print_type info fmt)
+let rec print_type info fmt ty = match ty.ty_node with
+  | Tyvar _ -> unsupported "smtv1: you must encode the polymorphism"
+  | Tyapp (ts, l) ->
+      begin match query_syntax info.info_syn ts.ts_name, l with
+      | Some s, _ -> syntax_arguments s (print_type info) fmt l
+      | None, [] -> fprintf fmt "%a" print_ident ts.ts_name
+      | None, _ ->
+          begin match Mty.find_opt ty !(info.complex_type) with
+          | Some ty -> print_type info fmt ty
+          | None ->
+              let ts = complex_type ty in let cty = ty_app ts [] in
+              let us = sprintf
+                ":extrasorts (%a)@\n@\n" print_ident ts.ts_name in
+              info.complex_type := Mty.add ty cty !(info.complex_type);
+              info.urg_output := us :: !(info.urg_output);
+              print_type info fmt cty
+          end
+      end
+
+let print_type info fmt ty = try print_type info fmt ty
+  with Unsupported s -> raise (UnsupportedType (ty,s))
 
 let rec print_term info fmt t = match t.t_node with
   | Tconst c ->
@@ -148,80 +161,82 @@ and print_fmla info fmt f = match f.t_node with
       "smtv1 : you must eliminate match"
   | Tvar _ | Tconst _ | Teps _ -> raise (FmlaExpected f)
 
+(*
 and _print_expr info fmt =
   TermTF.t_select (print_term info fmt) (print_fmla info fmt)
 
 and _print_triggers info fmt tl = print_list comma (_print_expr info) fmt tl
 
-
 let _print_logic_binder info fmt v =
   fprintf fmt "%a: %a" print_ident v.vs_name (print_type info) v.vs_ty
+*)
 
 let print_type_decl info fmt ts =
-  if Mid.mem ts.ts_name info.info_syn then false else
-  if ts.ts_args = [] then
-    (fprintf fmt ":extrasorts (%a)" print_ident ts.ts_name; true)
-  else unsupported "smtv1 : type with argument are not supported"
+  if ts.ts_args = [] && ts.ts_def = None then
+  if not (Mid.mem ts.ts_name info.info_syn) then
+  fprintf fmt ":extrasorts (%a)@\n@\n" print_ident ts.ts_name
 
 let print_param_decl info fmt ls = match ls.ls_value with
   | None ->
-      fprintf fmt "@[<hov 2>:extrapreds ((%a %a))@]@\n"
+      fprintf fmt "@[<hov 2>:extrapreds ((%a %a))@]@\n@\n"
         print_ident ls.ls_name
         (print_list space (print_type info)) ls.ls_args
   | Some value ->
-      fprintf fmt "@[<hov 2>:extrafuns ((%a %a %a))@]@\n"
+      fprintf fmt "@[<hov 2>:extrafuns ((%a %a %a))@]@\n@\n"
         print_ident ls.ls_name
         (print_list space (print_type info)) ls.ls_args
         (print_type info) value
 
 let print_param_decl info fmt ls =
-  if Mid.mem ls.ls_name info.info_syn then
-    false else (print_param_decl info fmt ls; true)
+  if not (Mid.mem ls.ls_name info.info_syn) then
+  print_param_decl info fmt ls
 
 let print_decl info fmt d = match d.d_node with
   | Dtype ts ->
       print_type_decl info fmt ts
-  | Ddata _ -> unsupported
-          "smtv1 : algebraic type are not supported"
+  | Ddata _ -> unsupportedDecl d
+      "smtv1 : algebraic types are not supported"
   | Dparam ls ->
       print_param_decl info fmt ls
-  | Dlogic _ -> unsupported
-      "Predicate and function definition aren't supported"
+  | Dlogic _ -> unsupportedDecl d
+      "smtv1 : predicate and function definitions are not supported"
   | Dind _ -> unsupportedDecl d
-      "smt : inductive definition are not supported"
-  | Dprop (Paxiom, pr, _) when Mid.mem pr.pr_name info.info_syn -> false
+      "smtv1 : inductive definitions are not supported"
+  | Dprop (Paxiom, pr, _) when Mid.mem pr.pr_name info.info_syn -> ()
   | Dprop (Paxiom, pr, f) ->
-      fprintf fmt "@[<hov 2>;; %s@\n:assumption@ %a@]@\n"
-        pr.pr_name.id_string
-        (print_fmla info) f; true
+      fprintf fmt "@[<hov 2>;; %s@\n:assumption@ %a@]@\n@\n"
+        pr.pr_name.id_string (print_fmla info) f
   | Dprop (Pgoal, pr, f) ->
       fprintf fmt "@[:formula@\n";
       fprintf fmt "@[;; %a@]@\n" print_ident pr.pr_name;
       (match pr.pr_name.id_loc with
-        | None -> ()
-        | Some loc -> fprintf fmt " @[;; %a@]@\n"
-            Loc.gen_report_position loc);
-      fprintf fmt "  @[(not@ %a)@]" (print_fmla info) f;true
+        | Some loc -> fprintf fmt " @[;; %a@]@\n" Loc.gen_report_position loc
+        | None -> ());
+      fprintf fmt "  @[(not@ %a)@]@\n" (print_fmla info) f
   | Dprop ((Plemma|Pskip), _, _) -> assert false
 
-let print_decl info fmt = catch_unsupportedDecl (print_decl info fmt)
-
-let print_task pr thpr _blacklist fmt task =
-  fprintf fmt "(benchmark why3@\n"
-    (*print_ident (Task.task_goal task).pr_name*);
+let print_decls =
+  let print_decl (sm,ct) fmt d =
+    let info = {info_syn = sm; complex_type = ref ct; urg_output = ref []} in
+    try print_decl info fmt d; (sm, !(info.complex_type)), !(info.urg_output)
+    with Unsupported s -> raise (UnsupportedDecl (d,s)) in
+  let print_decl = Printer.sprint_decl print_decl in
+  let print_decl task acc = print_decl task.Task.task_decl acc in
+  Discriminate.on_syntax_map (fun sm ->
+    Trans.fold print_decl ((sm,Mty.empty),[]))
+
+let print_task _env pr thpr _blacklist ?old:_ fmt task =
+  (* In trans-based p-printing [forget_all] is a no-no *)
+  (* forget_all ident_printer; *)
+  fprintf fmt "(benchmark why3@\n";
   fprintf fmt "  :status unknown@\n";
   print_prelude fmt pr;
   print_th_prelude task fmt thpr;
-  let info = {
-    info_syn = get_syntax_map task;
-  }
-  in
-  let decls = Task.task_decls task in
-  ignore (print_list_opt (add_flush newline2) (print_decl info) fmt decls);
-  fprintf fmt "@\n)@."
-
-let () = register_printer "smtv1"
-  (fun _env pr thpr blacklist ?old:_ fmt task ->
-     forget_all ident_printer;
-     print_task pr thpr blacklist fmt task)
+  let rec print = function
+    | x :: r -> print r; Pp.string fmt x
+    | [] -> () in
+  print (snd (Trans.apply print_decls task));
+  fprintf fmt ")@."
+
+let () = register_printer "smtv1" print_task
   ~desc:"Printer@ for@ the@ SMTlib@ version@ 1@ format."
diff --git a/src/printer/smtv2.ml b/src/printer/smtv2.ml
index 2bd2cd4a9162721f411f498910844b1afbc6b093..80660e7ef5ba74ec80504fedcfecadb9f10fe3ba 100644
--- a/src/printer/smtv2.ml
+++ b/src/printer/smtv2.ml
@@ -71,55 +71,23 @@ let ident_printer =
 let print_ident fmt id =
   fprintf fmt "%s" (id_unique ident_printer id)
 
-(** type *)
 type info = {
   info_syn : syntax_map;
-(*  complex_type : ty Hty.t; *)
 }
 
+(** type *)
 let rec print_type info fmt ty = match ty.ty_node with
   | Tyvar _ -> unsupported "smt : you must encode the polymorphism"
-  | Tyapp (ts, []) -> begin match query_syntax info.info_syn ts.ts_name with
-      | Some s -> syntax_arguments s (print_type info) fmt []
-      | None -> fprintf fmt "%a" print_ident ts.ts_name
-  end
   | Tyapp (ts, l) ->
-     begin match query_syntax info.info_syn ts.ts_name with
-      | Some s -> syntax_arguments s (print_type info) fmt l
-      | None -> fprintf fmt "(%a %a)" print_ident ts.ts_name
-        (print_list space (print_type info)) l
+     begin match query_syntax info.info_syn ts.ts_name, l with
+      | Some s, _ -> syntax_arguments s (print_type info) fmt l
+      | None, [] -> fprintf fmt "%a" print_ident ts.ts_name
+      | None, _ -> fprintf fmt "(%a %a)" print_ident ts.ts_name
+          (print_list space (print_type info)) l
      end
 
-(*
-let iter_complex_type info fmt () ty =
-    match ty.ty_node with
-      | Tyapp (_,_::_) when not (Hty.mem info.complex_type ty) ->
-        let id = id_fresh (Pp.string_of_wnl Pretty.print_ty ty) in
-        let ts = create_tysymbol id [] None in
-        let cty = ty_app ts [] in
-        fprintf fmt "(define-sorts ((%a %a)))@\n"
-          print_ident ts.ts_name
-          (print_type info) ty;
-        Hty.add info.complex_type ty cty
-      | _ -> ()
-
-let find_complex_type info fmt f =
-  t_ty_fold (iter_complex_type info fmt) () f
-
-let print_type info fmt ty =
-  print_type info fmt
-    (try
-       Hty.find info.complex_type ty
-     with Not_found -> ty)
-*)
-
-(* and print_tyapp info fmt = function *)
-(*   | [] -> () *)
-(*   | [ty] -> fprintf fmt "%a " (print_type info) ty *)
-(*   | tl -> fprintf fmt "(%a) " (print_list comma (print_type info)) tl *)
-
-let print_type info fmt =
-  catch_unsupportedType (print_type info fmt)
+let print_type info fmt ty = try print_type info fmt ty
+  with Unsupported s -> raise (UnsupportedType (ty,s))
 
 let print_type_value info fmt = function
   | None -> fprintf fmt "Bool"
@@ -246,10 +214,6 @@ and print_triggers info fmt = function
     (print_list space (print_trigger info)) a
     (print_triggers info) l
 
-let _print_logic_binder info fmt v =
-  fprintf fmt "%a: %a" print_ident v.vs_name
-    (print_type info) v.vs_ty
-
 let print_type_decl info fmt ts =
   if ts.ts_def <> None then () else
   if Mid.mem ts.ts_name info.info_syn then () else
@@ -304,66 +268,24 @@ let print_decl info fmt d = match d.d_node with
       if Mid.mem pr.pr_name info.info_syn then () else
       print_prop_decl info fmt k pr f
 
-let print_decl info fmt = catch_unsupportedDecl (print_decl info fmt)
-
-let distingued =
-  let dist_syntax mls = function
-    | [MAls ls;MAstr s] -> Mls.add ls s mls
-    | _ -> assert false in
-  let dist_dist syntax mls = function
-    | [MAls ls;MAls lsdis] ->
-      begin try
-              Mid.add lsdis.ls_name (Mls.find ls syntax) mls
-        with Not_found -> mls end
-    | _ -> assert false in
-  Trans.on_meta meta_syntax_logic (fun syntax ->
-    let syntax = List.fold_left dist_syntax Mls.empty syntax in
-    Trans.on_meta Discriminate.meta_lsinst (fun dis ->
-      let dis2 = List.fold_left (dist_dist syntax) Mid.empty dis in
-      Trans.return dis2))
-
-let print_task_old pr thpr _blacklist fmt task =
-  print_prelude fmt pr;
-  print_th_prelude task fmt thpr;
-  let info = {
-    info_syn = Mid.union (fun _ _ s -> Some s)
-      (get_syntax_map task) (Trans.apply distingued task);
-    (* complex_type = Hty.create 5; *)
-  }
-  in
-  let decls = Task.task_decls task in
-  fprintf fmt "%a@." (print_list nothing (print_decl info)) decls
-
-let () = register_printer "smtv2"
-  (fun _env pr thpr blacklist ?old:_ fmt task ->
-     forget_all ident_printer;
-     print_task_old pr thpr blacklist fmt task)
-  ~desc:"Printer for the SMTlib version 2 format."
-
-(*
 let print_decls =
-  let add_ls sm acc = function
-    | [MAls ls; MAls lsdis] ->
-        begin try
-          Mid.add lsdis.ls_name (Mid.find ls.ls_name sm) acc
-        with Not_found -> acc end
-    | _ -> assert false in
-  let print dls sm fmt d =
-    let info = {
-      info_syn = List.fold_left (add_ls sm) sm dls;
-    } in
-    print_decl info fmt d in
-  Trans.on_meta Discriminate.meta_lsinst (fun dls ->
-    Printer.sprint_decls (print dls))
+  let print_decl sm fmt d =
+    try print_decl {info_syn = sm} fmt d; sm, []
+    with Unsupported s -> raise (UnsupportedDecl (d,s)) in
+  let print_decl = Printer.sprint_decl print_decl in
+  let print_decl task acc = print_decl task.Task.task_decl acc in
+  Discriminate.on_syntax_map (fun sm -> Trans.fold print_decl (sm,[]))
 
 let print_task _env pr thpr _blacklist ?old:_ fmt task =
-  (* In trans-based p-printing [forget_all] is taboo *)
+  (* In trans-based p-printing [forget_all] is a no-no *)
   (* forget_all ident_printer; *)
   print_prelude fmt pr;
   print_th_prelude task fmt thpr;
-  fprintf fmt "%a@." (print_list nothing string)
-    (List.rev (Trans.apply print_decls task))
-
-let () = register_printer "smtv2new" print_task
-  ~desc:"Printer for the SMTlib version 2 format."
-*)
+  let rec print = function
+    | x :: r -> print r; Pp.string fmt x
+    | [] -> () in
+  print (snd (Trans.apply print_decls task));
+  pp_print_flush fmt ()
+
+let () = register_printer "smtv2" print_task
+  ~desc:"Printer@ for@ the@ SMTlib@ version@ 2@ format."
diff --git a/src/printer/why3printer.ml b/src/printer/why3printer.ml
index 9f83356386792e758353344fe7ffba3b5cd2f74d..6d1d46df32b6c784685e207c8180107832be136d 100644
--- a/src/printer/why3printer.ml
+++ b/src/printer/why3printer.ml
@@ -377,23 +377,12 @@ let print_tdecl fmt td = match td.td_node with
       fprintf fmt "@[<hov 2>(* meta %s %a *)@]@\n@\n"
         m.meta_name (print_list comma print_meta_arg) al
 
-(*
-let print_task_old _env pr thpr _blacklist ?old:_ fmt task =
-  forget_all ();
-  print_prelude fmt pr;
-  print_th_prelude task fmt thpr;
-  info := { info_syn = get_syntax_map task };
-  fprintf fmt "theory Task@\n%a@\nend@."
-    (print_list nothing print_tdecl) (Task.task_tdecls task)
-
-let () = register_printer "why3old" print_task_old ~desc:""
-*)
-
 let print_tdecls =
-  let print sm fmt td =
-    info := { info_syn = sm };
-    print_tdecl fmt td in
-  Printer.sprint_tdecls print
+  let print_tdecl sm fmt td =
+    info := {info_syn = sm}; print_tdecl fmt td; sm, [] in
+  let print_tdecl = Printer.sprint_tdecl print_tdecl in
+  let print_tdecl task acc = print_tdecl task.Task.task_decl acc in
+  Discriminate.on_syntax_map (fun sm -> Trans.fold print_tdecl (sm,[]))
 
 let print_task _env pr thpr _blacklist ?old:_ fmt task =
   (* In trans-based p-printing [forget_all] IST STRENG VERBOTEN *)
@@ -401,10 +390,11 @@ let print_task _env pr thpr _blacklist ?old:_ fmt task =
   print_prelude fmt pr;
   fprintf fmt "theory Task@\n";
   print_th_prelude task fmt thpr;
-  fprintf fmt "%a@\nend@."
-    (print_list nothing string)
-      (List.rev (Trans.apply print_tdecls task))
+  let rec print = function
+    | x :: r -> print r; Pp.string fmt x
+    | [] -> () in
+  print (snd (Trans.apply print_tdecls task));
+  fprintf fmt "end@."
 
 let () = register_printer "why3" print_task
-  ~desc:"Printer@ for@ the@ logical@ format@ of@ Why3.@ \
-    Used@ for@ debugging."
+  ~desc:"Printer@ for@ the@ logical@ format@ of@ Why3.@ Used@ for@ debugging."
diff --git a/src/printer/yices.ml b/src/printer/yices.ml
index a6cc08db681da774403d0d7162efd5818189f8a0..38ce6f5a8af957903997040706c2b450444c2bc2 100644
--- a/src/printer/yices.ml
+++ b/src/printer/yices.ml
@@ -52,56 +52,38 @@ let ident_printer =
 let print_ident fmt id =
   fprintf fmt "%s" (id_unique ident_printer id)
 
-(** type *)
 type info = {
-  info_syn : syntax_map;
-  complex_type : ty Hty.t;
+  info_syn     : syntax_map;
+  complex_type : ty Mty.t ref;
+  urg_output   : string list ref;
 }
 
-let rec print_type info fmt ty = match ty.ty_node with
-  | Tyvar _ -> unsupported "yices: you must encode polymorphism"
-  | Tyapp (ts, []) -> begin match query_syntax info.info_syn ts.ts_name with
-      | Some s -> syntax_arguments s (print_type info) fmt []
-      | None -> fprintf fmt "%a" print_ident ts.ts_name
-  end
-  | Tyapp (ts, l) ->
-     begin match query_syntax info.info_syn ts.ts_name with
-      | Some s -> syntax_arguments s (print_type info) fmt l
-      | None -> print_type info fmt (Hty.find info.complex_type ty)
-     end
-
-(* and print_tyapp info fmt = function *)
-(*   | [] -> () *)
-(*   | [ty] -> fprintf fmt "%a " (print_type info) ty *)
-(*   | tl -> fprintf fmt "(%a) " (print_list comma (print_type info)) tl *)
+(** type *)
+let complex_type = Wty.memoize 3 (fun ty ->
+  let s = Pp.string_of_wnl Pretty.print_ty ty in
+  create_tysymbol (id_fresh s) [] None)
 
-let rec iter_complex_type info fmt () ty = match ty.ty_node with
-  | Tyvar _ -> unsupported "yices: you must encode polymorphism"
-  | Tyapp (_, []) -> ()
+let rec print_type info fmt ty = match ty.ty_node with
+  | Tyvar _ -> unsupported "cvc3: you must encode the polymorphism"
   | Tyapp (ts, l) ->
-    begin match query_syntax info.info_syn ts.ts_name with
-      | Some _ -> List.iter (iter_complex_type info fmt ()) l
-      | None when not (Hty.mem info.complex_type ty) ->
-        let id = id_fresh (Pp.string_of_wnl Pretty.print_ty ty) in
-        let ts = create_tysymbol id [] None in
-        let cty = ty_app ts [] in
-        fprintf fmt "(define-type %a)@."
-          print_ident ts.ts_name;
-        Hty.add info.complex_type ty cty
-      | None -> ()
-    end
-
-let find_complex_type info fmt f =
-  t_ty_fold (iter_complex_type info fmt) () f
-
-let find_complex_type_expr info fmt f =
-  TermTF.t_selecti
-    (t_ty_fold (iter_complex_type info fmt))
-    (t_ty_fold (iter_complex_type info fmt))
-    () f
+      begin match query_syntax info.info_syn ts.ts_name, l with
+      | Some s, _ -> syntax_arguments s (print_type info) fmt l
+      | None, [] -> fprintf fmt "%a" print_ident ts.ts_name
+      | None, _ ->
+          begin match Mty.find_opt ty !(info.complex_type) with
+          | Some ty -> print_type info fmt ty
+          | None ->
+              let ts = complex_type ty in let cty = ty_app ts [] in
+              let us = sprintf
+                "(define-type %a)@\n@\n" print_ident ts.ts_name in
+              info.complex_type := Mty.add ty cty !(info.complex_type);
+              info.urg_output := us :: !(info.urg_output);
+              print_type info fmt cty
+          end
+      end
 
-let print_type info fmt =
-  catch_unsupportedType (print_type info fmt)
+let print_type info fmt ty = try print_type info fmt ty
+  with Unsupported s -> raise (UnsupportedType (ty,s))
 
 let print_type_value info fmt = function
   | None -> fprintf fmt "bool"
@@ -175,20 +157,13 @@ and print_fmla info fmt f = match f.t_node with
         end end
   | Tquant (q, fq) ->
       let q = match q with Tforall -> "forall" | Texists -> "exists" in
-      let vl, tl, f = t_open_quant fq in
+      let vl, _tl, f = t_open_quant fq in
       (* TODO trigger dépend des capacités du prover : 2 printers?
       smtwithtriggers/smtstrict *)
-      if true (*tl = []*) then
-        fprintf fmt "@[(%s@ (%a)@ %a)@]"
-          q
-          (print_var_list info) vl
-          (print_fmla info) f
-      else
-        fprintf fmt "@[(%s@ (%a)%a@ %a)@]"
-          q
-          (print_var_list info) vl
-          (print_triggers info) tl
-          (print_fmla info) f;
+      fprintf fmt "@[(%s@ (%a)@ %a)@]"
+        q
+        (print_var_list info) vl
+        (print_fmla info) f;
       List.iter forget_var vl
   | Tbinop (Tand, f1, f2) ->
       fprintf fmt "@[(and %a@ %a)@]" (print_fmla info) f1 (print_fmla info) f2
@@ -219,6 +194,7 @@ and print_fmla info fmt f = match f.t_node with
       "yices: you must eliminate match"
   | Tvar _ | Tconst _ | Teps _ -> raise (FmlaExpected f)
 
+(*
 and print_expr info fmt =
   TermTF.t_select (print_term info fmt) (print_fmla info fmt)
 
@@ -232,12 +208,12 @@ and print_triggers info fmt = function
 let print_logic_binder info fmt v =
   fprintf fmt "%a: %a" print_ident v.vs_name
     (print_type info) v.vs_ty
+*)
 
 let print_type_decl info fmt ts =
-  if Mid.mem ts.ts_name info.info_syn then false else
-  if ts.ts_args = [] then
-  (fprintf fmt "(define-type %a)" print_ident ts.ts_name; true)
-  else false
+  if ts.ts_args = [] && ts.ts_def = None then
+  if not (Mid.mem ts.ts_name info.info_syn) then
+  fprintf fmt "(define-type %a)@\n@\n" print_ident ts.ts_name
 
 let print_data_decl _info fmt = function
   | ts, csl (* monomorphic enumeration *)
@@ -249,88 +225,69 @@ let print_data_decl _info fmt = function
       unsupported "yices: algebraic types are not supported"
 
 let print_data_decl info fmt (ts, _ as d) =
-  if Mid.mem ts.ts_name info.info_syn then false
-  else begin print_data_decl info fmt d; true end
+  if not (Mid.mem ts.ts_name info.info_syn) then
+  print_data_decl info fmt d
 
 let print_param_decl info fmt ls =
-  List.iter (iter_complex_type info fmt ()) ls.ls_args;
-  Opt.iter (iter_complex_type info fmt ()) ls.ls_value;
   match ls.ls_args with
   | [] ->
-    fprintf fmt "@[<hov 2>(define %a::%a)@]@\n"
+    fprintf fmt "@[<hov 2>(define %a::%a)@]@\n@\n"
       print_ident ls.ls_name
       (print_type_value info) ls.ls_value
   | _ ->
-    fprintf fmt "@[<hov 2>(define %a::(-> %a %a))@]@\n"
+    fprintf fmt "@[<hov 2>(define %a::(-> %a %a))@]@\n@\n"
       print_ident ls.ls_name
       (print_list space (print_type info)) ls.ls_args
       (print_type_value info) ls.ls_value
 
 let print_param_decl info fmt ls =
-  if Mid.mem ls.ls_name info.info_syn then
-    false else (print_param_decl info fmt ls; true)
+  if not (Mid.mem ls.ls_name info.info_syn) then
+  print_param_decl info fmt ls
 
 let print_decl info fmt d = match d.d_node with
   | Dtype ts ->
       print_type_decl info fmt ts
   | Ddata dl ->
-      print_list_opt nothing (print_data_decl info) fmt dl
+      print_list nothing (print_data_decl info) fmt dl
   | Dparam ls ->
       print_param_decl info fmt ls
   | Dlogic _ -> unsupportedDecl d
       "yices: function and predicate definitions are not supported"
   | Dind _ -> unsupportedDecl d
       "yices: inductive definitions are not supported"
-  | Dprop (Paxiom, pr, _) when Mid.mem pr.pr_name info.info_syn -> false
+  | Dprop (Paxiom, pr, _) when Mid.mem pr.pr_name info.info_syn -> ()
   | Dprop (Paxiom, pr, f) ->
-    find_complex_type info fmt f;
-      fprintf fmt "@[<hov 2>;; %s@\n(assert@ %a);@]@\n"
-        pr.pr_name.id_string
-        (print_fmla info) f; true
+      fprintf fmt "@[<hov 2>;; %s@\n(assert@ %a);@]@\n@\n"
+        pr.pr_name.id_string (print_fmla info) f
   | Dprop (Pgoal, pr, f) ->
-    find_complex_type info fmt f;
       fprintf fmt "@[(assert@\n";
       fprintf fmt "@[;; %a@]@\n" print_ident pr.pr_name;
       (match pr.pr_name.id_loc with
-        | None -> ()
-        | Some loc -> fprintf fmt " @[;; %a@]@\n"
-            Loc.gen_report_position loc);
-      fprintf fmt "  @[(not %a)@])@]@\n(check)" (print_fmla info) f;
-      true
+        | Some loc -> fprintf fmt " @[;; %a@]@\n" Loc.gen_report_position loc
+        | None -> ());
+      fprintf fmt "  @[(not %a)@])@]@\n(check)@\n" (print_fmla info) f
   | Dprop ((Plemma|Pskip), _, _) -> assert false
 
-let print_decl info fmt = catch_unsupportedDecl (print_decl info fmt)
+let print_decls =
+  let print_decl (sm,ct) fmt d =
+    let info = {info_syn = sm; complex_type = ref ct; urg_output = ref []} in
+    try print_decl info fmt d; (sm, !(info.complex_type)), !(info.urg_output)
+    with Unsupported s -> raise (UnsupportedDecl (d,s)) in
+  let print_decl = Printer.sprint_decl print_decl in
+  let print_decl task acc = print_decl task.Task.task_decl acc in
+  Discriminate.on_syntax_map (fun sm ->
+    Trans.fold print_decl ((sm,Mty.empty),[]))
 
-let distingued =
-  let dist_syntax mls = function
-    | [MAls ls;MAstr s] -> Mls.add ls s mls
-    | _ -> assert false in
-  let dist_dist syntax mls = function
-    | [MAls ls;MAls lsdis] ->
-      begin try
-              Mid.add lsdis.ls_name (Mls.find ls syntax) mls
-        with Not_found -> mls end
-    | _ -> assert false in
-  Trans.on_meta meta_syntax_logic (fun syntax ->
-    let syntax = List.fold_left dist_syntax Mls.empty syntax in
-    Trans.on_meta Discriminate.meta_lsinst (fun dis ->
-      let dis2 = List.fold_left (dist_dist syntax) Mid.empty dis in
-      Trans.return dis2))
-
-let print_task pr thpr _blacklist fmt task =
+let print_task _env pr thpr _blacklist ?old:_ fmt task =
+  (* In trans-based p-printing [forget_all] is a no-no *)
+  (* forget_all ident_printer; *)
   print_prelude fmt pr;
   print_th_prelude task fmt thpr;
-  let info = {
-    info_syn = Mid.union (fun _ _ s -> Some s)
-      (get_syntax_map task) (Trans.apply distingued task);
-    complex_type = Hty.create 5;
-  }
-  in
-  let decls = Task.task_decls task in
-  ignore (print_list_opt (add_flush newline2) (print_decl info) fmt decls)
+  let rec print = function
+    | x :: r -> print r; Pp.string fmt x
+    | [] -> () in
+  print (snd (Trans.apply print_decls task));
+  pp_print_flush fmt ()
 
-let () = register_printer "yices"
-  (fun _env pr thpr blacklist ?old:_ fmt task ->
-     forget_all ident_printer;
-     print_task pr thpr blacklist fmt task)
+let () = register_printer "yices" print_task
   ~desc:"Printer@ for@ the@ Yices@ theorem@ prover version 1."
diff --git a/src/session/session_scheduler.ml b/src/session/session_scheduler.ml
index 45eb9ae07a9adbeec6760de292e2e66ec8dd8f78..ab2651f9d1198b52145e6db13ce98b50732ee82f 100644
--- a/src/session/session_scheduler.ml
+++ b/src/session/session_scheduler.ml
@@ -250,7 +250,7 @@ let idle_handler t =
                 in
                 Queue.push (callback,pre_call) t.proof_attempts_queue;
                 run_timeout_handler t
-              with e ->
+              with e when not (Debug.test_flag Debug.stack_trace) ->
                 Format.eprintf "@[Exception raise in Session.idle_handler:@ \
 %a@.@]"
                   Exn_printer.exn_printer e;
@@ -263,7 +263,7 @@ let idle_handler t =
     t.idle_handler_activated <- false;
     dprintf debug "[Sched] idle_handler stopped@.";
     false
-    | e ->
+    | e when not (Debug.test_flag Debug.stack_trace) ->
       Format.eprintf "@[Exception raise in Session.idle_handler:@ %a@.@]"
         Exn_printer.exn_printer e;
       eprintf "Session.idle_handler stopped@.";
diff --git a/src/session/termcode.ml b/src/session/termcode.ml
index a4dcdee9d0ed1e1e41bf4c0bafa5fce3dc2d9ca0..dde0aae4c606a3d6e08c778abc88a453ededc8d0 100644
--- a/src/session/termcode.ml
+++ b/src/session/termcode.ml
@@ -61,7 +61,9 @@ let debug = Debug.register_info_flag "session_pairing"
   ~desc:"Print@ debugging@ messages@ about@ reconstruction@ of@ \
          session@ trees@ after@ modification@ of@ source@ files."
 
-let current_shape_version = 3
+let current_shape_version = 4
+
+type shape_version = SV1 | SV2 | SV3
 
 (* similarity code of terms, or of "shapes"
 
@@ -138,32 +140,29 @@ let rec t_shape ~version ~(push:string->'a->'a) c m (acc:'a) t : 'a =
           l
     | Tif (f,t1,t2) ->
       begin match version with
-      | 1 | 2 -> fn (fn (fn (push tag_if acc) f) t1) t2
-      | 3 -> fn (fn (fn (push tag_if acc) t2) t1) f
-      | _ -> assert false
+      | SV1 | SV2 -> fn (fn (fn (push tag_if acc) f) t1) t2
+      | SV3 -> fn (fn (fn (push tag_if acc) t2) t1) f
       end
     | Tcase (t1,bl) ->
         let br_shape acc b =
           let p,t2 = t_open_branch b in
           match version with
-          | 1 | 2 ->
+          | SV1 | SV2 ->
             let acc = pat_shape ~push c m acc p in
             let m = pat_rename_alpha c m p in
             t_shape ~version ~push c m acc t2
-          | 3 ->
+          | SV3 ->
             let m1 = pat_rename_alpha c m p in
             let acc = t_shape ~version ~push c m1 acc t2 in
             pat_shape ~push c m acc p
-          | _ -> assert false
         in
         begin match version with
-        | 1 | 2 ->
+        | SV1 | SV2 ->
           List.fold_left br_shape (fn (push tag_case acc) t1) bl
-        | 3 ->
+        | SV3 ->
           let acc = push tag_case acc in
           let acc = List.fold_left br_shape acc bl in
           fn acc t1
-        | _ -> assert false
         end
     | Teps b ->
         let u,f = t_open_bound b in
@@ -197,18 +196,16 @@ let rec t_shape ~version ~(push:string->'a->'a) c m (acc:'a) t : 'a =
         let m = vs_rename_alpha c m u in
         begin
           match version with
-            | 1 ->
+            | SV1 ->
               t_shape ~version ~push c m (fn (push tag_let acc) t1) t2
-            | 2 | 3 ->
+            | SV2 | SV3 ->
               (* t2 first, intentionally *)
               fn (push tag_let (t_shape ~version ~push c m acc t2)) t1
-            | _ -> assert false
         end
     | Tnot f ->
       begin match version with
-      | 1 | 2 -> push tag_not (fn acc f)
-      | 3 -> fn (push tag_not acc) f
-      | _ -> assert false
+      | SV1 | SV2 -> push tag_not (fn acc f)
+      | SV3 -> fn (push tag_not acc) f
       end
     | Ttrue -> push tag_true acc
     | Tfalse -> push tag_false acc
@@ -221,20 +218,26 @@ let t_shape_buf ?(version=current_shape_version) t =
   Buffer.contents b
 *)
 
-let t_shape_task ?(version=current_shape_version) t =
+let t_shape_task ~version t =
   let b = Buffer.create 17 in
   let push t () = Buffer.add_string b t in
   begin match version with
-  | 1 | 2 -> ()
-  | 3 -> 
+  | SV1 | SV2 -> ()
+  | SV3 ->
     let _, expl, _ = goal_expl_task ~root:false t in
     Opt.iter (Buffer.add_string b) expl
-  | _ -> assert false
   end;
   let f = Task.task_goal_fmla t in
   let () = t_shape ~version ~push (ref (-1)) Mvs.empty () f in
   Buffer.contents b
 
+let t_shape_task ?(version=current_shape_version) t =
+  let version = match version with
+    | 1 -> SV1 | 2 -> SV2 | 3 | 4 -> SV3
+    | _ -> assert false
+  in
+  t_shape_task ~version t
+
 (* Checksums *)
 
 type checksum = string
@@ -244,16 +247,19 @@ let checksum_of_string x = x
 let equal_checksum x y = (x : checksum) = y
 let dumb_checksum = ""
 
+type checksum_version = CV1 | CV2
+
 module Checksum = struct
 
-  let char = Buffer.add_char
-  let int b i = char b 'i'; Buffer.add_string b (string_of_int i)
-  let string b s =
-    char b '"'; Buffer.add_string b (String.escaped s); char b '"'
+  let char (_,_,_,buf) c = Buffer.add_char buf c
+  let int (_,_,_,buf as b) i =
+    char b 'i'; Buffer.add_string buf (string_of_int i)
+  let string (_,_,_,buf as b) s =
+    char b '"'; Buffer.add_string buf (String.escaped s); char b '"'
   let option e b = function None -> char b 'n' | Some x -> char b 's'; e b x
   let list e b l = char b '['; List.iter (e b) l; char b ']'
 
-  let ident, clear_ident =
+  let ident_v1, clear_ident_v1 =
     let hident = Ident.Hid.create 17 in
     let c = ref 0 in
     (fun b id ->
@@ -261,6 +267,17 @@ module Checksum = struct
         with Not_found -> incr c; Ident.Hid.add hident id !c; !c)),
     (fun () -> Ident.Hid.clear hident; c := 0)
 
+  let ident_v2 (_,c,m,_ as b) id =
+    let i = match Ident.Mid.find_opt id !m with
+      | Some i -> i
+      | None -> incr c; m := Ident.Mid.add id !c !m; !c
+    in
+    int b i
+
+  let ident (v,_,_,_ as b) id = match v with
+    | CV1 -> ident_v1 b id
+    | CV2 -> ident_v2 b id
+
   let const b c =
     let buf = Buffer.create 17 in
     Format.bprintf buf "%a" Pretty.print_const c;
@@ -272,8 +289,9 @@ module Checksum = struct
     | Ty.Tyvar tv -> char b 'v'; tvsymbol b tv
     | Ty.Tyapp (ts, tyl) -> char b 'a'; ident b ts.Ty.ts_name; list ty b tyl
 
-  (* variable: the type, but not the name (we want alpha-equivalence) *)
-  let vsymbol b vs = ty b vs.vs_ty
+  let vsymbol (v,_,_,_ as b) vs = match v with
+    | CV1 -> ty b vs.vs_ty
+    | CV2 -> ident b vs.vs_name; ty b vs.vs_ty
 
   (* start: _ V ident a o *)
   let rec pat b p = match p.pat_node with
@@ -395,17 +413,52 @@ module Checksum = struct
         char b 'C'; ident b th.Theory.th_name; list string b th.Theory.th_path
     | Theory.Meta (m, mal) -> char b 'M'; meta b m; list meta_arg b mal
 
-  let task t =
+  let task_v1 =
+    let c = ref 0 in
+    let m = ref Ident.Mid.empty in
     let b = Buffer.create 8192 in
-    Task.task_iter (tdecl b) t;
-    clear_ident ();
-    let s = Buffer.contents b in
-    Digest.to_hex (Digest.string s)
-
+    fun t ->
+      Task.task_iter (tdecl (CV1,c,m,b)) t;
+      clear_ident_v1 ();
+      let dnew = Digest.string (Buffer.contents b) in
+      Buffer.clear b;
+      Digest.to_hex dnew
+
+  let task_v2 =
+    let c = ref 0 in
+    let m = ref Ident.Mid.empty in
+    let b = Buffer.create 8192 in
+    let task_hd t (cold,mold,dold) =
+      c := cold;
+      m := mold;
+      tdecl (CV2,c,m,b) t.Task.task_decl;
+      Buffer.add_string b (Digest.to_hex dold);
+      let dnew = Digest.string (Buffer.contents b) in
+      Buffer.clear b;
+      let mnew = match t.Task.task_decl.Theory.td_node with
+        | Theory.Decl { Decl.d_news = s } ->
+            Ident.Sid.fold (fun id a ->
+              Ident.Mid.add id (Ident.Mid.find id !m) a) s mold
+        | _ -> !m in
+      !c, mnew, dnew
+    in
+    let tr = Trans.fold task_hd (0, Ident.Mid.empty, Digest.string "") in
+    fun t ->
+      let _,_,dnew = Trans.apply tr t in
+      Digest.to_hex dnew
+
+  let task ~version t = match version with
+    | CV1 -> task_v1 t
+    | CV2 -> task_v2 t
 end
 
-let task_checksum ?(version=0) t = ignore version; Checksum.task t
-
+let task_checksum ?(version=current_shape_version) t =
+  let version = match version with
+    | 1 | 2 | 3 -> CV1
+    | 4 -> CV2
+    | _ -> assert false
+  in
+  Checksum.task ~version t
 
 (*************************************************************)
 (* Pairing of new and old subgoals                           *)
diff --git a/src/transform/abstraction.ml b/src/transform/abstraction.ml
index e3b22774a277c0c7d3ac08ee311108b5d3c5e0f5..b0425fc53d89b25c718539cff94b3d10a9b18695 100644
--- a/src/transform/abstraction.ml
+++ b/src/transform/abstraction.ml
@@ -15,7 +15,7 @@ open Term
 open Decl
 
 let abstraction (keep : lsymbol -> bool) =
-  let term_table = Hterm_alpha.create 257 in
+  let term_table = Hterm.create 257 in
   let extra_decls = ref [] in
 
   let rec abstract t : term =
@@ -26,10 +26,10 @@ let abstraction (keep : lsymbol -> bool) =
     | Tnot _ | Tbinop _ ->
         t_map abstract t
     | _ ->
-        let (ls, tabs) = try Hterm_alpha.find term_table t with Not_found ->
+        let (ls, tabs) = try Hterm.find term_table t with Not_found ->
           let ls = create_lsymbol (id_fresh "abstr") [] t.t_ty in
           let tabs = t_app ls [] t.t_ty in
-          Hterm_alpha.add term_table t (ls, tabs);
+          Hterm.add term_table t (ls, tabs);
           ls, tabs in
         extra_decls := ls :: !extra_decls;
         tabs in
diff --git a/src/transform/close_epsilon.ml b/src/transform/close_epsilon.ml
index 23bdeea88cf8f0d1737a0b948c35ea6e07a0e004..f867149c33754bc617883af808acbf000f864870 100644
--- a/src/transform/close_epsilon.ml
+++ b/src/transform/close_epsilon.ml
@@ -46,7 +46,7 @@ let is_lambda t = destruct_lambda t <> LNone
 let rec rewriteT t =
   match t.t_node with
   | Teps fb when is_lambda t ->
-      let fv = Mvs.keys t.t_vars in
+      let fv = Mvs.keys (t_vars t) in
       let x, f = t_open_bound fb in
       let f = rewriteF f in
       if fv = [] then t_eps_close x f
diff --git a/src/transform/discriminate.ml b/src/transform/discriminate.ml
index 4f830e06a076ea1fff9a518ca0b19c8f924fdc5e..9d8e53fb9a36a27ca811f6480d778ec57182b318 100644
--- a/src/transform/discriminate.ml
+++ b/src/transform/discriminate.ml
@@ -73,6 +73,17 @@ module Lsmap = struct
    instantié. Un tag sur un logique polymorphe doit être un tag sur toute
    la famille de fonctions *)
 
+  let ls_inst = Wls.memoize 3 (fun ls ->
+    let m = ref Mtyl.empty in
+    fun tyl tyv ->
+      let l = oty_cons tyl tyv in
+      match Mtyl.find_opt l !m with
+      | Some ls -> ls
+      | None    ->
+          let nls = create_lsymbol (id_clone ls.ls_name) tyl tyv in
+          m := Mtyl.add l nls !m;
+          nls)
+
   type t = lsymbol Mtyl.t Mls.t
 
   let empty = Mls.empty
@@ -81,9 +92,8 @@ module Lsmap = struct
     if ls_equal ls ps_equ then lsmap else
     if not (List.for_all Ty.ty_closed (oty_cons tyl tyv)) then lsmap else
     let newls = function
-      | None -> Some (create_lsymbol (id_clone ls.ls_name) tyl tyv)
-      | nls  -> nls
-    in
+      | None -> Some (ls_inst ls tyl tyv)
+      | nls  -> nls in
     let insts = Mls.find_def Mtyl.empty ls lsmap in
     Mls.add ls (Mtyl.change newls (oty_cons tyl tyv) insts) lsmap
 
@@ -295,3 +305,22 @@ let discriminate env = Trans.seq [
 let () = Trans.register_env_transform "discriminate" discriminate
   ~desc:"Generate@ monomorphic@ type@ instances@ of@ function@ and@ \
          predicate@ symbols@ and@ monomorphize@ task@ premises."
+
+let on_lsinst fn =
+  let add_ls acc = function
+    | [MAls ls; MAls nls] -> Mls.add nls ls acc
+    | _ -> assert false in
+  Trans.on_meta meta_lsinst (fun dls ->
+    fn (List.fold_left add_ls Mls.empty dls))
+
+let on_syntax_map fn =
+  let add_ls sm0 sm = function
+    | [MAls ls; MAls nls] ->
+        begin match Mid.find_opt ls.ls_name sm0 with
+          | Some s -> Mid.add nls.ls_name s sm
+          | None -> sm
+        end
+    | _ -> assert false in
+  Printer.on_syntax_map (fun sm0 ->
+  Trans.on_meta meta_lsinst (fun dls ->
+    fn (List.fold_left (fun sm dl -> add_ls sm0 sm dl) sm0 dls)))
diff --git a/src/transform/discriminate.mli b/src/transform/discriminate.mli
index 13f96c4cca885763d99092ee3c8ae20302b71398..3a24f273c0cb3848b32e07c1c84991ec6543eaaa 100644
--- a/src/transform/discriminate.mli
+++ b/src/transform/discriminate.mli
@@ -22,3 +22,6 @@ end
 val ft_select_inst   : (Env.env,Ty.Sty.t) Trans.flag_trans
 val ft_select_lskept : (Env.env,Term.Sls.t) Trans.flag_trans
 val ft_select_lsinst : (Env.env,Lsmap.t) Trans.flag_trans
+
+val on_lsinst : (Term.lsymbol Term.Mls.t -> 'a Trans.trans) -> 'a Trans.trans
+val on_syntax_map : (Printer.syntax_map -> 'a Trans.trans) -> 'a Trans.trans
diff --git a/src/transform/eliminate_algebraic.ml b/src/transform/eliminate_algebraic.ml
index e57f3cfb3c33e861db2d13a0ff3c96484997f287..df47371a1a9f08d640bc384fe9158cb4877bc643 100644
--- a/src/transform/eliminate_algebraic.ml
+++ b/src/transform/eliminate_algebraic.ml
@@ -132,7 +132,7 @@ let rec rewriteT kn state t = match t.t_node with
 and rewriteF kn state av sign f = match f.t_node with
   | Tcase (t1,bl) ->
       let t1 = rewriteT kn state t1 in
-      let av' = Mvs.set_diff av t1.t_vars in
+      let av' = Mvs.set_diff av (t_vars t1) in
       let mk_br (w,m) br =
         let (p,e) = t_open_branch br in
         let e = rewriteF kn state av' sign e in
@@ -182,7 +182,7 @@ and rewriteF kn state av sign f = match f.t_node with
       TermTF.t_map_sign (Util.const (rewriteT kn state))
         (rewriteF kn state av) sign f
   | Tlet (t1, _) ->
-      let av = Mvs.set_diff av t1.t_vars in
+      let av = Mvs.set_diff av (t_vars t1) in
       TermTF.t_map_sign (Util.const (rewriteT kn state))
         (rewriteF kn state av) sign f
   | _ ->
diff --git a/src/transform/encoding_twin.ml b/src/transform/encoding_twin.ml
index 29982ad07043b2988b8b71518bbe5e939fd15c6b..c70f7669709d38b404f44aa3dad3b5b21f7ffc3e 100644
--- a/src/transform/encoding_twin.ml
+++ b/src/transform/encoding_twin.ml
@@ -15,7 +15,7 @@ open Ty
 open Term
 open Decl
 
-let make_pont ty () =
+let make_pont = Wty.memoize 3 (fun ty ->
   let t2tb =
     let t2tb_name = "t2tb" in
     let t2tb_id = Libencoding.id_unprotected t2tb_name in
@@ -44,7 +44,7 @@ let make_pont ty () =
     let ax = t_forall_close [x_vs] [[t2tb_tb2t_x]] eq in
     let pr = create_prsymbol (id_fresh "BridgeR") in
     create_prop_decl Paxiom pr ax in
-  t2tb, tb2t, [t2tb_def; tb2t_def; bridge_l; bridge_r]
+  t2tb, tb2t, [t2tb_def; tb2t_def; bridge_l; bridge_r])
 
 let seen = Hty.create 7
 
@@ -109,6 +109,6 @@ let decl tenv d =
   add_decls tenv decls
 
 let t = Trans.on_tagged_ty Libencoding.meta_kept (fun s ->
-  Trans.decl (decl (Mty.mapi make_pont s)) None)
+  Trans.decl (decl (Mty.mapi (fun ty () -> make_pont ty) s)) None)
 
 let () = Hstr.replace Encoding.ft_enco_kept "twin" (Util.const t)
diff --git a/src/transform/inlining.ml b/src/transform/inlining.ml
index 5abaec02b87d5c1c6d379fb18e1c33a12b237902..6675015e9bab43f947437c4159b8e7eddb1d28f1 100644
--- a/src/transform/inlining.ml
+++ b/src/transform/inlining.ml
@@ -102,7 +102,7 @@ let trivial tl =
   let add vs t = match t.t_node with
     | Tvar v when Mvs.mem v vs -> raise Util.FoldSkip
     | Tvar v -> Svs.add v vs
-    | _ when Mvs.is_empty t.t_vars -> vs
+    | _ when t_closed t -> vs
     | _ -> raise Util.FoldSkip
   in
   try ignore (List.fold_left add Svs.empty tl); true
diff --git a/src/transform/libencoding.ml b/src/transform/libencoding.ml
index 9f26957ee9ba25f718c375cec92edf6162e0f21a..bb4038641e6928830a772ea5abe1b065e51b36e4 100644
--- a/src/transform/libencoding.ml
+++ b/src/transform/libencoding.ml
@@ -118,9 +118,8 @@ let t_monomorph ty_base kept lsmap consts vmap t =
   let rec t_mono vmap t = t_label_copy t (match t.t_node with
     | Tvar v ->
         Mvs.find v vmap
-    | Tconst _ when ty_equal (t_type t) ty_base ->
-        t
-    | Tconst _ when Sty.mem (t_type t) kept ->
+    | Tconst _ when ty_equal (t_type t) ty_base ||
+                    Sty.mem  (t_type t) kept ->
         t
     | Tconst _ ->
         let ls = ls_of_const ty_base t in
@@ -221,11 +220,14 @@ let monomorphise_task =
     Trans.decl decl (Task.add_decl None d_ts_base)))
 
 (* replace type variables in a goal with fresh type constants *)
+let ts_of_tv = Htv.memo 63 (fun tv ->
+  create_tysymbol (id_clone tv.tv_name) [] None)
+
 let monomorphise_goal = Trans.goal (fun pr f ->
   let stv = t_ty_freevars Stv.empty f in
   if Stv.is_empty stv then [create_prop_decl Pgoal pr f] else
   let mty,ltv = Stv.fold (fun tv (mty,ltv) ->
-    let ts = create_tysymbol (id_clone tv.tv_name) [] None in
+    let ts = ts_of_tv tv in
     Mtv.add tv (ty_app ts []) mty, ts::ltv) stv (Mtv.empty,[]) in
   let f = t_ty_subst mty Mvs.empty f in
   List.fold_left
diff --git a/src/transform/lift_epsilon.ml b/src/transform/lift_epsilon.ml
index feb5d84a4d960fc00d21c309ef7060ed5f345a6e..5da95575019d03d9258ecf69ed07c68762c4c77c 100644
--- a/src/transform/lift_epsilon.ml
+++ b/src/transform/lift_epsilon.ml
@@ -23,7 +23,7 @@ let lift kind =
   let rec term acc t =
     match t.t_node with
     | Teps fb ->
-        let fv = Mvs.keys t.t_vars in
+        let fv = Mvs.keys (t_vars t) in
         let x, f = t_open_bound fb in
         let acc, f = form acc f in
         let tys = List.map (fun x -> x.vs_ty) fv in
diff --git a/src/transform/simplify_array.ml b/src/transform/simplify_array.ml
index 0827739113903d81a3fc538e54a1ae4489e00605..6e586d668136462570fadc994c1429d102d16e75 100644
--- a/src/transform/simplify_array.ml
+++ b/src/transform/simplify_array.ml
@@ -33,7 +33,7 @@ let make_rt_rf env =
       | Tapp (lselect,[{t_node=Tapp(lstore,[_;a1;b])};a2])
           when lselect.ls_name == select &&
             lstore.ls_name == store &&
-            t_equal_alpha a1 a2 -> b
+            t_equal a1 a2 -> b
       | _ -> t
   and rf f = TermTF.t_map rt rf f  in
   rt,rf
diff --git a/src/transform/simplify_formula.ml b/src/transform/simplify_formula.ml
index db5161e2dff2cb8f20107d997a9b63e582d43566..6d8ac34117dbf777700dffa5ebe25a96dd58553a 100644
--- a/src/transform/simplify_formula.ml
+++ b/src/transform/simplify_formula.ml
@@ -201,7 +201,7 @@ let fmla_cond_subst filter f =
             for j = 0 to subl - 1 do
               if j <> i then
                 let (f, s) = subf.(j) in
-                subf.(j) <- (t_replace_alpha t1 t2 f, s);
+                subf.(j) <- (t_replace t1 t2 f, s);
             done in
           let (f, s) = subf.(i) in
           match f.t_node with
diff --git a/src/whyml/mlw_decl.ml b/src/whyml/mlw_decl.ml
index 956c1bb5af99c54a6b43bd8d2ead3cbc2e9d6ca4..18005c6900d86e9b60f7e6174681556ec20a9490 100644
--- a/src/whyml/mlw_decl.ml
+++ b/src/whyml/mlw_decl.ml
@@ -131,7 +131,7 @@ let create_data_decl tdl =
 
 let add_invariant pd its p =
   if not its.its_inv then invalid_arg "Mlw_decl.add_invariant";
-  Mvs.iter (fun vs _ -> raise (Decl.UnboundVar vs)) p.t_vars;
+  t_v_fold (fun _ vs -> raise (Decl.UnboundVar vs)) () p;
   let rec add = function
     | (s, cls, inv) :: tdl when its_equal s its ->
         check_post (t_type inv) p;
diff --git a/src/whyml/mlw_expr.ml b/src/whyml/mlw_expr.ml
index 47955e989f106d5eac7a0711d85df5810f7036f1..d1407701229e557a9e80dd4b0551f6ac4ddcb61b 100644
--- a/src/whyml/mlw_expr.ml
+++ b/src/whyml/mlw_expr.ml
@@ -1006,10 +1006,10 @@ let spec_purify sp =
   let vs, f = Mlw_ty.open_post sp.c_post in
   match f.t_node with
   | Tapp (ps, [{t_node = Tvar us}; t])
-    when ls_equal ps ps_equ && vs_equal vs us && not (Mvs.mem vs t.t_vars) ->
+    when ls_equal ps ps_equ && vs_equal vs us && t_v_occurs vs t = 0 ->
       t
   | Tbinop (Tiff, {t_node = Tapp (ps,[{t_node = Tvar us};{t_node = Ttrue}])},f)
-    when ls_equal ps ps_equ && vs_equal vs us && not (Mvs.mem vs f.t_vars) ->
+    when ls_equal ps ps_equ && vs_equal vs us && t_v_occurs vs f = 0 ->
       t_if f t_bool_true t_bool_false
   | _ -> raise Exit
 
diff --git a/src/whyml/mlw_interp.ml b/src/whyml/mlw_interp.ml
index cf841d4d73d26381f7d04b7fdc8da85038fba211..46d330e4716ce693616f0e402db2b28369493261 100644
--- a/src/whyml/mlw_interp.ml
+++ b/src/whyml/mlw_interp.ml
@@ -162,7 +162,7 @@ let eval_int_rel op _ty ls l =
   | _ -> assert false
 
 let term_equality t1 t2 =
-  if t_equal_alpha t1 t2 then Some true
+  if t_equal t1 t2 then Some true
   else
     try
       let i1 = big_int_of_term t1 in
diff --git a/src/whyml/mlw_ty.ml b/src/whyml/mlw_ty.ml
index d22a943f54a49fbdd1b6bc659e791ca8a1a7e6b7..e3038aa8abf608d6c10a1a085b02c96668bf72af 100644
--- a/src/whyml/mlw_ty.ml
+++ b/src/whyml/mlw_ty.ml
@@ -800,8 +800,8 @@ let spec_subst sbs c =
   }
 
 let spec_vsset c =
-  let add f s = Mvs.set_union f.t_vars s in
-  let s = add c.c_pre c.c_post.t_vars in
+  let add f s = Mvs.set_union (t_vars f) s in
+  let s = add c.c_pre (t_vars c.c_post) in
   let s = Mexn.fold (fun _ f s -> add f s) c.c_xpost s in
   List.fold_left (fun s (t,_) -> add t s) s c.c_variant
 
@@ -872,7 +872,7 @@ let create_pvsymbol, restore_pv =
 let pvs_of_vss pvs vss =
   Mvs.fold (fun vs _ s -> Spv.add (restore_pv vs) s) vss pvs
 
-let t_pvset pvs t = pvs_of_vss pvs t.t_vars
+let t_pvset pvs t = pvs_of_vss pvs (t_vars t)
 
 let spec_pvset pvs spec = pvs_of_vss pvs (spec_vsset spec)
 
diff --git a/src/whyml/mlw_typing.ml b/src/whyml/mlw_typing.ml
index 8a4b27d981d74d3c2010cda1d520268fb0c101ac..810cb5db4240cbebbf819044f39243a4534ed4b0 100644
--- a/src/whyml/mlw_typing.ml
+++ b/src/whyml/mlw_typing.ml
@@ -76,9 +76,10 @@ let ts_tuple n = Hint.replace ht_tuple n (); ts_tuple n
 let fs_tuple n = Hint.replace ht_tuple n (); fs_tuple n
 
 let check_at f0 =
+  let fvs0 = t_vars f0 in
   let rec check f = match f.t_node with
     | Term.Tapp (ls, _) when ls_equal ls fs_at ->
-        let d = Mvs.set_diff f.t_vars f0.t_vars in
+        let d = Mvs.set_diff (t_vars f) fvs0 in
         if not (Mvs.is_empty d) then errorm ?loc:f.t_loc
           "locally bound variable %a under `at'"
           Pretty.print_vs (fst (Mvs.choose d))
@@ -786,7 +787,7 @@ let rec check_reset rvs t = match t.t_node with
         under `old' in the postcondition" vs.vs_name.id_string
   | Tapp (ls,_) when ls_equal ls fs_at -> false
   | Tlet _ | Tcase _ | Teps _ | Tquant _ ->
-      let rvs = Mvs.set_inter rvs t.t_vars in
+      let rvs = Mvs.set_inter rvs (t_vars t) in
       if Mvs.is_empty rvs then false else
       t_any (check_reset rvs) t
   | _ ->
@@ -1117,7 +1118,7 @@ let rec type_c lenv pvs vars otv (dtyv, dsp) =
      ignored outside of "let rec" definitions, so WP are not affected. *)
   let del_pv pv s = Svs.remove pv.pv_vs s in
   let esvs = Spv.fold del_pv pvs esvs in
-  let drop _ t s = Mvs.set_diff s t.t_vars in
+  let drop _ t s = Mvs.set_diff s (t_vars t) in
   let esvs = drop () spec.c_pre esvs in
   let esvs = drop () spec.c_post esvs in
   let esvs = Mexn.fold drop spec.c_xpost esvs in
diff --git a/src/whyml/mlw_wp.ml b/src/whyml/mlw_wp.ml
index 5f0c3a232b100db00971f4eacb137ca9f2f6eb1d..78a3bae263c9128f6db1a6bcad3f17c05cc8bec2 100644
--- a/src/whyml/mlw_wp.ml
+++ b/src/whyml/mlw_wp.ml
@@ -152,7 +152,7 @@ let wp_forall vl f = t_forall_close_simp vl [] f
 
 let is_equality_for v f = match f.t_node with
   | Tapp (ps, [{ t_node = Tvar u }; t])
-    when ls_equal ps ps_equ && vs_equal u v && not (Mvs.mem v t.t_vars) ->
+    when ls_equal ps ps_equ && vs_equal u v && t_v_occurs v t = 0 ->
       Some t
   | _ ->
       None
@@ -294,7 +294,7 @@ let rec subst_at_now now mvs t = match t.t_node with
       t_map (subst_at_now now mvs) t
   | Tlet _ | Tcase _ | Teps _ | Tquant _ ->
       (* do not open unless necessary *)
-      let mvs = Mvs.set_inter mvs t.t_vars in
+      let mvs = Mvs.set_inter mvs (t_vars t) in
       if Mvs.is_empty mvs then t else
       t_map (subst_at_now now mvs) t
   | _ ->
@@ -330,7 +330,7 @@ let update_term env (mreg : vsymbol Mreg.t) f =
   let update vs _ = match update_var env mreg vs with
     | { t_node = Tvar nv } when vs_equal vs nv -> None
     | t -> Some t in
-  let vars = Mvs.mapi_filter update f.t_vars in
+  let vars = Mvs.mapi_filter update (t_vars f) in
   (* [vv'] : modified variable -> fresh variable *)
   let new_var vs _ = mk_var vs.vs_name model2_lab vs.vs_ty in
   let vv' = Mvs.mapi new_var vars in
@@ -345,11 +345,11 @@ let get_single_region_of_var vs =
 
 (* look for a variable with a single region equal to [reg] *)
 let var_of_region reg f =
-  let test vs _ acc =
+  let test acc vs =
     match get_single_region_of_var vs with
     | Some r when reg_equal r reg -> Some vs
     | _ -> acc in
-  Mvs.fold test f.t_vars None
+  t_v_fold test None f
 
 let quantify env regs f =
   (* mreg : modified region -> vs *)
@@ -980,7 +980,7 @@ let wp_let env km th { let_sym = lv; let_expr = e } =
   let env = mk_env env km th in
   let q, xq = default_post e.e_vty e.e_effect in
   let f = wp_expr env e q xq in
-  let f = wp_forall (Mvs.keys f.t_vars) f in
+  let f = wp_forall (Mvs.keys (t_vars f)) f in
   let id = match lv with
     | LetV pv -> pv.pv_vs.vs_name
     | LetA ps -> ps.ps_name in
@@ -992,7 +992,7 @@ let wp_rec env km th fdl =
   let add_one th d f =
     Debug.dprintf debug "wp %s = %a@\n----------------@."
       d.fun_ps.ps_name.id_string Pretty.print_term f;
-    let f = wp_forall (Mvs.keys f.t_vars) f in
+    let f = wp_forall (Mvs.keys (t_vars f)) f in
     add_wp_decl km d.fun_ps.ps_name f th
   in
   List.fold_left2 add_one th fdl fl
@@ -1213,7 +1213,7 @@ end = struct
         t_map (term subst) subterm
     | Tlet _ | Tcase _ | Teps _ | Tquant _ ->
         (* do not open unless necessary *)
-        let mvs = Mvs.set_inter s.now.subst_vars t.t_vars in
+        let mvs = Mvs.set_inter s.now.subst_vars (t_vars t) in
         if Mvs.is_empty mvs then t else
         t_map (term s) t
     | _ ->
@@ -1881,8 +1881,8 @@ and fast_wp_fun_defn env { fun_lambda = l } =
   let args = List.map (fun pv -> pv.pv_vs) l.l_args in
   let build_set svs =
     Mvs.fold (fun x _ acc -> Spv.add (restore_pv x) acc) svs Spv.empty in
-  let pre_vars = build_set c.c_pre.t_vars in
-  let post_vars = build_set c.c_post.t_vars in
+  let pre_vars = build_set (t_vars c.c_pre) in
+  let post_vars = build_set (t_vars c.c_post) in
   let all_vars = Spv.union l.l_expr.e_syms.syms_pv pre_vars in
   let all_vars = Spv.union all_vars post_vars in
   let prestate = Subst.init all_vars in
@@ -1914,7 +1914,7 @@ and fast_wp_fun_defn env { fun_lambda = l } =
      t_and_simp res.ok
      (wp_nimplies res.post.ne res.exn ((result, q.ne), xq)) in
   let f = wp_implies pre f in
-  let f = wp_forall args (t_forall_close (Mvs.keys f.t_vars) [] f) in
+  let f = wp_forall args (t_forall_close (Mvs.keys (t_vars f)) [] f) in
   f
 
 and fast_wp_rec_defn env fdl = List.map (fast_wp_fun_defn env) fdl
@@ -1923,7 +1923,7 @@ let fast_wp_let env km th { let_sym = lv; let_expr = e } =
   let env = mk_env env km th in
   let res =
     fast_wp_expr env (Subst.init e.e_syms.syms_pv) (result e) e in
-  let f = wp_forall (Mvs.keys res.ok.t_vars) res.ok in
+  let f = wp_forall (Mvs.keys (t_vars res.ok)) res.ok in
   let id = match lv with
     | LetV pv -> pv.pv_vs.vs_name
     | LetA ps -> ps.ps_name in
@@ -1935,7 +1935,7 @@ let fast_wp_rec env km th fdl =
   let add_one th d f =
     Debug.dprintf debug "wp %s = %a@\n----------------@."
       d.fun_ps.ps_name.id_string Pretty.print_term f;
-    let f = wp_forall (Mvs.keys f.t_vars) f in
+    let f = wp_forall (Mvs.keys (t_vars f)) f in
     add_wp_decl km d.fun_ps.ps_name f th
   in
   List.fold_left2 add_one th fdl fl
@@ -1973,7 +1973,7 @@ let wp_rec ~wp env kn th fdl =
       let f = wp_expr env e_void q Mexn.empty in
       let f = wp_implies spec.c_pre (erase_mark lab f) in
       let f = wp_forall args (quantify env (wp_fun_regs ps l) f) in
-      let f = t_forall_close (Mvs.keys f.t_vars) [] f in
+      let f = t_forall_close (Mvs.keys (t_vars f)) [] f in
       let lkn = Theory.get_known th in
       let f = if Debug.test_flag no_track then f else track_values lkn kn f in
       (*let f = if Debug.test_flag no_eval then f else