diff --git a/Makefile b/Makefile
index 78d9c93da1e1070f1357dbf07f5ca228338a37a0..309ee6e85998f690935644df6aeec0c4750b78fe 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,8 @@
 ##########################################################################
 
 all:
-	dune build --root=$$(pwd) @install colibri2.opam colibrics.opam colibrilib.opam
+	dune build --root=$$(pwd) @install colibri2.opam colibrics.opam colibrilib.opam \
+	src_colibri2/bin/colibri2_stage0.exe
 
 test:
 	dune runtest --root=$$(pwd)
diff --git a/src_colibri2/core/colibri2_core.mli b/src_colibri2/core/colibri2_core.mli
index e95a01dfd0ea327835ef9975289d88e04e574a23..fcfdad959bfb868558d72c63831d7bfb7632dd45 100644
--- a/src_colibri2/core/colibri2_core.mli
+++ b/src_colibri2/core/colibri2_core.mli
@@ -128,6 +128,7 @@ and Ground : sig
 
     val empty : t
     val distinct_union : t -> t -> t
+    val map_repr : _ Egraph.t -> t -> t
   end
 
   and Ty : sig
@@ -219,6 +220,18 @@ and Ground : sig
       Dolmen_std.Expr.term_var list ->
       Expr.term ->
       unit
+    (** [add d sym tys vars def] add the definition [def] for the symbol [sym] *)
+
+    val add_handler :
+      Egraph.wt ->
+      (Egraph.wt ->
+      Dolmen_std.Expr.Term.Const.t ->
+      Dolmen_std.Expr.Ty.Var.t list ->
+      Dolmen_std.Expr.Term.Var.t list ->
+      Expr.Term.t ->
+      unit) ->
+      unit
+    (** Called every time a definition is registered *)
   end
 
   module ClosedQuantifier : sig
@@ -288,6 +301,37 @@ and Ground : sig
     (** Return the user type. Raise if the ThTerm does not belong to this
         module *)
   end
+
+  val convert_one_app :
+    Subst.t ->
+    'a Egraph.t ->
+    Expr.term ->
+    Expr.ty list ->
+    Node.t Colibri2_popop_lib.IArray.t ->
+    Expr.ty ->
+    Node.t
+
+  val convert_one_cst :
+    Subst.t -> 'a Egraph.t -> Dolmen_std.Expr.term_cst -> Node.t
+
+  val convert_one_binder :
+    Subst.t -> 'a Egraph.t -> Expr.binder -> Expr.term -> Expr.ty -> Node.t
+
+  val convert_let_seq :
+    Subst.t ->
+    'a ->
+    (Dolmen_std.Expr.term_var * Expr.term) list ->
+    Expr.term ->
+    ('a -> Subst.t -> Expr.term -> Node.t) ->
+    Node.t
+
+  val convert_let_par :
+    Subst.t ->
+    'a ->
+    (Dolmen_std.Expr.term_var * Expr.term) list ->
+    Expr.term ->
+    ('a -> Subst.t -> Expr.term -> Node.t) ->
+    Node.t
 end
 
 (** {3 Different Object } *)
@@ -664,6 +708,7 @@ module Datastructure : sig
     val find_opt : 'a t -> _ Egraph.t -> key -> 'a option
     val mem : 'a t -> _ Egraph.t -> key -> bool
     val change : ('a option -> 'a option) -> 'a t -> _ Egraph.t -> key -> unit
+    val iter : f:(key -> 'a -> unit) -> 'a t -> _ Egraph.t -> unit
   end
 
   module Hashtbl (S : Colibri2_popop_lib.Popop_stdlib.Datatype) :
@@ -709,6 +754,7 @@ module Datastructure : sig
     val push : 'a t -> _ Egraph.t -> 'a -> unit
     val iter : f:('a -> unit) -> 'a t -> _ Egraph.t -> unit
     val fold : f:('acc -> 'a -> 'acc) -> init:'acc -> 'a t -> _ Egraph.t -> 'acc
+    val exists : f:('a -> bool) -> 'a t -> _ Egraph.t -> bool
     val length : 'a t -> _ Egraph.t -> int
     val get : 'a t -> _ Egraph.t -> int -> 'a
   end
@@ -968,6 +1014,7 @@ module Monad : sig
 
   val getd : ?def:'a -> 'a Dom.Kind.t -> Node.t -> 'a option monad
   val setd : 'a Dom.Kind.t -> Node.t -> 'a option monad -> sequence
+  val exec : (Egraph.wt -> unit) -> bool option monad -> sequence
 
   val updd :
     (Egraph.wt -> Node.t -> 'a -> unit) -> Node.t -> 'a option monad -> sequence
diff --git a/src_colibri2/core/datastructure.ml b/src_colibri2/core/datastructure.ml
index 8065d2c294e9cd953d07e60a0c66f3c340fe562a..8a04788671e3cb2cb3343f43db05276794fc1919 100644
--- a/src_colibri2/core/datastructure.ml
+++ b/src_colibri2/core/datastructure.ml
@@ -30,6 +30,7 @@ module type Sig =  sig
   val find_opt: 'a t -> _ Egraph.t -> key -> 'a option
   val mem: 'a t -> _ Egraph.t -> key -> bool
   val change : ('a option -> 'a option) -> 'a t -> _ Egraph.t -> key -> unit
+  val iter :  f:(key -> 'a -> unit) -> 'a t -> _ Egraph.t -> unit
 end
 
 module Hashtbl(S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Sig with type key := S.t = struct
@@ -97,6 +98,10 @@ module Hashtbl(S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Sig with type key :
     in
     S.H.change change h k
 
+  let iter ~f t d =
+    let h = Egraph.get_unsaved_env d t in
+    S.H.iter (fun k v -> Option.iter (f k) (Context.Ref.get v)) h
+
 end
 
 module type Sig2 =  sig
@@ -228,6 +233,9 @@ module Push = struct
   let fold ~f ~init t d =
     Context.Push.fold f init (Egraph.get_unsaved_env d t)
 
+  let exists ~f t d =
+    Context.Push.exists f (Egraph.get_unsaved_env d t)
+
   let length t d = Context.Push.length (Egraph.get_unsaved_env d t)
   let get t d i = Context.Push.get (Egraph.get_unsaved_env d t) i
 
@@ -251,3 +259,51 @@ module Ref = struct
   let get t d = Context.Ref.get (Egraph.get_unsaved_env d t)
   let set t d v = Context.Ref.set (Egraph.get_unsaved_env d t) v
 end
+
+module type Trie = sig
+  type 'a t
+  type key
+
+  val create: 'a Format.printer -> string -> 'a t
+
+  module List : sig
+    val set : 'a t ->  _ Egraph.t ->key list -> 'a -> unit
+    val find_def : default:(Context.creator -> 'a) -> 'a t ->  _ Egraph.t ->key list -> 'a
+  end
+
+  module Set : sig
+    type set
+
+    val set : 'a t -> _ Egraph.t -> set -> 'a -> unit
+    val find_def : default:(Context.creator -> 'a) -> 'a t -> _ Egraph.t -> set -> 'a
+  end
+end
+
+module Trie (S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Trie
+  with type key := S.t and type Set.set := S.S.t = struct
+
+  module Trie = Context.Trie(S)
+
+  type 'a t = 'a Trie.t Env.Unsaved.t
+
+  let create : type a. a Colibri2_popop_lib.Pp.pp -> _ -> a t = fun pp name ->
+    let module M = struct
+      type t = a Trie.t
+      let name = name end
+    in
+    let key = Env.Unsaved.create (module M) in
+    let init d = Trie.create d in
+    let pp = Trie.pp pp in
+    Env.Unsaved.register ~init ~pp key;
+    key
+
+  module List = struct
+    let set t d l v = Trie.List.set (Egraph.get_unsaved_env d t) l v
+    let find_def ~default t d l = Trie.List.find_def ~default (Egraph.get_unsaved_env d t) l
+  end
+
+  module Set = struct
+    let set t d l v = Trie.Set.set (Egraph.get_unsaved_env d t) l v
+    let find_def ~default t d l = Trie.Set.find_def ~default (Egraph.get_unsaved_env d t) l
+  end
+end
diff --git a/src_colibri2/core/datastructure.mli b/src_colibri2/core/datastructure.mli
index c411f6f263cedff8405cd848f2a90c55049dfe8c..b403340f72a91dc91d6ef283397f629924d589e6 100644
--- a/src_colibri2/core/datastructure.mli
+++ b/src_colibri2/core/datastructure.mli
@@ -32,6 +32,7 @@ module type Sig =  sig
   val find_opt: 'a t -> _ Egraph.t -> key -> 'a option
   val mem: 'a t -> _ Egraph.t -> key -> bool
   val change : ('a option -> 'a option) -> 'a t -> _ Egraph.t -> key -> unit
+  val iter :  f:(key -> 'a -> unit) -> 'a t -> _ Egraph.t -> unit
 end
 
 module Hashtbl (S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Sig with type key := S.t
@@ -76,6 +77,7 @@ module Push: sig
   val push: 'a t -> _ Egraph.t -> 'a -> unit
   val iter: f:('a -> unit) -> 'a t -> _ Egraph.t -> unit
   val fold: f:('acc -> 'a -> 'acc) ->  init:'acc -> 'a t -> _ Egraph.t -> 'acc
+  val exists : f:('a -> bool) -> 'a t -> _ Egraph.t -> bool
   val length: 'a t -> _ Egraph.t -> int
   val get: 'a t -> _ Egraph.t -> int -> 'a
 
@@ -87,3 +89,25 @@ module Ref: sig
   val get: 'a t -> _ Egraph.t -> 'a
   val set: 'a t -> _ Egraph.t -> 'a -> unit
 end
+
+module type Trie = sig
+  type 'a t
+  type key
+
+  val create: 'a Format.printer -> string -> 'a t
+
+  module List : sig
+    val set : 'a t ->  _ Egraph.t ->key list -> 'a -> unit
+    val find_def : default:(Context.creator -> 'a) -> 'a t ->  _ Egraph.t ->key list -> 'a
+  end
+
+  module Set : sig
+    type set
+
+    val set : 'a t -> _ Egraph.t -> set -> 'a -> unit
+    val find_def : default:(Context.creator -> 'a) -> 'a t -> _ Egraph.t -> set -> 'a
+  end
+end
+
+module Trie (S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Trie
+ with type key := S.t and type Set.set := S.S.t
diff --git a/src_colibri2/core/demon.ml b/src_colibri2/core/demon.ml
index a5d2d1e805f023e2d71e54a79664852d4ba3c144..e3154bfef07104c453b5abb1ed32d1aafa74854a 100644
--- a/src_colibri2/core/demon.ml
+++ b/src_colibri2/core/demon.ml
@@ -169,7 +169,7 @@ module Simple = struct
   end)
 
   module LastEffort = Make (struct
-    let name = "Demon.Simple.FixingModel"
+    let name = "Demon.Simple.LastEffort"
     let delay = Events.LastEffort 1
   end)
 
@@ -353,10 +353,12 @@ module Monad = struct
     | UpdD :
         Node.t * (Egraph.wt -> Node.t -> 'a -> unit) * 'a option monad
         -> sequence
+    | SExec : (Egraph.wt -> unit) * bool option monad -> sequence
 
   let getv m n = GetV (n, m)
   let setv m n f = SetV (n, m, f)
   let getd ?def m n = GetD (n, m, def)
+  let exec f m = SExec (f, m)
   let exec_ro f m = Exec (f, m)
   let setd m n f = SetD (n, m, f)
   let updd m n f = UpdD (n, m, f)
@@ -372,6 +374,7 @@ module Monad = struct
       | UpdD :
           Node.t * (Egraph.wt -> Node.t -> 'a -> unit) * 'a * runable
           -> runable
+      | SExec : (Egraph.wt -> unit) * runable -> runable
       | Nil : runable
 
     let print_runable = Fmt.nop
@@ -395,6 +398,9 @@ module Monad = struct
       | UpdD (n, upd, b, r) ->
           upd d n b;
           run d r
+      | SExec (g, r) ->
+          g d;
+          run d r
       | Nil -> ()
   end
 
@@ -432,6 +438,9 @@ module Monad = struct
     | UpdD (n, dom, f) -> (
         let v = compute d f in
         match v with None -> acc | Some v -> UpdD (n, dom, v, acc))
+    | SExec (g, f) -> (
+        let v = compute d f in
+        match v with None | Some false -> acc | Some true -> SExec (g, acc))
 
   type footprint = {
     doms : Node.S.t DomKind.Vector.t;
@@ -469,6 +478,7 @@ module Monad = struct
     | SetV (_, _, f) -> attach_aux compute d f
     | SetD (_, _, f) -> attach_aux compute d f
     | UpdD (_, _, f) -> attach_aux compute d f
+    | SExec (_, f) -> attach_aux compute d f
 
   let attach d ?thterm seq =
     let compute d =
diff --git a/src_colibri2/core/demon.mli b/src_colibri2/core/demon.mli
index 857579512325d6293a811f1ce3383ed7df3c57f3..2e9935e63da74d3d61f8196721492e3c36b2a00b 100644
--- a/src_colibri2/core/demon.mli
+++ b/src_colibri2/core/demon.mli
@@ -137,6 +137,7 @@ module Monad : sig
 
   val getd : ?def:'a -> 'a DomKind.t -> Node.t -> 'a option monad
   val setd : 'a DomKind.t -> Node.t -> 'a option monad -> sequence
+  val exec : (Egraph.wt -> unit) -> bool option monad -> sequence
 
   val updd :
     (Egraph.wt -> Node.t -> 'a -> unit) -> Node.t -> 'a option monad -> sequence
diff --git a/src_colibri2/core/egraph.ml b/src_colibri2/core/egraph.ml
index 0256693c365887386c726a87a249be31f620ae6d..f13c98f25959fb3df42c66462f2e32d4e5f3f2a0 100644
--- a/src_colibri2/core/egraph.ml
+++ b/src_colibri2/core/egraph.ml
@@ -34,8 +34,14 @@ let debug_few = Debug.register_info_flag
     ~desc:"for the core solver"
     "Egraph.few"
 
-let print_decision = Colibri2_stdlib.Debug.register_info_flag ~desc:"Print@ information@ about@ the@ decisions@ made" "decision"
-let print_contradiction = Colibri2_stdlib.Debug.register_info_flag ~desc:"Print@ information@ about@ the@ contradiction@ found" "contradiction"
+let print_decision =
+  Colibri2_stdlib.Debug.register_info_flag
+    ~desc:"Print@ information@ about@ the@ decisions@ made"
+    "decision"
+let print_contradiction =
+  Colibri2_stdlib.Debug.register_info_flag
+    ~desc:"Print@ information@ about@ the@ contradiction@ found"
+    "contradiction"
 
 let stats_set_dom =
   Debug.register_stats_int "Egraph.set_dom/merge"
diff --git a/src_colibri2/core/ground.ml b/src_colibri2/core/ground.ml
index 8ef12c068dbc8fafc412af139dbff9ab5665e9ce..a83c06bcc007894840f8b9f667dd419072ec117e 100644
--- a/src_colibri2/core/ground.ml
+++ b/src_colibri2/core/ground.ml
@@ -61,6 +61,9 @@ module Subst = struct
       term =
         Expr.Term.Var.M.union (fun _ _ -> assert false) subst1.term subst2.term;
     }
+
+  let map_repr d subst =
+    { subst with term = Expr.Term.Var.M.map (Egraph.find_def d) subst.term }
 end
 
 module Ty = struct
@@ -319,68 +322,60 @@ module NotTotallyApplied = struct
     RegisterThTerm (NotTotallyApplied0) : RegisteredThTerm with type s := s)
 end
 
-let rec convert_and_iter ?(subst = Subst.empty) fg fcq fnt (t : Expr.Term.t) =
-  match t.term_descr with
-  | Var v -> (
-      match Expr.Term.Var.M.find v subst.term with
-      | exception Not_found ->
-          invalid_arg (Fmt.str "Not_ground: %a" Expr.Term.Var.pp v)
-      | n -> n)
-  | App (f, tyargs, args) -> (
-      let ty = Ty.convert subst.ty t.term_ty in
-      match (ty.app.builtin, f.term_descr) with
-      | Ty.Arrow, _ | _, (Match _ | App _ | Var _ | Binder _) ->
-          let nt =
-            NotTotallyApplied.index
-            @@ App
-                 {
-                   app = convert_and_iter ~subst fg fcq fnt f;
-                   tyargs = List.map (Ty.convert subst.ty) tyargs;
-                   args =
-                     IArray.of_list_map
-                       ~f:(convert_and_iter ~subst fg fcq fnt)
-                       args;
-                   ty = Ty.convert subst.ty t.term_ty;
-                 }
-          in
-          fnt nt;
-          NotTotallyApplied.node nt
-      | _, Cst f ->
-          let g =
-            ThTerm.index
-            @@ {
-                 Term.app = f;
-                 tyargs = List.map (Ty.convert subst.ty) tyargs;
-                 args =
-                   IArray.of_list_map
-                     ~f:(convert_and_iter ~subst fg fcq fnt)
-                     args;
-                 ty = Ty.convert subst.ty t.term_ty;
-               }
-          in
-          fg g;
-          ThTerm.node g)
-  | Cst f ->
-      let ty_args, args, ty = Expr.Ty.poly_sig f.id_ty in
-      if List.is_empty args then (
-        assert (List.is_empty ty_args);
-        let g =
-          ThTerm.index
-          @@ {
-               Term.app = f;
-               tyargs = [];
-               args = IArray.empty;
-               ty = Ty.convert subst.ty ty;
+let rec convert_one_app_and_iter d (f : Expr.Term.t) tyargs args ty
+    (subst : Subst.t) fg fcq fnt =
+  let ty = Ty.convert subst.ty ty in
+  match (ty.app.builtin, f.term_descr) with
+  | Ty.Arrow, _ | _, (Match _ | App _ | Var _ | Binder _) ->
+      let nt =
+        NotTotallyApplied.index
+        @@ App
+             {
+               app = convert_and_iter fg fcq fnt d subst f;
+               tyargs = List.map (Ty.convert subst.ty) tyargs;
+               args;
+               ty;
              }
-        in
-        fg g;
-        ThTerm.node g)
-      else
-        let nt = NotTotallyApplied.index @@ Cst f in
-        fnt nt;
-        NotTotallyApplied.node nt
-  | Expr.Binder ((Exists (ty_vars, term_vars) as b), body)
-  | Expr.Binder ((Forall (ty_vars, term_vars) as b), body) ->
+      in
+      fnt d nt;
+      NotTotallyApplied.node nt
+  | _, Cst f ->
+      let g =
+        ThTerm.index
+        @@ {
+             Term.app = f;
+             tyargs = List.map (Ty.convert subst.ty) tyargs;
+             args;
+             ty;
+           }
+      in
+      fg d g;
+      ThTerm.node g
+
+and convert_one_cst_and_iter d (f : Expr.Term.Const.t) (subst : Subst.t) fg fnt
+    =
+  let ty_args, args, ty = Expr.Ty.poly_sig f.id_ty in
+  if List.is_empty args then (
+    assert (List.is_empty ty_args);
+    let g =
+      ThTerm.index
+      @@ {
+           Term.app = f;
+           tyargs = [];
+           args = IArray.empty;
+           ty = Ty.convert subst.ty ty;
+         }
+    in
+    fg d g;
+    ThTerm.node g)
+  else
+    let nt = NotTotallyApplied.index @@ Cst f in
+    fnt d nt;
+    NotTotallyApplied.node nt
+
+and convert_one_binder_and_iter d (b : Expr.binder) body ty subst fcq fnt =
+  match b with
+  | Exists (ty_vars, term_vars) | Forall (ty_vars, term_vars) ->
       let binder =
         match b with
         | Exists _ -> ClosedQuantifier0.Exists
@@ -390,56 +385,76 @@ let rec convert_and_iter ?(subst = Subst.empty) fg fcq fnt (t : Expr.Term.t) =
       let cq =
         ClosedQuantifier.index @@ { binder; ty_vars; term_vars; body; subst }
       in
-      fcq cq;
+      fcq d cq;
       ClosedQuantifier.node cq
-  | Expr.Binder (Lambda (ty_vars, term_vars), body) ->
+  | Lambda (ty_vars, term_vars) ->
       let nt =
         NotTotallyApplied.index
         @@ Lambda
-             {
-               ty_vars;
-               term_vars;
-               body;
-               subst;
-               ty = Ty.convert subst.ty t.term_ty;
-             }
+             { ty_vars; term_vars; body; subst; ty = Ty.convert subst.ty ty }
       in
-      fnt nt;
+      fnt d nt;
       NotTotallyApplied.node nt
-  | Expr.Binder (Let_seq l, body) ->
-      let subst_term =
-        List.fold_left
-          (fun term (v, t) ->
-            let n =
-              convert_and_iter ~subst:{ term; ty = subst.ty } fg fcq fnt t
-            in
-            Expr.Term.Var.M.add v n term)
-          subst.term l
+  | Let_seq _ | Let_par _ -> invalid_arg "convert_one_binder: let_* given"
+
+and convert_let_seq_and_iter d l body (subst : Subst.t) convert_and_iter =
+  let subst_term =
+    List.fold_left
+      (fun term (v, t) ->
+        let n = convert_and_iter d { Subst.term; ty = subst.ty } t in
+        Expr.Term.Var.M.add v n term)
+      subst.term l
+  in
+  convert_and_iter d { term = subst_term; ty = subst.ty } body
+
+and convert_let_par_and_iter d l body (subst : Subst.t) convert_and_iter =
+  let subst_term =
+    List.fold_left
+      (fun term (v, t) ->
+        let n = convert_and_iter d subst t in
+        Expr.Term.Var.M.add v n term)
+      subst.term l
+  in
+  convert_and_iter d { term = subst_term; ty = subst.ty } body
+
+and convert_and_iter fg fcq fnt d subst (t : Expr.Term.t) =
+  match t.term_descr with
+  | Var v -> (
+      match Expr.Term.Var.M.find v subst.term with
+      | exception Not_found ->
+          invalid_arg (Fmt.str "Not_ground: %a" Expr.Term.Var.pp v)
+      | n -> n)
+  | App (f, tyargs, args) ->
+      let args =
+        IArray.of_list_map ~f:(convert_and_iter fg fcq fnt d subst) args
       in
-      convert_and_iter
-        ~subst:{ term = subst_term; ty = subst.ty }
-        fg fcq fnt body
+      convert_one_app_and_iter d f tyargs args t.term_ty subst fg fcq fnt
+  | Cst f -> convert_one_cst_and_iter d f subst fg fnt
+  | Expr.Binder (((Exists _ | Forall _ | Lambda _) as b), body) ->
+      convert_one_binder_and_iter d b body t.term_ty subst fcq fnt
+  | Expr.Binder (Let_seq l, body) ->
+      convert_let_seq_and_iter d l body subst (convert_and_iter fg fcq fnt)
   | Expr.Binder (Let_par l, body) ->
-      let subst_term =
-        List.fold_left
-          (fun term (v, t) ->
-            let n = convert_and_iter ~subst fg fcq fnt t in
-            Expr.Term.Var.M.add v n term)
-          subst.term l
-      in
-      convert_and_iter
-        ~subst:{ term = subst_term; ty = subst.ty }
-        fg fcq fnt body
-  | Expr.Match (_, _) -> assert false
+      convert_let_par_and_iter d l body subst (convert_and_iter fg fcq fnt)
+  | Expr.Match (_, _) -> invalid_arg "match from dolmen not implemented"
 (* TODO convert to one multitest like
    the match of why3  and projection *)
 
-let convert ?subst d e =
-  convert_and_iter
-    (fun th -> Choice_group.make_choosable d (ThTerm.thterm th))
-    (fun th -> Choice_group.make_choosable d (ClosedQuantifier.thterm th))
-    (fun th -> Choice_group.make_choosable d (NotTotallyApplied.thterm th))
-    ?subst e
+let fg d th = Choice_group.make_choosable d (ThTerm.thterm th)
+let fcq d th = Choice_group.make_choosable d (ClosedQuantifier.thterm th)
+let fnt d th = Choice_group.make_choosable d (NotTotallyApplied.thterm th)
+let convert ?(subst = Subst.empty) d e = convert_and_iter fg fcq fnt d subst e
+
+let convert_one_app subst d a b c e =
+  convert_one_app_and_iter d a b c e subst fg fcq fnt
+
+let convert_one_cst subst d a = convert_one_cst_and_iter d a subst fg fnt
+
+let convert_one_binder subst d a b c =
+  convert_one_binder_and_iter d a b c subst fcq fnt
+
+let convert_let_seq subst d a b iter = convert_let_seq_and_iter d a b subst iter
+let convert_let_par subst d a b iter = convert_let_par_and_iter d a b subst iter
 
 let apply _ (f : Expr.Term.Const.t) tyargs args =
   let rec apply_ty subst tyargs (ty : Expr.Ty.t) =
@@ -469,9 +484,12 @@ module Defs = struct
 
   let pp_fundef _ _ = ()
   let fundefs = Expr.Term.Const.HC.create pp_fundef "SynTerm.fundefs"
+  let handler = Datastructure.Push.create Fmt.nop "Interp.check"
+  let add_handler d f = Datastructure.Push.push handler d f
 
   let add d tc tyl tvl body =
-    Expr.Term.Const.HC.set fundefs d tc { tyl; tvl; body }
+    Expr.Term.Const.HC.set fundefs d tc { tyl; tvl; body };
+    Datastructure.Push.iter handler d ~f:(fun f -> f d tc tyl tvl body)
 
   module ThTermH = Datastructure.Hashtbl (ThTerm)
 
@@ -509,8 +527,8 @@ module Defs = struct
               in
               let group = Choice_group.create d in
               let n =
-                convert_and_iter ~subst
-                  (fun th ->
+                convert_and_iter
+                  (fun d th ->
                     if level <= level_dec then
                       Choice_group.make_choosable d (ThTerm.thterm th)
                     else Choice_group.add_to_group d (ThTerm.thterm th) group;
@@ -521,14 +539,14 @@ module Defs = struct
                         | _ ->
                             if not (ThTermH.mem levels d th) then
                               ThTermH.set levels d th (1 + level)))
-                  (fun th ->
+                  (fun d th ->
                     if level <= level_dec then
                       Choice_group.make_choosable d (ClosedQuantifier.thterm th)
                     else
                       Choice_group.add_to_group d
                         (ClosedQuantifier.thterm th)
                         group)
-                  (fun th ->
+                  (fun d th ->
                     if level <= level_dec then
                       Choice_group.make_choosable d
                         (NotTotallyApplied.thterm th)
@@ -536,7 +554,7 @@ module Defs = struct
                       Choice_group.add_to_group d
                         (NotTotallyApplied.thterm th)
                         group)
-                  fundef.body
+                  d subst fundef.body
               in
               if level_dec < level && level <= level_dec_delayed then
                 Demon.Simple.LastEffort.schedule_immediately d (fun d ->
@@ -549,51 +567,59 @@ end
 let registered_converter = Datastructure.Push.create Fmt.nop "Ground.converters"
 let register_converter d f = Datastructure.Push.push registered_converter d f
 
-let dom_tys =
-  DomKind.create
-    (module struct
-      type nonrec t = Ty.S.t
-
-      let name = "Ground.tys"
-    end)
-
-let () =
-  Egraph.register_dom
-    (module struct
-      include Ty.S
-
-      let key = dom_tys
-      let merged tys0 tys1 = Option.equal equal tys0 tys1
-
-      let merge d (tys0, n0) (tys1, n1) _ =
-        let s =
-          Ty.S.union
-            (Base.Option.value ~default:Ty.S.empty tys0)
-            (Base.Option.value ~default:Ty.S.empty tys1)
-        in
-        Egraph.set_dom d key n0 s;
-        Egraph.set_dom d key n1 s
-    end)
-
-let tys d n = Base.Option.value ~default:Ty.S.empty (Egraph.get_dom d dom_tys n)
+module Tys : sig
+  val tys : _ Egraph.t -> Node.t -> Ty.S.t
+  val add_ty : Egraph.wt -> Node.t -> Ty.t -> unit
+end = struct
+  let dom_tys =
+    DomKind.create
+      (module struct
+        type nonrec t = Ty.S.t
+
+        let name = "Ground.tys"
+      end)
+
+  let () =
+    Egraph.register_dom
+      (module struct
+        include Ty.S
+
+        let key = dom_tys
+        let merged tys0 tys1 = Option.equal equal tys0 tys1
+
+        let merge d (tys0, n0) (tys1, n1) _ =
+          let s =
+            Ty.S.union
+              (Base.Option.value ~default:Ty.S.empty tys0)
+              (Base.Option.value ~default:Ty.S.empty tys1)
+          in
+          Egraph.set_dom d key n0 s;
+          Egraph.set_dom d key n1 s
+      end)
+
+  let tys d n =
+    Base.Option.value ~default:Ty.S.empty (Egraph.get_dom d dom_tys n)
+
+  let add_ty d n ty =
+    match Egraph.get_dom d dom_tys n with
+    | None -> Egraph.set_dom d dom_tys n (Ty.S.singleton ty)
+    | Some tys -> (
+        match Ty.S.add_new Exit ty tys with
+        | exception Exit -> ()
+        | tys -> Egraph.set_dom d dom_tys n tys)
+end
 
-let add_ty d n ty =
-  match Egraph.get_dom d dom_tys n with
-  | None -> Egraph.set_dom d dom_tys n (Ty.S.singleton ty)
-  | Some tys -> (
-      match Ty.S.add_new Exit ty tys with
-      | exception Exit -> ()
-      | tys -> Egraph.set_dom d dom_tys n tys)
+let tys = Tys.tys
 
 let init d =
   Demon.Simple.attach_reg_sem d ThTerm.key (fun d g ->
       let n = ThTerm.node g in
       let s = ThTerm.sem g in
-      add_ty d n s.ty;
+      Tys.add_ty d n s.ty;
       Defs.converter d g;
       Datastructure.Push.iter registered_converter d ~f:(fun f -> f d g));
   Demon.Simple.attach_reg_sem d ClosedQuantifier.key (fun d g ->
       let n = ClosedQuantifier.node g in
-      add_ty d n Ty.bool)
+      Tys.add_ty d n Ty.bool)
 
 include (ThTerm : RegisteredThTerm with type s := s and type t = ThTerm.t)
diff --git a/src_colibri2/core/ground.mli b/src_colibri2/core/ground.mli
index 3d8493ce3a8a105ab1c1cba65cf4356e44c00cfe..c331cda8a3d81f84bd78d25fc1aeab673565cf2a 100644
--- a/src_colibri2/core/ground.mli
+++ b/src_colibri2/core/ground.mli
@@ -40,6 +40,7 @@ module Subst : sig
 
   val empty : t
   val distinct_union : t -> t -> t
+  val map_repr : _ Egraph.t -> t -> t
 end
 
 module Ty : sig
@@ -114,12 +115,23 @@ val tys : _ Egraph.t -> Node.t -> Ty.S.t
 module Defs : sig
   val add :
     Egraph.wt ->
-    Dolmen_std.Expr.term_cst ->
-    Dolmen_std.Expr.ty_var list ->
-    Dolmen_std.Expr.term_var list ->
-    Expr.term ->
+    Dolmen_std.Expr.Term.Const.t ->
+    Dolmen_std.Expr.Ty.Var.t list ->
+    Dolmen_std.Expr.Term.Var.t list ->
+    Expr.Term.t ->
     unit
   (** [add d sym tys vars def] add the definition [def] for the symbol [sym] *)
+
+  val add_handler :
+    Egraph.wt ->
+    (Egraph.wt ->
+    Dolmen_std.Expr.Term.Const.t ->
+    Dolmen_std.Expr.Ty.Var.t list ->
+    Dolmen_std.Expr.Term.Var.t list ->
+    Expr.Term.t ->
+    unit) ->
+    unit
+  (** Called every time a definition is registered *)
 end
 
 module ClosedQuantifier : sig
@@ -157,10 +169,42 @@ module NotTotallyApplied : sig
 end
 
 val convert_and_iter :
-  ?subst:Subst.t ->
-  (t -> unit) ->
-  (ClosedQuantifier.t -> unit) ->
-  (NotTotallyApplied.t -> unit) ->
+  ('a -> t -> unit) ->
+  ('a -> ClosedQuantifier.t -> unit) ->
+  ('a -> NotTotallyApplied.t -> unit) ->
+  'a ->
+  Subst.t ->
   Expr.Term.t ->
   Node.t
 (** Iter on the new ground terms when converting, bottom_up *)
+
+val convert_one_app :
+  Subst.t ->
+  'a Egraph.t ->
+  Expr.term ->
+  Expr.ty list ->
+  Node.t IArray.t ->
+  Expr.ty ->
+  Node.t
+
+val convert_one_cst :
+  Subst.t -> 'a Egraph.t -> Dolmen_std.Expr.term_cst -> Node.t
+
+val convert_one_binder :
+  Subst.t -> 'a Egraph.t -> Expr.binder -> Expr.term -> Expr.ty -> Node.t
+
+val convert_let_seq :
+  Subst.t ->
+  'a ->
+  (Dolmen_std.Expr.term_var * Expr.term) list ->
+  Expr.term ->
+  ('a -> Subst.t -> Expr.term -> Node.t) ->
+  Node.t
+
+val convert_let_par :
+  Subst.t ->
+  'a ->
+  (Dolmen_std.Expr.term_var * Expr.term) list ->
+  Expr.term ->
+  ('a -> Subst.t -> Expr.term -> Node.t) ->
+  Node.t
diff --git a/src_colibri2/core/interp.ml b/src_colibri2/core/interp.ml
index a65a4a91bfaa2c72e69ddceebe140f060af7cacd..eb5db96ac1e8cff792125fe83589238151ded222 100644
--- a/src_colibri2/core/interp.ml
+++ b/src_colibri2/core/interp.ml
@@ -333,7 +333,7 @@ let check_not_totally_applied d =
 let interp d e =
   let n =
     Ground.convert_and_iter
-      (fun g ->
+      (fun d g ->
         check_args d g;
         let n = Ground.node g in
         Egraph.register d n;
@@ -346,7 +346,7 @@ let interp d e =
           Egraph.register d n;
           Egraph.set_value d n v;
           Egraph.flush_internal d))
-      (fun g ->
+      (fun d g ->
         let n = Ground.ClosedQuantifier.node g in
         Egraph.register d n;
         if Option.is_none (Egraph.get_value d n) then (
@@ -358,7 +358,7 @@ let interp d e =
           Egraph.register d n;
           Egraph.set_value d n v;
           Egraph.flush_internal d))
-      (fun g ->
+      (fun d g ->
         let n = Ground.NotTotallyApplied.node g in
         Egraph.register d n;
         if Option.is_none (Egraph.get_value d n) then (
@@ -370,7 +370,7 @@ let interp d e =
           Egraph.register d n;
           Egraph.set_value d n v;
           Egraph.flush_internal d))
-      e
+      d Ground.Subst.empty e
   in
   assert (Option.is_some (Egraph.get_value d n));
   Base.Option.value_exn (Egraph.get_value d n)
diff --git a/src_colibri2/core/structures/nodes.ml b/src_colibri2/core/structures/nodes.ml
index 477e0d0769439c1789d2a39a71ade0f54f01b2d6..7ce6396cd7439556ddc0cabb27c364f06d2d4b50 100644
--- a/src_colibri2/core/structures/nodes.ml
+++ b/src_colibri2/core/structures/nodes.ml
@@ -53,6 +53,8 @@ module Node = struct
   (** remove the empty string *)
   let () = DStr.H.add used_names "" 0
 
+  (* let () = DStr.H.add used_names "281" 0 *)
+
   let pp fmt x =
     Format.pp_print_char fmt '@';
     Format.pp_print_string fmt (Simple_vector.get names (tag x))
diff --git a/src_colibri2/solver/input.ml b/src_colibri2/solver/input.ml
index b0c90b1456b9053170963e6b4ffe598ea5148c91..00d373505afec9c396c0cdb01557a0ae565bf6fb 100644
--- a/src_colibri2/solver/input.ml
+++ b/src_colibri2/solver/input.ml
@@ -353,7 +353,10 @@ let handle_stmt ?(show_check_sat_result = true) ?(show_steps = false)
       match args with
       | [ { term = Symbol { name = Simple i; _ }; _ } ] -> (
           match int_of_string i with
-          | i -> Context.Ref.set st.solve_state.step_limit (Some i)
+          | i ->
+            (** only if there is already a step limit *)
+            if Option.is_some (Context.Ref.get st.solve_state.step_limit) then
+              Context.Ref.set st.solve_state.step_limit (Some i)
           | exception _ -> error st loc expected_integer_for_option ())
       | _ -> error st loc expected_integer_for_option ())
   | `Set_option _ -> ()
diff --git a/src_colibri2/solver/scheduler.ml b/src_colibri2/solver/scheduler.ml
index 5c27d24d584a81a03af71962a9abd586426a0c2e..6adbd53951cad76c09afdcdeafc6e32e933f571a 100644
--- a/src_colibri2/solver/scheduler.ml
+++ b/src_colibri2/solver/scheduler.ml
@@ -310,7 +310,7 @@ let push kind t =
 
 (** Go to and remove the backtrack point *)
 let pop_to t prev =
-  Debug.dprintf4 debug_pushpop "[Scheduler] pop from %a : %a" print_level t
+  Debug.dprintf4 debug_pushpop "[Scheduler] pop  from %a: %a" print_level t
     print_position_in_tree t;
   t.prev_scheduler_state <- prev.pre_prev_scheduler_state;
   t.level <- prev.pre_level;
@@ -321,7 +321,7 @@ let pop_to t prev =
     | [] -> [ min_int ]
     | i :: l -> (i + 1) :: l);
   Backtrackable.draw_graph t.solver_state;
-  Debug.dprintf4 debug_pushpop "[Scheduler] pop to   %a: %a" print_level t
+  Debug.dprintf4 debug_pushpop "[Scheduler] pop  to   %a: %a" print_level t
     print_position_in_tree t
 
 (** only fix model *)
@@ -454,11 +454,16 @@ let learning t =
 let conflict_analysis ~no_learning t =
   Option.iter
     (fun v ->
-      Debug.dprintf3 debug_learn "[Learnt|%i] %a is useful"
-        v.PrioLastEffort.Att.id Events.pp_daemon_key v.PrioLastEffort.Att.v;
+      let debug msg =
+        Debug.dprintf4 debug_learn "[Learnt|%i] %a is useful%s"
+          v.PrioLastEffort.Att.id Events.pp_daemon_key v.PrioLastEffort.Att.v
+          msg
+      in
       PrioLastEffort.change t.lasteffort v 2.;
-      if PrioLastEffort.get_prio t.lasteffort v = 16. then
-        Context.Clicket.push t.last_effort_learnt v.v)
+      if PrioLastEffort.get_prio t.lasteffort v = 16. then (
+        Context.Clicket.push t.last_effort_learnt v.v;
+        debug " and is now learnt")
+      else debug "")
     t.last_effort_made;
   Option.iter
     (fun v ->
@@ -550,7 +555,6 @@ let[@inline always] protect_against_contradiction ~no_learning t f g =
   | r -> g r
 
 let run_one_step_propagation ~nodec t =
-  Debug.incr stats_step;
   match Context.TimeWheel.next t.daemons with
   | Some att ->
       Debug.incr stats_propa;
@@ -621,6 +625,7 @@ let run_one_step_fix_model ~nodec t =
 
 let run_one_step ~nodec t =
   t.steps <- t.steps + 1;
+  Debug.incr stats_step;
   Debug.dprintf1 debug "[Scheduler] Step %i" t.steps;
   match Context.Ref.get t.solve_step with
   | Propagate -> (
diff --git a/src_colibri2/stdlib/context.ml b/src_colibri2/stdlib/context.ml
index 71c62c8a0d870749b334dcbceb6a10a242405fb5..951ebaf7379928f9ea469e45f229f38a5932aa9c 100644
--- a/src_colibri2/stdlib/context.ml
+++ b/src_colibri2/stdlib/context.ml
@@ -294,6 +294,10 @@ module Push = struct
     refresh t;
     Vector.fold f acc t.v
 
+  let exists f t =
+    refresh t;
+    Vector.exists f t.v
+
   let length t =
     refresh t;
     Vector.length t.v
@@ -460,17 +464,28 @@ module type HashtblWithDefault = sig
   type key
 
   val create : creator -> (creator -> 'a) -> 'a t
+  val pp : 'a Fmt.t -> 'a t Fmt.t
   val set : 'a t -> key -> 'a -> unit
   val find : 'a t -> key -> 'a
   val change : ('a -> 'a) -> 'a t -> key -> unit
 end
 
-module HashtblWithDefault (S : Colibri2_popop_lib.Popop_stdlib.Datatype) :
-  HashtblWithDefault with type key := S.t = struct
+module HashtblWithDefault (S : Colibri2_popop_lib.Popop_stdlib.Datatype) : sig
+  include HashtblWithDefault
+
+  val find_aux : 'a t -> key -> 'a Ref.t
+end
+with type key := S.t = struct
   type 'a t = { h : 'a Ref.t S.H.t; def : creator -> 'a; creator : creator }
 
   let create creator def = { h = S.H.create 5; def; creator }
 
+  let pp pp =
+    Fmt.(
+      iter_bindings ~sep:comma
+        (fun f t -> S.H.iter (fun k v -> f k (Ref.get v)) t.h)
+        (pair S.pp pp))
+
   let find_aux t k =
     match S.H.find_opt t.h k with
     | Some r -> r
@@ -566,3 +581,121 @@ module Clicket = struct
 
   let pp ?sep pp fmt v = Vector.pp ?pp_sep:sep pp fmt v.v
 end
+
+type 'k fold = { fold : 'a. ('a -> 'k -> 'a) -> 'a -> 'a }
+
+module type Trie = sig
+  type 'a t
+  type key
+
+  val create : creator -> 'a t
+  val pp : 'a Fmt.t -> 'a t Fmt.t
+
+  module List : sig
+    val set : 'a t -> key list -> 'a -> unit
+    val find_def : default:(creator -> 'a) -> 'a t -> key list -> 'a
+  end
+
+  module Set : sig
+    type set
+
+    val set : 'a t -> set -> 'a -> unit
+    val find_def : default:(creator -> 'a) -> 'a t -> set -> 'a
+  end
+
+  module Fold : sig
+    val set : 'a t -> key fold -> 'a -> unit
+    val find_def : default:(creator -> 'a) -> 'a t -> key fold -> 'a
+    val memo : default:(creator -> 'a) -> 'a t -> key fold -> 'a
+  end
+end
+
+module Trie (S : Colibri2_popop_lib.Popop_stdlib.Datatype) :
+  Trie with type key := S.t and type Set.set := S.S.t = struct
+  module H = HashtblWithDefault (S)
+
+  type 'a node =
+    | Empty
+    | Value of 'a
+    | Node of 'a node H.t
+    | NodeValue of 'a * 'a node H.t
+
+  type 'a t = 'a node Ref.t
+
+  let create c = Ref.create c Empty
+
+  let pp pp fmt t =
+    let rec aux fmt c =
+      match c with
+      | Empty -> ()
+      | Value v -> pp fmt v
+      | Node h -> H.pp aux fmt h
+      | NodeValue (v, h) ->
+          pp fmt v;
+          H.pp aux fmt h
+    in
+    aux fmt (Ref.get t)
+
+  module Fold = struct
+    let find_aux t { fold } =
+      let aux acc k =
+        match Ref.get acc with
+        | Empty ->
+            let h = H.create (Ref.creator acc) (fun _ -> Empty) in
+            Ref.set acc (Node h);
+            H.find_aux h k
+        | Value x ->
+            let h = H.create (Ref.creator acc) (fun _ -> Empty) in
+            Ref.set acc (NodeValue (x, h));
+            H.find_aux h k
+        | Node h | NodeValue (_, h) -> H.find_aux h k
+      in
+      let acc = fold aux t in
+      acc
+      [@@inline]
+
+    let set t fold v =
+      let r = find_aux t fold in
+      match Ref.get r with
+      | Empty -> Ref.set r (Value v)
+      | Value v' -> if Base.phys_equal v v' then Ref.set r (Value v)
+      | Node h | NodeValue (_, h) -> Ref.set r (NodeValue (v, h))
+      [@@inline]
+
+    let find_def ~default t fold =
+      let r = find_aux t fold in
+      match Ref.get r with
+      | Empty | Node _ -> default (Ref.creator r)
+      | Value v | NodeValue (v, _) -> v
+      [@@inline]
+
+    let memo ~default t fold =
+      let r = find_aux t fold in
+      match Ref.get r with
+      | Empty ->
+          let v = default (Ref.creator r) in
+          Ref.set r (Value v);
+          v
+      | Node h ->
+          let v = default (Ref.creator r) in
+          Ref.set r (NodeValue (v, h));
+          v
+      | Value v | NodeValue (v, _) -> v
+      [@@inline]
+  end
+
+  module List = struct
+    let set t l v =
+      Fold.set t { fold = (fun f acc -> List.fold_left f acc l) } v
+
+    let find_def ~default t l =
+      Fold.find_def ~default t { fold = (fun f acc -> List.fold_left f acc l) }
+  end
+
+  module Set = struct
+    let set t l v = Fold.set t { fold = (fun f acc -> S.S.fold_left f acc l) } v
+
+    let find_def ~default t l =
+      Fold.find_def ~default t { fold = (fun f acc -> S.S.fold_left f acc l) }
+  end
+end
diff --git a/src_colibri2/stdlib/context.mli b/src_colibri2/stdlib/context.mli
index 1341afb3843ba3308148d7860a693b61f4704a9a..d787183ee4a3aae553290fca7741c6a3c2489f76 100644
--- a/src_colibri2/stdlib/context.mli
+++ b/src_colibri2/stdlib/context.mli
@@ -166,6 +166,7 @@ module Push : sig
   val push : 'a t -> 'a -> unit
   val iter : ('a -> unit) -> 'a t -> unit
   val fold : ('acc -> 'a -> 'acc) -> 'acc -> 'a t -> 'acc
+  val exists : ('a -> bool) -> 'a t -> bool
   val length : 'a t -> int
   val get : 'a t -> int -> 'a
 
@@ -227,6 +228,7 @@ module type HashtblWithDefault = sig
   type key
 
   val create : creator -> (creator -> 'a) -> 'a t
+  val pp : 'a Fmt.t -> 'a t Fmt.t
   val set : 'a t -> key -> 'a -> unit
   val find : 'a t -> key -> 'a
   val change : ('a -> 'a) -> 'a t -> key -> unit
@@ -266,3 +268,36 @@ module type Clicket = sig
 end
 
 module Clicket : Clicket
+
+type 'k fold = { fold : 'a. ('a -> 'k -> 'a) -> 'a -> 'a }
+
+module type Trie = sig
+  type 'a t
+  type key
+
+  val create : creator -> 'a t
+  val pp : 'a Fmt.t -> 'a t Fmt.t
+
+  module List : sig
+    val set : 'a t -> key list -> 'a -> unit
+    val find_def : default:(creator -> 'a) -> 'a t -> key list -> 'a
+  end
+
+  module Set : sig
+    type set
+
+    val set : 'a t -> set -> 'a -> unit
+    val find_def : default:(creator -> 'a) -> 'a t -> set -> 'a
+  end
+
+  module Fold : sig
+    val set : 'a t -> key fold -> 'a -> unit
+    val find_def : default:(creator -> 'a) -> 'a t -> key fold -> 'a
+
+    val memo : default:(creator -> 'a) -> 'a t -> key fold -> 'a
+    (** find and add default if not present *)
+  end
+end
+
+module Trie (S : Colibri2_popop_lib.Popop_stdlib.Datatype) :
+  Trie with type key := S.t and type Set.set := S.S.t
diff --git a/src_colibri2/tests/solve/all/sat/dune.inc b/src_colibri2/tests/solve/all/sat/dune.inc
index b36ad2c81748d1665718cdc7dd13459fa99be10d..8f0f349d0f392e98adde6b553eb95e187cfbfe77 100644
--- a/src_colibri2/tests/solve/all/sat/dune.inc
+++ b/src_colibri2/tests/solve/all/sat/dune.inc
@@ -5,5 +5,8 @@
 --dont-print-result %{dep:div_abs2.smt2})) (package colibri2))
 (rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status sat --learning --dont-print-result %{dep:div_abs2.smt2})) (package colibri2))
 (rule (alias runtest) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status sat 
+--dont-print-result %{dep:test_sqrt_assert_KO_Why3_Colibri2_n_a.psmt2})) (package colibri2))
+(rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status sat --learning --dont-print-result %{dep:test_sqrt_assert_KO_Why3_Colibri2_n_a.psmt2})) (package colibri2))
+(rule (alias runtest) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status sat 
 --dont-print-result %{dep:union-Union-is_singletonqtvc_2.psmt2})) (package colibri2))
 (rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status sat --learning --dont-print-result %{dep:union-Union-is_singletonqtvc_2.psmt2})) (package colibri2))
diff --git a/src_colibri2/tests/solve/all/sat/test_sqrt_assert_KO_Why3_Colibri2_n_a.psmt2 b/src_colibri2/tests/solve/all/sat/test_sqrt_assert_KO_Why3_Colibri2_n_a.psmt2
new file mode 100644
index 0000000000000000000000000000000000000000..f22237ac677d4a87f57f0f31084def7044e274b6
--- /dev/null
+++ b/src_colibri2/tests/solve/all/sat/test_sqrt_assert_KO_Why3_Colibri2_n_a.psmt2
@@ -0,0 +1,8 @@
+;; produced by local colibri2.drv ;;
+(set-logic ALL)
+(set-info :smt-lib-version 2.6)
+
+;; sqrt_0
+(assert (= (colibri_sqrt 0.0) 0.0))
+
+(check-sat)
diff --git a/src_colibri2/tests/solve/all/unknown/dune b/src_colibri2/tests/solve/all/unknown/dune
new file mode 100644
index 0000000000000000000000000000000000000000..b83fe9c3ebfd43d0533cb0207aee56afe31582ce
--- /dev/null
+++ b/src_colibri2/tests/solve/all/unknown/dune
@@ -0,0 +1,13 @@
+(include dune.inc)
+
+(rule
+ (alias runtest)
+ (deps
+  (glob_files *.cnf)
+  (glob_files *.smt2)
+  (glob_files *.psmt2))
+ (action
+  (with-stdout-to
+   dune.inc
+   (run %{exe:../../../generate_tests/generate_dune_tests.exe} . unknown)))
+ (mode promote))
diff --git a/src_colibri2/tests/solve/all/unknown/dune.inc b/src_colibri2/tests/solve/all/unknown/dune.inc
new file mode 100644
index 0000000000000000000000000000000000000000..5d1390b3a59b077188a033370f2eff5a3ab2c4ce
--- /dev/null
+++ b/src_colibri2/tests/solve/all/unknown/dune.inc
@@ -0,0 +1,3 @@
+(rule (alias runtest) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unknown 
+--dont-print-result %{dep:float_interval-GenericFloat-div_finite_rev_1.psmt2})) (package colibri2))
+(rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unknown --learning --dont-print-result %{dep:float_interval-GenericFloat-div_finite_rev_1.psmt2})) (package colibri2))
diff --git a/src_colibri2/tests/solve/all/unknown/float_interval-GenericFloat-div_finite_rev_1.psmt2 b/src_colibri2/tests/solve/all/unknown/float_interval-GenericFloat-div_finite_rev_1.psmt2
new file mode 100644
index 0000000000000000000000000000000000000000..5ba2215d99dcb78839bc46757718304cf3a18ee3
--- /dev/null
+++ b/src_colibri2/tests/solve/all/unknown/float_interval-GenericFloat-div_finite_rev_1.psmt2
@@ -0,0 +1,118 @@
+;; produced by local colibri2.drv ;;
+(set-logic ALL)
+(set-info :smt-lib-version 2.6)
+;;; SMT-LIB2: integer arithmetic
+;;; SMT-LIB2: real arithmetic
+
+;; infix *.
+(declare-fun infix_asdt (Real
+  Real) Real)
+
+;; infix >=.
+(declare-fun infix_gteqdt (Real
+  Real) Bool)
+
+(declare-datatypes ((tuple1 1))
+  ((par (a) ((Tuple1 (Tuple1_proj_1 a))))))
+
+(declare-sort finite 0)
+
+;; r
+(declare-fun r (finite) Real)
+
+;; mk_finite
+(declare-fun mk_finite (Real) finite)
+
+(declare-datatypes ((t 0))
+  (((Zero (Zero_proj_1 Bool)) (Infinity (Infinity_proj_1 Bool))
+   (Finite (Finite_proj_1 finite)))))
+
+;; zeroF
+(define-fun zeroF () t (Zero false))
+
+;; prefix .-
+(declare-fun prefix_dtmn (t) t)
+
+;; to_real
+(declare-fun to_real1 (t) Real)
+
+;; is_positive
+(declare-fun is_positive (t) Bool)
+
+(declare-datatypes ((classify 0))
+  (((Is_normal) (Is_subnormal) (Is_zero) (Is_infinite))))
+
+;; first_normal
+(declare-fun first_normal () Real)
+
+;; classify
+(declare-fun classify1 (t) classify)
+
+(declare-datatypes ((tuple2 2))
+  ((par (a1 a2) ((Tuple2 (Tuple2_proj_1 a1)(Tuple2_proj_2 a2))))))
+
+;; infix .=
+(declare-fun infix_dteq (t
+  t) Bool)
+
+;; is_zero
+(define-fun is_zero ((f t)) Bool ((_ is Zero) f))
+
+;; is_finite
+(define-fun is_finite ((f t)) Bool
+  (ite ((_ is Zero) f) true (ite ((_ is Finite) f) true (ite ((_ is Infinity) f) false false))))
+
+;; zeroF_is_positive
+(assert (is_positive zeroF))
+
+;; zeroF_is_zero
+(assert (is_zero zeroF))
+
+;; same_sign
+ (define-fun same_sign ((x t) (y t)) Bool
+   (or
+     (and (is_positive x) (is_positive y))
+     (and (not (is_positive x)) (not (is_positive y)))))
+;;(declare-fun same_sign (t t) Bool)
+
+
+(assert (not (is_positive (Zero true))))
+(assert (is_finite (Zero true)))
+
+(assert (not (same_sign zeroF (prefix_dtmn zeroF))))
+(assert (not (same_sign (Zero false) (Zero true))))
+
+(assert (= (prefix_dtmn zeroF) (Zero true)))
+
+(assert (= (to_real1 zeroF) 0.0))
+(assert (= (to_real1 (Zero true)) 0.0))
+
+;; eq_zero
+(assert (infix_dteq zeroF (prefix_dtmn zeroF)))
+
+;; eq_special
+(assert
+  (forall ((x t) (y t))
+    (=>
+      (infix_dteq x y)
+          (or
+            (and (is_finite x) (is_finite y))
+            (and (not (is_finite x)) (and (not (is_finite y)) (same_sign x y)))))))
+
+(assert    (=>
+      (and (is_finite zeroF) (and (is_finite (prefix_dtmn zeroF)) (same_sign zeroF (prefix_dtmn zeroF))))
+      (infix_gteqdt (infix_asdt (to_real1 zeroF) (to_real1 (prefix_dtmn zeroF))) 0.0)))
+
+
+(assert (infix_gteqdt (infix_asdt (to_real1 zeroF) (to_real1 (prefix_dtmn zeroF))) 0.0))
+
+;; Goal div_finite_rev
+;; File "/home/bobot/Sources/colibrics/src_common/float_interval.mlw", line 584, characters 8-22
+(assert
+  (not
+    (=>
+         true
+           (not (is_zero zeroF))
+           )))
+
+(check-sat)
diff --git a/src_colibri2/tests/solve/all/unsat/dune.inc b/src_colibri2/tests/solve/all/unsat/dune.inc
index 6c5b832443db80c72eda273714c2b89398a73d65..c84d1e6c69c7da71aedaf78081961e9597199d2f 100644
--- a/src_colibri2/tests/solve/all/unsat/dune.inc
+++ b/src_colibri2/tests/solve/all/unsat/dune.inc
@@ -8,6 +8,9 @@
 --dont-print-result %{dep:fact-FactRecursive-fact_recqtvc.psmt2})) (package colibri2))
 (rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat --learning --dont-print-result %{dep:fact-FactRecursive-fact_recqtvc.psmt2})) (package colibri2))
 (rule (alias runtest) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat 
+--dont-print-result %{dep:float_interval-GenericFloat-add_special_1.psmt2})) (package colibri2))
+(rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat --learning --dont-print-result %{dep:float_interval-GenericFloat-add_special_1.psmt2})) (package colibri2))
+(rule (alias runtest) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat 
 --dont-print-result %{dep:interval-Convexe-exists_memqtvc_1.psmt2})) (package colibri2))
 (rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat --learning --dont-print-result %{dep:interval-Convexe-exists_memqtvc_1.psmt2})) (package colibri2))
 (rule (alias runtest) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat 
@@ -23,6 +26,12 @@
 --dont-print-result %{dep:ordered_is_ordered.psmt2})) (package colibri2))
 (rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat --learning --dont-print-result %{dep:ordered_is_ordered.psmt2})) (package colibri2))
 (rule (alias runtest) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat 
+--dont-print-result %{dep:range_loop_invariant_CHECK_preserved_Why3_Colibri2_n_a.psmt2})) (package colibri2))
+(rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat --learning --dont-print-result %{dep:range_loop_invariant_CHECK_preserved_Why3_Colibri2_n_a.psmt2})) (package colibri2))
+(rule (alias runtest) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat 
+--dont-print-result %{dep:range_loop_invariant_CHECK_preserved_Why3_Colibri2_n_a_simplified.psmt2})) (package colibri2))
+(rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat --learning --dont-print-result %{dep:range_loop_invariant_CHECK_preserved_Why3_Colibri2_n_a_simplified.psmt2})) (package colibri2))
+(rule (alias runtest) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat 
 --dont-print-result %{dep:union-Union-interqtvc_10.psmt2})) (package colibri2))
 (rule (alias runtest-learning) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat --learning --dont-print-result %{dep:union-Union-interqtvc_10.psmt2})) (package colibri2))
 (rule (alias runtest) (action (run %{bin:colibri2} --size=50M --time=60s --max-steps 3500 --check-status unsat 
diff --git a/src_colibri2/tests/solve/all/unsat/float_interval-GenericFloat-add_special_1.psmt2 b/src_colibri2/tests/solve/all/unsat/float_interval-GenericFloat-add_special_1.psmt2
new file mode 100644
index 0000000000000000000000000000000000000000..ee94fbbadfa27f1aefbf3d7e6f05cec390e9befc
--- /dev/null
+++ b/src_colibri2/tests/solve/all/unsat/float_interval-GenericFloat-add_special_1.psmt2
@@ -0,0 +1,1582 @@
+;; produced by local colibri2.drv ;;
+(set-logic ALL)
+(set-info :smt-lib-version 2.6)
+(set-option :max-steps-colibri2 8000)
+;;; SMT-LIB2: integer arithmetic
+;;; SMT-LIB2: real arithmetic
+(declare-sort string 0)
+
+(declare-datatypes ((tuple0 0))
+  (((Tuple0))))
+
+;; pow2
+(declare-fun pow2 (Int) Int)
+
+;; Power_0
+(assert (= (pow2 0) 1))
+
+;; Power_s
+(assert (forall ((n Int)) (=> (>= n 0) (= (pow2 (+ n 1)) (* 2 (pow2 n))))))
+
+;; Power_1
+(assert (= (pow2 1) 2))
+
+;; Power_sum
+(assert
+  (forall ((n Int) (m Int))
+    (=> (and (>= n 0) (>= m 0)) (= (pow2 (+ n m)) (* (pow2 n) (pow2 m))))))
+
+;; pow2pos
+(assert (forall ((i Int)) (=> (>= i 0) (> (pow2 i) 0))))
+
+;; pow2_0
+(assert (= (pow2 0) 1))
+
+;; pow2_1
+(assert (= (pow2 1) 2))
+
+;; pow2_2
+(assert (= (pow2 2) 4))
+
+;; pow2_3
+(assert (= (pow2 3) 8))
+
+;; pow2_4
+(assert (= (pow2 4) 16))
+
+;; pow2_5
+(assert (= (pow2 5) 32))
+
+;; pow2_6
+(assert (= (pow2 6) 64))
+
+;; pow2_7
+(assert (= (pow2 7) 128))
+
+;; pow2_8
+(assert (= (pow2 8) 256))
+
+;; pow2_9
+(assert (= (pow2 9) 512))
+
+;; pow2_10
+(assert (= (pow2 10) 1024))
+
+;; pow2_11
+(assert (= (pow2 11) 2048))
+
+;; pow2_12
+(assert (= (pow2 12) 4096))
+
+;; pow2_13
+(assert (= (pow2 13) 8192))
+
+;; pow2_14
+(assert (= (pow2 14) 16384))
+
+;; pow2_15
+(assert (= (pow2 15) 32768))
+
+;; pow2_16
+(assert (= (pow2 16) 65536))
+
+;; pow2_17
+(assert (= (pow2 17) 131072))
+
+;; pow2_18
+(assert (= (pow2 18) 262144))
+
+;; pow2_19
+(assert (= (pow2 19) 524288))
+
+;; pow2_20
+(assert (= (pow2 20) 1048576))
+
+;; pow2_21
+(assert (= (pow2 21) 2097152))
+
+;; pow2_22
+(assert (= (pow2 22) 4194304))
+
+;; pow2_23
+(assert (= (pow2 23) 8388608))
+
+;; pow2_24
+(assert (= (pow2 24) 16777216))
+
+;; pow2_25
+(assert (= (pow2 25) 33554432))
+
+;; pow2_26
+(assert (= (pow2 26) 67108864))
+
+;; pow2_27
+(assert (= (pow2 27) 134217728))
+
+;; pow2_28
+(assert (= (pow2 28) 268435456))
+
+;; pow2_29
+(assert (= (pow2 29) 536870912))
+
+;; pow2_30
+(assert (= (pow2 30) 1073741824))
+
+;; pow2_31
+(assert (= (pow2 31) 2147483648))
+
+;; pow2_32
+(assert (= (pow2 32) 4294967296))
+
+;; pow2_33
+(assert (= (pow2 33) 8589934592))
+
+;; pow2_34
+(assert (= (pow2 34) 17179869184))
+
+;; pow2_35
+(assert (= (pow2 35) 34359738368))
+
+;; pow2_36
+(assert (= (pow2 36) 68719476736))
+
+;; pow2_37
+(assert (= (pow2 37) 137438953472))
+
+;; pow2_38
+(assert (= (pow2 38) 274877906944))
+
+;; pow2_39
+(assert (= (pow2 39) 549755813888))
+
+;; pow2_40
+(assert (= (pow2 40) 1099511627776))
+
+;; pow2_41
+(assert (= (pow2 41) 2199023255552))
+
+;; pow2_42
+(assert (= (pow2 42) 4398046511104))
+
+;; pow2_43
+(assert (= (pow2 43) 8796093022208))
+
+;; pow2_44
+(assert (= (pow2 44) 17592186044416))
+
+;; pow2_45
+(assert (= (pow2 45) 35184372088832))
+
+;; pow2_46
+(assert (= (pow2 46) 70368744177664))
+
+;; pow2_47
+(assert (= (pow2 47) 140737488355328))
+
+;; pow2_48
+(assert (= (pow2 48) 281474976710656))
+
+;; pow2_49
+(assert (= (pow2 49) 562949953421312))
+
+;; pow2_50
+(assert (= (pow2 50) 1125899906842624))
+
+;; pow2_51
+(assert (= (pow2 51) 2251799813685248))
+
+;; pow2_52
+(assert (= (pow2 52) 4503599627370496))
+
+;; pow2_53
+(assert (= (pow2 53) 9007199254740992))
+
+;; pow2_54
+(assert (= (pow2 54) 18014398509481984))
+
+;; pow2_55
+(assert (= (pow2 55) 36028797018963968))
+
+;; pow2_56
+(assert (= (pow2 56) 72057594037927936))
+
+;; pow2_57
+(assert (= (pow2 57) 144115188075855872))
+
+;; pow2_58
+(assert (= (pow2 58) 288230376151711744))
+
+;; pow2_59
+(assert (= (pow2 59) 576460752303423488))
+
+;; pow2_60
+(assert (= (pow2 60) 1152921504606846976))
+
+;; pow2_61
+(assert (= (pow2 61) 2305843009213693952))
+
+;; pow2_62
+(assert (= (pow2 62) 4611686018427387904))
+
+;; pow2_63
+(assert (= (pow2 63) 9223372036854775808))
+
+;; pow2_64
+(assert (= (pow2 64) 18446744073709551616))
+
+;; add_div
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (=> (not (= z 0.0)) (= (/ (+ x y) z) (+ (/ x z) (/ y z))))))
+
+;; sub_div
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (=> (not (= z 0.0)) (= (/ (- x y) z) (- (/ x z) (/ y z))))))
+
+;; neg_div
+(assert
+  (forall ((x Real) (y Real))
+    (=> (not (= y 0.0)) (= (/ (- x) y) (- (/ x y))))))
+
+;; assoc_mul_div
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (=> (not (= z 0.0)) (= (/ (* x y) z) (* x (/ y z))))))
+
+;; assoc_div_mul
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (=>
+      (and (not (= y 0.0)) (not (= z 0.0)))
+      (= (/ (/ x y) z) (/ x (* y z))))))
+
+;; assoc_div_div
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (=>
+      (and (not (= y 0.0)) (not (= z 0.0)))
+      (= (/ x (/ y z)) (/ (* x z) y)))))
+
+;; abs
+(define-fun abs1 ((x Real)) Real
+  (ite (>= x 0.0) x (- x)))
+
+;; Abs_le
+(assert
+  (forall ((x Real) (y Real))
+    (= (<= (abs1 x) y) (and (<= (- y) x) (<= x y)))))
+
+;; Abs_pos
+(assert (forall ((x Real)) (>= (abs1 x) 0.0)))
+
+;; Abs_sum
+(assert
+  (forall ((x Real) (y Real)) (<= (abs1 (+ x y)) (+ (abs1 x) (abs1 y)))))
+
+;; Abs_prod
+(assert
+  (forall ((x Real) (y Real)) (= (abs1 (* x y)) (* (abs1 x) (abs1 y)))))
+
+;; triangular_inequality
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (<= (abs1 (- x z)) (+ (abs1 (- x y)) (abs1 (- y z))))))
+
+;; Zero
+(assert (= (to_real 0) 0.0))
+
+;; One
+(assert (= (to_real 1) 1.0))
+
+;; Add
+(assert
+  (forall ((x Int) (y Int))
+    (= (to_real (+ x y)) (+ (to_real x) (to_real y)))))
+
+;; Sub
+(assert
+  (forall ((x Int) (y Int))
+    (= (to_real (- x y)) (- (to_real x) (to_real y)))))
+
+;; Mul
+(assert
+  (forall ((x Int) (y Int))
+    (= (to_real (* x y)) (* (to_real x) (to_real y)))))
+
+;; Neg
+(assert (forall ((x Int)) (= (to_real (- x)) (- (to_real x)))))
+
+;; Injective
+(assert (forall ((x Int) (y Int)) (=> (= (to_real x) (to_real y)) (= x y))))
+
+;; Monotonic
+(assert
+  (forall ((x Int) (y Int)) (=> (<= x y) (<= (to_real x) (to_real y)))))
+
+;; truncate
+(declare-fun truncate (Real) Int)
+
+;; Truncate_int
+(assert (forall ((i Int)) (= (truncate (to_real i)) i)))
+
+;; Truncate_down_pos
+(assert
+  (forall ((x Real))
+    (=>
+      (>= x 0.0)
+      (and (<= (to_real (truncate x)) x) (< x (to_real (+ (truncate x) 1)))))))
+
+;; Truncate_up_neg
+(assert
+  (forall ((x Real))
+    (=>
+      (<= x 0.0)
+      (and (< (to_real (- (truncate x) 1)) x) (<= x (to_real (truncate x)))))))
+
+;; Real_of_truncate
+(assert
+  (forall ((x Real))
+    (and
+      (<= (- x 1.0) (to_real (truncate x)))
+      (<= (to_real (truncate x)) (+ x 1.0)))))
+
+;; Truncate_monotonic
+;;(assert
+;;  (forall ((x Real) (y Real)) (=> (<= x y) (<= (truncate x) (truncate y)))))
+
+;; Truncate_monotonic_int1
+(assert
+  (forall ((x Real) (i Int)) (=> (<= x (to_real i)) (<= (truncate x) i))))
+
+;; Truncate_monotonic_int2
+(assert
+  (forall ((x Real) (i Int)) (=> (<= (to_real i) x) (<= i (truncate x)))))
+
+;;Floor_int
+(assert (forall ((i Int)) (= (to_int (to_real i)) i)))
+
+;;Ceil_int
+(assert (forall ((i Int)) (= (- (to_int (- (to_real i)))) i)))
+
+;; Floor_down
+(assert
+  (forall ((x Real))
+    (and (<= (to_real (to_int x)) x) (< x (to_real (+ (to_int x) 1))))))
+
+;; Ceil_up
+(assert
+  (forall ((x Real))
+    (and
+      (< (to_real (- (- (to_int (- x))) 1)) x)
+      (<= x (to_real (- (to_int (- x))))))))
+
+;; Floor_monotonic
+(assert
+  (forall ((x Real) (y Real)) (=> (<= x y) (<= (to_int x) (to_int y)))))
+
+;; Ceil_monotonic
+(assert
+  (forall ((x Real) (y Real))
+    (=> (<= x y) (<= (- (to_int (- x))) (- (to_int (- y)))))))
+
+;; infix +.
+(define-fun infix_pldt ((x Real) (y Real)) Real
+  (+ x y))
+
+;; infix -.
+(define-fun infix_mndt ((x Real) (y Real)) Real
+  (- x y))
+
+;; infix *.
+(define-fun infix_asdt ((x Real) (y Real)) Real
+  (* x y))
+
+;; infix /.
+(define-fun infix_sldt ((x Real) (y Real)) Real
+  (/ x y))
+
+;; prefix -.
+(define-fun prefix_mndt ((x Real)) Real
+  (- x))
+
+;; inv
+(define-fun inv ((x Real)) Real
+  (/ 1.0 x))
+
+;; infix <=.
+(define-fun infix_lseqdt ((x Real) (y Real)) Bool
+  (<= x y))
+
+;; infix >=.
+(define-fun infix_gteqdt ((x Real) (y Real)) Bool
+  (>= x y))
+
+;; infix <.
+(define-fun infix_lsdt ((x Real) (y Real)) Bool
+  (< x y))
+
+;; infix >.
+(define-fun infix_gtdt ((x Real) (y Real)) Bool
+  (> x y))
+
+(declare-datatypes ((mode 0))
+  (((RNE1) (RNA1) (RTP1) (RTN1) (RTZ1))))
+
+;; to_nearest
+(define-fun to_nearest ((m mode)) Bool
+  (or (= m RNE1) (= m RNA1)))
+
+;; eb
+(declare-fun eb () Int)
+
+;; sb
+(declare-fun sb () Int)
+
+;; eb_gt_1
+(assert (< 1 eb))
+
+;; sb_gt_1
+(assert (< 1 sb))
+
+;; max_real
+(declare-fun max_real () Real)
+
+;; in_range
+(define-fun in_range ((x Real)) Bool
+  (and (infix_lseqdt (prefix_mndt max_real) x) (infix_lseqdt x max_real)))
+
+(declare-sort finite 0)
+
+;; r
+(declare-fun r (finite) Real)
+
+;; finite'invariant
+(assert
+  (forall ((self finite))
+    (! (and (in_range (r self)) (not (= (r self) 0.0))) :pattern ((r self)) )))
+
+;; mk_finite
+(declare-fun mk_finite (Real) finite)
+
+;; mk_finite_def
+(assert
+  (forall ((rr Real))
+    (! (=> (in_range rr) (=> (not (= rr 0.0)) (= (r (mk_finite rr)) rr))) :pattern (
+    (mk_finite
+      rr)) )))
+
+(declare-datatypes ((t 0))
+  (((Zero (Zero_proj_1 Bool)) (Infinity (Infinity_proj_1 Bool)) (NaN1)
+   (Finite (Finite_proj_1 finite)))))
+
+;; zeroF
+(declare-fun zeroF () t)
+
+;; sub
+(declare-fun sub (mode
+  t
+  t) t)
+
+;; mul
+(declare-fun mul (mode
+  t
+  t) t)
+
+;; div
+(declare-fun div1 (mode
+  t
+  t) t)
+
+;; abs
+(declare-fun abs2 (t) t)
+
+;; neg
+(declare-fun neg (t) t)
+
+;; fma
+(declare-fun fma (mode
+  t
+  t
+  t) t)
+
+;; sqrt
+(declare-fun sqrt1 (mode
+  t) t)
+
+;; prefix .-
+(define-fun prefix_dtmn ((x t)) t
+  (neg x))
+
+;; infix .-
+(define-fun infix_dtmn ((x t) (y t)) t
+  (sub RNE1 x y))
+
+;; infix .*
+(define-fun infix_dtas ((x t) (y t)) t
+  (mul RNE1 x y))
+
+;; infix ./
+(define-fun infix_dtsl ((x t) (y t)) t
+  (div1 RNE1 x y))
+
+;; roundToIntegral
+(declare-fun roundToIntegral (mode
+  t) t)
+
+;; min
+(declare-fun min (t
+  t) t)
+
+;; max
+(declare-fun max (t
+  t) t)
+
+;; sign
+(define-fun sign ((r1 Real)) Bool
+  (infix_lsdt r1 0.0))
+
+;; to_real
+(define-fun to_real1 ((x t)) Real
+  (ite ((_ is NaN1) x) (infix_pldt max_real 1.0) (ite ((_ is Infinity) x) 
+                                                   (let ((x1 (Infinity_proj_1 x))) 
+                                                     (ite (= x1 true)
+                                                       (infix_mndt
+                                                         (prefix_mndt
+                                                           max_real)
+                                                         1.0)
+                                                       (infix_pldt
+                                                         max_real
+                                                         1.0))) (ite ((_ is Zero) x) 0.0 
+                                                                  (let ((x2 (Finite_proj_1 x))) 
+                                                                    (r
+                                                                    x2))))))
+
+;; is_positive
+(define-fun is_positive ((f t)) Bool
+  (ite ((_ is NaN1) f) false (ite ((_ is Zero) f) (let ((neg1 (Zero_proj_1 f))) (= (not neg1) true)) 
+                               (ite ((_ is Finite) f) (let ((r1 (Finite_proj_1 f))) 
+                                                        (infix_lseqdt
+                                                          0.0
+                                                          (r r1))) (let ((neg2 (Infinity_proj_1 f))) (= (not neg2) true))))))
+
+;; is_negative
+(define-fun is_negative ((f t)) Bool
+  (ite ((_ is NaN1) f) false (ite ((_ is Zero) f) (let ((neg3 (Zero_proj_1 f))) (= neg3 true)) 
+                               (ite ((_ is Finite) f) (let ((r2 (Finite_proj_1 f))) 
+                                                        (infix_lseqdt
+                                                          (r r2)
+                                                          0.0)) (let ((neg4 (Infinity_proj_1 f))) (= neg4 true))))))
+
+(declare-datatypes ((classify 0))
+  (((Is_normal) (Is_subnormal) (Is_zero) (Is_infinite) (Is_nan))))
+
+;; first_normal
+(declare-fun first_normal () Real)
+
+;; classify
+(define-fun classify1 ((f t)) classify
+  (ite ((_ is Finite) f) (let ((x (Finite_proj_1 f))) (ite (and
+                                                             (infix_lsdt
+                                                               (prefix_mndt
+                                                                 first_normal)
+                                                               (r x))
+                                                             (infix_lsdt
+                                                               (r x)
+                                                               first_normal))
+                                                        Is_subnormal
+                                                        Is_normal)) (ite ((_ is Zero) f) 
+                                                                    Is_zero 
+                                                                    (ite ((_ is Infinity) f) 
+                                                                    Is_infinite 
+                                                                    Is_nan))))
+
+(declare-datatypes ((tuple2 2))
+  ((par (a a1) ((Tuple2 (Tuple2_proj_1 a)(Tuple2_proj_2 a1))))))
+
+;; le
+(define-fun le ((f1 t) (f2 t)) Bool
+  (ite ((_ is NaN1) f2) (ite ((_ is NaN1) f1) false (ite ((_ is Infinity) f1) false false)) 
+    (ite ((_ is Zero) f2) (ite ((_ is NaN1) f1) false (ite ((_ is Zero) f1) true 
+                                                        (ite ((_ is Finite) f1) 
+                                                          (let ((x3 (Finite_proj_1 f1))) 
+                                                            (infix_lseqdt
+                                                              (r x3)
+                                                              0.0)) (let ((x4 (Infinity_proj_1 f1))) (= x4 true))))) 
+      (ite ((_ is Finite) f2) (let ((x5 (Finite_proj_1 f2))) (ite ((_ is NaN1) f1) false 
+                                                               (ite ((_ is Zero) f1) 
+                                                                 (infix_lseqdt
+                                                                   0.0
+                                                                   (r x5)) 
+                                                                 (ite ((_ is Finite) f1) 
+                                                                   (let ((x6 (Finite_proj_1 f1))) 
+                                                                    (infix_lseqdt
+                                                                    (r x6)
+                                                                    (r x5))) 
+                                                                   (let ((x7 (Infinity_proj_1 f1))) (= x7 true)))))) 
+        (let ((x8 (Infinity_proj_1 f2))) (ite ((_ is NaN1) f1) false 
+                                           (ite ((_ is Infinity) f1) 
+                                             (let ((x9 (Infinity_proj_1 f1))) (= (or x9 (not x8)) true)) (= (not x8) true))))))))
+
+;; lt
+(declare-fun lt (t
+  t) Bool)
+
+;; ge
+(define-fun ge ((x10 t) (y t)) Bool
+  (le y x10))
+
+;; gt
+(define-fun gt ((x10 t) (y t)) Bool
+  (lt y x10))
+
+;; eq
+(declare-fun eq (t
+  t) Bool)
+
+;; infix .<=
+(define-fun infix_dtlseq ((x10 t) (y t)) Bool
+  (le x10 y))
+
+;; infix .<
+(define-fun infix_dtls ((x10 t) (y t)) Bool
+  (lt x10 y))
+
+;; infix .>=
+(define-fun infix_dtgteq ((x10 t) (y t)) Bool
+  (ge x10 y))
+
+;; infix .>
+(define-fun infix_dtgt ((x10 t) (y t)) Bool
+  (gt x10 y))
+
+;; infix .=
+(define-fun infix_dteq ((x10 t) (y t)) Bool
+  (eq x10 y))
+
+;; is_normal
+(define-fun is_normal ((f t)) Bool
+  (= (classify1 f) Is_normal))
+
+;; is_subnormal
+(define-fun is_subnormal ((f t)) Bool
+  (= (classify1 f) Is_subnormal))
+
+;; is_zero
+(define-fun is_zero ((f t)) Bool
+  (ite ((_ is Zero) f) true false))
+
+;; is_infinite
+(define-fun is_infinite ((f t)) Bool
+  (ite ((_ is Infinity) f) true false))
+
+;; is_nan
+(define-fun is_nan ((f t)) Bool
+  (ite ((_ is NaN1) f) true false))
+
+;; is_finite
+(define-fun is_finite ((f t)) Bool
+  (ite ((_ is Zero) f) true (ite ((_ is Finite) f) true (ite ((_ is Infinity) f) false false))))
+
+;; is_plus_infinity
+(define-fun is_plus_infinity ((x10 t)) Bool
+  (ite ((_ is Infinity) x10) (let ((neg5 (Infinity_proj_1 x10))) (= (not neg5) true)) false))
+
+;; is_minus_infinity
+(define-fun is_minus_infinity ((x10 t)) Bool
+  (ite ((_ is Infinity) x10) (let ((neg6 (Infinity_proj_1 x10))) (= neg6 true)) false))
+
+;; is_plus_zero
+(define-fun is_plus_zero ((x10 t)) Bool
+  (ite ((_ is Zero) x10) (let ((neg7 (Zero_proj_1 x10))) (= (not neg7) true)) false))
+
+;; is_minus_zero
+(define-fun is_minus_zero ((x10 t)) Bool
+  (ite ((_ is Zero) x10) (let ((neg8 (Zero_proj_1 x10))) (= neg8 true)) false))
+
+;; is_not_nan
+(define-fun is_not_nan ((x10 t)) Bool
+  (ite ((_ is NaN1) x10) false true))
+
+;; is_not_nan
+(assert (forall ((x10 t)) (= (is_not_nan x10) (not (is_nan x10)))))
+
+;; is_not_finite
+(assert
+  (forall ((x10 t))
+    (= (not (is_finite x10)) (or (is_infinite x10) (is_nan x10)))))
+
+;; zeroF_is_positive
+(assert (is_positive zeroF))
+
+;; zeroF_is_zero
+(assert (is_zero zeroF))
+
+;; zero_to_real
+(assert
+  (forall ((x10 t))
+    (! (= (is_zero x10) (and (is_finite x10) (= (to_real1 x10) 0.0))) :pattern (
+    (is_zero
+      x10)) )))
+
+;; of_int
+(declare-fun of_int (mode
+  Int) t)
+
+;; to_int
+(declare-fun to_int1 (mode
+  t) Int)
+
+;; zero_of_int
+(assert (forall ((m mode)) (= zeroF (of_int m 0))))
+
+;; round
+(declare-fun round (mode
+  Real) Real)
+
+;; max_int
+(declare-fun max_int () Int)
+
+;; emax
+(define-fun emax () Int
+  (pow2 (- eb 1)))
+
+;; max_real_bound
+(assert (infix_lsdt 0.0 max_real))
+
+;; max_int_bound
+(assert (< 0 max_int))
+
+;; max_int
+(assert (= max_int (- (pow2 emax) (pow2 (- emax sb)))))
+
+;; max_real_int
+(assert (= max_real (to_real max_int)))
+
+;; in_int_range
+(define-fun in_int_range ((i Int)) Bool
+  (and (<= (- max_int) i) (<= i max_int)))
+
+;; max_real_round
+(assert (forall ((m mode)) (= (round m max_real) max_real)))
+
+;; minus_max_real_round
+(assert
+  (forall ((m mode))
+    (= (round m (prefix_mndt max_real)) (prefix_mndt max_real))))
+
+;; is_finite
+(assert (forall ((x10 t)) (=> (is_finite x10) (in_range (to_real1 x10)))))
+
+;; no_overflow
+(define-fun no_overflow ((m mode) (x10 Real)) Bool
+  (in_range (round m x10)))
+
+;; Bounded_real_no_overflow
+(assert
+  (forall ((m mode) (x10 Real)) (=> (in_range x10) (no_overflow m x10))))
+
+;; Round_monotonic
+(assert
+  (forall ((m mode) (x10 Real) (y Real))
+    (=> (infix_lseqdt x10 y) (infix_lseqdt (round m x10) (round m y)))))
+
+;; Round_idempotent
+(assert
+  (forall ((m1 mode) (m2 mode) (x10 Real))
+    (= (round m1 (round m2 x10)) (round m2 x10))))
+
+;; Round_to_real
+(assert
+  (forall ((m mode) (x10 t))
+    (=> (is_finite x10) (= (round m (to_real1 x10)) (to_real1 x10)))))
+
+;; Round_down_le
+(assert (forall ((x10 Real)) (infix_lseqdt (round RTN1 x10) x10)))
+
+;; Round_up_ge
+(assert (forall ((x10 Real)) (infix_gteqdt (round RTP1 x10) x10)))
+
+;; Round_down_neg
+(assert
+  (forall ((x10 Real))
+    (= (round RTN1 (prefix_mndt x10)) (prefix_mndt (round RTP1 x10)))))
+
+;; Round_up_neg
+(assert
+  (forall ((x10 Real))
+    (= (round RTP1 (prefix_mndt x10)) (prefix_mndt (round RTN1 x10)))))
+
+;; pow2sb
+(declare-fun pow2sb () Int)
+
+;; pow2sb
+(assert (= pow2sb (pow2 sb)))
+
+;; in_safe_int_range
+(define-fun in_safe_int_range ((i Int)) Bool
+  (and (<= (- pow2sb) i) (<= i pow2sb)))
+
+;; Exact_rounding_for_integers
+(assert
+  (forall ((m mode) (i Int))
+    (=> (in_safe_int_range i) (= (round m (to_real i)) (to_real i)))))
+
+;; same_sign
+(define-fun same_sign ((x10 t) (y t)) Bool
+  (or
+    (and (is_positive x10) (is_positive y))
+    (and (is_negative x10) (is_negative y))))
+
+;; diff_sign
+(define-fun diff_sign ((x10 t) (y t)) Bool
+  (or
+    (and (is_positive x10) (is_negative y))
+    (and (is_negative x10) (is_positive y))))
+
+;; feq_eq
+(assert
+  (forall ((x10 t) (y t))
+    (=>
+      (is_finite x10)
+      (=>
+        (is_finite y)
+        (=> (not (is_zero x10)) (=> (infix_dteq x10 y) (= x10 y)))))))
+
+;; eq_feq
+(assert
+  (forall ((x10 t))
+    (=> (is_finite x10) (=> (is_finite x10) (infix_dteq x10 x10)))))
+
+;; eq_refl
+(assert (forall ((x10 t)) (=> (is_finite x10) (infix_dteq x10 x10))))
+
+;; eq_sym
+(assert (forall ((x10 t) (y t)) (=> (infix_dteq x10 y) (infix_dteq y x10))))
+
+;; eq_trans
+(assert
+  (forall ((x10 t) (y t) (z t))
+    (=> (infix_dteq x10 y) (=> (infix_dteq y z) (infix_dteq x10 z)))))
+
+;; eq_zero
+(assert (infix_dteq zeroF (prefix_dtmn zeroF)))
+
+;; eq_to_real_finite
+(assert
+  (forall ((x10 t) (y t))
+    (=>
+      (and (is_finite x10) (is_finite y))
+      (= (infix_dteq x10 y) (= (to_real1 x10) (to_real1 y))))))
+
+;; eq_special
+(assert
+  (forall ((x10 t) (y t))
+    (=>
+      (infix_dteq x10 y)
+      (and
+        (is_not_nan x10)
+        (and
+          (is_not_nan y)
+          (or
+            (and (is_finite x10) (is_finite y))
+            (and (is_infinite x10) (and (is_infinite y) (same_sign x10 y)))))))))
+
+;; lt_finite
+(assert
+  (forall ((x10 t) (y t))
+    (! (=>
+         (and (is_finite x10) (is_finite y))
+         (= (lt x10 y) (infix_lsdt (to_real1 x10) (to_real1 y)))) :pattern (
+    (lt
+      x10
+      y)) )))
+
+;; le_finite
+(assert
+  (forall ((x10 t) (y t))
+    (! (=>
+         (and (is_finite x10) (is_finite y))
+         (= (le x10 y) (infix_lseqdt (to_real1 x10) (to_real1 y)))) :pattern (
+    (le
+      x10
+      y)) )))
+
+;; le_lt_trans
+(assert
+  (forall ((x10 t) (y t) (z t))
+    (=> (and (infix_dtlseq x10 y) (infix_dtls y z)) (infix_dtls x10 z))))
+
+;; lt_le_trans
+(assert
+  (forall ((x10 t) (y t) (z t))
+    (=> (and (infix_dtls x10 y) (infix_dtlseq y z)) (infix_dtls x10 z))))
+
+;; le_ge_asym
+(assert
+  (forall ((x10 t) (y t))
+    (=> (and (infix_dtlseq x10 y) (infix_dtgteq x10 y)) (infix_dteq x10 y))))
+
+;; not_lt_ge
+(assert
+  (forall ((x10 t) (y t))
+    (=>
+      (and (not (infix_dtls x10 y)) (and (is_not_nan x10) (is_not_nan y)))
+      (infix_dtgteq x10 y))))
+
+;; not_gt_le
+(assert
+  (forall ((x10 t) (y t))
+    (=>
+      (and (not (infix_dtgt x10 y)) (and (is_not_nan x10) (is_not_nan y)))
+      (infix_dtlseq x10 y))))
+
+;; le_special
+(assert
+  (forall ((x10 t) (y t))
+    (! (=>
+         (le x10 y)
+         (or
+           (and (is_finite x10) (is_finite y))
+           (or
+             (and (is_minus_infinity x10) (is_not_nan y))
+             (and (is_not_nan x10) (is_plus_infinity y))))) :pattern (
+    (le
+      x10
+      y)) )))
+
+;; lt_special
+(assert
+  (forall ((x10 t) (y t))
+    (! (=>
+         (lt x10 y)
+         (or
+           (and (is_finite x10) (is_finite y))
+           (or
+             (and
+               (is_minus_infinity x10)
+               (and (is_not_nan y) (not (is_minus_infinity y))))
+             (and
+               (is_not_nan x10)
+               (and (not (is_plus_infinity x10)) (is_plus_infinity y)))))) :pattern (
+    (lt
+      x10
+      y)) )))
+
+;; lt_lt_finite
+(assert
+  (forall ((x10 t) (y t) (z t)) (=> (lt x10 y) (=> (lt y z) (is_finite y)))))
+
+;; positive_to_real
+(assert
+  (forall ((x10 t))
+    (! (=>
+         (is_finite x10)
+         (=> (is_positive x10) (infix_gteqdt (to_real1 x10) 0.0))) :pattern (
+    (is_positive
+      x10)) :pattern ((infix_gteqdt (to_real1 x10) 0.0)) )))
+
+;; to_real_positive
+(assert
+  (forall ((x10 t))
+    (! (=>
+         (is_finite x10)
+         (=> (infix_gtdt (to_real1 x10) 0.0) (is_positive x10))) :pattern (
+    (is_positive
+      x10)) )))
+
+;; negative_to_real
+(assert
+  (forall ((x10 t))
+    (! (=>
+         (is_finite x10)
+         (=> (is_negative x10) (infix_lseqdt (to_real1 x10) 0.0))) :pattern (
+    (is_negative
+      x10)) :pattern ((infix_lseqdt (to_real1 x10) 0.0)) )))
+
+;; to_real_negative
+(assert
+  (forall ((x10 t))
+    (! (=>
+         (is_finite x10)
+         (=> (infix_lsdt (to_real1 x10) 0.0) (is_negative x10))) :pattern (
+    (is_negative
+      x10)) )))
+
+;; negative_xor_positive
+(assert (forall ((x10 t)) (not (and (is_positive x10) (is_negative x10)))))
+
+;; negative_or_positive
+(assert
+  (forall ((x10 t))
+    (=> (is_not_nan x10) (or (is_positive x10) (is_negative x10)))))
+
+;; diff_sign_trans
+(assert
+  (forall ((x10 t) (y t) (z t))
+    (=> (and (diff_sign x10 y) (diff_sign y z)) (same_sign x10 z))))
+
+;; diff_sign_product
+(assert
+  (forall ((x10 t) (y t))
+    (=>
+      (and
+        (is_finite x10)
+        (and
+          (is_finite y)
+          (infix_lsdt (infix_asdt (to_real1 x10) (to_real1 y)) 0.0)))
+      (diff_sign x10 y))))
+
+;; same_sign_product
+(assert
+  (forall ((x10 t) (y t))
+    (=>
+      (and (is_finite x10) (and (is_finite y) (same_sign x10 y)))
+      (infix_gteqdt (infix_asdt (to_real1 x10) (to_real1 y)) 0.0))))
+
+;; product_sign
+(define-fun product_sign ((z t) (x10 t) (y t)) Bool
+  (and
+    (=> (same_sign x10 y) (is_positive z))
+    (=> (diff_sign x10 y) (is_negative z))))
+
+;; overflow_value
+(define-fun overflow_value ((m mode) (x10 t)) Bool
+  (ite ((_ is RTN1) m) (ite (is_positive x10)
+                         (and (is_finite x10) (= (to_real1 x10) max_real))
+                         (is_infinite x10)) (ite ((_ is RTP1) m) (ite 
+                                                                   (is_positive
+                                                                    x10)
+                                                                   (is_infinite
+                                                                    x10)
+                                                                   (and
+                                                                    (is_finite
+                                                                    x10)
+                                                                    (= 
+                                                                    (to_real1
+                                                                    x10) 
+                                                                    (prefix_mndt
+                                                                    max_real)))) 
+                                              (ite ((_ is RTZ1) m) (ite 
+                                                                    (is_positive
+                                                                    x10)
+                                                                    (and
+                                                                    (is_finite
+                                                                    x10)
+                                                                    (= 
+                                                                    (to_real1
+                                                                    x10) 
+                                                                    max_real))
+                                                                    (and
+                                                                    (is_finite
+                                                                    x10)
+                                                                    (= 
+                                                                    (to_real1
+                                                                    x10) 
+                                                                    (prefix_mndt
+                                                                    max_real)))) 
+                                                (ite ((_ is RNA1) m) 
+                                                  (is_infinite
+                                                    x10) (is_infinite x10))))))
+
+;; sign_zero_result
+(define-fun sign_zero_result ((m mode) (x10 t)) Bool
+  (=>
+    (is_zero x10)
+    (ite ((_ is RTN1) m) (is_negative x10) (is_positive x10))))
+
+;; is_RTN
+(define-fun is_RTN ((mode1 mode)) Bool
+  (ite ((_ is RTN1) mode1) true false))
+
+;; add
+(define-fun add ((mode1 mode) (x10 t) (y t)) t
+  (ite ((_ is NaN1) y) (ite ((_ is NaN1) x10) NaN1 (ite ((_ is Zero) x10) 
+                                                     NaN1 (ite ((_ is Infinity) x10) 
+                                                            NaN1 NaN1))) 
+    (ite ((_ is Zero) y) (let ((x11 (Zero_proj_1 y))) (ite ((_ is NaN1) x10) 
+                                                        NaN1 (ite ((_ is Zero) x10) 
+                                                               (let ((x12 (Zero_proj_1 x10))) 
+                                                                 (ite (= x12 x11)
+                                                                   (Zero x12)
+                                                                   (Zero
+                                                                    (is_RTN
+                                                                    mode1)))) 
+                                                               (ite ((_ is Infinity) x10) x10 x10)))) 
+      (ite ((_ is Infinity) y) (let ((x13 (Infinity_proj_1 y))) (ite ((_ is NaN1) x10) 
+                                                                  NaN1 
+                                                                  (ite ((_ is Zero) x10) y 
+                                                                    (ite ((_ is Infinity) x10) 
+                                                                    (let ((x14 (Infinity_proj_1 x10))) 
+                                                                    (ite (= x14 x13)
+                                                                    x10
+                                                                    NaN1)) y)))) 
+        (let ((x15 (Finite_proj_1 y))) (ite ((_ is NaN1) x10) NaN1 (ite ((_ is Zero) x10) y 
+                                                                    (ite ((_ is Infinity) x10) x10 
+                                                                    (let ((x16 (Finite_proj_1 x10))) 
+                                                                    (let ((r3 
+                                                                    (round
+                                                                    mode1
+                                                                    (infix_pldt
+                                                                    (r x16)
+                                                                    (r x15)))))
+                                                                    (ite (= r3 0.0)
+                                                                    (Zero
+                                                                    (is_RTN
+                                                                    mode1))
+                                                                    (ite 
+                                                                    (in_range
+                                                                    r3)
+                                                                    (Finite
+                                                                    (mk_finite
+                                                                    r3))
+                                                                    (ite ((_ is RTN1) mode1) 
+                                                                    (ite 
+                                                                    (sign
+                                                                    r3)
+                                                                    (Infinity
+                                                                    true)
+                                                                    (Finite
+                                                                    (mk_finite
+                                                                    max_real))) 
+                                                                    (ite ((_ is RTP1) mode1) 
+                                                                    (ite 
+                                                                    (sign
+                                                                    r3)
+                                                                    (Finite
+                                                                    (mk_finite
+                                                                    (prefix_mndt
+                                                                    max_real)))
+                                                                    (Infinity
+                                                                    false)) 
+                                                                    (ite ((_ is RTZ1) mode1) 
+                                                                    (ite 
+                                                                    (sign
+                                                                    r3)
+                                                                    (Finite
+                                                                    (mk_finite
+                                                                    (prefix_mndt
+                                                                    max_real)))
+                                                                    (Finite
+                                                                    (mk_finite
+                                                                    max_real))) 
+                                                                    (ite ((_ is RNA1) mode1) 
+                                                                    (Infinity
+                                                                    (ite 
+                                                                    (sign
+                                                                    r3)
+                                                                    true
+                                                                    false)) 
+                                                                    (Infinity
+                                                                    (ite 
+                                                                    (sign
+                                                                    r3)
+                                                                    true
+                                                                    false))))))))))))))))))
+
+;; infix .+
+(define-fun infix_dtpl ((x17 t) (y t)) t
+  (add RNE1 x17 y))
+
+;; sub_finite
+(assert
+  (forall ((m mode) (x17 t) (y t))
+    (! (=>
+         (is_finite x17)
+         (=>
+           (is_finite y)
+           (=>
+             (no_overflow m (infix_mndt (to_real1 x17) (to_real1 y)))
+             (and
+               (is_finite (sub m x17 y))
+               (= (to_real1 (sub m x17 y)) (round
+                                             m
+                                             (infix_mndt
+                                               (to_real1 x17)
+                                               (to_real1 y)))))))) :pattern (
+    (sub
+      m
+      x17
+      y)) )))
+
+;; sub_finite_rev
+(assert
+  (forall ((m mode) (x17 t) (y t))
+    (! (=> (is_finite (sub m x17 y)) (and (is_finite x17) (is_finite y))) :pattern (
+    (sub
+      m
+      x17
+      y)) )))
+
+;; sub_finite_rev_n
+(assert
+  (forall ((m mode) (x17 t) (y t))
+    (! (=>
+         (to_nearest m)
+         (=>
+           (is_finite (sub m x17 y))
+           (and
+             (no_overflow m (infix_mndt (to_real1 x17) (to_real1 y)))
+             (= (to_real1 (sub m x17 y)) (round
+                                           m
+                                           (infix_mndt
+                                             (to_real1 x17)
+                                             (to_real1 y))))))) :pattern (
+    (sub
+      m
+      x17
+      y)) )))
+
+;; mul_finite
+(assert
+  (forall ((m mode) (x17 t) (y t))
+    (! (=>
+         (is_finite x17)
+         (=>
+           (is_finite y)
+           (=>
+             (no_overflow m (infix_asdt (to_real1 x17) (to_real1 y)))
+             (and
+               (is_finite (mul m x17 y))
+               (= (to_real1 (mul m x17 y)) (round
+                                             m
+                                             (infix_asdt
+                                               (to_real1 x17)
+                                               (to_real1 y)))))))) :pattern (
+    (mul
+      m
+      x17
+      y)) )))
+
+;; mul_finite_rev
+(assert
+  (forall ((m mode) (x17 t) (y t))
+    (! (=> (is_finite (mul m x17 y)) (and (is_finite x17) (is_finite y))) :pattern (
+    (mul
+      m
+      x17
+      y)) )))
+
+;; mul_finite_rev_n
+(assert
+  (forall ((m mode) (x17 t) (y t))
+    (! (=>
+         (to_nearest m)
+         (=>
+           (is_finite (mul m x17 y))
+           (and
+             (no_overflow m (infix_asdt (to_real1 x17) (to_real1 y)))
+             (= (to_real1 (mul m x17 y)) (round
+                                           m
+                                           (infix_asdt
+                                             (to_real1 x17)
+                                             (to_real1 y))))))) :pattern (
+    (mul
+      m
+      x17
+      y)) )))
+
+;; div_finite
+(assert
+  (forall ((m mode) (x17 t) (y t))
+    (! (=>
+         (is_finite x17)
+         (=>
+           (is_finite y)
+           (=>
+             (not (is_zero y))
+             (=>
+               (no_overflow m (infix_sldt (to_real1 x17) (to_real1 y)))
+               (and
+                 (is_finite (div1 m x17 y))
+                 (= (to_real1 (div1 m x17 y)) (round
+                                                m
+                                                (infix_sldt
+                                                  (to_real1 x17)
+                                                  (to_real1 y))))))))) :pattern (
+    (div1
+      m
+      x17
+      y)) )))
+
+;; div_finite_rev
+(assert
+  (forall ((m mode) (x17 t) (y t))
+    (! (=>
+         (is_finite (div1 m x17 y))
+         (or
+           (and (is_finite x17) (and (is_finite y) (not (is_zero y))))
+           (and
+             (is_finite x17)
+             (and (is_infinite y) (= (to_real1 (div1 m x17 y)) 0.0))))) :pattern (
+    (div1
+      m
+      x17
+      y)) )))
+
+;; div_finite_rev_n
+(assert
+  (forall ((m mode) (x17 t) (y t))
+    (! (=>
+         (to_nearest m)
+         (=>
+           (is_finite (div1 m x17 y))
+           (=>
+             (is_finite y)
+             (and
+               (no_overflow m (infix_sldt (to_real1 x17) (to_real1 y)))
+               (= (to_real1 (div1 m x17 y)) (round
+                                              m
+                                              (infix_sldt
+                                                (to_real1 x17)
+                                                (to_real1 y)))))))) :pattern (
+    (div1
+      m
+      x17
+      y)) )))
+
+;; neg_finite
+(assert
+  (forall ((x17 t))
+    (! (=>
+         (is_finite x17)
+         (and
+           (is_finite (neg x17))
+           (= (to_real1 (neg x17)) (prefix_mndt (to_real1 x17))))) :pattern (
+    (neg
+      x17)) )))
+
+;; neg_finite_rev
+(assert
+  (forall ((x17 t))
+    (! (=>
+         (is_finite (neg x17))
+         (and
+           (is_finite x17)
+           (= (to_real1 (neg x17)) (prefix_mndt (to_real1 x17))))) :pattern (
+    (neg
+      x17)) )))
+
+;; abs_finite
+(assert
+  (forall ((x17 t))
+    (! (=>
+         (is_finite x17)
+         (and
+           (is_finite (abs2 x17))
+           (and
+             (= (to_real1 (abs2 x17)) (abs1 (to_real1 x17)))
+             (is_positive (abs2 x17))))) :pattern ((abs2 x17)) )))
+
+;; abs_finite_rev
+(assert
+  (forall ((x17 t))
+    (! (=>
+         (is_finite (abs2 x17))
+         (and
+           (is_finite x17)
+           (= (to_real1 (abs2 x17)) (abs1 (to_real1 x17))))) :pattern (
+    (abs2
+      x17)) )))
+
+;; abs_universal
+(assert
+  (forall ((x17 t))
+    (! (not (is_negative (abs2 x17))) :pattern ((abs2 x17)) )))
+
+;; fma_finite
+(assert
+  (forall ((m mode) (x17 t) (y t) (z t))
+    (! (=>
+         (is_finite x17)
+         (=>
+           (is_finite y)
+           (=>
+             (is_finite z)
+             (=>
+               (no_overflow
+                 m
+                 (infix_pldt
+                   (infix_asdt (to_real1 x17) (to_real1 y))
+                   (to_real1 z)))
+               (and
+                 (is_finite (fma m x17 y z))
+                 (= (to_real1 (fma m x17 y z)) (round
+                                                 m
+                                                 (infix_pldt
+                                                   (infix_asdt
+                                                     (to_real1 x17)
+                                                     (to_real1 y))
+                                                   (to_real1 z))))))))) :pattern (
+    (fma
+      m
+      x17
+      y
+      z)) )))
+
+;; fma_finite_rev
+(assert
+  (forall ((m mode) (x17 t) (y t) (z t))
+    (! (=>
+         (is_finite (fma m x17 y z))
+         (and (is_finite x17) (and (is_finite y) (is_finite z)))) :pattern (
+    (fma
+      m
+      x17
+      y
+      z)) )))
+
+;; fma_finite_rev_n
+(assert
+  (forall ((m mode) (x17 t) (y t) (z t))
+    (! (=>
+         (to_nearest m)
+         (=>
+           (is_finite (fma m x17 y z))
+           (and
+             (no_overflow
+               m
+               (infix_pldt
+                 (infix_asdt (to_real1 x17) (to_real1 y))
+                 (to_real1 z)))
+             (= (to_real1 (fma m x17 y z)) (round
+                                             m
+                                             (infix_pldt
+                                               (infix_asdt
+                                                 (to_real1 x17)
+                                                 (to_real1 y))
+                                               (to_real1 z))))))) :pattern (
+    (fma
+      m
+      x17
+      y
+      z)) )))
+
+;; sqr
+(define-fun sqr ((x17 Real)) Real
+  (* x17 x17))
+
+;; Sqrt_positive
+(assert (forall ((x17 Real)) (=> (>= x17 0.0) (>= (colibri_sqrt x17) 0.0))))
+
+;; Sqrt_square
+(assert
+  (forall ((x17 Real)) (=> (>= x17 0.0) (= (sqr (colibri_sqrt x17)) x17))))
+
+;; Square_sqrt
+(assert
+  (forall ((x17 Real)) (=> (>= x17 0.0) (= (colibri_sqrt (* x17 x17)) x17))))
+
+;; Sqrt_mul
+(assert
+  (forall ((x17 Real) (y Real))
+    (=>
+      (and (>= x17 0.0) (>= y 0.0))
+      (= (colibri_sqrt (* x17 y)) (* (colibri_sqrt x17) (colibri_sqrt y))))))
+
+;; Sqrt_le
+(assert
+  (forall ((x17 Real) (y Real))
+    (=>
+      (and (<= 0.0 x17) (<= x17 y))
+      (<= (colibri_sqrt x17) (colibri_sqrt y)))))
+
+;; sqrt_finite
+(assert
+  (forall ((m mode) (x17 t))
+    (! (=>
+         (is_finite x17)
+         (=>
+           (infix_gteqdt (to_real1 x17) 0.0)
+           (and
+             (is_finite (sqrt1 m x17))
+             (= (to_real1 (sqrt1 m x17)) (round
+                                           m
+                                           (colibri_sqrt (to_real1 x17))))))) :pattern (
+    (sqrt1
+      m
+      x17)) )))
+
+;; sqrt_finite_rev
+(assert
+  (forall ((m mode) (x17 t))
+    (! (=>
+         (is_finite (sqrt1 m x17))
+         (and
+           (is_finite x17)
+           (and
+             (infix_gteqdt (to_real1 x17) 0.0)
+             (= (to_real1 (sqrt1 m x17)) (round
+                                           m
+                                           (colibri_sqrt (to_real1 x17))))))) :pattern (
+    (sqrt1
+      m
+      x17)) )))
+
+;; same_sign_real
+(define-fun same_sign_real ((x17 t) (r3 Real)) Bool
+  (or
+    (and (is_positive x17) (infix_gtdt r3 0.0))
+    (and (is_negative x17) (infix_lsdt r3 0.0))))
+
+;; same_sign_real_round
+(assert
+  (forall ((x17 t) (m mode) (r3 Real))
+    (! (=> (same_sign_real x17 (round m r3)) (same_sign_real x17 r3)) :pattern (
+    (same_sign_real
+      x17
+      (round m r3))) )))
+
+;; m
+(declare-fun m () mode)
+
+;; x
+(declare-fun x17 () t)
+
+;; x
+(declare-fun x18 () finite)
+
+;; h
+(assert (= x17 (Finite x18)))
+
+;; y
+(declare-fun y () t)
+
+;; x
+(declare-fun x19 () finite)
+
+;; h
+(assert (= y (Finite x19)))
+
+;; r
+(define-fun r3 () t
+  (add m x17 y))
+
+;; h
+(assert (= r3 NaN1))
+
+;; H
+(assert (is_finite x17))
+
+;; H
+(assert (is_finite y))
+
+;; H
+(assert (not (no_overflow m (infix_pldt (to_real1 x17) (to_real1 y)))))
+
+;; h
+(assert (infix_gtdt (round m (infix_pldt (to_real1 x17) (to_real1 y))) 0.0))
+
+;; Goal add_special
+;; File "/home/bobot/Sources/colibrics/src_common/float_interval.mlw", line 609, characters 7-18
+(assert
+  (not
+  (or
+    (and
+      (is_positive r3)
+      (infix_gtdt (round m (infix_pldt (to_real1 x17) (to_real1 y))) 0.0))
+    (and
+      (is_negative r3)
+      (infix_lsdt (round m (infix_pldt (to_real1 x17) (to_real1 y))) 0.0)))))
+
+(check-sat)
diff --git a/src_colibri2/tests/solve/all/unsat/interval-Convexe-exists_memqtvc_2.psmt2 b/src_colibri2/tests/solve/all/unsat/interval-Convexe-exists_memqtvc_2.psmt2
index e0f3e1a2afcb09dc6e8ec61d498529a4f25edc7b..62d325e553fa75a80a623b1e54bbfe7cfd3a31cf 100644
--- a/src_colibri2/tests/solve/all/unsat/interval-Convexe-exists_memqtvc_2.psmt2
+++ b/src_colibri2/tests/solve/all/unsat/interval-Convexe-exists_memqtvc_2.psmt2
@@ -214,66 +214,66 @@
   (=> (not (= den1 0))
   (= (real (make num1 den1)) (/ (to_real num1) (to_real den1))))))
 
-(declare-fun truncate (Real) Int)
-
-;; Truncate_int
-  (assert (forall ((i Int)) (= (truncate (to_real i)) i)))
-
-;; Truncate_down_pos
-  (assert
-  (forall ((x Real))
-  (=> (>= x 0.0)
-  (and (<= (to_real (truncate x)) x) (< x (to_real (+ (truncate x) 1)))))))
-
-;; Truncate_up_neg
-  (assert
-  (forall ((x Real))
-  (=> (<= x 0.0)
-  (and (< (to_real (- (truncate x) 1)) x) (<= x (to_real (truncate x)))))))
-
-;; Real_of_truncate
-  (assert
-  (forall ((x Real))
-  (and (<= (- x 1.0) (to_real (truncate x)))
-  (<= (to_real (truncate x)) (+ x 1.0)))))
-
-;; Truncate_monotonic
-  (assert
-  (forall ((x Real) (y Real)) (=> (<= x y) (<= (truncate x) (truncate y)))))
-
-;; Truncate_monotonic_int1
-  (assert
-  (forall ((x Real) (i Int)) (=> (<= x (to_real i)) (<= (truncate x) i))))
-
-;; Truncate_monotonic_int2
-  (assert
-  (forall ((x Real) (i Int)) (=> (<= (to_real i) x) (<= i (truncate x)))))
-
-;; Floor_int
-  (assert (forall ((i Int)) (= (to_int (to_real i)) i)))
-
-;; Ceil_int
-  (assert (forall ((i Int)) (= (- (to_int (- (to_real i)))) i)))
-
-;; Floor_down
-  (assert
-  (forall ((x Real))
-  (and (<= (to_real (to_int x)) x) (< x (to_real (+ (to_int x) 1))))))
-
-;; Ceil_up
-  (assert
-  (forall ((x Real))
-  (and (< (to_real (- (- (to_int (- x))) 1)) x)
-  (<= x (to_real (- (to_int (- x))))))))
-
-;; Floor_monotonic
-  (assert
-  (forall ((x Real) (y Real)) (=> (<= x y) (<= (to_int x) (to_int y)))))
-
-;; Ceil_monotonic
-  (assert
-  (forall ((x Real) (y Real))
-  (=> (<= x y) (<= (- (to_int (- x))) (- (to_int (- y)))))))
+;; (declare-fun truncate (Real) Int)
+
+;; ;; Truncate_int
+;;   (assert (forall ((i Int)) (= (truncate (to_real i)) i)))
+
+;; ;; Truncate_down_pos
+;;   (assert
+;;   (forall ((x Real))
+;;   (=> (>= x 0.0)
+;;   (and (<= (to_real (truncate x)) x) (< x (to_real (+ (truncate x) 1)))))))
+
+;; ;; Truncate_up_neg
+;;   (assert
+;;   (forall ((x Real))
+;;   (=> (<= x 0.0)
+;;   (and (< (to_real (- (truncate x) 1)) x) (<= x (to_real (truncate x)))))))
+
+;; ;; Real_of_truncate
+;;   (assert
+;;   (forall ((x Real))
+;;   (and (<= (- x 1.0) (to_real (truncate x)))
+;;   (<= (to_real (truncate x)) (+ x 1.0)))))
+
+;; ;; Truncate_monotonic
+;;   (assert
+;;   (forall ((x Real) (y Real)) (=> (<= x y) (<= (truncate x) (truncate y)))))
+
+;; ;; Truncate_monotonic_int1
+;;   (assert
+;;   (forall ((x Real) (i Int)) (=> (<= x (to_real i)) (<= (truncate x) i))))
+
+;; ;; Truncate_monotonic_int2
+;;   (assert
+;;   (forall ((x Real) (i Int)) (=> (<= (to_real i) x) (<= i (truncate x)))))
+
+;; ;; Floor_int
+;;   (assert (forall ((i Int)) (= (to_int (to_real i)) i)))
+
+;; ;; Ceil_int
+;;   (assert (forall ((i Int)) (= (- (to_int (- (to_real i)))) i)))
+
+;; ;; Floor_down
+;;   (assert
+;;   (forall ((x Real))
+;;   (and (<= (to_real (to_int x)) x) (< x (to_real (+ (to_int x) 1))))))
+
+;; ;; Ceil_up
+;;   (assert
+;;   (forall ((x Real))
+;;   (and (< (to_real (- (- (to_int (- x))) 1)) x)
+;;   (<= x (to_real (- (to_int (- x))))))))
+
+;; ;; Floor_monotonic
+;;   (assert
+;;   (forall ((x Real) (y Real)) (=> (<= x y) (<= (to_int x) (to_int y)))))
+
+;; ;; Ceil_monotonic
+;;   (assert
+;;   (forall ((x Real) (y Real))
+;;   (=> (<= x y) (<= (- (to_int (- x))) (- (to_int (- y)))))))
 
 (declare-datatypes ((t2 0))
 (((Strict) (Large))))
diff --git a/src_colibri2/tests/solve/all/unsat/range_loop_invariant_CHECK_preserved_Why3_Colibri2_n_a.psmt2 b/src_colibri2/tests/solve/all/unsat/range_loop_invariant_CHECK_preserved_Why3_Colibri2_n_a.psmt2
new file mode 100644
index 0000000000000000000000000000000000000000..165ff7a4254c9ade85a78accd4072138c09af00d
--- /dev/null
+++ b/src_colibri2/tests/solve/all/unsat/range_loop_invariant_CHECK_preserved_Why3_Colibri2_n_a.psmt2
@@ -0,0 +1,672 @@
+;; produced by local colibri2.drv ;;
+(set-logic ALL)
+(set-info :smt-lib-version 2.6)
+;;; SMT-LIB2: integer arithmetic
+;;; SMT-LIB2: real arithmetic
+(declare-sort string 0)
+
+(declare-datatypes ((tuple0 0))
+  (((Tuple0))))
+
+;; abs
+(define-fun abs1 ((x Int)) Int
+  (ite (>= x 0) x (- x)))
+
+;; Abs_le
+(assert
+  (forall ((x Int) (y Int)) (= (<= (abs1 x) y) (and (<= (- y) x) (<= x y)))))
+
+;; Abs_pos
+(assert (forall ((x Int)) (>= (abs1 x) 0)))
+
+;; div
+(declare-fun div1 (Int
+  Int) Int)
+
+;; mod
+(declare-fun mod1 (Int
+  Int) Int)
+
+;; Div_mod
+(assert
+  (forall ((x Int) (y Int))
+    (=> (not (= y 0)) (= x (+ (* y (div1 x y)) (mod1 x y))))))
+
+;; Div_bound
+(assert
+  (forall ((x Int) (y Int))
+    (=> (and (>= x 0) (> y 0)) (and (<= 0 (div1 x y)) (<= (div1 x y) x)))))
+
+;; Mod_bound
+(assert
+  (forall ((x Int) (y Int))
+    (=>
+      (not (= y 0))
+      (and (< (- (abs1 y)) (mod1 x y)) (< (mod1 x y) (abs1 y))))))
+
+;; Div_sign_pos
+(assert
+  (forall ((x Int) (y Int)) (=> (and (>= x 0) (> y 0)) (>= (div1 x y) 0))))
+
+;; Div_sign_neg
+(assert
+  (forall ((x Int) (y Int)) (=> (and (<= x 0) (> y 0)) (<= (div1 x y) 0))))
+
+;; Mod_sign_pos
+(assert
+  (forall ((x Int) (y Int))
+    (=> (and (>= x 0) (not (= y 0))) (>= (mod1 x y) 0))))
+
+;; Mod_sign_neg
+(assert
+  (forall ((x Int) (y Int))
+    (=> (and (<= x 0) (not (= y 0))) (<= (mod1 x y) 0))))
+
+;; Rounds_toward_zero
+(assert
+  (forall ((x Int) (y Int))
+    (=> (not (= y 0)) (<= (abs1 (* (div1 x y) y)) (abs1 x)))))
+
+;; Div_1
+(assert (forall ((x Int)) (= (div1 x 1) x)))
+
+;; Mod_1
+(assert (forall ((x Int)) (= (mod1 x 1) 0)))
+
+;; Div_inf
+(assert
+  (forall ((x Int) (y Int)) (=> (and (<= 0 x) (< x y)) (= (div1 x y) 0))))
+
+;; Mod_inf
+(assert
+  (forall ((x Int) (y Int)) (=> (and (<= 0 x) (< x y)) (= (mod1 x y) x))))
+
+;; Div_mult
+(assert
+  (forall ((x Int) (y Int) (z Int))
+    (! (=>
+         (and (> x 0) (and (>= y 0) (>= z 0)))
+         (= (div1 (+ (* x y) z) x) (+ y (div1 z x)))) :pattern ((div1
+                                                                  (+ (* x y) z)
+                                                                  x)) )))
+
+;; Mod_mult
+(assert
+  (forall ((x Int) (y Int) (z Int))
+    (! (=>
+         (and (> x 0) (and (>= y 0) (>= z 0)))
+         (= (mod1 (+ (* x y) z) x) (mod1 z x))) :pattern ((mod1
+                                                            (+ (* x y) z)
+                                                            x)) )))
+
+;; add_div
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (=> (not (= z 0.0)) (= (/ (+ x y) z) (+ (/ x z) (/ y z))))))
+
+;; sub_div
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (=> (not (= z 0.0)) (= (/ (- x y) z) (- (/ x z) (/ y z))))))
+
+;; neg_div
+(assert
+  (forall ((x Real) (y Real))
+    (=> (not (= y 0.0)) (= (/ (- x) y) (- (/ x y))))))
+
+;; assoc_mul_div
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (=> (not (= z 0.0)) (= (/ (* x y) z) (* x (/ y z))))))
+
+;; assoc_div_mul
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (=>
+      (and (not (= y 0.0)) (not (= z 0.0)))
+      (= (/ (/ x y) z) (/ x (* y z))))))
+
+;; assoc_div_div
+(assert
+  (forall ((x Real) (y Real) (z Real))
+    (=>
+      (and (not (= y 0.0)) (not (= z 0.0)))
+      (= (/ x (/ y z)) (/ (* x z) y)))))
+
+;; infix +.
+(define-fun infix_pldt ((x Real) (y Real)) Real
+  (+ x y))
+
+;; infix -.
+(define-fun infix_mndt ((x Real) (y Real)) Real
+  (- x y))
+
+;; infix *.
+(define-fun infix_asdt ((x Real) (y Real)) Real
+  (* x y))
+
+;; infix /.
+(define-fun infix_sldt ((x Real) (y Real)) Real
+  (/ x y))
+
+;; prefix -.
+(define-fun prefix_mndt ((x Real)) Real
+  (- x))
+
+;; inv
+(define-fun inv ((x Real)) Real
+  (/ 1.0 x))
+
+;; infix <=.
+(define-fun infix_lseqdt ((x Real) (y Real)) Bool
+  (<= x y))
+
+;; infix >=.
+(define-fun infix_gteqdt ((x Real) (y Real)) Bool
+  (>= x y))
+
+;; infix <.
+(define-fun infix_lsdt ((x Real) (y Real)) Bool
+  (< x y))
+
+;; infix >.
+(define-fun infix_gtdt ((x Real) (y Real)) Bool
+  (> x y))
+
+;; Zero
+(assert (= (to_real 0) 0.0))
+
+;; One
+(assert (= (to_real 1) 1.0))
+
+;; Add
+(assert
+  (forall ((x Int) (y Int))
+    (= (to_real (+ x y)) (+ (to_real x) (to_real y)))))
+
+;; Sub
+(assert
+  (forall ((x Int) (y Int))
+    (= (to_real (- x y)) (- (to_real x) (to_real y)))))
+
+;; Mul
+(assert
+  (forall ((x Int) (y Int))
+    (= (to_real (* x y)) (* (to_real x) (to_real y)))))
+
+;; Neg
+(assert (forall ((x Int)) (= (to_real (- x)) (- (to_real x)))))
+
+;; Injective
+(assert (forall ((x Int) (y Int)) (=> (= (to_real x) (to_real y)) (= x y))))
+
+;; Monotonic
+(assert
+  (forall ((x Int) (y Int)) (=> (<= x y) (<= (to_real x) (to_real y)))))
+
+;; eqb
+(declare-fun eqb (par (a)
+  (a
+  a) Bool))
+
+;; eqb
+(assert (par (a) (forall ((x a) (y a)) (= (= (eqb x y) true) (= x y)))))
+
+;; neqb
+(declare-fun neqb (par (a)
+  (a
+  a) Bool))
+
+;; neqb
+(assert (par (a)
+  (forall ((x a) (y a)) (= (= (neqb x y) true) (not (= x y))))))
+
+;; zlt
+(declare-fun zlt (Int
+  Int) Bool)
+
+;; zleq
+(declare-fun zleq (Int
+  Int) Bool)
+
+;; zlt
+(assert (forall ((x Int) (y Int)) (= (= (zlt x y) true) (< x y))))
+
+;; zleq
+(assert (forall ((x Int) (y Int)) (= (= (zleq x y) true) (<= x y))))
+
+;; rlt
+(declare-fun rlt (Real
+  Real) Bool)
+
+;; rleq
+(declare-fun rleq (Real
+  Real) Bool)
+
+;; rlt
+(assert (forall ((x Real) (y Real)) (= (= (rlt x y) true) (infix_lsdt x y))))
+
+;; rleq
+(assert
+  (forall ((x Real) (y Real)) (= (= (rleq x y) true) (infix_lseqdt x y))))
+
+;; real_of_int
+(define-fun real_of_int ((x Int)) Real
+  (to_real x))
+
+;; c_euclidian
+(assert
+  (forall ((n Int) (d Int))
+    (! (=> (not (= d 0)) (= n (+ (* (div1 n d) d) (mod1 n d)))) :pattern (
+    (div1
+      n
+      d)
+    (mod1 n d)) )))
+
+;; cmod_remainder
+(assert
+  (forall ((n Int) (d Int))
+    (! (and
+         (=> (>= n 0) (=> (> d 0) (and (<= 0 (mod1 n d)) (< (mod1 n d) d))))
+         (and
+           (=>
+             (<= n 0)
+             (=> (> d 0) (and (< (- d) (mod1 n d)) (<= (mod1 n d) 0))))
+           (and
+             (=>
+               (>= n 0)
+               (=> (< d 0) (and (<= 0 (mod1 n d)) (< (mod1 n d) (- d)))))
+             (=>
+               (<= n 0)
+               (=> (< d 0) (and (< d (mod1 n d)) (<= (mod1 n d) 0))))))) :pattern (
+    (mod1
+      n
+      d)) )))
+
+;; cdiv_neutral
+(assert (forall ((a1 Int)) (! (= (div1 a1 1) a1) :pattern ((div1 a1 1)) )))
+
+;; cdiv_inv
+(assert
+  (forall ((a1 Int))
+    (! (=> (not (= a1 0)) (= (div1 a1 a1) 1)) :pattern ((div1 a1 a1)) )))
+
+;; cdiv_closed_remainder
+(assert
+  (forall ((a1 Int) (b Int) (n Int))
+    (=>
+      (<= 0 a1)
+      (=>
+        (<= 0 b)
+        (=>
+          (and (<= 0 (- b a1)) (< (- b a1) n))
+          (=> (= (mod1 a1 n) (mod1 b n)) (= a1 b)))))))
+
+(declare-sort infix_mngt 2)
+
+;; infix @
+(declare-fun infix_at (par (a1
+  b)
+  ((infix_mngt a1
+  b)
+  a1) b))
+
+;; get
+(define-fun get (par (a
+  b1)
+  ((f (infix_mngt a b1)) (x a)) b1
+  (infix_at f x)))
+
+;; set
+(declare-fun set (par (a
+  b1)
+  ((infix_mngt a
+  b1)
+  a
+  b1) (infix_mngt a
+  b1)))
+
+;; set'def
+(assert (par (a b1)
+  (forall ((f (infix_mngt a b1)) (x a) (v b1) (y a))
+    (= (infix_at (set f x v) y) (ite (= y x) v (infix_at f y))))))
+
+;; mixfix []
+(define-fun mixfix_lbrb (par (a
+  b1)
+  ((f (infix_mngt a b1)) (x a)) b1
+  (infix_at f x)))
+
+;; mixfix [<-]
+(define-fun mixfix_lblsmnrb (par (a
+  b1)
+  ((f (infix_mngt a b1)) (x a) (v b1)) (infix_mngt a b1)
+  (set f x v)))
+
+(declare-datatypes ((Init_S1_S 0))
+  (((Init_S1_S1 (Init_F1_S_i Bool)(Init_F1_S_a (infix_mngt Int Bool))))))
+
+(declare-datatypes ((S1_S 0))
+  (((S1_S1 (F1_S_i Int)(F1_S_a (infix_mngt Int Int))))))
+
+;; max_uint8
+(define-fun max_uint8 () Int
+  256)
+
+;; max_sint8
+(define-fun max_sint8 () Int
+  128)
+
+;; max_uint16
+(define-fun max_uint16 () Int
+  65536)
+
+;; max_sint16
+(define-fun max_sint16 () Int
+  32768)
+
+;; max_uint32
+(define-fun max_uint32 () Int
+  4294967296)
+
+;; max_sint32
+(define-fun max_sint32 () Int
+  2147483648)
+
+;; max_uint64
+(define-fun max_uint64 () Int
+  18446744073709551616)
+
+;; max_sint64
+(define-fun max_sint64 () Int
+  9223372036854775808)
+
+;; is_bool
+(define-fun is_bool ((x Int)) Bool
+  (or (= x 0) (= x 1)))
+
+;; is_uint8
+(declare-fun is_uint8 (Int) Bool)
+
+;; is_uint8_def
+(assert
+  (forall ((x Int))
+    (! (= (is_uint8 x) (and (<= 0 x) (< x max_uint8))) :pattern ((is_uint8 x)) )))
+
+;; is_sint8
+(declare-fun is_sint8 (Int) Bool)
+
+;; is_sint8_def
+(assert
+  (forall ((x Int))
+    (! (= (is_sint8 x) (and (<= (- max_sint8) x) (< x max_sint8))) :pattern (
+    (is_sint8
+      x)) )))
+
+;; is_uint16
+(declare-fun is_uint16 (Int) Bool)
+
+;; is_uint16_def
+(assert
+  (forall ((x Int))
+    (! (= (is_uint16 x) (and (<= 0 x) (< x max_uint16))) :pattern ((is_uint16
+                                                                    x)) )))
+
+;; is_sint16
+(define-fun is_sint16 ((x Int)) Bool
+  (and (<= (- max_sint16) x) (< x max_sint16)))
+
+;; is_uint32
+(declare-fun is_uint32 (Int) Bool)
+
+;; is_uint32_def
+(assert
+  (forall ((x Int))
+    (! (= (is_uint32 x) (and (<= 0 x) (< x max_uint32))) :pattern ((is_uint32
+                                                                    x)) )))
+
+;; is_sint32
+(declare-fun is_sint32 (Int) Bool)
+
+;; is_sint32_def
+(assert
+  (forall ((x Int))
+    (! (= (is_sint32 x) (and (<= (- max_sint32) x) (< x max_sint32))) :pattern (
+    (is_sint32
+      x)) )))
+
+;; is_uint64
+(declare-fun is_uint64 (Int) Bool)
+
+;; is_uint64_def
+(assert
+  (forall ((x Int))
+    (! (= (is_uint64 x) (and (<= 0 x) (< x max_uint64))) :pattern ((is_uint64
+                                                                    x)) )))
+
+;; is_sint64
+(declare-fun is_sint64 (Int) Bool)
+
+;; is_sint64_def
+(assert
+  (forall ((x Int))
+    (! (= (is_sint64 x) (and (<= (- max_sint64) x) (< x max_sint64))) :pattern (
+    (is_sint64
+      x)) )))
+
+;; is_bool0
+(assert (is_bool 0))
+
+;; is_bool1
+(assert (is_bool 1))
+
+;; to_bool
+(define-fun to_bool ((x Int)) Int
+  (ite (= x 0) 0 1))
+
+;; to_uint8
+(declare-fun to_uint8 (Int) Int)
+
+;; to_sint8
+(declare-fun to_sint8 (Int) Int)
+
+;; to_uint16
+(declare-fun to_uint16 (Int) Int)
+
+;; to_sint16
+(declare-fun to_sint16 (Int) Int)
+
+;; to_uint32
+(declare-fun to_uint32 (Int) Int)
+
+;; to_sint32
+(declare-fun to_sint32 (Int) Int)
+
+;; to_uint64
+(declare-fun to_uint64 (Int) Int)
+
+;; to_sint64
+(declare-fun to_sint64 (Int) Int)
+
+;; two_power_abs
+(declare-fun two_power_abs (Int) Int)
+
+;; is_uint
+(define-fun is_uint ((n Int) (x Int)) Bool
+  (and (<= 0 x) (< x (two_power_abs n))))
+
+;; is_sint
+(define-fun is_sint ((n Int) (x Int)) Bool
+  (and (<= (- (two_power_abs n)) x) (< x (two_power_abs n))))
+
+;; to_uint
+(declare-fun to_uint (Int
+  Int) Int)
+
+;; to_sint
+(declare-fun to_sint (Int
+  Int) Int)
+
+;; is_to_uint8
+(assert (forall ((x Int)) (is_uint8 (to_uint8 x))))
+
+;; is_to_sint8
+(assert (forall ((x Int)) (is_sint8 (to_sint8 x))))
+
+;; is_to_uint16
+(assert (forall ((x Int)) (is_uint16 (to_uint16 x))))
+
+;; is_to_sint16
+(assert (forall ((x Int)) (is_sint16 (to_sint16 x))))
+
+;; is_to_uint32
+(assert (forall ((x Int)) (is_uint32 (to_uint32 x))))
+
+;; is_to_sint32
+(assert (forall ((x Int)) (is_sint32 (to_sint32 x))))
+
+;; is_to_uint64
+(assert (forall ((x Int)) (is_uint64 (to_uint64 x))))
+
+;; is_to_sint64
+(assert (forall ((x Int)) (is_sint64 (to_sint64 x))))
+
+;; id_uint8
+(assert
+  (forall ((x Int))
+    (! (=> (and (<= 0 x) (< x max_uint8)) (= (to_uint8 x) x)) :pattern (
+    (to_uint8
+      x)) )))
+
+;; id_sint8
+(assert
+  (forall ((x Int))
+    (! (=> (and (<= (- max_sint8) x) (< x max_sint8)) (= (to_sint8 x) x)) :pattern (
+    (to_sint8
+      x)) )))
+
+;; id_uint16
+(assert
+  (forall ((x Int))
+    (! (=> (and (<= 0 x) (< x max_uint16)) (= (to_uint16 x) x)) :pattern (
+    (to_uint16
+      x)) )))
+
+;; id_sint16
+(assert
+  (forall ((x Int))
+    (! (=> (and (<= (- max_sint16) x) (< x max_sint16)) (= (to_sint16 x) x)) :pattern (
+    (to_sint16
+      x)) )))
+
+;; id_uint32
+(assert
+  (forall ((x Int))
+    (! (=> (and (<= 0 x) (< x max_uint32)) (= (to_uint32 x) x)) :pattern (
+    (to_uint32
+      x)) )))
+
+;; id_sint32
+(assert
+  (forall ((x Int))
+    (! (=> (and (<= (- max_sint32) x) (< x max_sint32)) (= (to_sint32 x) x)) :pattern (
+    (to_sint32
+      x)) )))
+
+;; id_uint64
+(assert
+  (forall ((x Int))
+    (! (=> (and (<= 0 x) (< x max_uint64)) (= (to_uint64 x) x)) :pattern (
+    (to_uint64
+      x)) )))
+
+;; id_sint64
+(assert
+  (forall ((x Int))
+    (! (=> (and (<= (- max_sint64) x) (< x max_sint64)) (= (to_sint64 x) x)) :pattern (
+    (to_sint64
+      x)) )))
+
+;; proj_int8
+(assert
+  (forall ((x Int))
+    (! (= (to_sint8 (to_uint8 x)) (to_sint8 x)) :pattern ((to_sint8
+                                                            (to_uint8 x))) )))
+
+;; proj_int16
+(assert
+  (forall ((x Int))
+    (! (= (to_sint16 (to_uint16 x)) (to_sint16 x)) :pattern ((to_sint16
+                                                               (to_uint16 x))) )))
+
+;; proj_int32
+(assert
+  (forall ((x Int))
+    (! (= (to_sint32 (to_uint32 x)) (to_sint32 x)) :pattern ((to_sint32
+                                                               (to_uint32 x))) )))
+
+;; proj_int64
+(assert
+  (forall ((x Int))
+    (! (= (to_sint64 (to_uint64 x)) (to_sint64 x)) :pattern ((to_sint64
+                                                               (to_uint64 x))) )))
+
+;; Goal wp_goal
+(assert
+  (not
+  (forall ((S Init_S1_S) (i Int) (i1 Int) (S1 S1_S) (t (infix_mngt Int Bool)) (t1 (infix_mngt Int Int)))
+    (let ((a2 (Init_F1_S_a S)))
+      (=>
+        (= (F1_S_i S1) 0)
+        (=>
+          (< 0 i1)
+          (=>
+            (<= 0 i)
+            (=>
+              (<= i1 4)
+              (=>
+                (<= i1 9)
+                (=>
+                  (<= 10 i)
+                  (=>
+                    (<= i 10)
+                    (=>
+                      (is_sint32 i1)
+                      (=>
+                        (is_sint32 i)
+                        (=>
+                          (= (Init_F1_S_i S) true)
+                          (=>
+                            (=>
+                              (< 0 i)
+                              (forall ((i2 Int))
+                                (=>
+                                  (<= 0 i2)
+                                  (=> (< i2 i) (= (get t i2) true)))))
+                            (=>
+                              (forall ((i2 Int))
+                                (=>
+                                  (<= 0 i2)
+                                  (=> (<= i2 9) (= (get t i2) true))))
+                              (=>
+                                (forall ((i2 Int))
+                                  (=>
+                                    (<= 0 i2)
+                                    (=> (<= i2 9) (= (get a2 i2) true))))
+                                (=>
+                                  (forall ((i2 Int))
+                                    (=>
+                                      (<= 0 i2)
+                                      (=>
+                                        (<= i2 9)
+                                        (=>
+                                          (or (<= i2 0) (<= 5 i2))
+                                          (= (get (F1_S_a S1) i2) (get t1 i2))))))
+                                  (forall ((i2 Int))
+                                    (=>
+                                      (<= 0 i2)
+                                      (=>
+                                        (<= i2 9)
+                                        (= (get (set a2 i1 true) i2) true))))))))))))))))))))))
+
+(check-sat)
diff --git a/src_colibri2/tests/solve/all/unsat/range_loop_invariant_CHECK_preserved_Why3_Colibri2_n_a_simplified.psmt2 b/src_colibri2/tests/solve/all/unsat/range_loop_invariant_CHECK_preserved_Why3_Colibri2_n_a_simplified.psmt2
new file mode 100644
index 0000000000000000000000000000000000000000..65d2ea3b02d2a8ba9a43e7cfec2daa4f5dc9f52d
--- /dev/null
+++ b/src_colibri2/tests/solve/all/unsat/range_loop_invariant_CHECK_preserved_Why3_Colibri2_n_a_simplified.psmt2
@@ -0,0 +1,51 @@
+;; simplified version of a WP VC, the full one is next to it ;;
+(set-logic ALL)
+(declare-sort infix_mngt 2)
+
+;; infix @
+(declare-fun infix_at (par (a1
+  b)
+  ((infix_mngt a1
+  b)
+  a1) b))
+
+;; get
+(define-fun get (par (a
+  b1)
+  ((f (infix_mngt a b1)) (x a)) b1
+  (infix_at f x)))
+
+;; set
+(declare-fun set (par (a
+  b1)
+  ((infix_mngt a
+  b1)
+  a
+  b1) (infix_mngt a
+  b1)))
+
+;; set'def
+(assert (par (a b1)
+  (forall ((f (infix_mngt a b1)) (x a) (v b1) (y a))
+    (= (infix_at (set f x v) y) (ite (= y x) v (infix_at f y))))))
+
+(declare-datatypes ((Init_S1_S 0))
+  (((Init_S1_S1 (Init_F1_S_i Bool)(Init_F1_S_a (infix_mngt Int Bool))))))
+
+(assert
+  (not
+  (forall ((S Init_S1_S) (i1 Int))
+    (let ((a2 (Init_F1_S_a S)))
+    (=>
+    (forall ((i2 Int))
+    (=>
+    (<= 0 i2)
+    (=> (<= i2 9) (= (get a2 i2) true))))
+    (forall ((i2 Int))
+    (=>
+    (<= 0 i2)
+    (=>
+    (<= i2 9)
+    (= (get (set a2 i1 true) i2) true)))))))))
+
+(check-sat)
diff --git a/src_colibri2/tests/solve/all/unsat/union-Union-interqtvc_10.psmt2 b/src_colibri2/tests/solve/all/unsat/union-Union-interqtvc_10.psmt2
index bd1131159f0eeaacbd0021e4559f0d2e9fc55613..965632576e3d90ba6e55110201466ecdc445ac94 100644
--- a/src_colibri2/tests/solve/all/unsat/union-Union-interqtvc_10.psmt2
+++ b/src_colibri2/tests/solve/all/unsat/union-Union-interqtvc_10.psmt2
@@ -1,7 +1,7 @@
 ;; produced by local colibri2.drv ;;
 (set-logic ALL)
 (set-info :smt-lib-version 2.6)
-(set-option :max-steps-colibri2 10000)
+(set-option :max-steps-colibri2 30000)
 ;;; SMT-LIB2: integer arithmetic
 ;;; SMT-LIB2: real arithmetic
 (declare-sort string 0)
diff --git a/src_colibri2/tests/solve/all/unsat/work_with_fourier_not_simplex2.psmt2 b/src_colibri2/tests/solve/all/unsat/work_with_fourier_not_simplex2.psmt2
index ce7b27a36cedef1ff8c8b5e9c3f8b4f25a53f95a..2119077046b0d362bb8aa55f7a0982512d3ecd6b 100644
--- a/src_colibri2/tests/solve/all/unsat/work_with_fourier_not_simplex2.psmt2
+++ b/src_colibri2/tests/solve/all/unsat/work_with_fourier_not_simplex2.psmt2
@@ -269,70 +269,70 @@
       (= (real (make num1 den1)) (/ (to_real num1) (to_real den1))))))
 
 ;; truncate
-(declare-fun truncate (Real) Int)
+;;(declare-fun truncate (Real) Int)
 
 ;; Truncate_int
-(assert (forall ((i Int)) (= (truncate (to_real i)) i)))
+;;(assert (forall ((i Int)) (= (truncate (to_real i)) i)))
 
 ;; Truncate_down_pos
-(assert
-  (forall ((x Real))
-    (=>
-      (>= x 0.0)
-      (and (<= (to_real (truncate x)) x) (< x (to_real (+ (truncate x) 1)))))))
+;;;; (assert
+;;;;   (forall ((x Real))
+;;;;     (=>
+;;;;       (>= x 0.0)
+;;;;       (and (<= (to_real (truncate x)) x) (< x (to_real (+ (truncate x) 1)))))))
 
 ;; Truncate_up_neg
-(assert
-  (forall ((x Real))
-    (=>
-      (<= x 0.0)
-      (and (< (to_real (- (truncate x) 1)) x) (<= x (to_real (truncate x)))))))
-
-;; Real_of_truncate
-(assert
-  (forall ((x Real))
-    (and
-      (<= (- x 1.0) (to_real (truncate x)))
-      (<= (to_real (truncate x)) (+ x 1.0)))))
-
-;; Truncate_monotonic
-(assert
-  (forall ((x Real) (y Real)) (=> (<= x y) (<= (truncate x) (truncate y)))))
+;; (assert
+;;   (forall ((x Real))
+;;     (=>
+;;       (<= x 0.0)
+;;       (and (< (to_real (- (truncate x) 1)) x) (<= x (to_real (truncate x)))))))
+
+;;;; ;; Real_of_truncate
+;;;; (assert
+;;;;   (forall ((x Real))
+;;;;     (and
+;;;;       (<= (- x 1.0) (to_real (truncate x)))
+;;;;       (<= (to_real (truncate x)) (+ x 1.0)))))
+
+;;;; ;; Truncate_monotonic
+;;;; (assert
+;;;;   (forall ((x Real) (y Real)) (=> (<= x y) (<= (truncate x) (truncate y)))))
 
 ;; Truncate_monotonic_int1
-(assert
-  (forall ((x Real) (i Int)) (=> (<= x (to_real i)) (<= (truncate x) i))))
-
-;; Truncate_monotonic_int2
-(assert
-  (forall ((x Real) (i Int)) (=> (<= (to_real i) x) (<= i (truncate x)))))
-
-;; Floor_int
-(assert (forall ((i Int)) (= (to_int (to_real i)) i)))
-
-;; Ceil_int
-(assert (forall ((i Int)) (= (- (to_int (- (to_real i)))) i)))
-
-;; Floor_down
-(assert
-  (forall ((x Real))
-    (and (<= (to_real (to_int x)) x) (< x (to_real (+ (to_int x) 1))))))
-
-;; Ceil_up
-(assert
-  (forall ((x Real))
-    (and
-      (< (to_real (- (- (to_int (- x))) 1)) x)
-      (<= x (to_real (- (to_int (- x))))))))
-
-;; Floor_monotonic
-(assert
-  (forall ((x Real) (y Real)) (=> (<= x y) (<= (to_int x) (to_int y)))))
-
-;; Ceil_monotonic
-(assert
-  (forall ((x Real) (y Real))
-    (=> (<= x y) (<= (- (to_int (- x))) (- (to_int (- y)))))))
+;; (assert
+;;   (forall ((x Real) (i Int)) (=> (<= x (to_real i)) (<= (truncate x) i))))
+
+;;;; ;; Truncate_monotonic_int2
+;;;; (assert
+;;;;   (forall ((x Real) (i Int)) (=> (<= (to_real i) x) (<= i (truncate x)))))
+
+;;;; ;; Floor_int
+;;;; (assert (forall ((i Int)) (= (to_int (to_real i)) i)))
+
+;;;; ;; Ceil_int
+;;;; (assert (forall ((i Int)) (= (- (to_int (- (to_real i)))) i)))
+
+;;;; ;; Floor_down
+;;;; (assert
+;;;;   (forall ((x Real))
+;;;;     (and (<= (to_real (to_int x)) x) (< x (to_real (+ (to_int x) 1))))))
+
+;;;; ;; Ceil_up
+;;;; (assert
+;;;;   (forall ((x Real))
+;;;;     (and
+;;;;       (< (to_real (- (- (to_int (- x))) 1)) x)
+;;;;       (<= x (to_real (- (to_int (- x))))))))
+
+;;;; ;; Floor_monotonic
+;;;; (assert
+;;;;   (forall ((x Real) (y Real)) (=> (<= x y) (<= (to_int x) (to_int y)))))
+
+;;;; ;; Ceil_monotonic
+;;;; (assert
+;;;;   (forall ((x Real) (y Real))
+;;;;     (=> (<= x y) (<= (- (to_int (- x))) (- (to_int (- y)))))))
 
 (declare-datatypes ((t2 0))
   (((Strict) (Large))))
diff --git a/src_colibri2/theories/ADT/adt.ml b/src_colibri2/theories/ADT/adt.ml
index cef2681da0c81e999a7294f1f4aaaed16c968c0f..a2a97564c5ebfd7d8724720ce1500f9d13c865f6 100644
--- a/src_colibri2/theories/ADT/adt.ml
+++ b/src_colibri2/theories/ADT/adt.ml
@@ -122,8 +122,12 @@ let converter d (f : Ground.t) =
    app = { builtin = Expr.Destructor { case; field; adt; _ }; _ };
    args;
    tyargs;
+   ty;
    _;
   } ->
+      (* not completely satisfactory but needed, it is not yet clear who has the responsibility of choice for booleans *)
+      if Ground.Ty.(equal ty bool) then
+        Choice.register_thterm d (Ground.thterm f) (Boolean.chobool r);
       let case = case_of_int case in
       let field = field_of_int field in
       let adt = Option.value_exn (Adt_value.MonoAdt.index adt tyargs) in
diff --git a/src_colibri2/theories/LRA/delta.ml b/src_colibri2/theories/LRA/delta.ml
index 130c89299f8f0432bdaeb09c1e2e58f0e61b0c61..eb67f3ca68bb5787d4dd47ae5869a2c0224c7c5f 100644
--- a/src_colibri2/theories/LRA/delta.ml
+++ b/src_colibri2/theories/LRA/delta.ml
@@ -65,7 +65,7 @@ let ta = Expr.Term.of_var a
 
 let floor_pattern =
   (* Other floor functions? *)
-  Colibri2_theories_quantifiers.Pattern.of_term ~subst:Ground.Subst.empty
+  Colibri2_theories_quantifiers.Pattern.of_term_exn ~subst:Ground.Subst.empty
     (Expr.Term.Real.floor_to_int ta)
 
 (* let ceiling_patterns =
@@ -73,7 +73,7 @@ let floor_pattern =
  *     (Expr.Term.Real.ceiling ta) *)
 
 let ceiling_pattern =
-  Colibri2_theories_quantifiers.Pattern.of_term ~subst:Ground.Subst.empty
+  Colibri2_theories_quantifiers.Pattern.of_term_exn ~subst:Ground.Subst.empty
     (Expr.Term.Int.minus
        (Expr.Term.Real.floor_to_int (Expr.Term.Real.minus ta)))
 
diff --git a/src_colibri2/theories/LRA/dom_interval.ml b/src_colibri2/theories/LRA/dom_interval.ml
index a3f80025160209441b3d79c78692364b31d01a5e..e20db442b859c76ab3dd5d21d97dd4eb874a72b6 100644
--- a/src_colibri2/theories/LRA/dom_interval.ml
+++ b/src_colibri2/theories/LRA/dom_interval.ml
@@ -266,6 +266,22 @@ module Propagate = struct
     | { app = { builtin = Expr.Gt }; tyargs = []; args; _ } ->
         let a, b = IArray.extract2_exn args in
         cmp d `Gt ~r ~a ~b
+    | {
+     app =
+       {
+         builtin = Expr.Floor | Expr.Ceiling | Expr.Floor_to_int | Expr.Truncate;
+       };
+     tyargs = [];
+     args;
+     _;
+    } ->
+        let a = IArray.extract1_exn args in
+        upd_dom d r D.integers;
+        attach d
+          (exec
+             (fun d -> Egraph.merge d a r)
+             (let+ va = get a in
+              D.is_integer va))
     | { app = { builtin = Expr.Equal }; tyargs = _; args; _ } ->
         if IArray.length args = 2 then (
           let a, b = IArray.extract2_exn args in
diff --git a/src_colibri2/theories/LRA/dom_product.ml b/src_colibri2/theories/LRA/dom_product.ml
index 4ce380cdd07b2e8549111296bc76f1661fd339ef..7da8bbdfc2da0b01e5aa778b15d0a75e26a49284 100644
--- a/src_colibri2/theories/LRA/dom_product.ml
+++ b/src_colibri2/theories/LRA/dom_product.ml
@@ -335,7 +335,8 @@ let converter d (f : Ground.t) =
             (* a = res ^ 2 *)
             SolveAbs.assume_equality d a
               (Product.of_list A.one [ (res, Q.two) ]);
-            SolveSign.assume_equality d res Sign_product.one))
+            (* sign res = sign a (don't forget 0 case) *)
+            SolveSign.assume_equality d res (Sign_product.of_one_node a)))
   | { app = { builtin = Expr.Add }; tyargs = []; args; _ } ->
       let a, b = IArray.extract2_exn args in
       reg a;
diff --git a/src_colibri2/theories/LRA/realValue.ml b/src_colibri2/theories/LRA/realValue.ml
index 47e6350781509cdf4782ffe496b14ca625caef6e..65b85afd0c4c67d6f7c0c94ab95c0b895a1ac24e 100644
--- a/src_colibri2/theories/LRA/realValue.ml
+++ b/src_colibri2/theories/LRA/realValue.ml
@@ -60,6 +60,16 @@ module Builtin = struct
       (Dolmen_std.Path.global "colibri_floor")
       (Expr.Ty.arrow [ Expr.Ty.real ] Expr.Ty.real)
 
+  let colibri_truncate =
+    Expr.Id.mk ~name:"colibri_truncate" ~builtin:Expr.Truncate
+      (Dolmen_std.Path.global "colibri_truncate")
+      (Expr.Ty.arrow [ Expr.Ty.real ] Expr.Ty.real)
+
+  let colibri_truncate_to_int =
+    Expr.Id.mk ~name:"colibri_truncate_to_int" ~builtin:Expr.Truncate
+      (Dolmen_std.Path.global "colibri_truncate_to_int")
+      (Expr.Ty.arrow [ Expr.Ty.real ] Expr.Ty.int)
+
   let colibri_sqrt =
     Expr.Id.mk ~name:"colibri_sqrt" ~builtin:Sqrt
       (Dolmen_std.Path.global "colibri_sqrt")
@@ -136,6 +146,14 @@ module Builtin = struct
             app2 env s colibri_cdiv
         | Dolmen_loop.Typer.T.Id { ns = Term; name = Simple "colibri_ceil" } ->
             app1 env s colibri_ceil
+        | Dolmen_loop.Typer.T.Id { ns = Term; name = Simple "colibri_floor" } ->
+            app1 env s colibri_floor
+        | Dolmen_loop.Typer.T.Id { ns = Term; name = Simple "colibri_truncate" }
+          ->
+            app1 env s colibri_truncate
+        | Dolmen_loop.Typer.T.Id
+            { ns = Term; name = Simple "colibri_truncate_to_int" } ->
+            app1 env s colibri_truncate_to_int
         | Dolmen_loop.Typer.T.Id { ns = Term; name = Simple "colibri_sqrt" } ->
             app1 env s colibri_sqrt
         | Dolmen_loop.Typer.T.Id { ns = Term; name = Simple "colibri_crem" } ->
@@ -373,6 +391,9 @@ module Check = struct
     | { app = { builtin = Expr.Floor }; tyargs = []; args; _ } ->
         let a = IArray.extract1_exn args in
         !<(A.floor !>a)
+    | { app = { builtin = Expr.Truncate }; tyargs = []; args; _ } ->
+        let a = IArray.extract1_exn args in
+        !<(A.truncate !>a)
     | { app = { builtin = Builtin.Sqrt }; tyargs = []; args; _ } ->
         let a = IArray.extract1_exn args in
         let a = !>a in
@@ -899,13 +920,66 @@ let converter d (f : Ground.t) =
       Check.attach d f
   | _ -> ()
 
+module Quantifier_skipped = struct
+  open Colibri2_theories_quantifiers.Quantifier.Quantifier_skipped
+
+  let coercion a = App (Expr.Coercion, [ TyAny; TyAny ], [ a ])
+  let to_int a = App (Expr.Floor_to_int, [], [ a ])
+  let equal a b = App (Expr.Equal, [ TyAny ], [ a; b ])
+  let le a b = App (Expr.Leq, [], [ a; b ])
+  let imply a b = App (Expr.Imply, [], [ a; b ])
+  let op op a b = App (op, [], [ a; b ])
+  let minus a = App (Expr.Minus, [], [ a ])
+  let x = 1
+  let y = 2
+
+  let filters : filter_quant list =
+    [
+      {
+        vars = [ x; y ];
+        filter =
+          (let x = Var x and y = Var y in
+           let morphism f =
+             equal (coercion (op f x y)) (op f (coercion x) (coercion y))
+           in
+           Choice
+             [
+               imply (equal (coercion x) (coercion y)) (equal x y);
+               imply (le x y) (le (coercion x) (coercion y));
+               (* imply (le x y) (le (to_int x) (to_int y)); *)
+               morphism Expr.Mul;
+               morphism Expr.Sub;
+               morphism Expr.Add;
+             ]);
+      };
+      {
+        vars = [ x ];
+        filter =
+          (let x = Var x in
+           Choice
+             [
+               equal (coercion (minus x)) (minus (coercion x));
+               equal (to_int (coercion x)) x;
+             ]);
+      };
+    ]
+
+  let register (q : Ground.ClosedQuantifier.s) = List.exists (match_ q) filters
+end
+
+let keep_relations =
+  Options.register ~pp:Fmt.bool "LRA.keep_relations"
+    Cmdliner.Arg.(
+      value & flag & info [ "lra-keep-relations-in-patterns" ] ~doc:"")
+
 let init env =
   Ground.register_converter env converter;
   init_ty env;
-  Check.init env
-
-let () =
-  Colibri2_theories_quantifiers.Trigger.register_builtin_skipped_for_trigger
+  Check.init env;
+  Colibri2_theories_quantifiers.Info.Builtin_skipped_for_trigger.register env
     (function
-    | Expr.Leq | Expr.Geq | Expr.Lt | Expr.Gt | Expr.Equal -> true
-    | _ -> false)
+    | Expr.Leq | Expr.Geq | Expr.Lt | Expr.Gt | Expr.Equal ->
+        not (Options.get env keep_relations)
+    | _ -> false);
+  Colibri2_theories_quantifiers.Quantifier.Quantifier_skipped.register env
+    Quantifier_skipped.register
diff --git a/src_colibri2/theories/LRA/simplex.ml b/src_colibri2/theories/LRA/simplex.ml
index cd582e8806071b0be468844e2e99c3fb623a01b8..65455483346ff7c34dc02f633541bf5a66eb6465 100644
--- a/src_colibri2/theories/LRA/simplex.ml
+++ b/src_colibri2/theories/LRA/simplex.ml
@@ -24,9 +24,6 @@ open Base
 
 let comparisons = Datastructure.Push.create Node.pp "LRA.simplex.comparisons"
 
-let scheduled =
-  Datastructure.Ref.create Base.Bool.pp "LRA.simplex.scheduled" false
-
 let debug =
   Debug.register_info_flag ~desc:"Reasoning about <= < in LRA" "simplex"
 
@@ -377,7 +374,6 @@ let update_domains d env =
 let simplex (d : Egraph.wt) =
   Debug.dprintf0 debug "[Simplex]";
   Debug.incr stats_run;
-  Datastructure.Ref.set scheduled d false;
   let eqs, vars =
     Datastructure.Push.fold comparisons d ~f:(make_equations d)
       ~init:(Polynome.H.create 10, Node.S.empty)
@@ -443,33 +439,53 @@ let simplex (d : Egraph.wt) =
 
 let simplex d = Debug.add_time_during stats_time (fun () -> simplex d)
 
-module DaemonSimplex = struct
-  let key =
-    Events.Dem.create
-      (module struct
-        type t = unit
+module DaemonSimplex : sig
+  val enqueue : _ Egraph.t -> _ -> Events.enqueue
+  val enqueue' : _ Egraph.t -> unit
+end = struct
+  module DaemonSimplex = struct
+    let key =
+      Events.Dem.create
+        (module struct
+          type t = unit
 
-        let name = "LRA.simplex"
-      end)
+          let name = "LRA.simplex"
+        end)
 
-  let enqueue d _ =
-    if Datastructure.Ref.get scheduled d then (
-      Debug.dprintf0 debug "[Scheduler] Simplex? No";
-      Events.EnqAlready)
-    else (
-      Debug.dprintf0 debug "[Scheduler] Simplex? Yes";
-      Datastructure.Ref.set scheduled d true;
-      Events.EnqRun (key, (), None))
+    let scheduled =
+      Datastructure.Ref.create Base.Bool.pp "LRA.simplex.scheduled" false
 
-  let delay = Events.Delayed_by 64
+    let enqueue_aux d =
+      if Datastructure.Ref.get scheduled d then (
+        Debug.dprintf0 debug "[Scheduler] Simplex? No";
+        false)
+      else (
+        Debug.dprintf0 debug "[Scheduler] Simplex? Yes";
+        Datastructure.Ref.set scheduled d true;
+        true)
 
-  type runable = unit
+    let enqueue d _ =
+      if enqueue_aux d then Events.EnqRun (key, (), None) else Events.EnqAlready
 
-  let print_runable = Unit.pp
-  let run d () = simplex d
-end
+    let delay = Events.Delayed_by 64
+
+    type runable = unit
+
+    let print_runable = Unit.pp
 
-let () = Events.register (module DaemonSimplex)
+    let run d () =
+      Debug.dprintf0 debug "[Scheduler] Simplex? Run";
+      Datastructure.Ref.set scheduled d false;
+      simplex d
+  end
+
+  let () = Events.register (module DaemonSimplex)
+  let enqueue = DaemonSimplex.enqueue
+
+  let enqueue' d =
+    if DaemonSimplex.enqueue_aux d then
+      Events.new_pending_daemon d DaemonSimplex.key ()
+end
 
 let ord_inv = function
   | Expr.Lt -> Expr.Gt
@@ -543,7 +559,7 @@ let converter d (f : Ground.t) =
         Events.attach_dom d n Dom_interval.dom DaemonSimplex.enqueue;
 
         Datastructure.Push.push comparisons d n;
-        Events.new_pending_daemon d DaemonSimplex.key ())
+        DaemonSimplex.enqueue' d)
   | _ -> ()
 
 let init env = Ground.register_converter env converter
diff --git a/src_colibri2/theories/quantifier/InvertedPath.ml b/src_colibri2/theories/quantifier/InvertedPath.ml
index a499059856b701b290f23e7f36dc25a781d03b87..ecac633da29b51cf28af3549187ca9c7286c96ec 100644
--- a/src_colibri2/theories/quantifier/InvertedPath.ml
+++ b/src_colibri2/theories/quantifier/InvertedPath.ml
@@ -30,6 +30,7 @@ open Common
 
 type t' = {
   triggers : Trigger.t list;  (** triggers reached *)
+  callbacks : Callback.t list;  (** generic triggers *)
   matches : t Pattern.M.t;
       (** Pattern to match the node against next top down *)
   any_matches : t Pattern.M.t;
@@ -45,30 +46,60 @@ type t' = {
 }
 (** All the alternative path to continue in parallel *)
 
-and t = t' Context.Ref.t [@@deriving show]
+and t = { id : int; r : t' Context.Ref.t } [@@deriving show]
 
-let create creator =
-  Context.Ref.create creator
+include (
+  Popop_stdlib.MakeMSH (struct
+    type nonrec t = t
+
+    let tag t = t.id
+    let pp = pp
+  end) :
+    Popop_stdlib.Datatype with type t := t)
+
+let create =
+  let get_counter, incr_counter = Util.get_counter () in
+  fun creator ->
+    incr_counter ();
     {
-      matches = Pattern.M.empty;
-      any_matches = Pattern.M.empty;
-      triggers = [];
-      ups = F_Pos.M.empty;
+      id = get_counter ();
+      r =
+        Context.Ref.create creator
+          {
+            matches = Pattern.M.empty;
+            any_matches = Pattern.M.empty;
+            triggers = [];
+            callbacks = [];
+            ups = F_Pos.M.empty;
+          };
     }
 
-let rec exec d acc substs n ip =
+let stat = Debug.register_stats_int "Quantifier.InvertedPath.exec"
+
+let rec exec d ((triggers, callbacks) as acc) substs n ip =
   Debug.dprintf5 debug_full "[Quant] Exec: %a, %a[%i]" Node.pp n
     Ground.Subst.S.pp substs
     (Ground.Subst.S.cardinal substs);
+  Debug.incr stat;
   (* pp ip; *)
   if Ground.Subst.S.is_empty substs then acc
   else
-    let ip = Context.Ref.get ip in
-    let acc =
+    let ip = Context.Ref.get ip.r in
+    let triggers =
       List.fold_left
         (fun acc tr ->
+          Debug.dprintf0 debug_full "[Quant] Trigger found";
           Trigger.M.add_change (fun s -> s) Ground.Subst.S.union tr substs acc)
-        acc ip.triggers
+        triggers ip.triggers
+    in
+    let callbacks =
+      List.fold_left
+        (fun acc call ->
+          Debug.dprintf2 debug_full "[Quant] Callback %a found" Callback.pp call;
+          Callback.M.add_change
+            (fun s -> s)
+            Ground.Subst.S.union call substs acc)
+        callbacks ip.callbacks
     in
     let acc =
       Pattern.M.fold_left
@@ -76,7 +107,7 @@ let rec exec d acc substs n ip =
           Debug.dprintf2 debug_full "[Quant] Exec match %a" Pattern.pp p;
           let substs = Pattern.match_term d substs n p in
           exec d acc substs n ip)
-        acc ip.matches
+        (triggers, callbacks) ip.matches
     in
     let acc =
       Pattern.M.fold_left
@@ -109,7 +140,8 @@ let rec exec d acc substs n ip =
             Ground.S.fold_left (match_one_app pt) acc parents
           in
           let forall_fpos acc p ptl =
-            Debug.dprintf2 debug_full "[Quant] Exec ups %a@." F_Pos.pp p;
+            Debug.dprintf4 debug_full "[Quant] Exec ups %a with %a@." F_Pos.pp p
+              Node.pp n;
             let parents = F_Pos.M.find_def Ground.S.empty p info.parents in
             List.fold_left (forall_triplets parents) acc ptl
           in
@@ -119,7 +151,7 @@ let rec exec d acc substs n ip =
 
 module HPC = Datastructure.Memo (PC)
 module HPP = Datastructure.Memo (PP)
-module HPT = Datastructure.Memo (F_Pos)
+module HPT = Datastructure.Memo (PT)
 module HPN = Datastructure.Memo (PN)
 
 (** parent-child, wait for a subterm with the right application *)
@@ -128,43 +160,48 @@ let pc_ips = HPC.create Fmt.nop "Quantifier.pc" (fun c _ -> create c)
 (** parent-parent, a variable appears two times *)
 let pp_ips = HPP.create Fmt.nop "Quantifier.pp" (fun c _ -> create c)
 
-(** parent-type, wait for a type to match a variable *)
-let pt_ips =
-  HPT.create Fmt.nop "Quantifier.pt" (fun c _ -> Context.Push.create c)
+(** parent-type, wait for a subterm with the right type (to match a variable) *)
+let pt_ips = HPT.create Fmt.nop "Quantifier.pt" (fun c _ -> create c)
 
 (** parent-node, wait for a subterm with the right class *)
 let pn_ips = HPN.create Fmt.nop "Quantifier.pn" (fun c _ -> create c)
 
 let add_trigger pat ip =
-  Context.Ref.set ip
+  Context.Ref.set ip.r
   @@
-  let ip = Context.Ref.get ip in
+  let ip = Context.Ref.get ip.r in
   { ip with triggers = pat :: ip.triggers }
 
+let add_callback pat ip =
+  Context.Ref.set ip.r
+  @@
+  let ip = Context.Ref.get ip.r in
+  { ip with callbacks = pat :: ip.callbacks }
+
 let add_match pat ipr =
-  let ip = Context.Ref.get ipr in
+  let ip = Context.Ref.get ipr.r in
   match Pattern.M.find_opt pat ip.matches with
   | Some ip' -> ip'
   | None ->
-      let ip' = create (Context.Ref.creator ipr) in
-      Context.Ref.set ipr
+      let ip' = create (Context.Ref.creator ipr.r) in
+      Context.Ref.set ipr.r
       @@ { ip with matches = Pattern.M.add pat ip' ip.matches };
       ip'
 
 let add_any_match pat ipr =
-  let ip = Context.Ref.get ipr in
+  let ip = Context.Ref.get ipr.r in
   match Pattern.M.find_opt pat ip.any_matches with
   | Some ip' -> ip'
   | None ->
-      let ip' = create (Context.Ref.creator ipr) in
-      Context.Ref.set ipr
+      let ip' = create (Context.Ref.creator ipr.r) in
+      Context.Ref.set ipr.r
       @@ { ip with any_matches = Pattern.M.add pat ip' ip.any_matches };
       ip'
 
 let add_up f_pos tytl tl ipr =
-  let ip = Context.Ref.get ipr in
-  let ip' = create (Context.Ref.creator ipr) in
-  Context.Ref.set ipr
+  let ip = Context.Ref.get ipr.r in
+  let ip' = create (Context.Ref.creator ipr.r) in
+  Context.Ref.set ipr.r
   @@ {
        ip with
        ups =
@@ -173,7 +210,7 @@ let add_up f_pos tytl tl ipr =
      };
   ip'
 
-let insert_pattern d (trigger : Trigger.t) =
+let insert_pattern d (pattern : Pattern.t) pats add =
   let rec aux (fp : F_Pos.t) pp_vars p =
     match p with
     | Pattern.Var v ->
@@ -182,8 +219,8 @@ let insert_pattern d (trigger : Trigger.t) =
           List.filter (fun pp -> F_Pos.equal fp pp.PP.parent1) pairs
         in
         let ips = List.map (fun pp -> HPP.find pp_ips d pp) pairs in
-        let ip = create (Egraph.context d) in
-        Context.Push.push (HPT.find pt_ips d fp) (v.ty, ip);
+        let pt = PT.create fp v.ty in
+        let ip = HPT.find pt_ips d pt in
         let ips = ip :: ips in
         let ips = List.map (add_match p) ips in
         ips
@@ -206,15 +243,36 @@ let insert_pattern d (trigger : Trigger.t) =
         ips @ acc)
       ~init:[] tl
   in
-  let pp_vars = Pattern.get_pps trigger.pat [] in
-  match trigger.pat with
+  let pp_vars = Pattern.get_pps pattern [] in
+  match pattern with
   | Var _ | Node _ -> ()
   | App (f, tytl, tl) ->
       let ips = insert_children pp_vars f tytl tl in
       let ips =
         List.map
-          (fun ip ->
-            List.fold_left (fun ip p -> add_any_match p ip) ip trigger.pats)
+          (fun ip -> List.fold_left (fun ip p -> add_any_match p ip) ip pats)
           ips
       in
-      List.iter (add_trigger trigger) ips
+      List.iter add ips
+
+let insert_trigger d (trigger : Trigger.t) =
+  insert_pattern d trigger.pat trigger.pats (add_trigger trigger)
+
+let add_callback d pat f =
+  let callback = Callback.mk d f pat in
+  Debug.dprintf4 Common.debug "Add callback %a for %a" Callback.pp callback
+    Pattern.pp pat;
+  Trigger.add_callback d callback;
+  insert_pattern d pat [] (add_callback callback);
+  let substs = Pattern.match_any_term d Pattern.init pat in
+  Callback.run d callback substs
+
+let add_trigger d t =
+  Trigger.add_trigger d t;
+  insert_trigger d t;
+  let substs =
+    List.fold_left
+      (fun acc pat -> Pattern.match_any_term d acc pat)
+      Pattern.init (t.pat :: t.pats)
+  in
+  Trigger.instantiate_many d t substs
diff --git a/src_colibri2/theories/quantifier/InvertedPath.mli b/src_colibri2/theories/quantifier/InvertedPath.mli
index 687935c730f2fb11fc7be6a21329177c8ee4e37d..ebe6d6a286dffc7f883e75e51480b49257916b6f 100644
--- a/src_colibri2/theories/quantifier/InvertedPath.mli
+++ b/src_colibri2/theories/quantifier/InvertedPath.mli
@@ -23,21 +23,24 @@ type t
    of triggers. It allows to know which nodes merge can create new substitutions
    for a pattern and how to find them. Cf Efficient E-matching + modifications *)
 
-val pp : t Fmt.t
+include Colibri2_popop_lib.Popop_stdlib.Datatype with type t := t
 
 val exec :
   _ Egraph.t ->
-  Ground.Subst.S.t Trigger.M.t ->
+  Ground.Subst.S.t Trigger.M.t * Ground.Subst.S.t Callback.M.t ->
   Ground.Subst.S.t ->
   Node.t ->
   t ->
-  Ground.Subst.S.t Trigger.M.t
+  Ground.Subst.S.t Trigger.M.t * Ground.Subst.S.t Callback.M.t
 (** [exec d acc substs n ip] adds to [acc] new substitutions to the triggers
    that are obtained by the execution of the invertedpath *)
 
-val insert_pattern : _ Egraph.t -> Trigger.t -> unit
-(** [insert_pattern d tri] insert the pattern in the database of inverted path
-   for all its subterms *)
+val add_callback :
+  Egraph.wt -> Pattern.t -> (Egraph.wt -> Ground.Subst.t -> unit) -> unit
+(** [add_callback d pat callback] wait for the pattern to be matched *)
+
+val add_trigger : Egraph.wt -> Trigger.t -> unit
+(** [add_trigger d trigger] wait for the trigger to be matched *)
 
 module HPP : Datastructure.Memo with type key := PP.t
 
@@ -49,11 +52,11 @@ module HPC : Datastructure.Memo with type key := PC.t
 val pc_ips : t HPC.t
 (** The database of inverted path for each parent-child pairs *)
 
-module HPT : Datastructure.Memo with type key := F_Pos.t
+module HPT : Datastructure.Memo with type key := PT.t
 
-val pt_ips : (Expr.Ty.t * t) Context.Push.t HPT.t
-(** The database of inverted path for each parent-type, needed for polymorphic
-    variables *)
+val pt_ips : t HPT.t
+(** The database of inverted path for each parent-type, needed for
+    variables present unique times *)
 
 module HPN : Datastructure.Memo with type key := PN.t
 
diff --git a/src_colibri2/theories/quantifier/PT.ml b/src_colibri2/theories/quantifier/PT.ml
new file mode 100644
index 0000000000000000000000000000000000000000..cc46f12d4dfeb2dcda0dd2deb767b05418c7668e
--- /dev/null
+++ b/src_colibri2/theories/quantifier/PT.ml
@@ -0,0 +1,32 @@
+(*************************************************************************)
+(*  This file is part of Colibri2.                                       *)
+(*                                                                       *)
+(*  Copyright (C) 2014-2021                                              *)
+(*    CEA   (Commissariat à l'énergie atomique et aux énergies           *)
+(*           alternatives)                                               *)
+(*                                                                       *)
+(*  you can redistribute it and/or modify it under the terms of the GNU  *)
+(*  Lesser General Public License as published by the Free Software      *)
+(*  Foundation, version 2.1.                                             *)
+(*                                                                       *)
+(*  It is distributed in the hope that it will be useful,                *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of       *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *)
+(*  GNU Lesser General Public License for more details.                  *)
+(*                                                                       *)
+(*  See the GNU Lesser General Public License version 2.1                *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
+(*************************************************************************)
+
+open Colibri2_popop_lib
+
+module T = struct
+  open! Base
+
+  type t = { parent : F_Pos.t; ty : Expr.Ty.t } [@@deriving show, ord, hash, eq]
+end
+
+include T
+include Popop_stdlib.MkDatatype (T)
+
+let create parent ty = { parent; ty }
diff --git a/src_colibri2/theories/quantifier/PT.mli b/src_colibri2/theories/quantifier/PT.mli
new file mode 100644
index 0000000000000000000000000000000000000000..4c053000c5b757a5a727e7398d568cabdbdc1c1b
--- /dev/null
+++ b/src_colibri2/theories/quantifier/PT.mli
@@ -0,0 +1,25 @@
+(*************************************************************************)
+(*  This file is part of Colibri2.                                       *)
+(*                                                                       *)
+(*  Copyright (C) 2014-2021                                              *)
+(*    CEA   (Commissariat à l'énergie atomique et aux énergies           *)
+(*           alternatives)                                               *)
+(*                                                                       *)
+(*  you can redistribute it and/or modify it under the terms of the GNU  *)
+(*  Lesser General Public License as published by the Free Software      *)
+(*  Foundation, version 2.1.                                             *)
+(*                                                                       *)
+(*  It is distributed in the hope that it will be useful,                *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of       *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *)
+(*  GNU Lesser General Public License for more details.                  *)
+(*                                                                       *)
+(*  See the GNU Lesser General Public License version 2.1                *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
+(*************************************************************************)
+
+type t = private { parent : F_Pos.t; ty : Expr.Ty.t }
+
+include Colibri2_popop_lib.Popop_stdlib.Datatype with type t := t
+
+val create : F_Pos.t -> Expr.Ty.t -> t
diff --git a/src_colibri2/theories/quantifier/SubstTrie.ml b/src_colibri2/theories/quantifier/SubstTrie.ml
new file mode 100644
index 0000000000000000000000000000000000000000..4a809dba786adcd9b3d053d5e4171e8f88e98108
--- /dev/null
+++ b/src_colibri2/theories/quantifier/SubstTrie.ml
@@ -0,0 +1,64 @@
+(*************************************************************************)
+(*  This file is part of Colibri2.                                       *)
+(*                                                                       *)
+(*  Copyright (C) 2014-2021                                              *)
+(*    CEA   (Commissariat à l'énergie atomique et aux énergies           *)
+(*           alternatives)                                               *)
+(*                                                                       *)
+(*  you can redistribute it and/or modify it under the terms of the GNU  *)
+(*  Lesser General Public License as published by the Free Software      *)
+(*  Foundation, version 2.1.                                             *)
+(*                                                                       *)
+(*  It is distributed in the hope that it will be useful,                *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of       *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *)
+(*  GNU Lesser General Public License for more details.                  *)
+(*                                                                       *)
+(*  See the GNU Lesser General Public License version 2.1                *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
+(*************************************************************************)
+
+module TTerm = Context.Trie (Node)
+(** Only for substitutions that have the same domain *)
+
+module TTy = Context.Trie (Ground.Ty)
+
+type 'a t = 'a TTy.t TTerm.t
+
+let create c = TTerm.create c
+
+let fold_of_term_map s : _ Context.fold =
+  {
+    fold =
+      (fun f acc -> Expr.Term.Var.M.fold_left (fun acc _ v -> f acc v) acc s);
+  }
+
+let fold_of_ty_map s : _ Context.fold =
+  {
+    fold = (fun f acc -> Expr.Ty.Var.M.fold_left (fun acc _ v -> f acc v) acc s);
+  }
+
+let find_and_add (t : bool t) (s : Ground.Subst.t) =
+  let tv =
+    TTerm.Fold.memo ~default:(fun c -> TTy.create c) t (fold_of_term_map s.term)
+  in
+  let not_set = ref false in
+  ignore
+    (TTy.Fold.memo
+       ~default:(fun _ ->
+         not_set := true;
+         true)
+       tv (fold_of_ty_map s.ty));
+  !not_set
+
+let find_def ~default (t : _ t) (s : Ground.Subst.t) =
+  let tv =
+    TTerm.Fold.memo ~default:(fun c -> TTy.create c) t (fold_of_term_map s.term)
+  in
+  TTy.Fold.find_def ~default:(fun _ -> default) tv (fold_of_ty_map s.ty)
+
+let set (t : _ t) (s : Ground.Subst.t) v =
+  let tv =
+    TTerm.Fold.memo ~default:(fun c -> TTy.create c) t (fold_of_term_map s.term)
+  in
+  TTy.Fold.set tv (fold_of_ty_map s.ty) v
diff --git a/src_colibri2/theories/quantifier/SubstTrie.mli b/src_colibri2/theories/quantifier/SubstTrie.mli
new file mode 100644
index 0000000000000000000000000000000000000000..353cdfee2f7471a3137ef62074b06816f77dfbe8
--- /dev/null
+++ b/src_colibri2/theories/quantifier/SubstTrie.mli
@@ -0,0 +1,34 @@
+(*************************************************************************)
+(*  This file is part of Colibri2.                                       *)
+(*                                                                       *)
+(*  Copyright (C) 2014-2021                                              *)
+(*    CEA   (Commissariat à l'énergie atomique et aux énergies           *)
+(*           alternatives)                                               *)
+(*                                                                       *)
+(*  you can redistribute it and/or modify it under the terms of the GNU  *)
+(*  Lesser General Public License as published by the Free Software      *)
+(*  Foundation, version 2.1.                                             *)
+(*                                                                       *)
+(*  It is distributed in the hope that it will be useful,                *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of       *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *)
+(*  GNU Lesser General Public License for more details.                  *)
+(*                                                                       *)
+(*  See the GNU Lesser General Public License version 2.1                *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
+(*************************************************************************)
+
+type 'a t
+(** A map of substitution *)
+
+val create : Context.creator -> 'a t
+
+val find_and_add : bool t -> Ground.Subst.t -> bool
+(** Return if the substitution is in the set, and add it if it is not the case *)
+
+val find_def : default:'a -> 'a t -> Ground.Subst.t -> 'a
+(** Return the value associated to the substitution, or [default] if it is not
+   binded *)
+
+val set : 'a t -> Ground.Subst.t -> 'a -> unit
+(** Return set the associated value of the substitution *)
diff --git a/src_colibri2/theories/quantifier/callback.ml b/src_colibri2/theories/quantifier/callback.ml
new file mode 100644
index 0000000000000000000000000000000000000000..4b24893dd5005146b5422b1310e04b33d1119275
--- /dev/null
+++ b/src_colibri2/theories/quantifier/callback.ml
@@ -0,0 +1,44 @@
+open Common
+open Colibri2_popop_lib
+
+type t = {
+  id : int;
+  f : Egraph.wt -> Ground.Subst.t -> unit;
+  pat : Pattern.t;
+  already : bool SubstTrie.t;
+}
+
+let pattern t = t.pat
+
+include (
+  Popop_stdlib.MakeMSH (struct
+    type nonrec t = t
+
+    let tag t = t.id
+    let pp fmt t = Format.pp_print_int fmt t.id
+  end) :
+    Popop_stdlib.Datatype with type t := t)
+
+let mk =
+  let c = ref (-1) in
+  fun d f pat ->
+    incr c;
+    { id = !c; f; already = SubstTrie.create (Egraph.context d); pat }
+
+let run d t substs =
+  let substs =
+    Ground.Subst.S.fold_left
+      (fun acc s -> Ground.Subst.S.add (Ground.Subst.map_repr d s) acc)
+      Ground.Subst.S.empty substs
+  in
+  let iter s =
+    let already = SubstTrie.find_and_add t.already s in
+    if not already then t.f d s
+  in
+
+  Ground.Subst.S.iter iter substs
+
+let match_ d t n =
+  Debug.dprintf4 debug "[Quant] match %a %a" pp t Node.pp n;
+  let mvar = Pattern.match_term d Pattern.init n t.pat in
+  run d t mvar
diff --git a/src_colibri2/theories/quantifier/callback.mli b/src_colibri2/theories/quantifier/callback.mli
new file mode 100644
index 0000000000000000000000000000000000000000..c2948a6a6326459a5285f8f6accf9d29a4921b65
--- /dev/null
+++ b/src_colibri2/theories/quantifier/callback.mli
@@ -0,0 +1,9 @@
+include Colibri2_popop_lib.Popop_stdlib.Datatype
+
+val pattern : t -> Pattern.t
+val mk : Egraph.wt -> (Egraph.wt -> Ground.Subst.t -> unit) -> Pattern.t -> t
+val run : Egraph.wt -> t -> Ground.Subst.S.t -> unit
+
+val match_ : Egraph.wt -> t -> Node.t -> unit
+(** [match_ d t n] match the callback [t] with [n] and run [t]
+    with the resulting substitutions *)
diff --git a/src_colibri2/theories/quantifier/common.ml b/src_colibri2/theories/quantifier/common.ml
index 54a1fe8d8c6adf6859bd8ea9e892f2a6662abb0d..a5b985dccf00588d5bcc551b7bf8a7abfa0b3ebd 100644
--- a/src_colibri2/theories/quantifier/common.ml
+++ b/src_colibri2/theories/quantifier/common.ml
@@ -21,10 +21,22 @@
 let debug =
   Debug.register_info_flag ~desc:"Handling of quantifiers" "quantifiers"
 
+let debug_instantiation =
+  Debug.register_info_flag ~desc:"Handling of quantifiers"
+    "quantifiers.instantiations"
+
 let debug_full =
   Debug.register_flag ~desc:"Handling of quantifiers full" "quantifiers.full"
 
-let nb_instantiation = Debug.register_stats_int "instantiation"
-let nb_eager_instantiation = Debug.register_stats_int "eager_instantiation"
-let nb_delayed_instantiation = Debug.register_stats_int "delayed_instantiation"
-let nb_new_instantiation = Debug.register_stats_int "new_instantiation"
+let nb_instantiation = Debug.register_stats_int "Quantifier.instantiation"
+
+let nb_eager_instantiation =
+  Debug.register_stats_int "Quantifier.eager_instantiation"
+
+let nb_delayed_instantiation =
+  Debug.register_stats_int "Quantifier.delayed_instantiation"
+
+let nb_new_instantiation =
+  Debug.register_stats_int "Quantifier.new_instantiation"
+
+let stats_time = Debug.register_stats_time "Quantifier.time"
diff --git a/src_colibri2/theories/quantifier/definitions.ml b/src_colibri2/theories/quantifier/definitions.ml
new file mode 100644
index 0000000000000000000000000000000000000000..f74ab260be4ec121062db4596d325c5862afb8ae
--- /dev/null
+++ b/src_colibri2/theories/quantifier/definitions.ml
@@ -0,0 +1,54 @@
+(*************************************************************************)
+(*  This file is part of Colibri2.                                       *)
+(*                                                                       *)
+(*  Copyright (C) 2014-2021                                              *)
+(*    CEA   (Commissariat à l'énergie atomique et aux énergies           *)
+(*           alternatives)                                               *)
+(*                                                                       *)
+(*  you can redistribute it and/or modify it under the terms of the GNU  *)
+(*  Lesser General Public License as published by the Free Software      *)
+(*  Foundation, version 2.1.                                             *)
+(*                                                                       *)
+(*  It is distributed in the hope that it will be useful,                *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of       *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *)
+(*  GNU Lesser General Public License for more details.                  *)
+(*                                                                       *)
+(*  See the GNU Lesser General Public License version 2.1                *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
+(*************************************************************************)
+
+open Colibri2_core
+open Colibri2_popop_lib
+
+let handler d (sym : Expr.Term.Const.t) tyl tvl body =
+  (* Check that it don't start with a builtin (can be changed) *)
+  if not (Info.Builtin_skipped_for_trigger.skipped d sym.builtin) then
+    let tys, tvs =
+      Expr.Term.free_vars (Expr.Ty.Var.S.empty, Expr.Term.Var.S.empty) body
+    in
+    if
+      List.for_all (fun v -> Expr.Ty.Var.S.mem v tys) tyl
+      && List.for_all (fun v -> Expr.Term.Var.S.mem v tvs) tvl
+    then
+      match Pattern.of_term_exn ~subst:Ground.Subst.empty body with
+      | exception Pattern.Unconvertible -> ()
+      | pat ->
+          Debug.dprintf2 Common.debug "[Def] Wait for folding %a"
+            Expr.Term.Const.pp sym;
+          InvertedPath.add_callback d pat (fun d subst ->
+              let t =
+                Ground.apply d sym
+                  (List.map
+                     (fun s -> Expr.Ty.Var.M.find_exn Impossible s subst.ty)
+                     tyl)
+                  (IArray.of_list_map
+                     ~f:(fun s ->
+                       Expr.Term.Var.M.find_exn Impossible s subst.term)
+                     tvl)
+              in
+              Debug.dprintf2 Common.debug "Fold definition of %a" Ground.Term.pp
+                t;
+              Egraph.register d (Ground.node (Ground.index t)))
+
+let th_register d = Ground.Defs.add_handler d handler
diff --git a/src_colibri2/theories/quantifier/definitions.mli b/src_colibri2/theories/quantifier/definitions.mli
new file mode 100644
index 0000000000000000000000000000000000000000..8f115936a4b087bd606e6069f158e6354d85fe51
--- /dev/null
+++ b/src_colibri2/theories/quantifier/definitions.mli
@@ -0,0 +1,23 @@
+(*************************************************************************)
+(*  This file is part of Colibri2.                                       *)
+(*                                                                       *)
+(*  Copyright (C) 2014-2021                                              *)
+(*    CEA   (Commissariat à l'énergie atomique et aux énergies           *)
+(*           alternatives)                                               *)
+(*                                                                       *)
+(*  you can redistribute it and/or modify it under the terms of the GNU  *)
+(*  Lesser General Public License as published by the Free Software      *)
+(*  Foundation, version 2.1.                                             *)
+(*                                                                       *)
+(*  It is distributed in the hope that it will be useful,                *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of       *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *)
+(*  GNU Lesser General Public License for more details.                  *)
+(*                                                                       *)
+(*  See the GNU Lesser General Public License version 2.1                *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
+(*************************************************************************)
+
+(** Try to fold definitions *)
+
+val th_register : Egraph.wt -> unit
diff --git a/src_colibri2/theories/quantifier/info.ml b/src_colibri2/theories/quantifier/info.ml
index ea4acbcd1bdf588f41d505ff8d9da537c512553b..7859026dc23b381af874d8b64586831d6648f3ed 100644
--- a/src_colibri2/theories/quantifier/info.ml
+++ b/src_colibri2/theories/quantifier/info.ml
@@ -24,6 +24,7 @@ open Colibri2_popop_lib
 type t = {
   parents : Ground.S.t F_Pos.M.t;  (** parents *)
   apps : Ground.S.t F.M.t;  (** parent parent *)
+  ty : Ground.Ty.S.t;  (** same as in ground but simplify incrementalism *)
 }
 [@@deriving show]
 
@@ -75,9 +76,11 @@ let merge d ~other ~repr info info' =
     parents = congruence_closure d ~other ~repr info.parents info'.parents;
     apps =
       F.M.union (fun _ a b -> Some (Ground.S.union a b)) info.apps info'.apps;
+    ty = Ground.Ty.S.union info.ty info'.ty;
   }
 
-let empty = { parents = F_Pos.M.empty; apps = F.M.empty }
+let empty =
+  { parents = F_Pos.M.empty; apps = F.M.empty; ty = Ground.Ty.S.empty }
 
 let dom =
   Dom.Kind.create
@@ -86,3 +89,22 @@ let dom =
 
       let name = "Quantifier.info"
     end)
+
+let tys d n =
+  Opt.get_def Ground.Ty.S.empty
+  @@
+  let open CCOption in
+  let+ info = Egraph.get_dom d dom n in
+  info.ty
+
+module Builtin_skipped_for_trigger = struct
+  let q = Datastructure.Push.create Fmt.nop "builtin_skipped_for_trigger"
+  let register d f = Datastructure.Push.push q d f
+
+  let skipped d builtin =
+    match builtin with
+    | Expr.And | Expr.Equal | Expr.Equiv | Expr.Or | Expr.Xor | Expr.Imply
+    | Expr.Ite | Expr.Neg ->
+        true
+    | _ -> Datastructure.Push.exists q d ~f:(fun p -> p builtin)
+end
diff --git a/src_colibri2/theories/quantifier/info.mli b/src_colibri2/theories/quantifier/info.mli
index cfe519e74a7ded3b87ee34004b64ff8d35924221..2deb6e80fe881aa7b835386f8088daca89207623 100644
--- a/src_colibri2/theories/quantifier/info.mli
+++ b/src_colibri2/theories/quantifier/info.mli
@@ -21,6 +21,7 @@
 type t = {
   parents : Ground.S.t F_Pos.M.t;  (** parents *)
   apps : Ground.S.t F.M.t;  (** parent parent *)
+  ty : Ground.Ty.S.t;  (** same as in ground but simplify incrementalism *)
 }
 [@@deriving show]
 
@@ -29,3 +30,14 @@ val merge : Egraph.wt -> other:Node.t -> repr:Node.t -> t -> t -> t
 
 val empty : t
 val dom : t Dom.Kind.t
+
+val tys : _ Egraph.t -> Node.t -> Ground.Ty.S.t
+(** Same as Ground.Tys but from Info.t *)
+
+module Builtin_skipped_for_trigger : sig
+  val register : _ Egraph.t -> (Expr.builtin -> bool) -> unit
+  (** The registered function tells when an application should be skipped when
+      looking for patterns in a term (top down) *)
+
+  val skipped : _ Egraph.t -> Expr.builtin -> bool
+end
diff --git a/src_colibri2/theories/quantifier/pattern.ml b/src_colibri2/theories/quantifier/pattern.ml
index 46489b54dfc1fd9b93ed8c62fcc2a9e267a7d2f9..6043ef820437188727b2f88ccd3c854de07fe128 100644
--- a/src_colibri2/theories/quantifier/pattern.ml
+++ b/src_colibri2/theories/quantifier/pattern.ml
@@ -72,14 +72,17 @@ let rec subst_aux_ty subst (ty : Expr.Ty.t) =
 and subst_ty subst t =
   if Expr.Ty.Var.M.is_empty subst then t else subst_aux_ty subst t
 
-let rec of_term ~subst (t : Expr.Term.t) =
+exception Unconvertible
+
+let rec of_term_exn ?(coercion = true) ~subst (t : Expr.Term.t) =
   match t.term_descr with
   | Var v -> (
       match Expr.Term.Var.M.find v subst.Ground.Subst.term with
       | exception Not_found -> Var { var = v; ty = subst_ty subst.ty v.id_ty }
       | n -> Node n)
-  | App ({ term_descr = Cst { builtin = Expr.Coercion; _ }; _ }, _, [ a ]) ->
-      of_term ~subst a
+  | App ({ term_descr = Cst { builtin = Expr.Coercion; _ }; _ }, _, [ a ])
+    when not coercion ->
+      of_term_exn ~subst a
   | App
       ( { term_descr = Cst { builtin = Expr.Ite; _ }; _ },
         _,
@@ -89,16 +92,14 @@ let rec of_term ~subst (t : Expr.Term.t) =
           { term_descr = Cst { builtin = Expr.False; _ }; _ };
         ] ) ->
       (* Why3 generates spurious (if v then true else false) *)
-      of_term ~subst cond
+      of_term_exn ~subst cond
   | App ({ term_descr = Cst f; _ }, tys, tl) ->
       App
         ( f,
           List.map (subst_ty subst.ty) tys,
-          IArray.of_list_map ~f:(of_term ~subst) tl )
+          IArray.of_list_map ~f:(of_term_exn ~subst) tl )
   | Cst f -> App (f, [], IArray.empty)
-  | _ ->
-      Fmt.epr "of_term: %a@." Expr.Term.pp t;
-      (* absurd *) assert false
+  | _ -> raise Unconvertible
 
 let init = Ground.Subst.S.singleton Ground.Subst.empty
 
@@ -136,9 +137,9 @@ let rec match_term d (substs : Ground.Subst.S.t) (n : Node.t) (p : t) :
           Ground.Subst.S.union (match_ty substs ty v.ty) acc
         in
         Debug.dprintf4 debug_full "[Quant] Var: %a as type: %a." Node.pp n
-          Ground.Ty.S.pp (Ground.tys d n);
+          Ground.Ty.S.pp (Info.tys d n);
         let substs =
-          Ground.Ty.S.fold_left match_ty Ground.Subst.S.empty (Ground.tys d n)
+          Ground.Ty.S.fold_left match_ty Ground.Subst.S.empty (Info.tys d n)
         in
         Ground.Subst.S.fold_left
           (fun acc subst ->
@@ -156,7 +157,7 @@ let rec match_term d (substs : Ground.Subst.S.t) (n : Node.t) (p : t) :
           Opt.get_def Ground.S.empty
           @@
           let open CCOption in
-          let* info = Egraph.get_dom d Info.dom (Egraph.find_def d n) in
+          let* info = Egraph.get_dom d Info.dom n in
           F.M.find_opt pf info.apps
         in
         Ground.S.fold_left
@@ -189,7 +190,7 @@ let rec check_term d (subst : Ground.Subst.t) (n : Node.t) (p : t) : bool =
   Debug.dprintf4 debug "[Quant] check %a %a" pp p Node.pp n;
   match p with
   | Var v -> (
-      Ground.Ty.S.exists (fun ty -> check_ty subst ty v.ty) (Ground.tys d n)
+      Ground.Ty.S.exists (fun ty -> check_ty subst ty v.ty) (Info.tys d n)
       &&
       match Expr.Term.Var.M.find v.var subst.term with
       | exception Not_found -> false
@@ -223,49 +224,80 @@ let rec check_term_exists_exn d (subst : Ground.Subst.t) (p : t) : Node.S.t =
       | n ->
           if
             (Ground.Ty.S.exists (fun ty -> check_ty subst ty v.ty))
-              (Ground.tys d n)
+              (Info.tys d n)
           then Node.S.singleton (Egraph.find_def d n)
           else raise Not_found)
-  | App (pf, ptyl, pargs) when IArray.is_empty pargs ->
-      let g =
-        Ground.apply d pf
-          (List.map (Ground.Ty.convert subst.ty) ptyl)
-          IArray.empty
-        |> Ground.index |> Ground.node
-      in
-      if Egraph.is_registered d g then Node.S.singleton (Egraph.find d g)
-      else raise Not_found
   | App (pf, ptyl, pargs) ->
-      let find_app pos n =
-        Opt.get_def Ground.S.empty
-        @@
-        let open CCOption in
-        let* info = Egraph.get_dom d Info.dom (Egraph.find_def d n) in
-        F_Pos.M.find_opt { f = pf; pos } info.parents
-      in
-      let get_parents pos parg =
-        let nodes = check_term_exists_exn d subst parg in
-        let nodes =
-          Node.S.fold_left
-            (fun acc n ->
-              Ground.S.fold_left
-                (fun acc g ->
-                  if List.for_all2 (check_ty subst) (Ground.sem g).tyargs ptyl
-                  then Node.S.add (Ground.node g) acc
-                  else acc)
-                acc (find_app pos n))
-            Node.S.empty nodes
-        in
-        nodes
-      in
-      let nodes =
-        IArray.foldi_non_empty_exn
-          ~f:(fun i acc parg -> Node.S.inter acc (get_parents i parg))
-          ~init:(get_parents 0) pargs
-      in
+      let nodes_args = IArray.map ~f:(check_term_exists_exn d subst) pargs in
+      let nodes = find_existing_app d subst pf ptyl nodes_args in
       if Node.S.is_empty nodes then raise Not_found else nodes
   | Node n -> Node.S.singleton n
 
+and find_existing_app d subst pf ptyl nodes_args =
+  if IArray.is_empty nodes_args then
+    let g =
+      Ground.apply d pf
+        (List.map (Ground.Ty.convert subst.ty) ptyl)
+        IArray.empty
+      |> Ground.index |> Ground.node
+    in
+    if Egraph.is_registered d g then Node.S.singleton (Egraph.find d g)
+    else Node.S.empty
+  else
+    let find_app pos n =
+      Opt.get_def Ground.S.empty
+      @@
+      let open CCOption in
+      let app = { F_Pos.f = pf; pos } in
+      let* info = Egraph.get_dom d Info.dom n in
+      let+ parents = F_Pos.M.find_opt app info.parents in
+      (* Debug.dprintf6 debug "find_app %a: %a -- %a" F_Pos.pp app Node.pp n
+       *   Ground.S.pp parents; *)
+      parents
+    in
+    let get_parents pos nodes =
+      let nodes =
+        Node.S.fold_left
+          (fun acc n ->
+            Ground.S.fold_left
+              (fun acc g ->
+                if List.for_all2 (check_ty subst) (Ground.sem g).tyargs ptyl
+                then Node.S.add (Ground.node g) acc
+                else acc)
+              acc (find_app pos n))
+          Node.S.empty nodes
+      in
+      nodes
+    in
+    (* let inter s1 s2 =
+     *   (\* intersection modulo equality which keeps original node *\)
+     *   Debug.dprintf4 debug "inter: %a -- %a" Node.S.pp s1 Node.S.pp s2;
+     *   let cmp_with_repr n1 n2 =
+     *     Node.compare (Egraph.find d n1) (Egraph.find d n2)
+     *   in
+     *   let s1 = Node.S.elements s1 |> List.sort_uniq cmp_with_repr in
+     *   let s2 = Node.S.elements s2 |> List.sort_uniq cmp_with_repr in
+     *   let rec inter l1 l2 acc =
+     *     match (l1, l2) with
+     *     | [], _ | _, [] -> acc
+     *     | a :: l1', b :: l2' ->
+     *         let c = cmp_with_repr a b in
+     *         if c = 0 then inter l1' l2' (a :: acc)
+     *         else if c < 0 then inter l1' l2 acc
+     *         else inter l1 l2' acc
+     *   in
+     *   Node.S.of_list (inter s1 s2 [])
+     * in *)
+    let nodes =
+      IArray.foldi_non_empty_exn
+        ~f:(fun i acc nodes_arg ->
+          (* It is important to just use [Node.S.inter] because we want to do
+             [Ground.S.inter] so we should not take the representative *)
+          Node.S.inter acc (get_parents i nodes_arg))
+        ~init:(get_parents 0) nodes_args
+    in
+    nodes
+
 let check_term_exists d (subst : Ground.Subst.t) (p : t) : Node.S.t =
   try check_term_exists_exn d subst p with Not_found -> Node.S.empty
 
diff --git a/src_colibri2/theories/quantifier/pattern.mli b/src_colibri2/theories/quantifier/pattern.mli
index 252a806f9bd6150397d496145feb871fd3520fb1..d61d7a25c75e7483ff4cd45f26ef83d655bd2ceb 100644
--- a/src_colibri2/theories/quantifier/pattern.mli
+++ b/src_colibri2/theories/quantifier/pattern.mli
@@ -29,7 +29,9 @@ type t =
 
 include Colibri2_popop_lib.Popop_stdlib.Datatype with type t := t
 
-val of_term : subst:Ground.Subst.t -> Expr.Term.t -> t
+exception Unconvertible
+
+val of_term_exn : ?coercion:bool -> subst:Ground.Subst.t -> Expr.Term.t -> t
 
 val init : Ground.Subst.S.t
 (** Singleton set with the empty substitution, can be used as initial value for
@@ -73,3 +75,13 @@ module EnvTy : Datastructure.Memo with type key := Ground.Ty.t
 
 val env_node_by_ty : Node.t Context.Push.t EnvTy.t
 (** The set of nodes sorted by their type. A node can have multiple types *)
+
+val find_existing_app :
+  'a Egraph.t ->
+  Ground.Subst.t ->
+  F.t ->
+  Expr.ty list ->
+  Node.S.t IArray.t ->
+  Node.S.t
+(** [find_existing_app d s f tyl nodes_args] find existing application of [f] with one
+   of the nodes as arguments *)
diff --git a/src_colibri2/theories/quantifier/quantifier.ml b/src_colibri2/theories/quantifier/quantifier.ml
index 57eb1da18d84f35089b76cdb3d660711eef1433b..c07d92463c6e01107c5c125c67981405cb3f81cd 100644
--- a/src_colibri2/theories/quantifier/quantifier.ml
+++ b/src_colibri2/theories/quantifier/quantifier.ml
@@ -24,142 +24,278 @@ open Colibri2_popop_lib
 open Colibri2_core
 open Common
 
-let add_trigger d t =
-  Trigger.add_trigger d t;
-  InvertedPath.insert_pattern d t;
-  let substs =
-    List.fold_left
-      (fun acc pat -> Pattern.match_any_term d acc pat)
-      Pattern.init (t.pat :: t.pats)
-  in
-  Ground.Subst.S.iter (Trigger.instantiate d t) substs
+module Quantifier_skipped = struct
+  let q = Datastructure.Push.create Fmt.nop "quantifier_skipped"
+  let register d f = Datastructure.Push.push q d f
+  let skipped d builtin = Datastructure.Push.exists q d ~f:(fun p -> p builtin)
 
-let find_new_event d n (info : Info.t) n' (info' : Info.t) =
-  Debug.dprintf8 debug "Find_new_event %a %a %a %a" Node.pp n Info.pp info
-    Node.pp n' Info.pp info';
-  let symmetric f acc na a nb b =
-    if CCEqual.physical a b && Node.equal na nb then f acc na a nb b
-    else f (f acc na a nb b) nb b na a
-  in
-  let do_pp pp ip acc =
-    let aux acc _ info1 _ info2 =
-      match
-        ( F_Pos.M.find_opt pp.PP.parent1 info1.Info.parents,
-          F_Pos.M.find_opt pp.PP.parent2 info2.Info.parents )
-      with
-      | Some _, Some _ ->
-          (* Ground.S.fold_left
-           *   (fun acc n ->
-           *     let n = Ground.node n in
-           *     InvertedPath.exec d acc n ip)
-           *   acc parents *)
-          Debug.dprintf4 debug_full "[Quant] PP %a found for %a" PP.pp pp
-            Node.pp n;
-          ip :: acc
-      | _ -> acc
+  type filter_term =
+    | App of Expr.builtin * filter_ty list * filter_term list
+    | Var of int
+    | Choice of filter_term list
+    | Any
+
+  and filter_ty = TyApp of Expr.builtin * filter_ty list | TyAny
+  and filter_quant = { vars : int list; filter : filter_term }
+
+  let rec match_term env (filter : filter_term) (t : Expr.Term.t) =
+    match (filter, t) with
+    | ( App (fb, ftyl, ftl),
+        {
+          term_descr = App ({ term_descr = Cst { builtin = b; _ }; _ }, tyl, tl);
+          _;
+        } ) ->
+        Base.Poly.equal fb b
+        && List.for_all2 match_ty ftyl tyl
+        && List.for_all2 (match_term env) ftl tl
+    | Var v, { term_descr = Var v'; _ } ->
+        Expr.Term.Var.equal (Popop_stdlib.DInt.M.find v env) v'
+    | Choice filters, t -> List.exists (fun f -> match_term env f t) filters
+    | Any, _ -> true
+    | _ -> false
+
+  and match_ty (filter : filter_ty) (ty : Expr.Ty.t) =
+    match (filter, ty) with
+    | TyApp (fb, ftyl), { ty_descr = TyApp ({ builtin = b; _ }, tyl); _ } ->
+        Base.Poly.equal fb b && List.for_all2 match_ty ftyl tyl
+    | TyAny, _ -> true
+    | _ -> false
+
+  and match_ (quant : Ground.ClosedQuantifier.s) filter =
+    Base.List.is_empty quant.ty_vars
+    &&
+    match
+      Base.List.fold2 ~init:Popop_stdlib.DInt.M.empty filter.vars
+        quant.term_vars ~f:(fun acc i v ->
+          Popop_stdlib.DInt.M.add_new Impossible i v acc)
+    with
+    | Unequal_lengths -> false
+    | Ok env -> match_term env filter.filter quant.body
+end
+
+module Find_new_event = struct
+  let two d n (info : Info.t) n' (info' : Info.t) acc =
+    Debug.dprintf8 debug "Find_new_event %a %a %a %a" Node.pp n Info.pp info
+      Node.pp n' Info.pp info';
+    let symmetric f acc na a nb b =
+      if CCEqual.physical a b && Node.equal na nb then f acc na a nb b
+      else f (f acc na a nb b) nb b na a
     in
-    symmetric aux acc n info n' info'
-  in
-  let do_pc pc ip acc =
-    let aux acc _ info1 _ info2 =
-      match
-        ( F_Pos.M.find_opt pc.PC.parent info1.Info.parents,
-          F.M.find_opt pc.PC.child info2.Info.apps )
-      with
-      | Some _, Some _ ->
-          (* Ground.S.fold_left
-           *   (fun acc n ->
-           *     let n = Ground.node n in
-           *     InvertedPath.exec d acc n ip)
-           *   acc parents *)
-          Debug.dprintf4 debug_full "[Quant] PC %a found for %a" PC.pp pc
-            Node.pp n;
-          ip :: acc
-      | _ -> acc
+    let do_pp pp ip acc =
+      let aux acc _ info1 _ info2 =
+        match
+          ( F_Pos.M.find_opt pp.PP.parent1 info1.Info.parents,
+            F_Pos.M.find_opt pp.PP.parent2 info2.Info.parents )
+        with
+        | Some _, Some _ ->
+            (* Ground.S.fold_left
+             *   (fun acc n ->
+             *     let n = Ground.node n in
+             *     InvertedPath.exec d acc n ip)
+             *   acc parents *)
+            Debug.dprintf4 debug_full "[Quant] PP %a found for %a" PP.pp pp
+              Node.pp n;
+            ip :: acc
+        | _ -> acc
+      in
+      symmetric aux acc n info n' info'
     in
-    symmetric aux acc n info n' info'
-  in
-  (* parent node *)
-  let do_pn pn ip acc =
-    let aux acc n info1 n' _ =
-      if Egraph.is_equal d n' pn.PN.node then
-        match F_Pos.M.find_opt pn.PN.parent info1.Info.parents with
-        | Some _ ->
-            Debug.dprintf4 debug_full "[Quant] PC %a found for %a" PN.pp pn
+    let do_pc pc ip acc =
+      let aux acc _ info1 _ info2 =
+        match
+          ( F_Pos.M.find_opt pc.PC.parent info1.Info.parents,
+            F.M.find_opt pc.PC.child info2.Info.apps )
+        with
+        | Some _, Some _ ->
+            (* Ground.S.fold_left
+             *   (fun acc n ->
+             *     let n = Ground.node n in
+             *     InvertedPath.exec d acc n ip)
+             *   acc parents *)
+            Debug.dprintf4 debug_full "[Quant] PC %a found for %a" PC.pp pc
               Node.pp n;
             ip :: acc
         | _ -> acc
-      else acc
+      in
+      symmetric aux acc n info n' info'
     in
-    symmetric aux acc n info n' info'
-  in
-  (* parent type *)
-  let do_pt f_pos q acc =
-    let aux acc n info1 n' _ =
-      match F_Pos.M.find_opt f_pos info1.Info.parents with
-      | Some _ ->
-          Context.Push.fold
-            (fun acc (vty, ip) ->
-              let substs_by n0 =
-                let match_ty (acc : Ground.Subst.S.t) ty : Ground.Subst.S.t =
-                  Ground.Subst.S.union
-                    (Pattern.match_ty Pattern.init ty vty)
-                    acc
-                in
-                let substs =
-                  Ground.Ty.S.fold_left match_ty Pattern.init (Ground.tys d n0)
-                in
-                substs
-              in
-              let substs2 = substs_by n in
-              let substs1 =
-                if Node.equal n n' then Ground.Subst.S.empty else substs_by n'
+    (* parent node *)
+    let do_pn pn ip acc =
+      let aux acc n info1 n' _ =
+        if Egraph.is_equal d n' pn.PN.node then
+          match F_Pos.M.find_opt pn.PN.parent info1.Info.parents with
+          | Some _ ->
+              Debug.dprintf4 debug_full "[Quant] PC %a found for %a" PN.pp pn
+                Node.pp n;
+              ip :: acc
+          | _ -> acc
+        else acc
+      in
+      symmetric aux acc n info n' info'
+    in
+    (* parent type *)
+    let do_pt { PT.parent = f_pos; ty = vty } ip acc =
+      let aux acc n (info1 : Info.t) _ (info2 : Info.t) =
+        match F_Pos.M.mem f_pos info1.parents with
+        | true ->
+            let tys = Ground.Ty.S.diff info2.ty info1.ty in
+            if Ground.Ty.S.is_empty tys then acc
+            else
+              let no_match ty : bool =
+                Ground.Subst.S.is_empty (Pattern.match_ty Pattern.init ty vty)
               in
-              if Ground.Subst.S.subset substs2 substs1 then acc
+              if Ground.Ty.S.for_all no_match tys then acc
               else (
                 Debug.dprintf6 debug_full "[Quant] PT %a %a found for %a"
                   F_Pos.pp f_pos Expr.Ty.pp vty Node.pp n;
-                ip :: acc))
-            acc q
-      | None -> acc
+                ip :: acc)
+        | _ -> acc
+      in
+      symmetric aux acc n info n' info'
     in
-    symmetric aux acc n info n' info'
-  in
-  let acc = [] in
-  let acc = InvertedPath.HPP.fold do_pp InvertedPath.pp_ips d acc in
-  let acc = InvertedPath.HPC.fold do_pc InvertedPath.pc_ips d acc in
-  let acc = InvertedPath.HPT.fold do_pt InvertedPath.pt_ips d acc in
-  let acc = InvertedPath.HPN.fold do_pn InvertedPath.pn_ips d acc in
-  acc
+    let acc = InvertedPath.HPP.fold do_pp InvertedPath.pp_ips d acc in
+    let acc = InvertedPath.HPC.fold do_pc InvertedPath.pc_ips d acc in
+    let acc = InvertedPath.HPT.fold do_pt InvertedPath.pt_ips d acc in
+    let acc = InvertedPath.HPN.fold do_pn InvertedPath.pn_ips d acc in
+    acc
 
-let process_inverted_path d n acc =
-  let acc =
-    List.fold_left
-      (fun acc ip -> InvertedPath.exec d acc Pattern.init n ip)
-      Trigger.M.empty acc
-  in
-  Trigger.M.iter
-    (fun tri substs -> Ground.Subst.S.iter (Trigger.instantiate d tri) substs)
+  let one d n (info : Info.t) acc =
+    Debug.dprintf4 debug "Find_new_event %a %a" Node.pp n Info.pp info;
+    let do_pp pp ip acc =
+      let aux acc _ info1 =
+        match
+          ( F_Pos.M.find_opt pp.PP.parent1 info1.Info.parents,
+            F_Pos.M.find_opt pp.PP.parent2 info1.Info.parents )
+        with
+        | Some _, Some _ ->
+            (* Ground.S.fold_left
+             *   (fun acc n ->
+             *     let n = Ground.node n in
+             *     InvertedPath.exec d acc n ip)
+             *   acc parents *)
+            Debug.dprintf4 debug_full "[Quant] PP %a found for %a" PP.pp pp
+              Node.pp n;
+            ip :: acc
+        | _ -> acc
+      in
+      aux acc n info
+    in
+    let do_pc pc ip acc =
+      let aux acc _ info1 =
+        match
+          ( F_Pos.M.find_opt pc.PC.parent info1.Info.parents,
+            F.M.find_opt pc.PC.child info1.Info.apps )
+        with
+        | Some _, Some _ ->
+            (* Ground.S.fold_left
+             *   (fun acc n ->
+             *     let n = Ground.node n in
+             *     InvertedPath.exec d acc n ip)
+             *   acc parents *)
+            Debug.dprintf4 debug_full "[Quant] PC %a found for %a" PC.pp pc
+              Node.pp n;
+            ip :: acc
+        | _ -> acc
+      in
+      aux acc n info
+    in
+    (* parent node *)
+    let do_pn pn ip acc =
+      let aux acc n info1 =
+        if Egraph.is_equal d n pn.PN.node then
+          match F_Pos.M.find_opt pn.PN.parent info1.Info.parents with
+          | Some _ ->
+              Debug.dprintf4 debug_full "[Quant] PC %a found for %a" PN.pp pn
+                Node.pp n;
+              ip :: acc
+          | _ -> acc
+        else acc
+      in
+      aux acc n info
+    in
+    (* parent type *)
+    let do_pt { PT.parent = f_pos; ty = vty } ip acc =
+      let aux acc n info1 =
+        match F_Pos.M.find_opt f_pos info1.Info.parents with
+        | Some _ ->
+            let no_match ty : bool =
+              Ground.Subst.S.is_empty (Pattern.match_ty Pattern.init ty vty)
+            in
+            if Ground.Ty.S.for_all no_match info1.ty then acc
+            else (
+              Debug.dprintf6 debug_full "[Quant] PT %a %a found for %a" F_Pos.pp
+                f_pos Expr.Ty.pp vty Node.pp n;
+              ip :: acc)
+        | None -> acc
+      in
+      aux acc n info
+    in
+    let acc = InvertedPath.HPP.fold do_pp InvertedPath.pp_ips d acc in
+    let acc = InvertedPath.HPC.fold do_pc InvertedPath.pc_ips d acc in
+    let acc = InvertedPath.HPT.fold do_pt InvertedPath.pt_ips d acc in
+    let acc = InvertedPath.HPN.fold do_pn InvertedPath.pn_ips d acc in
     acc
+end
 
-module Delayed_find_new_event = struct
-  let key =
-    Events.Dem.create
-      (module struct
-        type t = Node.t * InvertedPath.t list
+module Delayed_find_new_event : sig
+  val enqueue : _ Egraph.t -> Node.t -> InvertedPath.t list -> unit
+end = struct
+  module Delayed_find_new_event = struct
+    let key =
+      Events.Dem.create
+        (module struct
+          type t = unit
 
-        let name = "Quantifier.new_event"
-      end)
+          let name = "Quantifier.new_event"
+        end)
 
-  let delay = Events.Delayed_by 10
+    let delay = Events.Delayed_by 15
 
-  type runable = Node.t * InvertedPath.t list [@@deriving show]
+    type runable = unit
 
-  let print_runable = pp_runable
-  let run d (n, ips) = process_inverted_path d n ips
-end
+    let print_runable = Unit.pp
 
-let () = Events.register (module Delayed_find_new_event)
+    let scheduled =
+      Datastructure.Ref.create Fmt.nop "Quant.delayed_find_new_event"
+        Node.M.empty
+
+    let run d () =
+      let run () =
+        let m = Datastructure.Ref.get scheduled d in
+        Datastructure.Ref.set scheduled d Node.M.empty;
+        let triggers, callbacks =
+          Node.M.fold_left
+            (fun acc n ips ->
+              InvertedPath.S.fold_left
+                (fun acc ip -> InvertedPath.exec d acc Pattern.init n ip)
+                acc ips)
+            (Trigger.M.empty, Callback.M.empty)
+            m
+        in
+        Trigger.M.iter
+          (fun tri substs -> Trigger.instantiate_many d tri substs)
+          triggers;
+        Callback.M.iter
+          (fun callback substs -> Callback.run d callback substs)
+          callbacks
+      in
+      Debug.add_time_during stats_time run
+  end
+
+  let () = Events.register (module Delayed_find_new_event)
+
+  let enqueue d n l =
+    if not (Base.List.is_empty l) then (
+      let m = Datastructure.Ref.get Delayed_find_new_event.scheduled d in
+      if Node.M.is_empty m then
+        Events.new_pending_daemon d Delayed_find_new_event.key ();
+      let m =
+        Node.M.add_change InvertedPath.S.of_list
+          (fun l v -> List.fold_right InvertedPath.S.add l v)
+          n l m
+      in
+      Datastructure.Ref.set Delayed_find_new_event.scheduled d m)
+end
 
 let () =
   Dom.register
@@ -187,9 +323,9 @@ let () =
             let info = Info.merge d ~other ~repr info0 info1 in
             Egraph.set_dom d Info.dom cl0 info;
             Egraph.set_dom d Info.dom cl1 info;
-            let ips = find_new_event d cl0 info0 cl1 info1 in
-            if not (Base.List.is_empty ips) then
-              Events.new_pending_daemon d Delayed_find_new_event.key (repr, ips)
+            Debug.add_time_during stats_time (fun () ->
+                let ips = Find_new_event.two d cl0 info0 cl1 info1 [] in
+                Delayed_find_new_event.enqueue d repr ips)
     end)
 
 let skolemize d (e : Ground.ClosedQuantifier.s) =
@@ -217,10 +353,14 @@ let attach d th =
           Debug.dprintf2 debug "[Quant] Skolemize %a" Ground.ClosedQuantifier.pp
             th;
           Egraph.merge d (skolemize d e) n
+      | ({ binder = Exists; _ } as e), false
+      | ({ binder = Forall; _ } as e), true
+        when Quantifier_skipped.skipped d e ->
+          Debug.dprintf2 debug "[Quant] Skip %a" Ground.ClosedQuantifier.pp th
       | { binder = Exists; _ }, false | { binder = Forall; _ }, true ->
           let triggers =
-            match Trigger.get_user_triggers th with
-            | [] -> Trigger.compute_top_triggers th
+            match Trigger.get_user_triggers d th with
+            | [] -> Trigger.compute_top_triggers d th
             | triggers -> triggers
           in
           Debug.dprintf4 debug "[Quant] For %a adds %a"
@@ -231,7 +371,7 @@ let attach d th =
                    (fun t -> t.Trigger.pats)
                    (list ~sep:comma Pattern.pp)))
             triggers;
-          List.iter (add_trigger d) triggers
+          List.iter (InvertedPath.add_trigger d) triggers
       (* Todo match with current terms *))
 
 let quantifier_registered d th =
@@ -271,11 +411,13 @@ let add_info_on_ground_terms d thg =
     match Egraph.get_dom d Info.dom repr with
     | None ->
         Egraph.set_dom d Info.dom repr info;
-        process_inverted_path d repr (find_new_event d repr info repr info)
+        Delayed_find_new_event.enqueue d repr
+          (Find_new_event.one d repr info [])
     | Some info' ->
         Egraph.set_dom d Info.dom repr (Info.merge d ~repr ~other info info');
-        process_inverted_path d repr (find_new_event d repr info repr info);
-        process_inverted_path d repr (find_new_event d repr info repr info')
+        Find_new_event.one d repr info []
+        |> Find_new_event.two d repr info repr info'
+        |> Delayed_find_new_event.enqueue d repr
   in
   let add_pc pos n =
     merge_info n
@@ -286,20 +428,29 @@ let add_info_on_ground_terms d thg =
   in
   IArray.iteri ~f:add_pc g.args;
   merge_info res
-    { Info.empty with apps = F.M.singleton g.app (Ground.S.singleton thg) };
+    {
+      Info.empty with
+      apps = F.M.singleton g.app (Ground.S.singleton thg);
+      ty = Ground.Ty.S.singleton g.ty;
+    };
   Context.Push.push (F.EnvApps.find Pattern.env_ground_by_apps d g.app) thg;
   Context.Push.push (Pattern.EnvTy.find Pattern.env_node_by_ty d g.ty) res;
   (* Try pattern from the start *)
   let trgs = F.EnvApps.find Trigger.env_tri_by_apps d g.app in
-  Context.Push.iter (fun trg -> Trigger.match_ d trg res) trgs
+  Context.Push.iter
+    (function
+      | Trigger.Trigger trg -> Trigger.match_ d trg res
+      | Trigger.Callback call -> Callback.match_ d call res)
+    trgs
 
 let th_register d =
   (* let delay = Events.Delayed_by 10 in *)
   Daemon.attach_reg_sem d Ground.ClosedQuantifier.key quantifier_registered;
   Ground.register_converter d (fun d g ->
-      if application_useless d g then
-        Debug.dprintf2 debug "[Info] %a is redundant" Ground.pp g
-      else add_info_on_ground_terms d g);
+      Debug.add_time_during stats_time (fun () ->
+          if application_useless d g then
+            Debug.dprintf2 debug "[Info] %a is redundant" Ground.pp g
+          else add_info_on_ground_terms d g));
   Interp.Register.check_closed_quantifier d (fun d g ->
       let n = Ground.ClosedQuantifier.node g in
       let unknown =
@@ -307,6 +458,7 @@ let th_register d =
         | Forall -> Boolean.is_true d n
         | Exists -> Boolean.is_false d n
       in
-      if unknown then Unknown else Right)
+      if unknown then Unknown else Right);
+  Definitions.th_register d
 
 let () = Init.add_default_theory th_register
diff --git a/src_colibri2/theories/quantifier/quantifier.mli b/src_colibri2/theories/quantifier/quantifier.mli
index ea1e233032147771b03480dede93c545ff84a82a..e1791146f3e4b136de2319fbfaa74eef456124be 100644
--- a/src_colibri2/theories/quantifier/quantifier.mli
+++ b/src_colibri2/theories/quantifier/quantifier.mli
@@ -19,3 +19,18 @@
 (*************************************************************************)
 
 val th_register : Egraph.wt -> unit
+
+module Quantifier_skipped : sig
+  val register : _ Egraph.t -> (Ground.ClosedQuantifier.s -> bool) -> unit
+
+  type filter_term =
+    | App of Expr.builtin * filter_ty list * filter_term list
+    | Var of int
+    | Choice of filter_term list
+    | Any
+
+  and filter_ty = TyApp of Expr.builtin * filter_ty list | TyAny
+  and filter_quant = { vars : int list; filter : filter_term }
+
+  val match_ : Ground.ClosedQuantifier.s -> filter_quant -> bool
+end
diff --git a/src_colibri2/theories/quantifier/subst.ml b/src_colibri2/theories/quantifier/subst.ml
new file mode 100644
index 0000000000000000000000000000000000000000..96990e7f243d254013983ad484d697995025afd6
--- /dev/null
+++ b/src_colibri2/theories/quantifier/subst.ml
@@ -0,0 +1,276 @@
+(*************************************************************************)
+(*  This file is part of Colibri2.                                       *)
+(*                                                                       *)
+(*  Copyright (C) 2014-2021                                              *)
+(*    CEA   (Commissariat à l'énergie atomique et aux énergies           *)
+(*           alternatives)                                               *)
+(*                                                                       *)
+(*  you can redistribute it and/or modify it under the terms of the GNU  *)
+(*  Lesser General Public License as published by the Free Software      *)
+(*  Foundation, version 2.1.                                             *)
+(*                                                                       *)
+(*  It is distributed in the hope that it will be useful,                *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of       *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *)
+(*  GNU Lesser General Public License for more details.                  *)
+(*                                                                       *)
+(*  See the GNU Lesser General Public License version 2.1                *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
+(*************************************************************************)
+
+open Colibri2_popop_lib
+
+(** Copied from ground.ml *)
+
+let debug = Debug.register_flag ~desc:"" "Quant.Subst"
+
+type mode = { context : bool; avoid_new_term : bool }
+
+exception New_term
+
+let of_node mode d n =
+  if mode.avoid_new_term && not (Egraph.is_registered d n) then raise New_term;
+  Node.S.singleton n
+
+(**
+   subst_old: substitution applied on top of the quantification
+   subst_new: substitution to substitute the variable quantified
+   subst: the disjoint merge of the two
+ *)
+
+let rec convert_and_iter mode d (subst_old : Ground.Subst.t)
+    (subst_new : Ground.Subst.t) subst (t : Expr.Term.t) :
+    Node.S.t * bool (* with freevars *) =
+  match t.term_descr with
+  | Var v -> (
+      Debug.dprintf2 debug "ci var %a" Expr.Term.pp t;
+      match
+        ( Expr.Term.Var.M.find_opt v subst_old.term,
+          Expr.Term.Var.M.find_opt v subst_new.term )
+      with
+      | None, None -> invalid_arg (Fmt.str "Not_ground: %a" Expr.Term.Var.pp v)
+      | Some n1, Some n2 ->
+          invalid_arg
+            (Fmt.str "convert_iter: duplicate variable %a: %a -- %a"
+               Expr.Term.Var.pp v Node.pp n1 Node.pp n2)
+      | None, Some n -> (Node.S.singleton n, true)
+      | Some n, None -> (Node.S.singleton n, false))
+  | App
+      ( { term_descr = Cst { builtin = Expr.Ite; _ }; _ },
+        _,
+        [
+          cond;
+          { term_descr = Cst { builtin = Expr.True; _ }; _ };
+          { term_descr = Cst { builtin = Expr.False; _ }; _ };
+        ] ) ->
+      (* Why3 generates spurious (if v then true else false) *)
+      convert_and_iter mode d subst_old subst_new subst cond
+  | App (({ term_descr = Cst cst; _ } as f), tyargs, args) ->
+      Debug.dprintf2 debug "ci app cst %a" Expr.Term.pp t;
+      let with_freevars = ref false in
+      let args =
+        IArray.of_list_map
+          ~f:(fun arg ->
+            let arg', wf =
+              convert_and_iter mode d subst_old subst_new subst arg
+            in
+            Debug.dprintf3 debug "fv %a: %b" Expr.Term.pp arg wf;
+            with_freevars := !with_freevars || wf;
+            arg')
+          args
+      in
+      let nodes = Pattern.find_existing_app d subst cst tyargs args in
+      Debug.dprintf6 debug "find_existing_app: %a[%a] -> %a" F.pp cst
+        (IArray.pp Node.S.pp) args Node.S.pp nodes;
+      let mode =
+        if mode.context then
+          if Info.Builtin_skipped_for_trigger.skipped d cst.builtin then mode
+          else { mode with context = false }
+        else mode
+      in
+      if Node.S.is_empty nodes then (
+        if !with_freevars && mode.avoid_new_term && not mode.context then (
+          Debug.dprintf2 debug "new term cst: %a" Expr.Term.pp t;
+          raise New_term);
+        let args = IArray.map ~f:Node.S.choose args in
+        let n = Ground.convert_one_app subst d f tyargs args t.term_ty in
+        (Node.S.singleton n, !with_freevars))
+      else (nodes, !with_freevars)
+  | App (f, tyargs, args) ->
+      Debug.dprintf2 debug "ci app %a" Expr.Term.pp t;
+      if mode.avoid_new_term then (
+        Debug.dprintf2 debug "new term generic: %a" Expr.Term.pp t;
+        raise New_term);
+      let with_freevars = ref false in
+      let args =
+        IArray.of_list_map
+          ~f:(fun arg ->
+            let arg, wf =
+              convert_and_iter mode d subst_old subst_new subst arg
+            in
+            with_freevars := !with_freevars || wf;
+            arg)
+          args
+      in
+      let args = IArray.map ~f:Node.S.choose args in
+      let n = Ground.convert_one_app subst d f tyargs args t.term_ty in
+      (Node.S.singleton n, !with_freevars)
+  | Cst f ->
+      Debug.dprintf2 debug "ci cst %a" Expr.Term.pp t;
+      (* even if it could create a new term, it will create it only once (global term) *)
+      (Node.S.singleton (Ground.convert_one_cst subst d f), false)
+  | Expr.Binder (((Exists _ | Forall _ | Lambda _) as b), body) ->
+      ( Ground.convert_one_binder subst d b body t.term_ty |> of_node mode d,
+        true )
+  | Expr.Binder (Let_seq l, body) ->
+      let subst_old, subst_new, subst =
+        List.fold_left
+          (fun (subst_old, subst_new, subst) (v, t) ->
+            let n, fv =
+              convert_and_iter
+                { mode with context = false }
+                d subst_old subst_new subst t
+            in
+            let n = Node.S.choose n in
+            let add (s : Ground.Subst.t) =
+              { s with term = Expr.Term.Var.M.add v n s.term }
+            in
+            if fv then (subst_old, add subst_new, add subst)
+            else (add subst_old, subst_new, add subst))
+          (subst_old, subst_new, subst)
+          l
+      in
+      convert_and_iter mode d subst_old subst_new subst body
+  | Expr.Binder (Let_par l, body) ->
+      let subst_old, subst_new, subst =
+        List.fold_left
+          (fun (subst_old', subst_new', subst') (v, t) ->
+            let n, fv =
+              convert_and_iter
+                { mode with context = false }
+                d subst_old subst_new subst t
+            in
+            let n = Node.S.choose n in
+            let add (s : Ground.Subst.t) =
+              { s with term = Expr.Term.Var.M.add v n s.term }
+            in
+            if fv then (subst_old', add subst_new', add subst')
+            else (add subst_old', subst_new', add subst'))
+          (subst_old, subst_new, subst)
+          l
+      in
+      convert_and_iter mode d subst_old subst_new subst body
+  | Expr.Match (_, _) -> invalid_arg "match from dolmen not implemented"
+(* TODO convert to one multitest like
+   the match of why3  and projection *)
+
+let rec check_context_aux d (subst_old : Ground.Subst.t)
+    (subst_new : Ground.Subst.t) (subst : Ground.Subst.t) (t : Expr.Term.t) =
+  match t.term_descr with
+  | Var _ -> true
+  | App
+      ( { term_descr = Cst { builtin = Expr.Ite; _ }; _ },
+        _,
+        [
+          cond;
+          { term_descr = Cst { builtin = Expr.True; _ }; _ };
+          { term_descr = Cst { builtin = Expr.False; _ }; _ };
+        ] ) ->
+      (* Why3 generates spurious (if v then true else false) *)
+      check_context d subst_old subst_new subst cond
+  | App ({ term_descr = Cst cst; _ }, _, args) ->
+      if Info.Builtin_skipped_for_trigger.skipped d cst.builtin then
+        List.for_all (check_context d subst_old subst_new subst) args
+      else
+        let n, _ =
+          convert_and_iter
+            { context = true; avoid_new_term = true }
+            d subst_old subst_new subst t
+        in
+        not (Node.S.is_empty n)
+  | App _ -> false
+  | Cst _ ->
+      true
+      (* Ground.convert_one_cst subst d f
+       * |> of_node { context = true; avoid_new_term = true } d
+       * |> Node.S.is_empty |> not *)
+  | Expr.Binder (((Exists _ | Forall _ | Lambda _) as b), body) ->
+      Ground.convert_one_binder subst d b body t.term_ty
+      |> of_node { context = true; avoid_new_term = true } d
+      |> Node.S.is_empty |> not
+  | Expr.Binder (Let_seq l, body) ->
+      let subst_old, subst_new, subst =
+        List.fold_left
+          (fun (subst_old, subst_new, subst) (v, t) ->
+            let n, fv =
+              convert_and_iter
+                { context = false; avoid_new_term = true }
+                d subst_old subst_new subst t
+            in
+            let n = Node.S.choose n in
+            let add (s : Ground.Subst.t) =
+              { s with term = Expr.Term.Var.M.add v n s.term }
+            in
+            if fv then (subst_old, add subst_new, add subst)
+            else (add subst_old, subst_new, subst))
+          (subst_old, subst_new, subst)
+          l
+      in
+      check_context d subst_old subst_new subst body
+  | Expr.Binder (Let_par l, body) ->
+      let subst_old, subst_new, subst =
+        List.fold_left
+          (fun (subst_old', subst_new', subst') (v, t) ->
+            let n, fv =
+              convert_and_iter
+                { context = false; avoid_new_term = true }
+                d subst_old subst_new subst t
+            in
+            let n = Node.S.choose n in
+            let add (s : Ground.Subst.t) =
+              { s with term = Expr.Term.Var.M.add v n s.term }
+            in
+            if fv then (subst_old', add subst_new', add subst')
+            else (add subst_old', subst_new', subst'))
+          (subst_old, subst_new, subst)
+          l
+      in
+      check_context d subst_old subst_new subst body
+  | Expr.Match (_, _) -> invalid_arg "match from dolmen not implemented"
+(* TODO convert to one multitest like
+   the match of why3  and projection *)
+
+and check_context d subst_old subst_new subst t =
+  let c = check_context_aux d subst_old subst_new subst t in
+  if not c then Debug.dprintf2 debug "check false: %a" Expr.Term.pp t;
+  c
+
+let convert ~subst_old ~subst_new d t =
+  let subst = Ground.Subst.distinct_union subst_old subst_new in
+  try
+    let n, _ =
+      convert_and_iter
+        { context = true; avoid_new_term = false }
+        d subst_old subst_new subst t
+    in
+    Node.S.choose n
+  with New_term -> assert false
+
+let convert_avoid_new_terms ~subst_old ~subst_new d t =
+  let subst = Ground.Subst.distinct_union subst_old subst_new in
+  let b =
+    try check_context d subst_old subst_new subst t
+    with New_term ->
+      Debug.dprintf0 debug "check_context";
+      false
+  in
+  if b then
+    try
+      let n, _ =
+        convert_and_iter
+          { context = true; avoid_new_term = true }
+          d subst_old subst_new subst t
+      in
+      Some (Node.S.choose n)
+    with New_term -> None
+  else None
diff --git a/src_colibri2/theories/quantifier/subst.mli b/src_colibri2/theories/quantifier/subst.mli
new file mode 100644
index 0000000000000000000000000000000000000000..e9b262c70dd33c5d2057b0408b30b4ccf39e99e5
--- /dev/null
+++ b/src_colibri2/theories/quantifier/subst.mli
@@ -0,0 +1,37 @@
+(*************************************************************************)
+(*  This file is part of Colibri2.                                       *)
+(*                                                                       *)
+(*  Copyright (C) 2014-2021                                              *)
+(*    CEA   (Commissariat à l'énergie atomique et aux énergies           *)
+(*           alternatives)                                               *)
+(*                                                                       *)
+(*  you can redistribute it and/or modify it under the terms of the GNU  *)
+(*  Lesser General Public License as published by the Free Software      *)
+(*  Foundation, version 2.1.                                             *)
+(*                                                                       *)
+(*  It is distributed in the hope that it will be useful,                *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of       *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *)
+(*  GNU Lesser General Public License for more details.                  *)
+(*                                                                       *)
+(*  See the GNU Lesser General Public License version 2.1                *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
+(*************************************************************************)
+
+val convert :
+  subst_old:Ground.Subst.t ->
+  subst_new:Ground.Subst.t ->
+  _ Egraph.t ->
+  Expr.Term.t ->
+  Node.t
+(** Same as {!Ground.convert} but try to reuse terms that are equal and already
+   in the egraph *)
+
+val convert_avoid_new_terms :
+  subst_old:Ground.Subst.t ->
+  subst_new:Ground.Subst.t ->
+  _ Egraph.t ->
+  Expr.Term.t ->
+  Node.t option
+(** Same as {!convert} but doesn't create new terms (except for skipped builtins
+   {!Trigger.Builtin_skipped_for_trigger.register} *)
diff --git a/src_colibri2/theories/quantifier/trigger.ml b/src_colibri2/theories/quantifier/trigger.ml
index d05efcaa16cf4e1023bbe419f5534d437376ce9e..7a8305445bba8051eee3057c70100053ec26b3e2 100644
--- a/src_colibri2/theories/quantifier/trigger.ml
+++ b/src_colibri2/theories/quantifier/trigger.ml
@@ -21,17 +21,43 @@
 open Colibri2_popop_lib
 open Common
 
-module T = struct
+type inst_step = NotSeen | Delayed | Instantiated
+
+module T : sig
+  type t = private {
+    id : int;
+    pat : Pattern.t;
+    pats : Pattern.t list;
+    checks : Pattern.t list;
+    form : Ground.ClosedQuantifier.t;
+    eager : bool;
+    substs : inst_step SubstTrie.t;
+  }
+
+  include Popop_stdlib.TaggedType with type t := t
+
+  val mk :
+    pat:Pattern.t ->
+    pats:Pattern.t list ->
+    checks:Pattern.t list ->
+    form:Ground.ClosedQuantifier.t ->
+    eager:bool ->
+    _ Egraph.t ->
+    t
+end = struct
   open! Base
 
   type t = {
+    id : int;
     pat : Pattern.t;
     pats : Pattern.t list;
     checks : Pattern.t list;
     form : Ground.ClosedQuantifier.t;
     eager : bool;
+    substs : inst_step SubstTrie.t;
   }
-  [@@deriving eq, ord, hash]
+
+  let tag t = t.id
 
   let pp fmt t =
     Fmt.pf fmt "[%a, %a ( %a ) -> %a]" Pattern.pp t.pat
@@ -39,17 +65,39 @@ module T = struct
       t.pats
       Fmt.(list ~sep:comma Pattern.pp)
       t.checks Ground.ClosedQuantifier.pp t.form
+
+  let id_get, id_incr = Util.get_counter ()
+
+  let mk ~pat ~pats ~checks ~form ~eager d =
+    id_incr ();
+    {
+      id = id_get ();
+      pat;
+      pats;
+      checks;
+      form;
+      eager;
+      substs = SubstTrie.create (Egraph.context d);
+    }
 end
 
 include T
-include Popop_stdlib.MkDatatype (T)
+include (Popop_stdlib.MakeMSH (T) : Popop_stdlib.Datatype with type t := t)
 
-let register_builtin_skipped_for_trigger, builtin_skipped_for_trigger =
-  let q = Base.Queue.create () in
-  ( Base.Queue.enqueue q,
-    fun builtin -> Base.Queue.exists q ~f:(fun p -> p builtin) )
+let pattern_remove_coercion_option =
+  Options.register ~pp:Fmt.bool "Quant.pattern_coercion"
+    Cmdliner.Arg.(
+      value & flag
+      & info [ "remove-coercion-in-pattern" ] ~doc:"Remove coercion in patterns")
 
-let compute_top_triggers (cq : Ground.ClosedQuantifier.t) =
+let pattern_of_term d (cq : Ground.ClosedQuantifier.s) pat =
+  try
+    Pattern.of_term_exn
+      ~coercion:(not (Options.get d pattern_remove_coercion_option))
+      ~subst:cq.subst pat
+  with Pattern.Unconvertible -> raise Impossible
+
+let compute_top_triggers d (cq : Ground.ClosedQuantifier.t) =
   let cq' = Ground.ClosedQuantifier.sem cq in
   let tyvs = cq'.ty_vars in
   let tvs = cq'.term_vars in
@@ -76,24 +124,12 @@ let compute_top_triggers (cq : Ground.ClosedQuantifier.t) =
         aux pats (Expr.Term.subst Expr.Subst.empty subst f)
     | Expr.Binder (_, _) -> pats (* todo *)
     | Expr.Match (_, _) -> pats (* todo *)
-    | Expr.App
-        ( {
-            term_descr =
-              Cst
-                {
-                  builtin =
-                    ( Expr.And | Expr.Equal | Expr.Equiv | Expr.Or | Expr.Xor
-                    | Expr.Imply | Expr.Ite | Expr.Neg );
-                  _;
-                };
-            _;
-          },
-          _,
-          tl ) ->
-        List.fold_left aux pats tl
     | Expr.App ({ term_descr = Cst { builtin; _ }; _ }, _, tl)
-      when builtin_skipped_for_trigger builtin ->
+      when Info.Builtin_skipped_for_trigger.skipped d builtin ->
         List.fold_left aux pats tl
+    | Expr.Var _ ->
+        (* variable alone are bad pattern *)
+        pats
     | _ -> t :: pats
   in
   let pats = CCList.sort_uniq ~cmp:Expr.Term.compare (aux [] t) in
@@ -105,7 +141,7 @@ let compute_top_triggers (cq : Ground.ClosedQuantifier.t) =
         let sty, st =
           Expr.Term.free_vars (Expr.Ty.Var.S.empty, Expr.Term.Var.S.empty) pat
         in
-        let pat = Pattern.of_term ~subst:cq'.subst pat in
+        let pat = pattern_of_term d cq' pat in
         (pat, sty, st))
       pats
   in
@@ -157,13 +193,8 @@ let compute_top_triggers (cq : Ground.ClosedQuantifier.t) =
         | [] -> acc
         | a :: l ->
             aux
-              ({
-                 pat = a;
-                 pats = other @ l;
-                 checks = pats_partial;
-                 form = cq;
-                 eager = true;
-               }
+              (mk d ~pat:a ~pats:(other @ l) ~checks:pats_partial ~form:cq
+                 ~eager:true
               :: acc)
               (a :: other) l
       in
@@ -184,13 +215,9 @@ let compute_top_triggers (cq : Ground.ClosedQuantifier.t) =
         | [] -> acc
         | a :: l ->
             aux
-              ({
-                 pat = a;
-                 pats = [];
-                 checks = other @ l @ pats_partial;
-                 form = cq;
-                 eager = true;
-               }
+              (mk d ~pat:a ~pats:[]
+                 ~checks:(other @ l @ pats_partial)
+                 ~form:cq ~eager:true
               :: acc)
               (a :: other) l
       in
@@ -207,7 +234,7 @@ let compute_top_triggers (cq : Ground.ClosedQuantifier.t) =
       pats_full_with_others;
     pats_full_with_others
 
-let compute_all_triggers (cq : Ground.ClosedQuantifier.t) =
+let compute_all_triggers d (cq : Ground.ClosedQuantifier.t) =
   let cq' = Ground.ClosedQuantifier.sem cq in
   let tyvs = cq'.ty_vars in
   let tvs = cq'.term_vars in
@@ -252,19 +279,14 @@ let compute_all_triggers (cq : Ground.ClosedQuantifier.t) =
       (fun (c, (sty, st)) ->
         if Expr.Ty.Var.S.subset tyvs sty && Expr.Term.Var.S.subset tvs st then
           Some
-            {
-              pat = Pattern.of_term ~subst:cq'.subst c;
-              pats = [];
-              form = cq;
-              eager = true;
-              checks = [];
-            }
+            (mk d ~pat:(pattern_of_term d cq' c) ~pats:[] ~form:cq ~eager:true
+               ~checks:[])
         else None)
       pats
   in
   pats
 
-let get_user_triggers (cq : Ground.ClosedQuantifier.t) =
+let get_user_triggers d (cq : Ground.ClosedQuantifier.t) =
   let cq' = Ground.ClosedQuantifier.sem cq in
   let pats = Expr.Term.get_tag_list cq'.body Expr.Tags.triggers in
   let tyvs = Expr.Ty.Var.S.of_list cq'.ty_vars in
@@ -278,18 +300,12 @@ let get_user_triggers (cq : Ground.ClosedQuantifier.t) =
             pats
         in
         if Expr.Ty.Var.S.subset tyvs sty && Expr.Term.Var.S.subset tvs st then
-          let pats = List.map (Pattern.of_term ~subst:cq'.subst) pats in
+          let pats = List.map (pattern_of_term d cq') pats in
           let rec aux acc other = function
             | [] -> acc
             | a :: l ->
                 aux
-                  ({
-                     pat = a;
-                     pats = other @ l;
-                     checks = [];
-                     form = cq;
-                     eager = true;
-                   }
+                  (mk d ~pat:a ~pats:(other @ l) ~checks:[] ~form:cq ~eager:true
                   :: acc)
                   (a :: other) l
           in
@@ -298,26 +314,35 @@ let get_user_triggers (cq : Ground.ClosedQuantifier.t) =
   in
   pats
 
-let env_vars = Datastructure.Push.create pp "Quantifier.Trigger.vars"
+type tri_callback = Trigger of t | Callback of Callback.t [@@deriving show]
+
+let env_vars =
+  Datastructure.Push.create pp_tri_callback "Quantifier.Trigger.vars"
 
 let env_tri_by_apps =
-  F.EnvApps.create (Context.Push.pp ~sep:Fmt.semi pp)
+  F.EnvApps.create (Context.Push.pp ~sep:Fmt.semi pp_tri_callback)
     "Quantifier.Trigger.tri_by_apps" (fun c _ -> Context.Push.create c)
 
-let add_trigger d t =
-  match t.pat with
+let register_pattern d (pat : Pattern.t) t =
+  match pat with
   | Var _ -> Datastructure.Push.push env_vars d t
   | App (f, _, _) -> Context.Push.push (F.EnvApps.find env_tri_by_apps d f) t
   | Node _ -> ()
 
+let add_trigger d t = register_pattern d t.pat (Trigger t)
+let add_callback d c = register_pattern d (Callback.pattern c) (Callback c)
+
 let instantiate_aux d tri subst =
+  SubstTrie.set tri.substs subst Instantiated;
   let form = Ground.ClosedQuantifier.sem tri.form in
   Debug.incr nb_instantiation;
   let subst = Ground.Subst.distinct_union subst form.subst in
   let n = Ground.convert ~subst d form.body in
+  (* let n = Subst.convert ~subst_old:form.subst ~subst_new:subst d form.body in *)
   if
     Colibri2_stdlib.Debug.test_flag Colibri2_stdlib.Debug.stats
-    && not (Egraph.is_registered d n)
+    && not (Egraph.is_equal d n (Ground.ClosedQuantifier.node tri.form))
+    (* not (Egraph.is_registered d n) *)
   then Debug.incr nb_new_instantiation;
   Egraph.register d n;
   Egraph.merge d n (Ground.ClosedQuantifier.node tri.form)
@@ -339,9 +364,10 @@ module Delayed_instantiation = struct
 
   let run d (tri, subst) =
     let instantiate d =
-      Debug.dprintf8 debug
-        "[Quant] %a delayed instantiation %a, pat %a, checks:%a" Ground.Subst.pp
-        subst Ground.ClosedQuantifier.pp tri.form
+      Debug.dprintf10 debug_instantiation
+        "[Quant] %a delayed instantiation %a, pat %a %a, checks:%a"
+        Ground.Subst.pp subst Ground.ClosedQuantifier.pp tri.form Pattern.pp
+        tri.pat
         Fmt.(list ~sep:comma Pattern.pp)
         tri.pats
         Fmt.(list ~sep:comma Pattern.pp)
@@ -359,34 +385,88 @@ end
 
 let () = Events.register (module Delayed_instantiation)
 
-let instantiate d tri subst =
-  let subst =
-    {
-      subst with
-      Ground.Subst.term =
-        Expr.Term.Var.M.map (Egraph.find_def d) subst.Ground.Subst.term;
-    }
+let mode_option =
+  Options.register ~pp:Fmt.bool "Quant.old"
+    Cmdliner.Arg.(
+      value & flag & info [ "quant-old" ] ~doc:"Use quant old heuristic")
+
+let no_eager_instantiation =
+  Options.register ~pp:Fmt.bool "Quant.no_eager_instantiation"
+    Cmdliner.Arg.(
+      value & flag
+      & info [ "no-eager-instantiation" ] ~doc:"Don't do eager instantiation")
+
+let instantiate' d tri subst =
+  let show_debug debug =
+    Debug.dprintf11 debug
+      "[Quant] %a instantiation found %a, pat %a,%a, checks:%a, eager:%b"
+      Ground.Subst.pp subst Ground.ClosedQuantifier.pp tri.form Pattern.pp
+      tri.pat
+      Fmt.(list ~sep:comma Pattern.pp)
+      tri.pats
+      Fmt.(list ~sep:comma Pattern.pp)
+      tri.checks tri.eager
   in
-  Debug.dprintf9 debug
-    "[Quant] %a instantiation found %a, pat %a, checks:%a, eager:%b"
-    Ground.Subst.pp subst Ground.ClosedQuantifier.pp tri.form
-    Fmt.(list ~sep:comma Pattern.pp)
-    tri.pats
-    Fmt.(list ~sep:comma Pattern.pp)
-    tri.checks tri.eager;
-  if
-    tri.eager
-    && List.for_all
-         (fun pat ->
-           not (Node.S.is_empty (Pattern.check_term_exists d subst pat)))
-         tri.checks
-  then (
-    Debug.incr nb_eager_instantiation;
-    instantiate_aux d tri subst)
-  else (
-    Debug.dprintf0 debug "[Quant] Delayed";
-    Debug.incr nb_delayed_instantiation;
-    Events.new_pending_daemon d Delayed_instantiation.key (tri, subst))
+  let level_inst = SubstTrie.find_def ~default:NotSeen tri.substs subst in
+  let delayed () =
+    match level_inst with
+    | NotSeen ->
+        SubstTrie.set tri.substs subst Delayed;
+
+        Debug.dprintf0 debug_instantiation "[Quant]   Delayed";
+        Debug.incr nb_delayed_instantiation;
+        Events.new_pending_daemon d Delayed_instantiation.key (tri, subst)
+    | Delayed | Instantiated ->
+        Debug.dprintf0 debug_instantiation "[Quant] Already delayed"
+  in
+  let no_eager_instantiation = Options.get d no_eager_instantiation in
+  match level_inst with
+  | Instantiated -> show_debug debug_full
+  | Delayed when no_eager_instantiation -> show_debug debug_full
+  | NotSeen when no_eager_instantiation -> delayed ()
+  | _ ->
+      show_debug debug_instantiation;
+      if Options.get d mode_option then
+        if
+          tri.eager
+          && List.for_all
+               (fun pat ->
+                 not (Node.S.is_empty (Pattern.check_term_exists d subst pat)))
+               tri.checks
+        then (
+          Debug.incr nb_eager_instantiation;
+          instantiate_aux d tri subst;
+          Debug.dprintf0 debug "[Quant]   Done")
+        else delayed ()
+      else if tri.eager then
+        let form = Ground.ClosedQuantifier.sem tri.form in
+        match
+          Subst.convert_avoid_new_terms ~subst_old:form.subst ~subst_new:subst d
+            form.body
+        with
+        | Some n ->
+            SubstTrie.set tri.substs subst Instantiated;
+            Debug.incr nb_instantiation;
+            Debug.incr nb_eager_instantiation;
+            if
+              Colibri2_stdlib.Debug.test_flag Colibri2_stdlib.Debug.stats
+              && not (Egraph.is_registered d n)
+            then Debug.incr nb_new_instantiation;
+            Egraph.register d n;
+            Egraph.merge d n (Ground.ClosedQuantifier.node tri.form);
+            Debug.dprintf0 debug "[Quant]   Done"
+        | None -> delayed ()
+      else delayed ()
+
+let instantiate d t subst = instantiate' d t (Ground.Subst.map_repr d subst)
+
+let instantiate_many d t substs =
+  let substs =
+    Ground.Subst.S.fold_left
+      (fun acc s -> Ground.Subst.S.add (Ground.Subst.map_repr d s) acc)
+      Ground.Subst.S.empty substs
+  in
+  Ground.Subst.S.iter (instantiate' d t) substs
 
 let match_ d tri n =
   Debug.dprintf4 debug "[Quant] match %a %a" pp tri Node.pp n;
diff --git a/src_colibri2/theories/quantifier/trigger.mli b/src_colibri2/theories/quantifier/trigger.mli
index 3299fe2f1b42a1c64565f1515a8b2d600f903755..3e77f52321b71b5524881a6559a133ad6c721f8f 100644
--- a/src_colibri2/theories/quantifier/trigger.mli
+++ b/src_colibri2/theories/quantifier/trigger.mli
@@ -20,7 +20,10 @@
 
 (** Trigger *)
 
-type t = {
+type inst_step = NotSeen | Delayed | Instantiated
+
+type t = private {
+  id : int;
   pat : Pattern.t;  (** The pattern on which to wait for a substitution *)
   pats : Pattern.t list;
       (** The other ones used to obtain a complete
@@ -29,29 +32,35 @@ type t = {
   form : Ground.ClosedQuantifier.t;  (** the body of the formula *)
   eager : bool;
       (** If it should be eagerly applied, otherwise wait for LastEffort *)
+  substs : inst_step SubstTrie.t;
 }
 
 include Colibri2_popop_lib.Popop_stdlib.Datatype with type t := t
 
-val compute_top_triggers : Ground.ClosedQuantifier.t -> t list
+val compute_top_triggers : _ Egraph.t -> Ground.ClosedQuantifier.t -> t list
 (** Compute triggers, that should only add logical connective or equalities are
    new terms *)
 
-val compute_all_triggers : Ground.ClosedQuantifier.t -> t list
+val compute_all_triggers : _ Egraph.t -> Ground.ClosedQuantifier.t -> t list
 (** Compute all the triggers whose patterns contain all the variables of the formula *)
 
-val get_user_triggers : Ground.ClosedQuantifier.t -> t list
+val get_user_triggers : _ Egraph.t -> Ground.ClosedQuantifier.t -> t list
 (** return the triggers given by the user *)
 
-val env_vars : t Datastructure.Push.t
+type tri_callback = Trigger of t | Callback of Callback.t [@@deriving show]
+
+val env_vars : tri_callback Datastructure.Push.t
 (** Triggers that are only variables *)
 
-val env_tri_by_apps : t Context.Push.t F.EnvApps.t
+val env_tri_by_apps : tri_callback Context.Push.t F.EnvApps.t
 (** Triggers sorted by their top symbol *)
 
 val add_trigger : Egraph.wt -> t -> unit
 (** Register a new trigger *)
 
+val add_callback : Egraph.wt -> Callback.t -> unit
+(** Register a new trigger *)
+
 val instantiate : Egraph.wt -> t -> Ground.Subst.t -> unit
 (** [instantiate d tri subst] instantiates the trigger [tri] with the
    substitution [subst]:
@@ -62,10 +71,8 @@ val instantiate : Egraph.wt -> t -> Ground.Subst.t -> unit
    * at last effort otherwise
 *)
 
+val instantiate_many : Egraph.wt -> t -> Ground.Subst.S.t -> unit
+
 val match_ : Egraph.wt -> t -> Node.t -> unit
 (** [match_ d tri n] match the pattern of [tri] with [n] and instantiate [tri]
     with the resulting substitutions *)
-
-val register_builtin_skipped_for_trigger : (Expr.builtin -> bool) -> unit
-(** The registered function tells when an application should be skipped when
-   looking for patterns in a term (top down) *)
diff --git a/src_common/float_interval.mlw b/src_common/float_interval.mlw
index 939ba180713b94a29789b115370e5e37bde13a6f..962cdbcd623e2d02677113b3ab8d3a78a239f1af 100644
--- a/src_common/float_interval.mlw
+++ b/src_common/float_interval.mlw
@@ -20,6 +20,7 @@ module GenericFloat
   use real.Truncate as Truncate
   use real.RealInfix
   use export RoundingMode
+  use bool.Bool
 
   (** {2 Part I - Public Interface}   *)
 
@@ -36,24 +37,35 @@ module GenericFloat
   constant max_real : real (* defined when cloning *)
 
   predicate in_range (x:real) = -. max_real <=. x <=. max_real
+  
+  axiom max_real_not_zero: max_real <> 0.
 
   type finite = abstract {
     r : real
   }
   invariant { in_range r }
   invariant { r <> 0. }
+  by { r = max_real }
 
   meta coercion function r
 
+  function mk_finite real : finite
+  
+  axiom mk_finite_def: forall rr [mk_finite rr].
+    in_range rr -> rr <> 0. -> (mk_finite rr).r = rr
+
+  axiom mk_finite_fed: forall f:finite [r f].
+    (mk_finite (r f)) = f
+
   type t =
   | Zero bool
   | Infinity bool
   | NaN
-  | Finite finite
+  | Finite finite 
 
   (** {3 Constructors and Constants} *)
 
-  val constant zeroF     : t   (** +0.0 *)
+  let constant zeroF     : t  = Zero false (** +0.0 *)
   (* exp_bias = 2^(eb - 1) - 1 *)
   (* max_finite_exp = 2^sb - 2 - exp_bias = exp_bias *)
   (* max_significand = (2^eb + 2^eb - 1) * 2^(1-eb) *)
@@ -63,19 +75,29 @@ module GenericFloat
 
   (** {3 Operators} *)
 
-  val function add mode t t : t
   val function sub mode t t : t
   val function mul mode t t : t
   val function div mode t t : t
     (** The four basic operations, rounded in the given mode *)
 
   val function abs         t   : t   (** Absolute value *)
-  val function neg         t   : t   (** Opposite *)
+  
+  (** Opposite *)
+  function neg    (x:t)   : t =
+   match x with
+   | NaN -> NaN
+   | Zero neg -> Zero (notb neg)
+   | Finite f -> Finite (mk_finite (-. (f.r)))
+   | Infinity neg -> Infinity (notb neg)
+   end
+   
+   val neg (x:t) : t
+    ensures { result = neg x }
+  
   val function fma  mode t t t : t   (** Fused multiply-add: x * y + z *)
   val function sqrt mode   t   : t   (** Square root *)
 
   let function (.-_) (x:t)   : t = neg x
-  let function (.+)  (x y:t) : t = add RNE x y
   let function (.-)  (x y:t) : t = sub RNE x y
   let function (.*)  (x y:t) : t = mul RNE x y
   let function (./)  (x y:t) : t = div RNE x y
@@ -102,9 +124,10 @@ module GenericFloat
    *)
 
   (** {3 Comparisons} *)
+  predicate sign (r:real) = r <. 0.
   function to_real   (x:t)    : real =
     match x with
-    | NaN -> max_real +. 1.
+    | NaN -> max_real +. 2.
     | Infinity neg -> if neg then -. max_real -. 1. else max_real +. 1.
     | Zero _ -> 0.
     | Finite r -> r
@@ -148,7 +171,7 @@ module GenericFloat
      | Zero _,  Zero _ -> true
      | Zero _, Finite r -> 0. <=. r
      | Finite r, Zero _ -> r <=. 0.
-     | Finite r1, Finite r2 -> r1 <=. r2
+     | Finite r1, Finite r2 -> r1.r <=. r2.r
      | Infinity neg1, Infinity neg2 -> orb neg1 (notb neg2)
      | _, Infinity neg2 -> notb neg2
      | Infinity neg1, _ -> neg1
@@ -157,10 +180,36 @@ module GenericFloat
   val le (f1:t) (f2:t) : bool
     ensures { result = le f1 f2 }
 
-  val predicate lt t t
+  predicate lt (f1:t) (f2:t) =
+     match f1, f2 with
+     | NaN, _ | _, NaN -> false
+     | Zero _,  Zero _ -> false
+     | Zero _, Finite r -> 0. <. r
+     | Finite r, Zero _ -> r <. 0.
+     | Finite r1, Finite r2 -> r1.r <. r2.r
+     | Infinity neg1, Infinity neg2 -> andb neg1 (notb neg2)
+     | _, Infinity neg2 -> notb neg2
+     | Infinity neg1, _ -> neg1
+     end
+
+  val lt (f1:t) (f2:t) : bool
+    ensures { result = lt f1 f2 }
+
+  predicate eq (f1:t) (f2:t) =
+     match f1, f2 with
+     | Zero _,  Zero _ -> true
+     | Finite r1, Finite r2 -> r1.r = r2.r
+     | Infinity neg1, Infinity neg2 -> neg1 = neg2
+     | _ -> false
+     end
+
+
+  val eq (f1:t) (f2:t) : bool
+    ensures { result = eq f1 f2 }
+
+
   let predicate ge (x:t) (y:t) = le y x
   let predicate gt (x:t) (y:t) = lt y x
-  val predicate eq t t
   (** equality on floats, different from = since not (eq NaN NaN) *)
 
   let predicate (.<=) (x:t) (y:t) = le x y
@@ -196,8 +245,6 @@ module GenericFloat
   axiom is_not_finite: forall x:t.
     not (is_finite x) <-> (is_infinite x \/ is_nan x)
 
-
-
   (** {3 Conversions from other sorts} *)
 
   (* from bitvec binary interchange                           *)
@@ -280,7 +327,7 @@ module GenericFloat
 
   axiom minus_max_real_round : forall m. round m (-. max_real) = -. max_real
 
-  axiom is_finite: forall x:t. is_finite x -> in_range (to_real x)
+  goal is_finite: forall x:t. is_finite x <-> in_range (to_real x)
 
   (* used as a condition to propagate is_finite *)
   predicate no_overflow (m:mode) (x:real) = in_range (round m x)
@@ -332,62 +379,62 @@ module GenericFloat
   predicate diff_sign (x y : t) =
     (is_positive x /\ is_negative y) \/ (is_negative x /\ is_positive y)
 
-  axiom feq_eq: forall x y.
+  goal feq_eq: forall x y.
     is_finite x -> is_finite y -> not (is_zero x) -> x .= y -> x = y
 
-  axiom eq_feq: forall x y.
+  goal eq_feq: forall x y.
     is_finite x -> is_finite y -> x = y -> x .= y
 
-  axiom eq_refl: forall x. is_finite x -> x .= x
+  goal eq_refl: forall x. is_finite x -> x .= x
 
-  axiom eq_sym :
+  goal eq_sym :
     forall x y. x .= y -> y .= x
 
-  axiom eq_trans :
+  goal eq_trans :
     forall x y z. x .= y -> y .= z -> x .= z
 
-  axiom eq_zero: zeroF .= (.- zeroF)
+  goal eq_zero: zeroF .= (.- zeroF)
 
-  axiom eq_to_real_finite: forall x y.
+  goal eq_to_real_finite: forall x y.
     is_finite x /\ is_finite y -> (x .= y <-> to_real x = to_real y)
 
-  axiom eq_special: forall x y. x .= y ->
+  goal eq_special: forall x y. x .= y ->
        (is_not_nan x  /\ is_not_nan y
     /\ ((is_finite x /\ is_finite y)
         \/ (is_infinite x /\ is_infinite y /\ same_sign x y)))
 
-  axiom lt_finite: forall x y [lt x y].
+  goal lt_finite: forall x y [lt x y].
     is_finite x /\ is_finite y -> (lt x y <-> to_real x <. to_real y)
 
-  axiom le_finite: forall x y [le x y].
+  goal le_finite: forall x y [le x y].
     is_finite x /\ is_finite y -> (le x y <-> to_real x <=. to_real y)
 
-  lemma le_lt_trans:
+  goal le_lt_trans:
     forall x y z:t. x .<= y /\ y .< z -> x .< z
 
-  lemma lt_le_trans:
+  goal lt_le_trans:
     forall x y z:t. x .< y /\ y .<= z -> x .< z
 
-  lemma le_ge_asym:
+  goal le_ge_asym:
     forall x y:t. x .<= y /\ x .>= y -> x .= y
 
-  lemma not_lt_ge: forall x y:t.
+  goal not_lt_ge: forall x y:t.
     not (x .< y) /\ is_not_nan x /\ is_not_nan y -> x .>= y
 
-  lemma not_gt_le: forall x y:t.
+  goal not_gt_le: forall x y:t.
     not (x .> y) /\ is_not_nan x /\ is_not_nan y -> x .<= y
 
-  axiom le_special: forall x y [le x y]. le x y ->
+  goal le_special: forall x y [le x y]. le x y ->
       ((is_finite x /\ is_finite y)
    \/ ((is_minus_infinity x /\ is_not_nan y)
    \/  (is_not_nan x /\ is_plus_infinity y)))
 
-  axiom lt_special: forall x y [lt x y]. lt x y ->
+  goal lt_special: forall x y [lt x y]. lt x y ->
       ((is_finite x /\ is_finite y)
    \/ ((is_minus_infinity x /\ is_not_nan y /\ not (is_minus_infinity y))
    \/  (is_not_nan x /\ not (is_plus_infinity x) /\ is_plus_infinity y)))
 
-  axiom lt_lt_finite: forall x y z. lt x y -> lt y z -> is_finite y
+  goal lt_lt_finite: forall x y z. lt x y -> lt y z -> is_finite y
 
   (*  lemmas on sign *)
   axiom positive_to_real: forall x[is_positive x|to_real x >=. 0.0].
@@ -405,15 +452,15 @@ module GenericFloat
   axiom negative_or_positive: forall x.
     is_not_nan x -> is_positive x \/ is_negative x
 
-  lemma diff_sign_trans:
+  goal diff_sign_trans:
     forall x y z:t. (diff_sign x y /\ diff_sign y z) -> same_sign x z
 
-  lemma diff_sign_product:
+  goal diff_sign_product:
     forall x y:t.
       (is_finite x /\ is_finite y /\ to_real x *. to_real y <. 0.0) ->
         diff_sign x y
 
-  lemma same_sign_product:
+  goal same_sign_product:
     forall x y:t.
       (is_finite x /\ is_finite y /\ same_sign x y) ->
         to_real x *. to_real y >=. 0.0
@@ -447,17 +494,54 @@ module GenericFloat
     end
 
   (** {3 binary operations} *)
+  let function is_RTN mode =
+     match mode with
+     | RTN -> true
+     | _ -> false
+     end
 
-  axiom add_finite: forall m:mode, x y:t [add m x y].
+  function add (mode:mode) (x:t) (y:t) : t =
+    match x, y with
+    | NaN, _ -> NaN
+    | _, NaN -> NaN
+    | Zero z1, Zero z2 -> if z1 = z2 then Zero z1 else Zero (is_RTN mode)
+    | Zero _, _ -> y
+    | _, Zero _ -> x
+    | Infinity z1, Infinity z2 -> if z1 = z2 then x else NaN
+    | Infinity _, _ -> x
+    | _, Infinity _ -> y
+    | Finite x, Finite y ->
+       let r = (round mode (x +. y)) in
+       if r = 0. then Zero (is_RTN mode)
+       else if in_range r then
+         Finite (mk_finite r)
+       else
+       match mode with
+        | RTN -> if sign r then Infinity true
+                           else Finite (mk_finite max_real)
+        | RTP -> if sign r then Finite (mk_finite (-. max_real))
+                           else Infinity false
+        | RTZ -> if sign r then Finite (mk_finite (-. max_real))
+                           else Finite (mk_finite max_real)
+        | (RNA | RNE) -> Infinity (sign r)
+      end
+    end
+
+  val add (mode:mode) (x y:t) : t
+    ensures { result = add mode x y }
+
+  let function (.+)  (x y:t) : t = add RNE x y
+
+  goal add_finite: forall m:mode, x y:t [add m x y].
     is_finite x -> is_finite y -> no_overflow m (to_real x +. to_real y) ->
     is_finite (add m x y) /\
     to_real (add m x y) = round m (to_real x +. to_real y)
 
-  lemma add_finite_rev: forall m:mode, x y:t [add m x y].
+  goal add_finite_rev: forall m:mode, x y:t [add m x y].
     is_finite (add m x y) ->
     is_finite x /\ is_finite y
 
-  lemma add_finite_rev_n: forall m:mode, x y:t [add m x y].
+  goal add_finite_rev_n: forall m:mode, x y:t [add m x y].
     to_nearest m ->
     is_finite (add m x y) ->
     no_overflow m (to_real x +. to_real y) /\
@@ -468,11 +552,11 @@ module GenericFloat
     is_finite (sub m x y) /\
     to_real (sub m x y) = round m (to_real x -. to_real y)
 
-  lemma sub_finite_rev: forall m:mode, x y:t [sub m x y].
+  goal sub_finite_rev: forall m:mode, x y:t [sub m x y].
     is_finite (sub m x y) ->
     is_finite x /\ is_finite y
 
-  lemma sub_finite_rev_n: forall m:mode, x y:t [sub m x y].
+  goal sub_finite_rev_n: forall m:mode, x y:t [sub m x y].
     to_nearest m ->
     is_finite (sub m x y) ->
     no_overflow m (to_real x -. to_real y) /\
@@ -483,11 +567,11 @@ module GenericFloat
     is_finite (mul m x y) /\
     to_real (mul m x y) = round m (to_real x *. to_real y)
 
-  lemma mul_finite_rev: forall m:mode, x y:t [mul m x y].
+  goal mul_finite_rev: forall m:mode, x y:t [mul m x y].
     is_finite (mul m x y) ->
     is_finite x /\ is_finite y
 
-  lemma mul_finite_rev_n: forall m:mode, x y:t [mul m x y].
+  goal mul_finite_rev_n: forall m:mode, x y:t [mul m x y].
     to_nearest m ->
     is_finite (mul m x y) ->
     no_overflow m (to_real x *. to_real y) /\
@@ -499,12 +583,12 @@ module GenericFloat
     is_finite (div m x y) /\
     to_real (div m x y) = round m (to_real x /. to_real y)
 
-  lemma div_finite_rev: forall m:mode, x y:t [div m x y].
+  goal div_finite_rev: forall m:mode, x y:t [div m x y].
     is_finite (div m x y) ->
     (is_finite x /\ is_finite y /\ not is_zero y) \/
     (is_finite x /\ is_infinite y /\ to_real (div m x y) = 0.)
 
-  lemma div_finite_rev_n: forall m:mode, x y:t [div m x y].
+  goal div_finite_rev_n: forall m:mode, x y:t [div m x y].
     to_nearest m ->
     is_finite (div m x y) -> is_finite y ->
     no_overflow m (to_real x /. to_real y) /\
@@ -515,7 +599,7 @@ module GenericFloat
     is_finite (neg x) /\
     to_real (neg x) = -. to_real x
 
-  lemma neg_finite_rev: forall x:t [neg x].
+  goal neg_finite_rev: forall x:t [neg x].
     is_finite (neg x) ->
     is_finite x /\
     to_real (neg x) = -. to_real x
@@ -526,7 +610,7 @@ module GenericFloat
     to_real (abs x) = Abs.abs (to_real x) /\
     is_positive (abs x)
 
-  lemma abs_finite_rev: forall x:t [abs x].
+  goal abs_finite_rev: forall x:t [abs x].
     is_finite (abs x) ->
     is_finite x /\
     to_real (abs x) = Abs.abs (to_real x)
@@ -539,11 +623,11 @@ module GenericFloat
     is_finite (fma m x y z) /\
     to_real (fma m x y z) = round m (to_real x *. to_real y +. to_real z)
 
-  lemma fma_finite_rev: forall m:mode, x y z:t [fma m x y z].
+  goal fma_finite_rev: forall m:mode, x y z:t [fma m x y z].
     is_finite (fma m x y z) ->
     is_finite x /\ is_finite y /\ is_finite z
 
-  lemma fma_finite_rev_n: forall m:mode, x y z:t [fma m x y z].
+  goal fma_finite_rev_n: forall m:mode, x y z:t [fma m x y z].
     to_nearest m ->
     is_finite (fma m x y z) ->
     no_overflow m (to_real x *. to_real y +. to_real z) /\
@@ -556,7 +640,7 @@ module GenericFloat
     is_finite (sqrt m x) /\
     to_real (sqrt m x) = round m (S.sqrt (to_real x))
 
-  lemma sqrt_finite_rev: forall m:mode, x:t [sqrt m x].
+  goal sqrt_finite_rev: forall m:mode, x:t [sqrt m x].
     is_finite (sqrt m x) ->
     is_finite x /\ to_real x >=. 0. /\
     to_real (sqrt m x) = round m (S.sqrt (to_real x))
@@ -566,7 +650,7 @@ module GenericFloat
 
   axiom same_sign_real_round: forall x m r[same_sign_real x (round m r)]. same_sign_real x (round m r) -> same_sign_real x r
 
-  axiom add_special: forall m:mode, x y:t [add m x y].
+  goal add_special: forall m:mode, x y:t [add m x y].
     let r = add m x y in
     (is_nan x \/ is_nan y -> is_nan r)
     /\
@@ -698,10 +782,10 @@ module GenericFloat
 
   (* min and max *)
 
-  lemma Min_r : forall x y:t. y .<= x -> (min x y) .= y
-  lemma Min_l : forall x y:t. x .<= y -> (min x y) .= x
-  lemma Max_r : forall x y:t. y .<= x -> (max x y) .= x
-  lemma Max_l : forall x y:t. x .<= y -> (max x y) .= y
+  goal Min_r : forall x y:t. y .<= x -> (min x y) .= y
+  goal Min_l : forall x y:t. x .<= y -> (min x y) .= x
+  goal Max_r : forall x y:t. y .<= x -> (max x y) .= x
+  goal Max_l : forall x y:t. x .<= y -> (max x y) .= y
 
   (* _____________ *)
 
@@ -855,7 +939,7 @@ module Float_interval
   predicate valid (x:t) =
     match x with
     | Inan -> true
-    | Intv l h _ -> F.(l .<= h)
+    | Intv l h _ -> F.(l .<= h) /\ F.is_not_nan l /\ F.is_not_nan h
     end
 
   predicate mem (x:F.t) (i:t) =
@@ -895,64 +979,28 @@ module Float_interval
       F.is_nan (F.add m f1 f2) -> F.is_infinite f1
       
   goal G1: forall f. F.is_plus_infinity f -> f = F.Infinity false
-      
-  let ghost test3  m f1 f2 f3 =
-    requires { not F.(is_nan (add m f1 f3)) }
-    requires { not F.(is_nan (add m f2 f3)) }
+
+  lemma G2: forall m f1 f2 f3.
+    not F.(is_nan (add m f1 f3)) -> not F.(is_nan (add m f2 f3)) -> F.(le f1 f2) ->
+     F.(le (add m f1 f3) (add m f2 f3))
+
+  let ghost monotone_add (m:F.mode) (f1:F.t) (f2:F.t) (f3:F.t) =
+    requires { F.(is_not_nan (add m f1 f3)) }
+    requires { F.(is_not_nan (add m f2 f3)) }
     requires { F.(le f1 f2) }
-    ensures { F.(le (add m f1 f3) (add m f2 f3)) }
-       if F.is_finite f1 then
-         if F.is_finite f2 then
-          if F.is_finite f3 then
-           if F.no_overflow m F.((to_real f1) +. (to_real f3)) then
- 1
-       else             if F.no_overflow m F.((to_real f2) +. (to_real f3)) then begin
-
-(*          assert { F.(to_real f1) <=. (F.to_real f2) };
-          assert { (F.to_real f1) +. (F.to_real f3) <=. (F.to_real f2) +. (F.to_real f3) };
-          assert { (F.to_real (F.add m f1 f3)) <=. (F.to_real (F.add m f2 f3)) };
-          assert { (F.is_finite (F.add m f1 f3)) };
-          assert { (F.is_finite (F.add m f2 f3)) };
-          assert { F.(le (add m f1 f3) (add m f2 f3)) }; *)
-          6
-       end
-       else begin (*
-         assert { F.overflow_value m (F.add m f2 f3) };
-         assert { F.overflow_value m (F.add m f1 f3) }; *)
-         if F.is_plus_infinity (F.add m f2 f3) then begin
-          (* assert { not (F.is_nan F.(add m f1 f3)) }; *)
-          (* assert { F.(same_sign_real (add m f2 f3) ((to_real f2) +. (to_real f3))) }; *)
-          (* assert { F.(same_sign_real (add m f1 f3) ((to_real f1) +. (to_real f3))) }; *)
-          51
-          end
-         else if F.is_minus_infinity (F.add m f2 f3) then begin
-           52
-          end
-         else if F.(to_real (F.add m f2 f3) = max_real) then 53 else
-         if F.(to_real (F.add m f2 f3) = -. max_real) then 54
-          else 55
-       end 
-      else begin
-      4
-      end
-      else 2
-    else begin
-      if F.is_plus_infinity f1 then begin
-        assert { F.is_plus_infinity f2 };
-        assert { f1 = F.Infinity false };
-        assert { f2 = F.Infinity false };
-        66;
-      end else begin
-       assert { F.is_minus_infinity f1 };
-       67      
-       end
-    end  
-
-  let cadd (m : F.mode) plus_infinity minus_infinity (i1 i2: t) : t
+    ensures  { F.(le (add m f1 f3) (add m f2 f3)) } ()
+
+  let ghost monotone_add2 (m:F.mode) (f3:F.t) (f1:F.t) (f2:F.t) =
+    requires { F.(is_not_nan (add m f3 f1)) }
+    requires { F.(is_not_nan (add m f3 f2)) }
+    requires { F.(le f1 f2) }
+    ensures  { F.(le (add m f3 f1) (add m f3 f2)) } ()
+
+
+
+  let cadd (m : F.mode) (i1 i2: t) : t
      requires { valid i1 }
      requires { valid i2 }
-     requires { F.is_plus_infinity plus_infinity }
-     requires { F.is_minus_infinity minus_infinity }
      ensures { forall f1 f2. mem f1 i1 -> mem f2 i2 -> mem F.(add m f1 f2) result } =
      match i1, i2 with
      | Inan, _ | _, Inan -> Inan
@@ -979,14 +1027,97 @@ module Float_interval
             assert { F.is_plus_infinity h1 \/ F.is_plus_infinity h2 };
             assert { forall f1 f2. mem f1 i1 -> mem f2 i2 -> (F.is_plus_infinity f1 \/ F.is_plus_infinity f2 \/ F.is_nan f1 \/ F.is_nan f2) };
             assert { forall f1 f2. mem f1 i1 -> mem f2 i2 -> (F.is_plus_infinity F.(f1.+f2) \/ F.is_nan F.(f1.+f2)) };
-            Intv plus_infinity plus_infinity true
+            Intv (F.Infinity false) (F.Infinity false) true
           end
         else
           if F.is_nan sum2 then
-          Intv minus_infinity minus_infinity true
+          Intv (F.Infinity true) (F.Infinity true) true
           else Intv sum1 sum2 (orb (orb (orb b1 b2)
            F.(andb (F.is_plus_infinity h1) (F.is_minus_infinity l2)))
            F.(andb (F.is_plus_infinity h2) (F.is_minus_infinity l1)))
       end
 
+(*  let ghost add_nan (m:mode) (f1:F.t) (f2:F.t) F.is_not_nan f1 -> F.is_not_nan f2 -> F.is_nan (F.add m f1 f2) -> F.diff_sign f1 f2 /\ F.is_infinite f1 /\ F.is_infinite f2 *)
+
+  let ghost add_nan (m:F.mode) (f1:F.t) (f2:F.t)
+    requires { F.is_not_nan f1 }
+    requires { F.is_not_nan f2 }
+    requires { F.is_nan (F.add m f1 f2) }
+    ensures { match f1, f2 with
+     | F.Infinity neg1, F.Infinity neg2 -> neg1 <> neg2
+     | _ -> false
+     end } = ()
+
+  let ghost add_not_nan (m:F.mode) (f1:F.t) (f2:F.t)
+    requires { F.is_not_nan (F.add m f1 f2) }
+    ensures { match f1, f2 with
+     | F.NaN, _ | _, F.NaN -> false
+     | F.Infinity neg1, F.Infinity neg2 -> neg1 = neg2
+     | _ -> true
+     end } = ()
+
+
+  goal add_not_nan: forall m f1 f2[F.is_nan (F.add m f1 f2)]. F.is_not_nan f1 -> F.is_not_nan f2 -> F.is_not_nan (F.add m f1 f2) ->
+                         (F.same_sign f1 f2 /\ F.is_infinite f1 /\ F.is_infinite f2) \/ F.is_finite f1 \/ F.is_finite f2
+
+  let cadd2 (m : F.mode) (i1 i2: t) : t
+     requires { valid i1 }
+     requires { valid i2 }
+     ensures { forall f1 f2. mem f1 i1 -> mem f2 i2 -> mem F.(add m f1 f2) result }
+     ensures { valid result } =
+     match i1, i2 with
+     | Inan, _ | _, Inan -> Inan
+     | Intv l1 h1 b1, Intv l2 h2 b2 ->
+        let sum1 = F.add m l1 l2 in
+        let sum2 = F.add m h1 h2 in
+        if F.is_nan sum1 then
+          if F.is_nan sum2 then begin
+            Inan
+            end
+          else begin
+            Intv (F.Infinity false) (F.Infinity false) true
+          end
+        else
+          if F.is_nan sum2 then
+          Intv (F.Infinity true) (F.Infinity true) true
+          else Intv sum1 sum2 (orb (orb (orb b1 b2)
+           F.(andb (F.is_plus_infinity h1) (F.is_minus_infinity l2)))
+           F.(andb (F.is_plus_infinity h2) (F.is_minus_infinity l1)))
+      end
+
+  let cadd3 (m : F.mode) (i1 i2: t) : t
+     requires { valid i1 }
+     requires { valid i2 }
+     ensures { forall f1 f2. mem f1 i1 -> mem f2 i2 -> mem F.(add m f1 f2) result }
+     ensures { valid result } =
+     match i1, i2 with
+     | Inan, _ | _, Inan -> Inan
+     | Intv l1 h1 b1, Intv l2 h2 b2 ->
+        let sum1 = F.add m l1 l2 in
+        let sum2 = F.add m h1 h2 in
+        match F.is_nan sum1, F.is_nan sum2 with
+        | True, True ->  add_nan m l1 l2; add_nan m h1 h2; Inan
+        | True, False -> add_nan m l1 l2; Intv (F.Infinity false) (F.Infinity false) true
+        | False, True -> add_nan m h1 h2; Intv (F.Infinity true) (F.Infinity true) true
+        | False, False ->begin
+            add_not_nan m l1 l2;
+            add_not_nan m h1 h2;
+            let lemma sum1_le  (f1:F.t) (f2:F.t) =
+              requires { mem f1 i1 }
+              requires { mem f2 i2 }
+              requires { F.is_not_nan (F.add m l1 l2) }
+              requires { F.is_not_nan (F.add m f1 f2) }
+              ensures  { F.le (F.add m l1 l2) (F.add m f1 f2) }
+               add_not_nan m f1 f2;
+               monotone_add m l1 f1 f2;
+               monotone_add2 m l1 l2 f2;
+            in
+            Intv sum1 sum2 (orb (orb (orb b1 b2)
+            F.(andb (F.is_plus_infinity h1) (F.is_minus_infinity l2)))
+            F.(andb (F.is_plus_infinity h2) (F.is_minus_infinity l1)))
+           end
+      end
+      end
+
+
 end
diff --git a/src_common/float_interval/why3session.xml b/src_common/float_interval/why3session.xml
index 23f3b80bbcbcd13fbf8d7e98185d7554a9d734be..94c561372187f2d385b52fa1b1d8ff75d8eaa9e1 100644
--- a/src_common/float_interval/why3session.xml
+++ b/src_common/float_interval/why3session.xml
@@ -6,67 +6,160 @@
 <file format="whyml">
 <path name=".."/><path name="float_interval.mlw"/>
 <theory name="GenericFloat">
- <goal name="finite&#39;vc" expl="VC for finite">
+ <goal name="finite&#39;vc" expl="VC for finite" proved="true">
+ <proof prover="0"><result status="valid" time="0.06"/></proof>
  </goal>
- <goal name="le_lt_trans">
+ <goal name="is_finite" proved="true">
+ <proof prover="0"><result status="valid" time="0.11"/></proof>
  </goal>
- <goal name="lt_le_trans">
+ <goal name="feq_eq" proved="true">
+ <proof prover="0"><result status="valid" time="0.07"/></proof>
  </goal>
- <goal name="le_ge_asym">
+ <goal name="eq_feq" proved="true">
+ <proof prover="0"><result status="valid" time="0.07"/></proof>
  </goal>
- <goal name="not_lt_ge">
+ <goal name="eq_refl" proved="true">
+ <proof prover="0"><result status="valid" time="0.07"/></proof>
  </goal>
- <goal name="not_gt_le">
+ <goal name="eq_sym" proved="true">
+ <proof prover="0"><result status="valid" time="0.07"/></proof>
  </goal>
- <goal name="diff_sign_trans">
+ <goal name="eq_trans" proved="true">
+ <proof prover="0"><result status="valid" time="0.08"/></proof>
  </goal>
- <goal name="diff_sign_product">
+ <goal name="eq_zero" proved="true">
+ <proof prover="0"><result status="valid" time="0.03"/></proof>
  </goal>
- <goal name="same_sign_product">
+ <goal name="eq_to_real_finite" proved="true">
+ <proof prover="0"><result status="valid" time="0.16"/></proof>
  </goal>
- <goal name="add_finite_rev">
+ <goal name="eq_special" proved="true">
+ <proof prover="0"><result status="valid" time="0.18"/></proof>
  </goal>
- <goal name="add_finite_rev_n">
+ <goal name="lt_finite" proved="true">
+ <proof prover="0"><result status="valid" time="0.18"/></proof>
+ </goal>
+ <goal name="le_finite" proved="true">
+ <proof prover="0"><result status="valid" time="0.10"/></proof>
+ </goal>
+ <goal name="le_lt_trans" proved="true">
+ <proof prover="0"><path name="float_interval-GenericFloat-le_lt_trans_2.psmt2"/><undone/></proof>
+ <transf name="introduce_premises" proved="true" >
+  <goal name="le_lt_trans.0" proved="true">
+  <proof prover="0" obsolete="true"><path name="float_interval-GenericFloat-le_lt_trans_1.psmt2"/><result status="unknown" time="0.00" steps="0"/></proof>
+  <transf name="destruct_term" proved="true" arg1="x">
+   <goal name="le_lt_trans.0.0" proved="true">
+   <proof prover="0"><result status="valid" time="0.11"/></proof>
+   </goal>
+   <goal name="le_lt_trans.0.1" proved="true">
+   <proof prover="0"><result status="valid" time="0.07"/></proof>
+   </goal>
+   <goal name="le_lt_trans.0.2" proved="true">
+   <proof prover="0"><result status="valid" time="0.12"/></proof>
+   </goal>
+   <goal name="le_lt_trans.0.3" proved="true">
+   <proof prover="0"><result status="valid" time="0.13"/></proof>
+   </goal>
+  </transf>
+  </goal>
+ </transf>
+ </goal>
+ <goal name="lt_le_trans" proved="true">
+ <proof prover="0"><result status="valid" time="0.15"/></proof>
+ </goal>
+ <goal name="le_ge_asym" proved="true">
+ <proof prover="0"><result status="valid" time="0.13"/></proof>
+ </goal>
+ <goal name="not_lt_ge" proved="true">
+ <proof prover="0"><result status="valid" time="0.10"/></proof>
+ </goal>
+ <goal name="not_gt_le" proved="true">
+ <proof prover="0"><result status="valid" time="0.11"/></proof>
+ </goal>
+ <goal name="le_special" proved="true">
+ <proof prover="0"><result status="valid" time="0.18"/></proof>
+ </goal>
+ <goal name="lt_special" proved="true">
+ <proof prover="0"><result status="valid" time="0.19"/></proof>
+ </goal>
+ <goal name="lt_lt_finite" proved="true">
+ <proof prover="0"><result status="valid" time="0.09"/></proof>
+ </goal>
+ <goal name="diff_sign_trans" proved="true">
+ <proof prover="0"><result status="valid" time="0.12"/></proof>
+ </goal>
+ <goal name="diff_sign_product" proved="true">
+ <proof prover="0"><result status="valid" time="0.16"/></proof>
+ </goal>
+ <goal name="same_sign_product" proved="true">
+ <proof prover="0"><result status="valid" time="0.16"/></proof>
+ </goal>
+ <goal name="add_finite" proved="true">
+ <proof prover="0"><result status="valid" time="0.13"/></proof>
+ </goal>
+ <goal name="add_finite_rev" proved="true">
+ <proof prover="0"><result status="valid" time="0.20"/></proof>
+ </goal>
+ <goal name="add_finite_rev_n" proved="true">
+ <proof prover="0"><result status="valid" time="0.40"/></proof>
  </goal>
  <goal name="sub_finite_rev">
+ <proof prover="0"><result status="unknown" time="0.19"/></proof>
  </goal>
  <goal name="sub_finite_rev_n">
+ <proof prover="0"><result status="unknown" time="0.19"/></proof>
  </goal>
  <goal name="mul_finite_rev">
+ <proof prover="0"><result status="unknown" time="0.20"/></proof>
  </goal>
  <goal name="mul_finite_rev_n">
+ <proof prover="0"><result status="timeout" time="5.00"/></proof>
  </goal>
  <goal name="div_finite_rev">
+ <proof prover="0"><result status="unknown" time="0.12"/></proof>
  </goal>
  <goal name="div_finite_rev_n">
+ <proof prover="0"><result status="unknown" time="0.12"/></proof>
  </goal>
- <goal name="neg_finite_rev">
+ <goal name="neg_finite_rev" proved="true">
+ <proof prover="0"><result status="valid" time="0.09"/></proof>
  </goal>
  <goal name="abs_finite_rev">
+ <proof prover="0"><result status="unknown" time="0.12"/></proof>
  </goal>
- <goal name="fma_finite_rev">
+ <goal name="fma_finite_rev" proved="true">
+ <proof prover="0" timelimit="20"><result status="valid" time="0.16"/></proof>
  </goal>
  <goal name="fma_finite_rev_n">
+ <proof prover="0"><result status="unknown" time="0.11"/></proof>
  </goal>
  <goal name="sqrt_finite_rev">
+ <proof prover="0"><result status="timeout" time="5.00"/></proof>
+ </goal>
+ <goal name="add_special">
+ <proof prover="0"><result status="unknown" time="0.72"/></proof>
  </goal>
  <goal name="Min_r">
+ <proof prover="0"><result status="unknown" time="0.13"/></proof>
  </goal>
  <goal name="Min_l">
+ <proof prover="0"><result status="unknown" time="0.12"/></proof>
  </goal>
  <goal name="Max_r">
+ <proof prover="0"><result status="unknown" time="0.13"/></proof>
  </goal>
  <goal name="Max_l">
+ <proof prover="0"><result status="unknown" time="0.14"/></proof>
  </goal>
 </theory>
 <theory name="Float_interval">
  <goal name="Test2" proved="true">
- <proof prover="0"><result status="valid" time="0.14"/></proof>
- <transf name="split_vc" >
-  <goal name="Test2.0">
-  <transf name="instantiate" arg1="is_not_finite" arg2="f1">
-   <goal name="Test2.0.0">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.05"/></proof>
+ <proof prover="0"><result status="valid" time="0.04"/></proof>
+ <transf name="split_vc" proved="true" >
+  <goal name="Test2.0" proved="true">
+  <transf name="instantiate" proved="true" arg1="is_not_finite" arg2="f1">
+   <goal name="Test2.0.0" proved="true">
+   <proof prover="0"><result status="valid" time="0.05"/></proof>
    </goal>
   </transf>
   </goal>
@@ -85,7 +178,7 @@
  </transf>
  </goal>
  <goal name="G1" proved="true">
- <proof prover="0"><path name="float_interval-Float_interval-G1_1.psmt2"/><result status="timeout" time="5.00"/></proof>
+ <proof prover="0"><result status="valid" time="0.09"/></proof>
  <transf name="split_vc" proved="true" >
   <goal name="G1.0" proved="true">
   <transf name="unfold" proved="true" arg1="is_plus_infinity" arg2="in" arg3="H">
@@ -109,519 +202,264 @@
   </goal>
  </transf>
  </goal>
- <goal name="test3&#39;vc" expl="VC for test3">
- <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
+ <goal name="G2" proved="true">
+ <proof prover="0"><result status="valid" time="1.76"/></proof>
+ </goal>
+ <goal name="monotone_add&#39;vc" expl="VC for monotone_add" proved="true">
+ <proof prover="0"><result status="valid" time="0.31"/></proof>
+ </goal>
+ <goal name="monotone_add2&#39;vc" expl="VC for monotone_add2" proved="true">
+ <proof prover="0" timelimit="100"><result status="valid" time="5.68"/></proof>
+ </goal>
+ <goal name="cadd&#39;vc" expl="VC for cadd">
  <transf name="split_vc" >
-  <goal name="test3&#39;vc.0" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="valid" time="0.21"/></proof>
+  <goal name="cadd&#39;vc.0" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.88"/></proof>
   </goal>
-  <goal name="test3&#39;vc.1" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-  <transf name="split_vc" >
-   <goal name="test3&#39;vc.1.0" expl="assertion">
-   <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-   </goal>
-  </transf>
+  <goal name="cadd&#39;vc.1" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="4.28"/></proof>
   </goal>
-  <goal name="test3&#39;vc.2" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-  <transf name="split_vc" >
-   <goal name="test3&#39;vc.2.0" expl="assertion">
-   <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-   </goal>
-  </transf>
+  <goal name="cadd&#39;vc.2" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="2.38"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.3" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.10"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.4" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.84"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.5" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.24"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.6" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.58"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.7" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.29"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.8" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.87"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.9" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.80"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.10" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.23"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.11" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.10"/></proof>
   </goal>
-  <goal name="test3&#39;vc.3" expl="assertion">
+  <goal name="cadd&#39;vc.12" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.53"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.13" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="0.88"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.14" expl="assertion" proved="true">
+  <proof prover="0"><result status="valid" time="2.14"/></proof>
+  </goal>
+  <goal name="cadd&#39;vc.15" expl="postcondition">
   <transf name="split_vc" >
-   <goal name="test3&#39;vc.3.0" expl="assertion">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.24"/></proof>
+   <goal name="cadd&#39;vc.15.0" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.05"/></proof>
    </goal>
-   <goal name="test3&#39;vc.3.1" expl="postcondition">
-   <proof prover="0"><path name="float_interval-Float_interval-test3qtvc_1.psmt2"/><undone/></proof>
+   <goal name="cadd&#39;vc.15.1" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.12"/></proof>
    </goal>
-   <goal name="test3&#39;vc.3.2" expl="postcondition">
-   <proof prover="0"><undone/></proof>
-   </goal>
-   <goal name="test3&#39;vc.3.3" expl="postcondition">
-   <proof prover="0"><undone/></proof>
-   </goal>
-   <goal name="test3&#39;vc.3.4" expl="postcondition">
-   <proof prover="0"><undone/></proof>
+   <goal name="cadd&#39;vc.15.2" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.13"/></proof>
    </goal>
-   <goal name="test3&#39;vc.3.5" expl="postcondition">
-   <proof prover="0"><undone/></proof>
+   <goal name="cadd&#39;vc.15.3" expl="postcondition">
+   <proof prover="0"><result status="timeout" time="5.00"/></proof>
    </goal>
-   <goal name="test3&#39;vc.3.6" expl="postcondition">
-   <proof prover="0"><undone/></proof>
+  </transf>
+  </goal>
+ </transf>
+ </goal>
+ <goal name="add_nan&#39;vc" expl="VC for add_nan" proved="true">
+ <proof prover="0"><result status="valid" time="0.11"/></proof>
+ </goal>
+ <goal name="add_not_nan&#39;vc" expl="VC for add_not_nan" proved="true">
+ <proof prover="0"><result status="valid" time="0.10"/></proof>
+ </goal>
+ <goal name="add_not_nan" proved="true">
+ <proof prover="0"><result status="valid" time="0.09"/></proof>
+ </goal>
+ <goal name="cadd2&#39;vc" expl="VC for cadd2">
+ <proof prover="0" timelimit="100" obsolete="true"><result status="timeout" time="177.00"/></proof>
+ <transf name="remove" arg1="zero,one,(-),(&gt;),(&lt;=),(&gt;=),zero1,one1,(&gt;&#39;),(&lt;=&#39;),(&gt;=&#39;),(-&#39;),(/),( *.),(&lt;=.),andb,orb,notb,xorb,implb,Assoc1,Unit_def_l,Unit_def_r,Inv_def_l,Inv_def_r,Comm1,Assoc,Mul_distr_l,Mul_distr_r,Comm,Unitary,NonTrivialRing,Refl,Trans,Antisymm,Total,ZeroLessOne,CompatOrderAdd,CompatOrderMult,Assoc3,Unit_def_l1,Unit_def_r1,Inv_def_l1,Inv_def_r1,Comm3,Assoc2,Mul_distr_l1,Mul_distr_r1,Comm2,Unitary1,NonTrivialRing1,Inverse,add_div,sub_div,neg_div,assoc_mul_div,assoc_div_mul,assoc_div_div,Refl1,Trans1,Antisymm1,Total1,ZeroLessOne1,CompatOrderAdd1,CompatOrderMult1,Power_0,Power_s,Power_1,Power_sum,pow2_0,pow2_2,pow2_4,pow2_5,pow2_6">
+  <goal name="cadd2&#39;vc.0" expl="VC for cadd2">
+  <proof prover="0"><result status="timeout" time="5.00"/></proof>
+  </goal>
+ </transf>
+ <transf name="split_vc" >
+  <goal name="cadd2&#39;vc.0" expl="postcondition">
+  <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
+  <transf name="split_vc" >
+   <goal name="cadd2&#39;vc.0.0" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.05"/></proof>
    </goal>
-   <goal name="test3&#39;vc.3.7" expl="postcondition">
-   <proof prover="0"><undone/></proof>
+   <goal name="cadd2&#39;vc.0.1" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.11"/></proof>
    </goal>
-   <goal name="test3&#39;vc.3.8" expl="postcondition">
-   <proof prover="0"><undone/></proof>
+   <goal name="cadd2&#39;vc.0.2" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.13"/></proof>
    </goal>
-   <goal name="test3&#39;vc.3.9" expl="postcondition">
-   <proof prover="0"><undone/></proof>
-   </goal>
-   <goal name="test3&#39;vc.3.10" expl="postcondition">
-   <proof prover="0"><undone/></proof>
+   <goal name="cadd2&#39;vc.0.3" expl="postcondition">
+   <proof prover="0"><result status="timeout" time="5.00"/></proof>
    </goal>
   </transf>
   </goal>
-  <goal name="test3&#39;vc.4" expl="postcondition">
+  <goal name="cadd2&#39;vc.1" expl="postcondition">
   <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-  </goal>
-  <goal name="test3&#39;vc.5" expl="postcondition">
   <transf name="split_vc" >
-   <goal name="test3&#39;vc.5.0" expl="postcondition">
-   <proof prover="0"><undone/></proof>
-   </goal>
-   <goal name="test3&#39;vc.5.1" expl="postcondition">
-   <proof prover="0"><undone/></proof>
+   <goal name="cadd2&#39;vc.1.0" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.04"/></proof>
    </goal>
-   <goal name="test3&#39;vc.5.2" expl="postcondition">
-   <proof prover="0"><undone/></proof>
+   <goal name="cadd2&#39;vc.1.1" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.04"/></proof>
    </goal>
-   <goal name="test3&#39;vc.5.3" expl="postcondition">
-   <proof prover="0"><undone/></proof>
+   <goal name="cadd2&#39;vc.1.2" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.03"/></proof>
    </goal>
-   <goal name="test3&#39;vc.5.4" expl="postcondition">
-   <proof prover="0"><undone/></proof>
-   </goal>
-   <goal name="test3&#39;vc.5.5" expl="postcondition">
-   <proof prover="0"><undone/></proof>
-   </goal>
-   <goal name="test3&#39;vc.5.6" expl="postcondition">
-   <proof prover="0"><undone/></proof>
+   <goal name="cadd2&#39;vc.1.3" expl="postcondition">
+   <proof prover="0"><result status="timeout" time="5.00"/></proof>
    </goal>
   </transf>
   </goal>
  </transf>
  </goal>
- <goal name="cadd&#39;vc" expl="VC for cadd">
- <transf name="split_vc" >
-  <goal name="cadd&#39;vc.0" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="valid" time="0.47"/></proof>
+ <goal name="cadd3&#39;vc" expl="VC for cadd3" proved="true">
+ <proof prover="0" timelimit="100" obsolete="true"><result status="timeout" time="100.00"/></proof>
+ <transf name="split_vc" proved="true" >
+  <goal name="cadd3&#39;vc.0" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.05"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.1" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="valid" time="0.91"/></proof>
+  <goal name="cadd3&#39;vc.1" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.05"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.2" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="valid" time="0.78"/></proof>
+  <goal name="cadd3&#39;vc.2" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.06"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.3" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="valid" time="0.30"/></proof>
+  <goal name="cadd3&#39;vc.3" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.03"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.4" expl="assertion">
-  <transf name="split_vc" >
-   <goal name="cadd&#39;vc.4.0" expl="assertion">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.35"/></proof>
-   </goal>
-  </transf>
+  <goal name="cadd3&#39;vc.4" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.05"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.5" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="valid" time="0.27"/></proof>
+  <goal name="cadd3&#39;vc.5" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.06"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.6" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="valid" time="0.29"/></proof>
+  <goal name="cadd3&#39;vc.6" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.04"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.7" expl="assertion">
-  <transf name="split_vc" >
-   <goal name="cadd&#39;vc.7.0" expl="assertion">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.26"/></proof>
+  <goal name="cadd3&#39;vc.7" expl="precondition" proved="true">
+  <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
+  <transf name="split_vc" proved="true" >
+   <goal name="cadd3&#39;vc.7.0" expl="precondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.05"/></proof>
    </goal>
-  </transf>
-  </goal>
-  <goal name="cadd&#39;vc.8" expl="assertion">
-  <transf name="split_vc" >
-   <goal name="cadd&#39;vc.8.0" expl="assertion">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.50"/></proof>
+   <goal name="cadd3&#39;vc.7.1" expl="postcondition">
+   <proof prover="0" obsolete="true"><result status="valid" time="0.11"/></proof>
+   </goal>
+   <goal name="cadd3&#39;vc.7.2" expl="postcondition">
+   <proof prover="0" obsolete="true"><result status="valid" time="0.13"/></proof>
+   </goal>
+   <goal name="cadd3&#39;vc.7.3" expl="postcondition">
+   <proof prover="0" timelimit="20" obsolete="true"><result status="timeout" time="20.00"/></proof>
+   <transf name="split_vc" >
+    <goal name="cadd3&#39;vc.7.3.0" expl="postcondition">
+    <proof prover="0" obsolete="true"><result status="timeout" time="10.00"/></proof>
+    </goal>
+    <goal name="cadd3&#39;vc.7.3.1" expl="postcondition">
+    <proof prover="0" obsolete="true"><result status="timeout" time="10.00"/></proof>
+    </goal>
+    <goal name="cadd3&#39;vc.7.3.2" expl="postcondition">
+    <proof prover="0" obsolete="true"><result status="timeout" time="10.00"/></proof>
+    </goal>
+    <goal name="cadd3&#39;vc.7.3.3" expl="postcondition">
+    <proof prover="0" obsolete="true"><result status="timeout" time="10.00"/></proof>
+    </goal>
+   </transf>
    </goal>
   </transf>
   </goal>
-  <goal name="cadd&#39;vc.9" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="valid" time="0.37"/></proof>
+  <goal name="cadd3&#39;vc.8" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.04"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.10" expl="assertion">
-  <proof prover="0" obsolete="true"><result status="valid" time="0.27"/></proof>
+  <goal name="cadd3&#39;vc.9" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.05"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.11" expl="assertion">
-  <transf name="split_vc" >
-   <goal name="cadd&#39;vc.11.0" expl="assertion">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.28"/></proof>
-   </goal>
-  </transf>
+  <goal name="cadd3&#39;vc.10" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.05"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.12" expl="assertion">
-  <transf name="split_vc" >
-   <goal name="cadd&#39;vc.12.0" expl="assertion">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.27"/></proof>
-   </goal>
-  </transf>
+  <goal name="cadd3&#39;vc.11" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.03"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.13" expl="assertion">
-  <transf name="split_vc" >
-   <goal name="cadd&#39;vc.13.0" expl="assertion">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.80"/></proof>
-   </goal>
-  </transf>
+  <goal name="cadd3&#39;vc.12" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.04"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.14" expl="assertion">
-  <transf name="split_vc" >
-   <goal name="cadd&#39;vc.14.0" expl="assertion">
-   <proof prover="0" obsolete="true"><result status="valid" time="2.31"/></proof>
-   </goal>
-  </transf>
+  <goal name="cadd3&#39;vc.13" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.03"/></proof>
   </goal>
-  <goal name="cadd&#39;vc.15" expl="postcondition">
-  <transf name="split_vc" >
-   <goal name="cadd&#39;vc.15.0" expl="postcondition">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.10"/></proof>
+  <goal name="cadd3&#39;vc.14" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.06"/></proof>
+  </goal>
+  <goal name="cadd3&#39;vc.15" expl="precondition" proved="true">
+  <proof prover="0" timelimit="100"><result status="valid" time="46.74"/></proof>
+  </goal>
+  <goal name="cadd3&#39;vc.16" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.03"/></proof>
+  </goal>
+  <goal name="cadd3&#39;vc.17" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.06"/></proof>
+  </goal>
+  <goal name="cadd3&#39;vc.18" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.03"/></proof>
+  </goal>
+  <goal name="cadd3&#39;vc.19" expl="precondition" proved="true">
+  <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
+  <transf name="split_vc" proved="true" >
+   <goal name="cadd3&#39;vc.19.0" expl="precondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.43"/></proof>
    </goal>
-   <goal name="cadd&#39;vc.15.1" expl="postcondition">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.11"/></proof>
+   <goal name="cadd3&#39;vc.19.1" expl="postcondition">
+   <proof prover="0"><undone/></proof>
    </goal>
-   <goal name="cadd&#39;vc.15.2" expl="postcondition">
-   <proof prover="0" obsolete="true"><result status="valid" time="0.10"/></proof>
+   <goal name="cadd3&#39;vc.19.2" expl="postcondition">
+   <proof prover="0"><undone/></proof>
    </goal>
-   <goal name="cadd&#39;vc.15.3" expl="postcondition">
-   <proof prover="0" obsolete="true"><result status="valid" time="1.22"/></proof>
+   <goal name="cadd3&#39;vc.19.3" expl="postcondition">
+   <proof prover="0"><undone/></proof>
    </goal>
-   <goal name="cadd&#39;vc.15.4" expl="postcondition">
-   <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-   <transf name="case" arg1="(is_plus_infinity (f1 .+ f2))">
-    <goal name="cadd&#39;vc.15.4.0" expl="true case (postcondition)">
-    <proof prover="0" obsolete="true"><result status="valid" time="2.21"/></proof>
-    </goal>
-    <goal name="cadd&#39;vc.15.4.1" expl="false case (postcondition)">
-    <proof prover="0" obsolete="true"><result status="valid" time="1.71"/></proof>
-    </goal>
-   </transf>
-   <transf name="eliminate_let" >
-    <goal name="cadd&#39;vc.15.4.0" expl="postcondition">
-    <transf name="instantiate" arg1="H3" arg2="f1,f2">
-     <goal name="cadd&#39;vc.15.4.0.0" expl="postcondition">
-     <proof prover="0" obsolete="true"><result status="valid" time="2.42"/></proof>
-     </goal>
-    </transf>
-    </goal>
-   </transf>
+  </transf>
+  </goal>
+  <goal name="cadd3&#39;vc.20" expl="precondition" proved="true">
+  <proof prover="0"><result status="valid" time="0.11"/></proof>
+  </goal>
+  <goal name="cadd3&#39;vc.21" expl="postcondition" proved="true">
+  <proof prover="0" timelimit="100"><result status="valid" time="5.80"/></proof>
+  </goal>
+  <goal name="cadd3&#39;vc.22" expl="postcondition" proved="true">
+  <proof prover="0" timelimit="100"><result status="valid" time="89.44"/></proof>
+  <transf name="split_vc" proved="true" >
+   <goal name="cadd3&#39;vc.22.0" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.05"/></proof>
    </goal>
-   <goal name="cadd&#39;vc.15.5" expl="postcondition">
-   <proof prover="0" obsolete="true"><result status="valid" time="3.04"/></proof>
+   <goal name="cadd3&#39;vc.22.1" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.10"/></proof>
    </goal>
-   <goal name="cadd&#39;vc.15.6" expl="postcondition">
-   <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-   <transf name="case" arg1="(is_plus_infinity x1)">
-    <goal name="cadd&#39;vc.15.6.0" expl="true case (postcondition)">
-    <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-    <transf name="case" arg1="(is_plus_infinity x4)">
-     <goal name="cadd&#39;vc.15.6.0.0" expl="true case (postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-     <goal name="cadd&#39;vc.15.6.0.1" expl="false case (true case. postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-    </transf>
-    <transf name="case" arg1="(is_minus_infinity x2)">
-     <goal name="cadd&#39;vc.15.6.0.0" expl="true case (postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-     <goal name="cadd&#39;vc.15.6.0.1" expl="false case (true case. postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-    </transf>
-    <transf name="case" arg1="(is_minus_infinity x5)">
-     <goal name="cadd&#39;vc.15.6.0.0" expl="true case (postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-     <goal name="cadd&#39;vc.15.6.0.1" expl="false case (true case. postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-    </transf>
-    </goal>
-    <goal name="cadd&#39;vc.15.6.1" expl="false case (postcondition)">
-    <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-    <transf name="case" arg1="(is_plus_infinity x4)">
-     <goal name="cadd&#39;vc.15.6.1.0" expl="false case (true case. postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-     <goal name="cadd&#39;vc.15.6.1.1" expl="false case (postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-    </transf>
-    <transf name="case" arg1="(is_minus_infinity x2)">
-     <goal name="cadd&#39;vc.15.6.1.0" expl="false case (true case. postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-     <goal name="cadd&#39;vc.15.6.1.1" expl="false case (postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-    </transf>
-    <transf name="case" arg1="(is_minus_infinity x5)">
-     <goal name="cadd&#39;vc.15.6.1.0" expl="false case (true case. postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-     <goal name="cadd&#39;vc.15.6.1.1" expl="false case (postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-    </transf>
-    </goal>
-   </transf>
-   <transf name="case" arg1="(is_finite1 f1)">
-    <goal name="cadd&#39;vc.15.6.0" expl="true case (postcondition)">
-    <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-    <transf name="case" arg1="(is_finite1 f2)">
-     <goal name="cadd&#39;vc.15.6.0.0" expl="true case (postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     <transf name="eliminate_let_fmla" >
-      <goal name="cadd&#39;vc.15.6.0.0.0" expl="true case (postcondition)">
-      <transf name="case" arg1="(no_overflow m ((to_real f1) +. (to_real f2)))">
-       <goal name="cadd&#39;vc.15.6.0.0.0.0" expl="true case (postcondition)">
-       <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-       <transf name="case" arg1="(no_overflow m (to_real x5 +. to_real x2))">
-        <goal name="cadd&#39;vc.15.6.0.0.0.0.0" expl="true case (postcondition)">
-        <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-        <transf name="case" arg1="(is_finite1 x5)">
-         <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0" expl="true case (postcondition)">
-         <transf name="case" arg1="(is_finite1 x2)">
-          <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0" expl="true case (postcondition)">
-          <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-          <transf name="cut" arg1="((to_real x2) &lt;=. (to_real f1))">
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0" expl="true case (postcondition)">
-           <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-           <transf name="cut" arg1="((to_real x5) &lt;=. (to_real f2))">
-            <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0" expl="true case (postcondition)">
-            <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-            <transf name="cut" arg1="(((to_real x5) +. (to_real x2)) &lt;=. ((to_real f2) +. (to_real f1)))">
-             <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0.0" expl="true case (postcondition)">
-             <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-             <transf name="cut" arg1="(round m ((to_real x5) +. (to_real x2)) &lt;=. round m ((to_real f2) +. (to_real f1)))">
-              <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0.0.0" expl="true case (postcondition)">
-              <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-              <transf name="cut" arg1="((to_real (add m x5 x2)) &lt;=. (to_real (add m f2 f1)))">
-               <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0.0.0.0" expl="true case (postcondition)">
-               <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-               </goal>
-               <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0.0.0.1" expl="asserted formula">
-               <proof prover="0" obsolete="true"><result status="valid" time="1.14"/></proof>
-               <transf name="instantiate" arg1="add_finite" arg2="m, x5, x2">
-                <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0.0.0.1.0" expl="asserted formula">
-                <transf name="instantiate" arg1="add_finite" arg2="m, f2, f1">
-                 <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0.0.0.1.0.0" expl="asserted formula">
-                 <proof prover="0" obsolete="true"><result status="valid" time="1.14"/></proof>
-                 <transf name="case" arg1="(no_overflow m (to_real x5 +. to_real x2))">
-                  <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0" expl="asserted formula (true case)">
-                  <proof prover="0" obsolete="true"><result status="valid" time="1.07"/></proof>
-                  </goal>
-                  <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0.0.0.1.0.0.1" expl="asserted formula (false case)">
-                  <proof prover="0" obsolete="true"><result status="valid" time="0.03"/></proof>
-                  </goal>
-                 </transf>
-                 </goal>
-                </transf>
-                </goal>
-               </transf>
-               </goal>
-              </transf>
-              </goal>
-              <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0.0.1" expl="asserted formula">
-              <proof prover="0" obsolete="true"><result status="valid" time="0.11"/></proof>
-              </goal>
-             </transf>
-             </goal>
-             <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.0.1" expl="asserted formula">
-             <proof prover="0" obsolete="true"><result status="valid" time="0.24"/></proof>
-             </goal>
-            </transf>
-            </goal>
-            <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0.1" expl="asserted formula">
-            <proof prover="0" obsolete="true"><result status="valid" time="0.77"/></proof>
-            </goal>
-           </transf>
-           </goal>
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.1" expl="asserted formula">
-           <proof prover="0" obsolete="true"><result status="valid" time="0.76"/></proof>
-           </goal>
-          </transf>
-          </goal>
-          <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.1" expl="false case (true case. postcondition)">
-          <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-          <transf name="cut" arg1="((to_real x2) &lt;=. (to_real f1))">
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.1.0" expl="false case (true case. postcondition)">
-           <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-           </goal>
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.1.1" expl="asserted formula">
-           <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-           </goal>
-          </transf>
-          </goal>
-         </transf>
-         </goal>
-         <goal name="cadd&#39;vc.15.6.0.0.0.0.0.1" expl="false case (true case. postcondition)">
-         <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-         </goal>
-        </transf>
-        </goal>
-        <goal name="cadd&#39;vc.15.6.0.0.0.0.1" expl="false case (true case. postcondition)">
-        <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-        </goal>
-       </transf>
-       <transf name="cut" arg1="(le (add m x2 x5) (f1 .+ f2))">
-        <goal name="cadd&#39;vc.15.6.0.0.0.0.0" expl="true case (postcondition)">
-        <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-        <transf name="case" arg1="(is_finite1 x5)">
-         <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0" expl="true case (postcondition)">
-         <transf name="case" arg1="(is_finite1 x2)">
-          <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0" expl="true case (postcondition)">
-          <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-          <transf name="cut" arg1="((to_real x2) &lt;=. (to_real f1))">
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.0" expl="true case (postcondition)">
-           <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-           </goal>
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.0.1" expl="asserted formula">
-           <proof prover="0" obsolete="true"><result status="valid" time="0.28"/></proof>
-           </goal>
-          </transf>
-          </goal>
-          <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.1" expl="false case (true case. postcondition)">
-          <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-          <transf name="cut" arg1="((to_real x2) &lt;=. (to_real f1))">
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.1.0" expl="false case (true case. postcondition)">
-           <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-           </goal>
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.0.0.1.1" expl="asserted formula">
-           <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-           </goal>
-          </transf>
-          </goal>
-         </transf>
-         </goal>
-         <goal name="cadd&#39;vc.15.6.0.0.0.0.0.1" expl="false case (true case. postcondition)">
-         <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-         </goal>
-        </transf>
-        </goal>
-        <goal name="cadd&#39;vc.15.6.0.0.0.0.1" expl="asserted formula">
-        <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-        <transf name="case" arg1="(is_finite1 x5)">
-         <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0" expl="asserted formula (true case)">
-         <transf name="case" arg1="(is_finite1 x2)">
-          <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0" expl="asserted formula (true case)">
-          <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-          <transf name="cut" arg1="((to_real x2) &lt;=. (to_real f1))">
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0" expl="asserted formula (true case)">
-           <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-           <transf name="cut" arg1="((to_real x5) &lt;=. (to_real f2))">
-            <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0" expl="asserted formula (true case)">
-            <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-            <transf name="cut" arg1="(((to_real x5) +. (to_real x2)) &lt;=. ((to_real f2) +. (to_real f1)))">
-             <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0.0" expl="asserted formula (true case)">
-             <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-             <transf name="cut" arg1="(round m ((to_real x5) +. (to_real x2)) &lt;=. round m ((to_real f2) +. (to_real f1)))">
-              <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0.0.0" expl="asserted formula (true case)">
-              <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-              <transf name="cut" arg1="((to_real (add m x5 x2)) &lt;=. (to_real (add m f2 f1)))">
-               <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0.0.0.0" expl="asserted formula (true case)">
-               <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-               </goal>
-               <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0.0.0.1" expl="asserted formula">
-               <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-               <transf name="instantiate" arg1="add_finite" arg2="m, x5, x2">
-                <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0.0.0.1.0" expl="asserted formula">
-                <transf name="instantiate" arg1="add_finite" arg2="m, f2, f1">
-                 <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0.0.0.1.0.0" expl="asserted formula">
-                 <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-                 <transf name="case" arg1="(no_overflow m (to_real x5 +. to_real x2))">
-                  <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0.0.0.1.0.0.0" expl="asserted formula (true case)">
-                  <proof prover="0" obsolete="true"><result status="valid" time="1.07"/></proof>
-                  </goal>
-                  <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0.0.0.1.0.0.1" expl="asserted formula (false case)">
-                  <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-                  </goal>
-                 </transf>
-                 </goal>
-                </transf>
-                </goal>
-               </transf>
-               </goal>
-              </transf>
-              </goal>
-              <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0.0.1" expl="asserted formula">
-              <proof prover="0" obsolete="true"><result status="valid" time="0.10"/></proof>
-              </goal>
-             </transf>
-             </goal>
-             <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.0.1" expl="asserted formula">
-             <proof prover="0" obsolete="true"><result status="valid" time="0.23"/></proof>
-             </goal>
-            </transf>
-            </goal>
-            <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.0.1" expl="asserted formula">
-            <proof prover="0" obsolete="true"><result status="valid" time="0.63"/></proof>
-            </goal>
-           </transf>
-           </goal>
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.0.1" expl="asserted formula">
-           <proof prover="0" obsolete="true"><result status="valid" time="0.60"/></proof>
-           </goal>
-          </transf>
-          </goal>
-          <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.1" expl="asserted formula (false case. true case)">
-          <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-          <transf name="cut" arg1="((to_real x2) &lt;=. (to_real f1))">
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.1.0" expl="asserted formula (false case. true case)">
-           <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-           </goal>
-           <goal name="cadd&#39;vc.15.6.0.0.0.0.1.0.1.1" expl="asserted formula">
-           <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-           </goal>
-          </transf>
-          </goal>
-         </transf>
-         </goal>
-         <goal name="cadd&#39;vc.15.6.0.0.0.0.1.1" expl="asserted formula (false case)">
-         <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-         </goal>
-        </transf>
-        </goal>
-       </transf>
-       </goal>
-       <goal name="cadd&#39;vc.15.6.0.0.0.1" expl="false case (true case. postcondition)">
-       <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-       </goal>
-      </transf>
-      <transf name="cut" arg1="(le (add m x2 x5) (f1 .+ f2))">
-       <goal name="cadd&#39;vc.15.6.0.0.0.0" expl="true case (postcondition)">
-       <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-       </goal>
-       <goal name="cadd&#39;vc.15.6.0.0.0.1" expl="asserted formula">
-       <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-       </goal>
-      </transf>
-      </goal>
-     </transf>
-     </goal>
-     <goal name="cadd&#39;vc.15.6.0.1" expl="false case (true case. postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-    </transf>
-    </goal>
-    <goal name="cadd&#39;vc.15.6.1" expl="false case (postcondition)">
-    <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-    <transf name="case" arg1="(is_finite1 f2)">
-     <goal name="cadd&#39;vc.15.6.1.0" expl="false case (true case. postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-     <goal name="cadd&#39;vc.15.6.1.1" expl="false case (postcondition)">
-     <proof prover="0" obsolete="true"><result status="timeout" time="5.00"/></proof>
-     </goal>
-    </transf>
-    </goal>
-   </transf>
+   <goal name="cadd3&#39;vc.22.2" expl="postcondition" proved="true">
+   <proof prover="0"><result status="valid" time="0.11"/></proof>
+   </goal>
+   <goal name="cadd3&#39;vc.22.3" expl="postcondition" proved="true">
+   <proof prover="0" timelimit="100"><result status="valid" time="58.99"/></proof>
    </goal>
   </transf>
   </goal>
+  <goal name="cadd3&#39;vc.23" expl="postcondition" proved="true">
+  <proof prover="0"><result status="valid" time="1.22"/></proof>
+  </goal>
  </transf>
  </goal>
 </theory>