diff --git a/Makefile b/Makefile
index 7e960182f3bbea98549bf2cad5f016fd3ad59223..8b904d0f486664e8f7f0b953a19539ed572645ad 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@
 ##########################################################################
 
 all:
-	dune build --root=$$(pwd)
+	dune build --root=$$(pwd) @install
 
 test:
 	dune runtest --root=$$(pwd)
diff --git a/src_colibri2/bin/dune b/src_colibri2/bin/dune
new file mode 100644
index 0000000000000000000000000000000000000000..88e93b1f91bc235181149288bf7d1ad893efa5c1
--- /dev/null
+++ b/src_colibri2/bin/dune
@@ -0,0 +1,29 @@
+(executable
+  (name           main)
+  (public_name    colibri2)
+  (libraries
+    ; external deps
+    cmdliner fmt gen
+    ; dolmen deps
+    dolmen dolmen.intf dolmen.std
+    dolmen_type dolmen_loop
+    ; colibrics
+    colibri2.solver
+    colibri2.theories.bool
+    colibri2.theories.LRA
+  )
+   (package colibri2)
+)
+
+; Rule to generate a man page for colibrics
+(rule
+  (target        colibri2.1)
+  (action (with-outputs-to %{target} (run colibri2 --help=groff)))
+)
+
+; Install the man page
+(install
+ (files    colibri2.1)
+ (section  man)
+ (package  colibri2)
+)
diff --git a/src_colibri2/bin/main.ml b/src_colibri2/bin/main.ml
new file mode 100644
index 0000000000000000000000000000000000000000..5dc0bb5589b7d82f61a49d8295ce9181861fcd1e
--- /dev/null
+++ b/src_colibri2/bin/main.ml
@@ -0,0 +1,30 @@
+(* This file is free software, copied from dolmen. See file "LICENSE" for more information *)
+
+let theories =
+  [Colibri2_theories_bool.Boolean.th_register;
+   Colibri2_theories_bool.Equality.th_register;
+   Colibri2_theories_bool.Uninterp.th_register;
+   Colibri2_theories_LRA.LRA.th_register]
+
+let () =
+  let man = [
+    `S Options.common_section;
+    `P "Common options for the colibrics binary";
+    `S Options.gc_section;
+    `P "Options to fine-tune the gc, only experts should use these.";
+    `S Cmdliner.Manpage.s_bugs;
+    `P "You can report bugs at https://git.frama-c.com/";
+    `S Cmdliner.Manpage.s_authors;
+    `P "Francois Bobot <francois.bobot@cea.fr>"
+  ] in
+  let info = Cmdliner.Term.info ~man ~version:"0.1" "dolmen" in
+  let st,step_limit = match Cmdliner.Term.eval (Options.state theories, info) with
+    | `Version | `Help -> exit 0
+    | `Error `Parse | `Error `Term | `Error `Exn -> exit 2
+    | `Ok opt -> opt
+  in
+  Colibri2_solver.Input.read
+    ?limit:step_limit
+    ~set_true:Colibri2_theories_bool.Boolean.set_true
+    ~handle_exn:Colibri2_solver.Input.handle_exn_with_exit
+    st
diff --git a/src_colibri2/bin/options.ml b/src_colibri2/bin/options.ml
new file mode 100644
index 0000000000000000000000000000000000000000..97beea19d407815042d140dc5240dba092eeec20
--- /dev/null
+++ b/src_colibri2/bin/options.ml
@@ -0,0 +1,301 @@
+
+(* This file is free software, part of dolmen. See file "LICENSE" for more information *)
+
+open Cmdliner
+
+(* Sections *)
+(* ************************************************************************* *)
+
+let gc_section = "GC OPTIONS"
+let common_section = Manpage.s_options
+
+(* State creation *)
+(* ************************************************************************* *)
+
+let gc_opts
+    minor_heap_size major_heap_increment
+    space_overhead max_overhead allocation_policy =
+  Gc.({ (get ()) with
+        minor_heap_size; major_heap_increment;
+        space_overhead; max_overhead; allocation_policy;
+      }
+     )
+
+let mk_state theories
+    gc gc_opt bt colors
+    time_limit size_limit
+    input_lang input_mode input
+    header_check header_licenses
+    header_lang_version
+    type_check type_strict
+    debug context max_warn step_limit
+    debug_flags
+  =
+  List.iter Colibri2_popop_lib.Debug.(fun s -> set_flag (lookup_flag s)) debug_flags;
+  if debug then
+    Colibri2_popop_lib.Debug.(
+      List.iter (fun (_,f,_,_) -> set_flag f) (list_flags ()));
+  Colibri2_solver.Input.mk_state
+    ~gc ~gc_opt ~bt ~colors ~time_limit
+    ~size_limit ?input_lang ?input_mode ~input
+    ~header_check ~header_licenses ~header_lang_version
+    ~type_check ~type_strict
+    ~debug ~context ~max_warn theories, step_limit
+
+(* Input source converter *)
+(* ************************************************************************* *)
+
+(* Converter for input formats/languages *)
+let input_format_conv = Arg.enum Dolmen_loop.Logic.enum
+
+(* Converter for input file/stdin *)
+let input_to_string = function
+  | `Stdin -> "<stdin>"
+  | `Raw _ -> "<raw>"
+  | `File f -> f
+
+let input_source_conv =
+  let parse x = Ok (`File x) in
+  let print fmt i = Format.fprintf fmt "%s" (input_to_string i) in
+  Arg.conv (parse, print)
+
+(* Converter for permissions *)
+let perm_conv = Arg.enum [
+    "allow", Dolmen_loop.State.Allow;
+    "warn", Dolmen_loop.State.Warn;
+    "error", Dolmen_loop.State.Error;
+  ]
+
+(* Converter for input modes *)
+let mode_conv = Arg.enum [
+    "full", `Full;
+    "incremental", `Incremental;
+  ]
+
+(* Output converters *)
+(* ************************************************************************* *)
+
+let output_to_string = function
+  | `Stdout -> "<stdout>"
+  | `File f -> f
+
+let parse_output = function
+  | "stdout" -> Ok `Stdout
+  | f -> Ok (`File f)
+
+let output_conv =
+  let print fmt o = Format.fprintf fmt "%s" (output_to_string o) in
+  Arg.conv (parse_output, print)
+
+
+(* Argument converter for integer with multiplier suffix *)
+(* ************************************************************************ *)
+
+let nb_sec_minute = 60
+let nb_sec_hour = 60 * nb_sec_minute
+let nb_sec_day = 24 * nb_sec_hour
+
+let time_string f =
+  let n = int_of_float f in
+  let aux n div = n / div, n mod div in
+  let n_day, n = aux n nb_sec_day in
+  let n_hour, n = aux n nb_sec_hour in
+  let n_min, n = aux n nb_sec_minute in
+  let print_aux s n = if n <> 0 then (string_of_int n) ^ s else "" in
+  (print_aux "d" n_day) ^
+  (print_aux "h" n_hour) ^
+  (print_aux "m" n_min) ^
+  (print_aux "s" n)
+
+let print_time fmt f = Format.fprintf fmt "%s" (time_string f)
+
+let parse_time arg =
+  let l = String.length arg in
+  let multiplier m =
+    let arg1 = String.sub arg 0 (l-1) in
+    `Ok (m *. (float_of_string arg1))
+  in
+  assert (l > 0);
+  try
+    match arg.[l-1] with
+    | 's' -> multiplier 1.
+    | 'm' -> multiplier 60.
+    | 'h' -> multiplier 3600.
+    | 'd' -> multiplier 86400.
+    | '0'..'9' -> `Ok (float_of_string arg)
+    | _ -> `Error "bad numeric argument"
+  with Failure _ -> `Error "bad numeric argument"
+
+let size_string f =
+  let n = int_of_float f in
+  let aux n div = n / div, n mod div in
+  let n_tera, n = aux n 1_000_000_000_000 in
+  let n_giga, n = aux n 1_000_000_000 in
+  let n_mega, n = aux n 1_000_000 in
+  let n_kilo, n = aux n 1_000 in
+  let print_aux s n = if n <> 0 then (string_of_int n) ^ s else "" in
+  (print_aux "To" n_tera) ^
+  (print_aux "Go" n_giga) ^
+  (print_aux "Mo" n_mega) ^
+  (print_aux "ko" n_kilo) ^
+  (print_aux "" n)
+
+let print_size fmt f =
+  Format.fprintf fmt "%s" (size_string f)
+
+let parse_size arg =
+  let l = String.length arg in
+  let multiplier m =
+    let arg1 = String.sub arg 0 (l-1) in
+    `Ok (m *. (float_of_string arg1))
+  in
+  assert (l > 0);
+  try
+    match arg.[l-1] with
+    | 'k' -> multiplier 1e3
+    | 'M' -> multiplier 1e6
+    | 'G' -> multiplier 1e9
+    | 'T' -> multiplier 1e12
+    | '0'..'9' -> `Ok (float_of_string arg)
+    | _ -> `Error "bad numeric argument"
+  with Failure _ -> `Error "bad numeric argument"
+
+let c_time = parse_time, print_time
+let c_size = parse_size, print_size
+
+(* Gc Options parsing *)
+(* ************************************************************************* *)
+
+let gc_t =
+  let docs = gc_section in
+  let minor_heap_size =
+    let doc = "Set Gc.minor_heap_size" in
+    Arg.(value & opt int 1_000_000 & info ["gc-s"] ~doc ~docs)
+  in
+  let major_heap_increment =
+    let doc = "Set Gc.major_heap_increment" in
+    Arg.(value & opt int 100 & info ["gc-i"] ~doc ~docs)
+  in
+  let space_overhead =
+    let doc = "Set Gc.space_overhead" in
+    Arg.(value & opt int 200 & info ["gc-o"] ~doc ~docs)
+  in
+  let max_overhead =
+    let doc = "Set Gc.max_overhead" in
+    Arg.(value & opt int 500 & info ["gc-O"] ~doc ~docs)
+  in
+  let allocation_policy =
+    let doc = "Set Gc.allocation policy" in
+    Arg.(value & opt int 0 & info ["gc-a"] ~doc ~docs)
+  in
+  Term.((const gc_opts $ minor_heap_size $ major_heap_increment $
+         space_overhead $ max_overhead $ allocation_policy))
+
+(* Main Options parsing *)
+(* ************************************************************************* *)
+
+let state theories =
+  let docs = common_section in
+  let gc =
+    let doc = "Print statistics about the gc upon exiting" in
+    Arg.(value & flag & info ["g"; "gc"] ~doc ~docs)
+  in
+  let bt =
+    let doc = "Enables printing of backtraces." in
+    Arg.(value & flag & info ["b"; "backtrace"] ~doc ~docs)
+  in
+  let colors =
+    let doc = "Activate coloring of output" in
+    Arg.(value & opt bool true & info ["color"] ~doc ~docs)
+  in
+  let time =
+    let doc = "Stop the program after a time lapse of $(docv).
+                 Accepts usual suffixes for durations : s,m,h,d.
+                 Without suffix, default to a time in seconds." in
+    Arg.(value & opt c_time 300. & info ["t"; "time"] ~docv:"TIME" ~doc ~docs)
+  in
+  let size =
+    let doc = "Stop the program if it tries and use more the $(docv) memory space. " ^
+              "Accepts usual suffixes for sizes : k,M,G,T. " ^
+              "Without suffix, default to a size in octet." in
+    Arg.(value & opt c_size 1_000_000_000. & info ["s"; "size"] ~docv:"SIZE" ~doc ~docs)
+  in
+  let in_lang =
+    let doc = Format.asprintf
+        "Set the input language to $(docv) (%s)."
+        (Arg.doc_alts_enum ~quoted:false Dolmen_loop.Logic.enum) in
+    Arg.(value & opt (some input_format_conv) None & info ["i"; "input"; "lang"] ~docv:"INPUT" ~doc ~docs)
+  in
+  let in_mode =
+    let doc = Format.asprintf
+        "Set the input mode. the full mode parses the entire file before iterating
+         over its contents whereas the incremental mode processes each delcaration
+         before parsing the next one. Default is incremental mode." in
+    Arg.(value & opt (some mode_conv) None & info ["m"; "mode"] ~doc ~docs)
+  in
+  let input =
+    let doc = "Input problem file. If no file is specified,
+               dolmen will enter interactive mode and read on stdin." in
+    Arg.(value & pos 0 input_source_conv `Stdin & info [] ~docv:"FILE" ~doc)
+  in
+  let header_check =
+    let doc = "If true, then the presence of headers will be checked in the
+               input file (and errors raised if they are not present)." in
+    Arg.(value & opt bool false & info ["check-headers"] ~doc ~docs)
+  in
+  let header_licenses =
+    let doc = "Set the allowed set of licenses in the headers.
+               An empty list means allow everything." in
+    Arg.(value & opt (list string) [] & info ["header-licenses"] ~doc ~docs)
+  in
+  let header_lang_version =
+    let doc = "Set the only allowed language verison for headers. If not set,
+               all conforming version numbers are allowed." in
+    Arg.(value & opt (some string) None & info ["header-lang-version"] ~docs ~doc)
+  in
+  let typing =
+    let doc = "Decide whether to type-check input expressions. If false, only parsing
+               is done. " in
+    Arg.(value & opt bool true & info ["type"] ~doc ~docs)
+  in
+  let strict =
+    let doc = "Be strict or more lenient wrt to typing" in
+    Arg.(value & opt bool true & info ["strict"] ~doc ~docs)
+  in
+  (*
+  let locs =
+    let doc = "Whether to keep location information during typing. \
+               Setting this to true results in better warning/error \
+               messages, but will use more memory when running." in
+    Arg.(value & opt bool true & info ["locs"] ~doc ~docs)
+  in
+  *)
+  let debug =
+    let doc = Format.asprintf
+        "Print the parsed dolmen statement (after expansion of includes)" in
+    Arg.(value & flag & info ["debug"] ~docs ~doc)
+  in
+  let context =
+    let doc = Format.asprintf
+        "Print the context / fragment of parsed AST with errors" in
+    Arg.(value & flag & info ["context"] ~docs ~doc)
+  in
+  let max_warn =
+    let doc = Format.asprintf
+        "Maximum number of warnings to display (excess warnings will be
+         counted and a count of silenced warnings repoted at the end)." in
+    Arg.(value & opt int max_int & info ["max-warn"] ~docs ~doc)
+  in
+  let step_limit =
+    let doc = Format.asprintf
+        "Maximum number of steps." in
+    Arg.(value & opt (some int) None & info ["max-step"] ~docs ~doc)
+  in
+  let debug_flags =
+    let doc = Format.asprintf "Debug flags." in
+    Arg.(value & opt_all string []  & info ["debug-flag"] ~docs ~doc)
+  in
+  Term.(const (mk_state theories) $ gc $ gc_t $ bt $ colors $
+        time $ size $ in_lang $ in_mode $ input $
+        header_check $ header_licenses $ header_lang_version $
+        typing $ strict $ debug $ context $ max_warn $ step_limit $ debug_flags)
diff --git a/src_colibri2/core/colibri2_core.ml b/src_colibri2/core/colibri2_core.ml
index f8db92ec3ba08f5c739bd1cb6333228af6467f72..cf40ddff8b2f943c1581fd440b6cad03b12a683a 100644
--- a/src_colibri2/core/colibri2_core.ml
+++ b/src_colibri2/core/colibri2_core.ml
@@ -28,6 +28,7 @@ module Keys = Keys
 
 module Node = struct
   include Nodes.Node
+  module HC = Datastructure.HNode
 end
 
 module ThTermKind = struct
@@ -85,6 +86,8 @@ module Egraph = Egraph
 module Events = Events
 module Demon  = Demon
 
+module Datastructure = Datastructure
+
 exception UnwaitedEvent = Nodes.UnwaitedEvent
 (** Can be raised by daemon when receiving an event that they don't
     waited for. It is the sign of a bug in the core solver *)
diff --git a/src_colibri2/core/datastructure.ml b/src_colibri2/core/datastructure.ml
new file mode 100644
index 0000000000000000000000000000000000000000..e28c7200245e7a5f647b837d5daa074646e99d14
--- /dev/null
+++ b/src_colibri2/core/datastructure.ml
@@ -0,0 +1,89 @@
+(*************************************************************************)
+(*  This file is part of Colibrics.                                      *)
+(*                                                                       *)
+(*  Copyright (C) 2017                                                   *)
+(*    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 type Sig =  sig
+  type 'a t
+  type key
+
+  val create: 'a Format.printer -> string -> 'a t
+
+  val remove : 'a t -> Egraph.t -> key -> unit
+  val set : 'a t -> Egraph.t -> key -> 'a -> unit
+  val find : 'a t -> Egraph.t -> key -> 'a
+  val change : ('a option -> 'a option) -> 'a t -> Egraph.t -> key -> unit
+end
+
+module Hashtbl(S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Sig with type key := S.t = struct
+
+  type 'a t = 'a option Context.Ref.t S.H.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 option Context.Ref.t S.H.t
+      let name = name end
+    in
+    let key = Env.Unsaved.create_key (module M) in
+    let init () = S.H.create 5 in
+    let iter f = S.H.iter (fun k r -> match Context.Ref.get r with None -> () | Some v -> f k v) in
+    let pp = Colibri2_popop_lib.Pp.(iter2 iter semi arrow S.pp pp) in
+    Env.Unsaved.register ~init ~pp key;
+    key
+
+  let find t d k =
+    let r = S.H.find (Egraph.get_unsaved_env d t) k in
+    match Context.Ref.get r with
+    | Some v -> v
+    | None -> raise Not_found
+
+  let set t d k v =
+    let h = Egraph.get_unsaved_env d t in
+    let r = match S.H.find_opt h k with
+      | Some r -> r
+      | None ->
+        let r = Context.Ref.create (Egraph.context d) None in
+        S.H.add h k r;
+        r
+    in
+    Context.Ref.set r (Some v)
+
+  let remove t d k =
+    let h = Egraph.get_unsaved_env d t in
+    match S.H.find_opt h k with
+      | Some r -> Context.Ref.set r None
+      | None -> ()
+
+  let change f t d k =
+    let h = Egraph.get_unsaved_env d t in
+    let change = function
+      | Some r as o ->
+        let v = f (Context.Ref.get r) in
+        Context.Ref.set r v;
+        o
+      | None ->
+        let r = Context.Ref.create (Egraph.context d) None in
+        let v = f None in
+        Context.Ref.set r v;
+        (Some r)
+    in
+    S.H.change change h k
+
+end
+
+module HNode = Hashtbl(Nodes.Node)
diff --git a/src_colibri2/core/datastructure.mli b/src_colibri2/core/datastructure.mli
new file mode 100644
index 0000000000000000000000000000000000000000..86dd3cf6b61f6735117ab2743daefe7213f5e58f
--- /dev/null
+++ b/src_colibri2/core/datastructure.mli
@@ -0,0 +1,36 @@
+(*************************************************************************)
+(*  This file is part of Colibrics.                                      *)
+(*                                                                       *)
+(*  Copyright (C) 2017                                                   *)
+(*    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 type Sig =  sig
+  type 'a t
+  type key
+
+  val create: 'a Format.printer -> string -> 'a t
+
+  val remove : 'a t -> Egraph.t -> key -> unit
+  val set : 'a t -> Egraph.t -> key -> 'a -> unit
+  val find: 'a t -> Egraph.t -> key -> 'a
+  val change : ('a option -> 'a option) -> 'a t -> Egraph.t -> key -> unit
+end
+
+
+module Hashtbl (S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Sig with type key := S.t
+
+module HNode : Sig with type key := Nodes.Node.t
diff --git a/src_colibri2/core/demon.ml b/src_colibri2/core/demon.ml
index eb2fecf18f0a4585f05f3253abfe001d2f720531..5a68dc1b0ee9c0d731d4a843bc2771a6ca0f050d 100644
--- a/src_colibri2/core/demon.ml
+++ b/src_colibri2/core/demon.ml
@@ -87,7 +87,7 @@ module Key = struct
 
   type ('k,'d,'i) t = {
     dk_id : ('k * 'd, 'k) Events.Dem.t;
-    dk_data : ('k,'d,'i) demtable Env.t;
+    dk_data : ('k,'d,'i) demtable Env.Saved.t;
   }
 
   let create (type k d i) name =
@@ -96,7 +96,7 @@ module Key = struct
           type nonrec d = k
           let name = name
         end);
-      dk_data = Env.create_key (module struct
+      dk_data = Env.Saved.create_key (module struct
           type t = (k,d,i) demtable
           let name = name
         end)
@@ -241,7 +241,7 @@ module Key = struct
         let l = DT.Key.M.bindings DT.state in
         Format.list ~sep:newline aux fmt l
       in
-      Env.register print_demtable D.key.dk_data;
+      Env.Saved.register print_demtable D.key.dk_data;
     (** Interface for generic daemon *)
     let module Dem = struct
       type runable = D.Key.t
@@ -348,7 +348,7 @@ module Fast = struct
 
   type 'd t = {
     dk_id : ('d, unit) Events.Dem.t;
-    dk_data : 'd Events.Fired.event list Env.t;
+    dk_data : 'd Events.Fired.event list Env.Saved.t;
     (** for throttling *)
     mutable dk_remaining: int; (** 0 if the demon is not the current one *)
     dk_current : 'd Events.Fired.event Queue.t; (** empty if idem *)
@@ -361,7 +361,7 @@ module Fast = struct
           type d = unit
           let name = name
         end);
-      dk_data = Env.create_key (module struct
+      dk_data = Env.Saved.create_key (module struct
           type t = d Events.Fired.event list
           let name = name
         end);
@@ -452,7 +452,7 @@ module Fast = struct
 
     let () =
       let print_demtable = Format.(list ~sep:(const char ',') Events.Fired.pp) in
-      Env.register print_demtable D.key.dk_data;
+      Env.Saved.register print_demtable D.key.dk_data;
     (** Interface for generic daemon *)
     let module Dem = struct
       type runable = unit
diff --git a/src_colibri2/core/egraph.ml b/src_colibri2/core/egraph.ml
index 465a0e1eda12c1297d2e43570cf624ed109b85d4..615913292903f5294cdbd3aad8c468fe78e69a6e 100644
--- a/src_colibri2/core/egraph.ml
+++ b/src_colibri2/core/egraph.ml
@@ -72,7 +72,7 @@ module Def = struct
       saved_dom   : delayed_t VDomTable.t;
       saved_sem   : semtable VSemTable.t;
       saved_value : unit VValueTable.t;
-      saved_envs  : Env.VectorH.t;
+      saved_envs  : Env.Saved.VectorH.t;
     }
 
 
@@ -87,8 +87,9 @@ module Def = struct
       dom   : delayed_t VDomTable.t;
       sem   : semtable VSemTable.t;
       value : unit VValueTable.t;
-      envs  : Env.VectorH.t;
+      envs  : Env.Saved.VectorH.t;
       mutable current_delayed  : delayed_t; (** For assert-check *)
+      unsaved_envs: Env.Unsaved.VectorH.t;
       history : saved Context.history;
     }
 
@@ -119,7 +120,7 @@ module Def = struct
 
   and choice_state =
     | DecNo
-    | DecTodo of (delayed_t -> unit)
+    | DecTodo of (delayed_t -> unit) list
 
   and choice = {
     choice: delayed_t -> choice_state;
@@ -137,7 +138,7 @@ type choice = Def.choice = {
 }
 type choice_state = Def.choice_state =
   | DecNo
-  | DecTodo of (delayed_t -> unit)
+  | DecTodo of (delayed_t -> unit) list
 
 (** {2 Define events} *)
 
@@ -185,7 +186,7 @@ module Hidden = Context.Make(struct
         saved_dom = VDomTable.copy t.dom;
         saved_sem = VSemTable.copy t.sem;
         saved_value = VValueTable.copy t.value;
-        saved_envs = Env.VectorH.copy t.envs;
+        saved_envs = Env.Saved.VectorH.copy t.envs;
       }
 
     let restore (s:saved) (t:t) =
@@ -198,7 +199,7 @@ module Hidden = Context.Make(struct
       VDomTable.move ~from:s.saved_dom ~to_:t.dom;
       VSemTable.move ~from:s.saved_sem ~to_:t.sem;
       VValueTable.move ~from:s.saved_value ~to_:t.value;
-      Env.VectorH.move ~from:s.saved_envs ~to_:t.envs;
+      Env.Saved.VectorH.move ~from:s.saved_envs ~to_:t.envs;
       t.current_delayed <- dumb_delayed
 
     let get_history t = t.history
@@ -266,18 +267,28 @@ module T = struct
     let node = find_def t node in
     get_direct_value t value node
 
-  let get_env : type a. t -> a Env.t -> a
+  let get_env : type a. t -> a Env.Saved.t -> a
     = fun t k ->
-      Env.check_is_registered k;
-      if Env.VectorH.is_uninitialized t.envs k then
-        raise (UninitializedEnv (Env.name k))
+      Env.Saved.check_is_registered k;
+      if Env.Saved.VectorH.is_uninitialized t.envs k then
+        raise (UninitializedEnv (Env.Saved.name k))
       else
-        Env.VectorH.get t.envs k
+        Env.Saved.VectorH.get t.envs k
 
-  let set_env : type a. t -> a Env.t -> a -> unit
+  let set_env : type a. t -> a Env.Saved.t -> a -> unit
     = fun t k ->
-      Env.check_is_registered k;
-      Env.VectorH.set t.envs k
+      Env.Saved.check_is_registered k;
+      Env.Saved.VectorH.set t.envs k
+
+  let get_unsaved_env : type a. t -> a Env.Unsaved.t -> a
+    = fun t k ->
+      Env.Unsaved.check_is_registered k;
+      if Env.Unsaved.VectorH.is_uninitialized t.unsaved_envs k then
+        let v = Env.Unsaved.init k in
+        Env.Unsaved.VectorH.set t.unsaved_envs k v;
+        v
+      else
+        Env.Unsaved.VectorH.get t.unsaved_envs k
 
   let is_registered t node =
     Node.M.mem node t.repr
@@ -431,6 +442,10 @@ module Delayed = struct
     assert (is_current_env t);
     set_env t.env env v
 
+  let get_unsaved_env t env =
+    assert (is_current_env t);
+    get_unsaved_env t.env env
+
   let is_registered t node =
     assert (is_current_env t);
     is_registered t.env node
@@ -599,10 +614,11 @@ module Delayed = struct
     let old_other_s = Node.M.find_opt node1 domtable.table in
     let old_repr_s = Node.M.find_opt node2  domtable.table in
     let (module Dom) = VDom.get_dom dom in
-    Debug.dprintf12 debug_few
-      "[Egraph] @[merge dom (%a(%a),%a)@ and (%a(%a),%a)@]"
+    Debug.dprintf13 debug_few
+      "[Egraph] @[merge dom (%a(%a),%a)@ %s@ (%a(%a),%a)@]"
       Node.pp node1 Node.pp node1_0
       (Format.opt Dom.pp) old_other_s
+      (if inv then "<-" else "->")
       Node.pp node2 Node.pp node2_0
       (Format.opt Dom.pp) old_repr_s;
     match old_other_s, old_repr_s with
@@ -984,7 +1000,8 @@ module Backtrackable = struct
     dom = VDomTable.create 5;
     sem = VSemTable.create 5;
     value = VValueTable.create 5;
-    envs = Env.VectorH.create 5;
+    envs = Env.Saved.VectorH.create 5;
+    unsaved_envs = Env.Unsaved.VectorH.create 5;
     current_delayed = dumb_delayed;
     history = Hidden.create context;
   }
@@ -1001,7 +1018,7 @@ module Backtrackable = struct
    *     dom = VDomTable.copy t.dom;
    *     sem = VSemTable.copy t.sem;
    *     value = VValueTable.copy t.value;
-   *     envs = Env.VectorH.copy t.envs;
+   *     envs = Env.Saved.VectorH.copy t.envs;
    *     trail = Trail.new_handle t.trail;
    *     current_delayed = t.current_delayed;
    *   } *)
@@ -1074,6 +1091,11 @@ module Backtrackable = struct
     assert (check_disabled_delayed t);
     T.set_env t env v
 
+  let get_unsaved_env t env =
+    let t = Hidden.rw t in
+    assert (check_disabled_delayed t);
+    T.get_unsaved_env t env
+
   let is_repr t node =
     let t = Hidden.rw t in
     assert (check_disabled_delayed t);
@@ -1113,8 +1135,9 @@ module type Getter = sig
 
   val is_registered : t -> Node.t -> bool
 
-  val get_env : t -> 'a Env.t -> 'a
-  val set_env : t -> 'a Env.t -> 'a -> unit
+  val get_env : t -> 'a Env.Saved.t -> 'a
+  val set_env : t -> 'a Env.Saved.t -> 'a -> unit
+  val get_unsaved_env : t -> 'a Env.Unsaved.t -> 'a
 
   val context : t -> Context.creator
 
diff --git a/src_colibri2/core/egraph.mli b/src_colibri2/core/egraph.mli
index 3321434f6e6a17683c7e7310149d57e305f2d965..f5b86bcfe7a2ffb6e42266b78d098fefdfb8f4ea 100644
--- a/src_colibri2/core/egraph.mli
+++ b/src_colibri2/core/egraph.mli
@@ -49,8 +49,10 @@ module type Getter = sig
 
   val is_registered : t -> Node.t -> bool
 
-  val get_env : t -> 'a Env.t -> 'a
-  val set_env : t -> 'a Env.t -> 'a -> unit
+  val get_env : t -> 'a Env.Saved.t -> 'a
+  val set_env : t -> 'a Env.Saved.t -> 'a -> unit
+
+  val get_unsaved_env : t -> 'a Env.Unsaved.t -> 'a
 
   val context : t -> Context.creator
 
@@ -108,9 +110,9 @@ val attach_node: t -> Node.t -> ('event,'r) Events.Dem.t -> 'event -> unit
 
 type choice_state =
   | DecNo
-  | DecTodo of (t -> unit)
+  | DecTodo of (t -> unit) list
 
-type choice = {
+and choice = {
   choice: t -> choice_state;
   prio: int;
 }
diff --git a/src_colibri2/core/env.ml b/src_colibri2/core/env.ml
index a93539cdc946e6739d84d8d08150468d37fc46bd..8480613c5a8db73fbd95bbe6cf27ce140a883241 100644
--- a/src_colibri2/core/env.ml
+++ b/src_colibri2/core/env.ml
@@ -18,18 +18,41 @@
 (*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
 (*************************************************************************)
 
-module Env = Keys.Make_key(struct end)
+module Saved = struct
+  module Env = Keys.Make_key(struct end)
 
-include Env
+  include Env
 
-type 'a data = {key: 'a Env.t; pp: 'a Format.printer}
+  type 'a data = {key: 'a Env.t; pp: 'a Format.printer}
 
-module VEnv = Env.Make_Registry(struct
-    type nonrec 'a data = 'a data
-    let pp d = d.pp
-    let key d = d.key
-  end)
+  module VEnv = Env.Make_Registry(struct
+      type nonrec 'a data = 'a data
+      let pp d = d.pp
+      let key d = d.key
+    end)
 
-let register pp key = VEnv.register {key;pp}
-let print = VEnv.print
-let check_is_registered = VEnv.check_is_registered
+  let register pp key = VEnv.register {key;pp}
+  let print = VEnv.print
+  let check_is_registered = VEnv.check_is_registered
+end
+
+module Unsaved = struct
+  module Env = Keys.Make_key(struct end)
+
+  include Env
+
+  type 'a data = {key: 'a Env.t; pp: 'a Format.printer;
+                  init : (unit -> 'a)}
+
+  module VEnv = Env.Make_Registry(struct
+      type nonrec 'a data = 'a data
+      let pp (d:_ data) = d.pp
+      let key (d:_ data) = d.key
+    end)
+
+  let register ~init ~pp key = VEnv.register {key;pp;init}
+  let print = VEnv.print
+  let check_is_registered = VEnv.check_is_registered
+  let init k = (VEnv.get k).init ()
+
+end
diff --git a/src_colibri2/core/env.mli b/src_colibri2/core/env.mli
index bf2e683bfdc1548bcc0809e8686acdf02d6472f7..a3ff99395f89f2f29a5f061f7a3d98e4a59f6be8 100644
--- a/src_colibri2/core/env.mli
+++ b/src_colibri2/core/env.mli
@@ -20,16 +20,36 @@
 
 (** Theory specific environment *)
 
-(** Environment should currently be persistent data-structure in order
-    to be backtracked correctly *)
+module Saved: sig
+  (** Environment should currently be persistent data-structure in order
+      to be backtracked correctly *)
 
-include Keys.Key
+  include Keys.Key
 
-val register: 'a Format.printer -> 'a t -> unit
-(** Only a pretty printer is needed for registration *)
+  val register: 'a Format.printer -> 'a t -> unit
+  (** Only a pretty printer is needed for registration *)
 
-val print: 'a t -> 'a Format.printer
-(** Get a pretty printer for a particular environment *)
+  val print: 'a t -> 'a Format.printer
+  (** Get a pretty printer for a particular environment *)
 
-val check_is_registered: 'a t -> unit
-(** Check if all the keys created have been registered *)
+  val check_is_registered: 'a t -> unit
+  (** Check if all the keys created have been registered *)
+end
+
+module Unsaved: sig
+  (** These environment are context insensitive *)
+
+  include Keys.Key
+
+  val register: init:(unit -> 'a) -> pp:'a Format.printer -> 'a t -> unit
+  (** Only a pretty printer and an initialization function is needed for registration *)
+
+  val print: 'a t -> 'a Format.printer
+  (** Get a pretty printer for a particular environment *)
+
+  val check_is_registered: 'a t -> unit
+  (** Check if all the keys created have been registered *)
+
+  val init: 'a t -> 'a
+  (** Create the initial value *)
+end
diff --git a/src_colibri2/core/structures/domKind.mli b/src_colibri2/core/structures/domKind.mli
index 07abe1cf62749a9bec986110b47b7435bd38c3ed..71cc718a0a29e93796b76515f0ac082f1f5dd8d8 100644
--- a/src_colibri2/core/structures/domKind.mli
+++ b/src_colibri2/core/structures/domKind.mli
@@ -36,6 +36,11 @@ module type Dom_partial = sig
     t option * Node.t -> t option * Node.t ->
     bool ->
     unit
+  (** [merge d (dom1,cl1) (dom2,cl2) inv]
+      - if inv is false, cl2 will be the new representative
+      - if inv is true, cl1 will be the new representative
+  *)
+
   val pp: Format.formatter  -> t  -> unit
   val key: t dom
 end
diff --git a/src_colibri2/core/synTerm.ml b/src_colibri2/core/synTerm.ml
index 9161e0cadef3c0a0f2faa5293fc883017762f650..17550576e19fb735cdcac850d832b17394a8f912 100644
--- a/src_colibri2/core/synTerm.ml
+++ b/src_colibri2/core/synTerm.ml
@@ -39,7 +39,7 @@ type env = {
   decvars: (Expr.Term.t -> Node.t -> Egraph.choice option) list;
 }
 
-let converters = Env.create_key (module struct
+let converters = Env.Saved.create_key (module struct
     type t = env
     let name = "Synsem.converters"
   end)
@@ -52,7 +52,7 @@ let register_decvars env r =
   let e = Egraph.get_env env converters in
   Egraph.set_env env converters {e with decvars = r::e.decvars}
 
-let () = Env.register (fun _ _ -> ()) converters
+let () = Env.Saved.register (fun _ _ -> ()) converters
 
 module DaemonConvertTerm = struct
   let key = Demon.Fast.create "Synsem.DaemonConvertTerm"
diff --git a/src_colibri2/solver/input.ml b/src_colibri2/solver/input.ml
index 024c098b59128511f7150519c860b21a7ce72e0d..4d5d445056a7fa7f45cbfd91e17eaa103c9f16fc 100644
--- a/src_colibri2/solver/input.ml
+++ b/src_colibri2/solver/input.ml
@@ -288,7 +288,7 @@ let mk_state
     ?input_lang ?input_mode ~input
     ?(header_check=false) ?(header_licenses=[])
     ?(header_lang_version=None)
-    ?(type_strict=true)
+    ?(type_check=true) ?(type_strict=true)
     ?(debug=false) ?(context=true) ?(max_warn=max_int)
     theories
   =
@@ -317,7 +317,7 @@ let mk_state
     header_check; header_licenses; header_lang_version;
     header_state = Dolmen_loop.Headers.empty;
 
-    type_check = true; type_strict;
+    type_check; type_strict;
     type_state = Dolmen_loop.Typer.new_state ();
 
     solve_state = create_ctx theories;
diff --git a/src_colibri2/solver/scheduler.ml b/src_colibri2/solver/scheduler.ml
index 50c8a377e1bad0c0a28cd3dfa3bd00f66c87ec2a..4461c9feb28b7ed1b848290e79e26e51567bd824 100644
--- a/src_colibri2/solver/scheduler.ml
+++ b/src_colibri2/solver/scheduler.ml
@@ -72,11 +72,13 @@ type bp =
   { pre_wakeup_daemons    : Prio.t;
     pre_prev_scheduler_state : bp option;
     pre_backtrack_point      : Context.bp;
+    pre_choices              : (Egraph.t -> unit) list;
   }
 
 type t =
   { mutable wakeup_daemons    : Prio.t;
     mutable prev_scheduler_state : bp option;
+    mutable choices              : (Egraph.t -> unit) list;
             solver_state      : Egraph.Backtrackable.t;
     mutable delayed           : Egraph.t option;
     (* global *)
@@ -109,6 +111,7 @@ let new_solver () =
   let context = Context.create () in
   { wakeup_daemons = Prio.empty;
     prev_scheduler_state = None;
+    choices = [];
     solver_state = Egraph.Backtrackable.new_t (Context.creator context);
     context;
     delayed    = None;
@@ -124,6 +127,7 @@ let push t =
     { pre_wakeup_daemons    = t.wakeup_daemons;
       pre_prev_scheduler_state = t.prev_scheduler_state;
       pre_backtrack_point      = Context.bp t.context;
+      pre_choices = t.choices;
     } in
   t.prev_scheduler_state <- Some prev;
   ignore (Context.push t.context);
@@ -240,26 +244,35 @@ and conflict_analysis t =
 and try_run_dec:
   t -> Egraph.t -> Prio.t -> Egraph.choice -> Egraph.t = fun t d prio choice ->
     (** First we verify its the decision is at this point needed *)
-    try
+  assert (t.choices = []);
+  try
       match choice.choice d with
-      | Egraph.DecNo ->
+      | Egraph.DecNo | Egraph.DecTodo [] ->
         t.wakeup_daemons <- prio;
         d (** d can be precised by choose_decision *)
-      | Egraph.DecTodo todo ->
-        Debug.incr stats_dec;
-        Egraph.Backtrackable.delayed_stop d;
-        (** The registered state keep the old prio *)
-        ignore (push t);
-        (** We use the priority list without the decision only in the
-            branch where the decision is made *)
+      | Egraph.DecTodo (todo::todos) ->
+        (** We remove the decision it is replaced by the todos,
+            we can change the interface of choice and in that case
+            we want to keep the decision in the current branch *)
         t.wakeup_daemons <- prio;
-        let d = new_delayed t in
-        todo d;
-        d
+        Debug.incr stats_dec;
+        make_choice t d todo todos
     with Egraph.Contradiction ->
       Debug.dprintf0 debug "[Scheduler] Contradiction";
       conflict_analysis t
 
+and make_choice t d todo todos =
+  Egraph.Backtrackable.delayed_stop d;
+  t.choices <- todos;
+  begin match todos with
+    | [] -> ()
+    | _ -> ignore (push t)
+  end;
+  let d = new_delayed t in
+  todo d;
+  d
+
+
 and run_until_dec t d =
   let act = Prio.min t.wakeup_daemons in
   match act with
@@ -275,18 +288,27 @@ and run_until_dec t d =
 
 
 let run_one_step t d =
-  let act, prio = Prio.extract_min t.wakeup_daemons in
-  match act with
-  | Att.Daemon (_,att) -> begin
-      Debug.incr stats_propa;
-      t.wakeup_daemons <- prio;
-      try
-        Egraph.Backtrackable.run_daemon d att; d
-      with Egraph.Contradiction ->
-        Debug.dprintf0 debug "[Scheduler] Contradiction";
-        conflict_analysis t
+  match t.choices with
+  | [] -> begin
+      let act, prio = Prio.extract_min t.wakeup_daemons in
+      match act with
+      | Att.Daemon (_,att) -> begin
+          Debug.incr stats_propa;
+          t.wakeup_daemons <- prio;
+          try
+            Egraph.Backtrackable.run_daemon d att; d
+          with Egraph.Contradiction ->
+            Debug.dprintf0 debug "[Scheduler] Contradiction";
+            conflict_analysis t
+        end
+      | Att.Decision (_,chogen) -> try_run_dec t d prio chogen
     end
-  | Att.Decision (_,chogen) -> try_run_dec t d prio chogen
+  | todo::todos ->
+    try
+      make_choice t d todo todos
+    with Egraph.Contradiction ->
+      Debug.dprintf0 debug "[Scheduler] Contradiction";
+      conflict_analysis t
 
 let rec flush t d =
   try
diff --git a/src_colibri2/stdlib/keys.ml b/src_colibri2/stdlib/keys.ml
index 19ba8d71d095e831219cfe42a6aea4f5a5d05404..cf4545104a196c751fdc6bde4c6d92cabb9c1c00 100644
--- a/src_colibri2/stdlib/keys.ml
+++ b/src_colibri2/stdlib/keys.ml
@@ -38,7 +38,7 @@ module Make_key(X:sig end) = struct
                 id   : int;
                 iseq : 'b. 'b gadt -> ('a,'b) Poly.iseq }
 
-  let pp fmt x = String.pp fmt x.name
+  let pp fmt x = Format.pp_print_string fmt x.name
   let equal a b = a.id = b.id
   let compare x y = compare x.id y.id
   let hash x = x.id
diff --git a/src_colibri2/stdlib/std.ml b/src_colibri2/stdlib/std.ml
index bed8dab1037c2a3e8a2f3386038d0db88c8ab582..fd01bf8840645b84aa52679e165c675610c18243 100644
--- a/src_colibri2/stdlib/std.ml
+++ b/src_colibri2/stdlib/std.ml
@@ -99,4 +99,22 @@ module Q = struct
         in
         Q.(sgn * (int_part + dec_part))
 
+  let is_integer q = Z.equal Z.one q.Q.den
+
+  let floor q =
+    if is_integer q then q
+    else Q.of_bigint
+        (if Q.lt q Q.zero
+         then Z.pred (Q.to_bigint q)
+         else Q.to_bigint q)
+
+  let ceil q =
+    if is_integer q then q
+    else
+      Q.of_bigint
+        (if Q.gt q Q.zero
+         then Z.succ (Q.to_bigint q)
+         else Q.to_bigint q)
+
+
 end
diff --git a/src_colibri2/stdlib/std.mli b/src_colibri2/stdlib/std.mli
index 041b1e0d96da25a25b615de2bfdc5bb420f4ee9c..e4100647a86f0536591dea6e08d5329a4a3a8a39 100644
--- a/src_colibri2/stdlib/std.mli
+++ b/src_colibri2/stdlib/std.mli
@@ -57,4 +57,7 @@ module Q : sig
   val ge  : t -> t -> bool
   val le  : t -> t -> bool
   val of_string_decimal : string -> t
+  val floor: t -> t
+  val ceil : t -> t
+  val is_integer : t -> bool
 end
diff --git a/src_colibri2/tests/dune b/src_colibri2/tests/dune
index 010bdcbd5dc61bde01c9aa0532c7f42196b871d6..7695ec893c847a0506a979fdddc5d76d9891a26d 100644
--- a/src_colibri2/tests/dune
+++ b/src_colibri2/tests/dune
@@ -10,6 +10,6 @@
  (alias runtest)
  (deps
   (:< tests.exe)
-  (source_tree solve/))
+ )
  (action
   (run %{<})))
diff --git a/src_colibri2/tests/generate_tests/dune b/src_colibri2/tests/generate_tests/dune
new file mode 100644
index 0000000000000000000000000000000000000000..1d7c405ab1f2488562b00be79164024fce522079
--- /dev/null
+++ b/src_colibri2/tests/generate_tests/dune
@@ -0,0 +1,3 @@
+(executable
+ (name generate_dune_tests)
+)
diff --git a/src_colibri2/tests/generate_tests/generate_dune_tests.ml b/src_colibri2/tests/generate_tests/generate_dune_tests.ml
new file mode 100644
index 0000000000000000000000000000000000000000..59da80597db18f56350d1dde44e73c4e9f41dcbf
--- /dev/null
+++ b/src_colibri2/tests/generate_tests/generate_dune_tests.ml
@@ -0,0 +1,22 @@
+let dir = Sys.argv.(1)
+let result = Sys.argv.(2)
+
+let print_test cout file =
+  Printf.fprintf cout
+    "(rule (action (with-stdout-to %s.res (run colibri2 --max-step 1000 %s))))\n"
+    file file;
+  Printf.fprintf cout
+    "(rule (alias runtest) (action (diff oracle %s.res)))\n"
+    file
+
+let () =
+  let files = Sys.readdir dir in
+  Array.sort String.compare files;
+  let files = Array.to_list files in
+  let files = List.filter (fun f -> Filename.check_suffix f "cnf" || Filename.check_suffix f ".smt2") files in
+  let cout = open_out (Filename.concat dir "dune.inc") in
+    Printf.fprintf cout
+    "(rule (action (with-stdout-to oracle (echo %S))))\n"
+    (result^"\n");
+  List.iter (print_test cout) files;
+  close_out cout
diff --git a/src_colibri2/tests/solve/dimacs/sat/dune b/src_colibri2/tests/solve/dimacs/sat/dune
new file mode 100644
index 0000000000000000000000000000000000000000..74e69b2c52ff290765701e5e65358570a665fafc
--- /dev/null
+++ b/src_colibri2/tests/solve/dimacs/sat/dune
@@ -0,0 +1,7 @@
+(include dune.inc)
+
+(rule
+ (deps (glob_files *.cnf) (glob_files *.smt2))
+ (action (with-stdout-to dune.inc (run %{exe:../../../generate_tests/generate_dune_tests.exe} . sat)))
+ (mode promote)
+)
diff --git a/src_colibri2/tests/solve/dimacs/sat/dune.inc b/src_colibri2/tests/solve/dimacs/sat/dune.inc
new file mode 100644
index 0000000000000000000000000000000000000000..e534f7ee2fec92a81db1775ce7d085d66d374241
--- /dev/null
+++ b/src_colibri2/tests/solve/dimacs/sat/dune.inc
@@ -0,0 +1,23 @@
+(rule (action (with-stdout-to oracle (echo "sat\n"))))
+(rule (action (with-stdout-to anomaly_agetooold.cnf.res (run colibri2 --max-step 1000 anomaly_agetooold.cnf))))
+(rule (alias runtest) (action (diff oracle anomaly_agetooold.cnf.res)))
+(rule (action (with-stdout-to anomaly_agetooold2.cnf.res (run colibri2 --max-step 1000 anomaly_agetooold2.cnf))))
+(rule (alias runtest) (action (diff oracle anomaly_agetooold2.cnf.res)))
+(rule (action (with-stdout-to assertion_fail.cnf.res (run colibri2 --max-step 1000 assertion_fail.cnf))))
+(rule (alias runtest) (action (diff oracle assertion_fail.cnf.res)))
+(rule (action (with-stdout-to fuzzing1.cnf.res (run colibri2 --max-step 1000 fuzzing1.cnf))))
+(rule (alias runtest) (action (diff oracle fuzzing1.cnf.res)))
+(rule (action (with-stdout-to fuzzing2.cnf.res (run colibri2 --max-step 1000 fuzzing2.cnf))))
+(rule (alias runtest) (action (diff oracle fuzzing2.cnf.res)))
+(rule (action (with-stdout-to par8-1-c.cnf.res (run colibri2 --max-step 1000 par8-1-c.cnf))))
+(rule (alias runtest) (action (diff oracle par8-1-c.cnf.res)))
+(rule (action (with-stdout-to pigeon-2.cnf.res (run colibri2 --max-step 1000 pigeon-2.cnf))))
+(rule (alias runtest) (action (diff oracle pigeon-2.cnf.res)))
+(rule (action (with-stdout-to pigeon-3.cnf.res (run colibri2 --max-step 1000 pigeon-3.cnf))))
+(rule (alias runtest) (action (diff oracle pigeon-3.cnf.res)))
+(rule (action (with-stdout-to pigeon-4.cnf.res (run colibri2 --max-step 1000 pigeon-4.cnf))))
+(rule (alias runtest) (action (diff oracle pigeon-4.cnf.res)))
+(rule (action (with-stdout-to quinn.cnf.res (run colibri2 --max-step 1000 quinn.cnf))))
+(rule (alias runtest) (action (diff oracle quinn.cnf.res)))
+(rule (action (with-stdout-to simple_v3_c2.cnf.res (run colibri2 --max-step 1000 simple_v3_c2.cnf))))
+(rule (alias runtest) (action (diff oracle simple_v3_c2.cnf.res)))
diff --git a/src_colibri2/tests/tests.ml b/src_colibri2/tests/tests.ml
index 9a3751374b7e0b32ab513ce4e420f3ca8a2d95b1..ef4d208e1d2d772299fabe39799866cf6304795c 100644
--- a/src_colibri2/tests/tests.ml
+++ b/src_colibri2/tests/tests.ml
@@ -44,13 +44,15 @@ let tests () =
     (!opt_seed + 1) (!opt_seed + 9)in
   make_tests l None
 
+let debug = OUnit2.Conf.make_bool "debug" false " activate debugging"
+
 let tests () =
   (* if Printexc.backtrace_status ()
    * then
-   *   (test_decorate
+   *   (OUnitTest.test_decorate
    *      (fun f ->
-   *         fun () ->
-   *           try f ()
+   *         fun ctx ->
+   *           try f ctx
    *           with
    *           | exn ->
    *             Format.fprintf (Colibri2_popop_lib.Debug.get_debug_formatter ()) "%s"
@@ -58,6 +60,15 @@ let tests () =
    *             raise exn
    *      )) (test_list (tests ()))
    * else *)
+  OUnitTest.test_decorate
+    (fun f ->
+       fun ctx ->
+         let debug = debug ctx in
+         if debug then
+           Colibri2_popop_lib.Debug.(
+             List.iter (fun (_,f,_,_) -> set_flag f) (list_flags ()));
+         f ctx
+    )
     (test_list (tests ()))
 
 (** From oUnit.ml v 1.2.2 *)
diff --git a/src_colibri2/theories/LRA/LRA.ml b/src_colibri2/theories/LRA/LRA.ml
index afbfacf8e7d06428a992826f0953d824626f4aec..d0363923d25a10874da9f727005159c7ee44ce3c 100644
--- a/src_colibri2/theories/LRA/LRA.ml
+++ b/src_colibri2/theories/LRA/LRA.ml
@@ -79,6 +79,7 @@ module SE = ThTermKind.Register(S)
 module D = Interval.Convexe
 
 let dom = DomKind.create_key (module struct type t = D.t let name = "ARITH" end)
+let dom_poly = DomKind.create_key (module struct type t = Polynome.t let name = "ARITH_POLY" end)
 
 let set_dom d node v =
   match D.is_singleton v with
@@ -89,6 +90,140 @@ let set_dom d node v =
     (** the pexp must be in the dom *)
     Egraph.set_dom d dom node v
 
+(** Polynome *)
+let propa_dem = Demon.Key.create "Arith.DaemonPropa"
+
+let print_bag_cl = Colibri2_popop_lib.Bag.pp Pp.comma Node.pp
+
+let used_in_poly : Node.t Bag.t Node.HC.t = Node.HC.create (Bag.pp Pp.semi Node.pp) "used_in_poly"
+
+module T = struct
+  include Polynome
+  let key = ThTermKind.create_key (module struct type nonrec t = t let name = "SARITH_POLY" end)
+end
+
+module ThE = ThTermKind.Register(T)
+
+let set_poly d cl p =
+  Egraph.set_dom d dom_poly cl p;
+  match Polynome.is_one_node p with
+  | None -> Egraph.set_thterm d cl (ThE.thterm (ThE.index p))
+  | Some cl' -> Egraph.merge d cl cl'
+
+let add_used d cl' new_cl =
+  Node.M.iter (fun used _ ->
+      Node.HC.change (function
+          | Some b -> Some (Bag.append b cl')
+          | None -> Some (Bag.elt cl')
+        ) used_in_poly d used
+    ) new_cl
+
+let subst_doms d cl (p:Polynome.t) =
+  let b = match Node.HC.find used_in_poly d cl with
+    | exception Not_found -> Bag.empty
+    | b -> b
+  in
+  Bag.iter (fun cl' ->
+      match Egraph.get_dom d dom_poly cl' with
+      | None -> assert false (** absurd: can't be used and absent *)
+      | Some q ->
+        let new_cl = Node.M.set_diff p.poly q.poly in
+        let q, _ = Polynome.subst q cl p in
+        add_used d cl' new_cl;
+        set_poly d cl' q
+    ) b;
+  add_used d cl p.poly;
+  set_poly d cl p
+
+module Th = struct
+  include Polynome
+
+  let merged v1 v2 =
+    match v1,v2 with
+    | None, None -> true
+    | Some v', Some v -> equal v' v
+    | _ -> false
+
+    let norm_dom cl = function
+      | None ->
+        let r = monome Q.one cl in
+        r
+      | Some p ->
+        p
+
+    let add_itself d cl norm =
+      add_used d cl norm.poly;
+      Egraph.set_dom d dom_poly cl norm
+
+    let merge d ((p1o,cl1) as a1) ((p2o,cl2) as a2) inv =
+      assert (not (Egraph.is_equal d cl1 cl2));
+      assert (not (CCOpt.is_none p1o && CCOpt.is_none p2o));
+      let (pother, other), (prepr, repr) = if inv then a2,a1 else a1,a2 in
+      let other = Egraph.find d other in
+      let repr = Egraph.find d repr in
+      let p1 = norm_dom other pother in
+      let p2 = norm_dom repr prepr in
+      let diff = sub p1 p2 in
+      (* 0 = other - repr = p1 - p2 = diff *)
+      Debug.dprintf2 debug "[Arith] @[solve 0=%a@]" pp diff;
+      begin match Polynome.extract diff with
+      | Zero -> (** no new equality already equal *)
+        begin
+          match pother, prepr with
+          | Some _, Some _ | None, None ->
+            assert false (** absurd: no need of merge *)
+          | Some p, None ->
+            (** p = repr *)
+            add_itself d repr p
+          | None, Some p ->
+            (** p = other *)
+            add_itself d other p
+        end
+      | Cst _ ->
+        (* 0 = cst <> 0 *)
+        Egraph.contradiction d
+      | Var(q,x,p') ->
+        (** diff = qx + p' *)
+        assert ( not (Q.equal Q.zero q) );
+        Debug.dprintf2 debug "[Arith] @[pivot %a@]" Node.pp x;
+        let add_if_default n norm = function
+          | Some _ -> ()
+          | None ->
+            add_itself d n norm
+        in
+        add_if_default other p1 pother;
+        add_if_default repr p2 prepr;
+        subst_doms d x (Polynome.mult_cst (Q.div Q.one (Q.neg q)) p')
+      end;
+      assert (CCOpt.compare Polynome.compare
+                (Egraph.get_dom d dom_poly repr)
+                (Egraph.get_dom d dom_poly other) = 0)
+
+    let solve_one d cl p1 =
+      match Egraph.get_dom d dom_poly cl with
+      | None ->
+        subst_doms d cl p1
+      | Some p2 ->
+        let diff = Polynome.sub p1 p2 in
+        (* 0 = p1 - p2 = diff *)
+        Debug.dprintf2 debug "[Arith] @[solve in init 0=%a@]" Polynome.pp diff;
+        begin match Polynome.extract diff with
+          | Zero -> ()
+          | Cst _ ->
+            (* 0 = cst <> 0 *)
+            Egraph.contradiction d
+          | Var(q,x,p') ->
+            (** diff = qx + p' *)
+            assert ( not (Q.equal Q.zero q) );
+            Debug.dprintf2 debug "[Arith] @[pivot %a@]" Node.pp x;
+            subst_doms d x (Polynome.mult_cst (Q.div Q.one (Q.neg q)) p')
+        end
+
+    let key = dom_poly
+end
+
+let () = Egraph.register_dom(module Th)
+
 let minus_or_one inv =
   if inv then Q.minus_one else Q.one
 
@@ -199,23 +334,25 @@ module DaemonPropa = struct
       propagate del s
     | _ -> raise UnwaitedEvent
 
-  let init del s =
+  let init d s =
     begin match SE.sem s with
-      | S.Add (_,cl1,_,cl2) ->
-    Debug.dprintf2 debug "TOTO: %a" SE.pp s;
-        Egraph.register del cl1; Egraph.register del cl2;
-        Demon.Fast.attach del key
+      | S.Add (c1,cl1,c2,cl2) ->
+        Egraph.register d cl1; Egraph.register d cl2;
+        Demon.Fast.attach d key
           [Demon.Create.EventValue(SE.node s, real, s);
            Demon.Create.EventValue(cl1, real, s);
            Demon.Create.EventValue(cl2, real, s);
-          ]
+          ];
+        let cl = (SE.node s) in
+        let p1 = Polynome.of_list Q.zero [cl1,c1;cl2,c2] in
+        Th.solve_one d cl p1
       | GZero (node,_) ->
-        Egraph.register del node;
-        Demon.Fast.attach del key
+        Egraph.register d node;
+        Demon.Fast.attach d key
           [Demon.Create.EventValue(SE.node s, Boolean.dom, s);
            Demon.Create.EventValue(node, real, s)]
     end;
-    propagate del s;
+    propagate d s;
 end
 
 module RDaemonPropa = Demon.Fast.Register(DaemonPropa)
@@ -259,240 +396,6 @@ let to_poly = function
   | S.Add(q1,cl1,q2,cl2) -> Polynome.of_list Q.one [cl1,q1;cl2,q2]
   | GZero _ -> raise Impossible
 
-(** Choice *)
-(*
-(** Conflict *)
-(** Reason of equalities between arithmetical terms
-    exp: with all the decisions and propagation applied
-    imp: without any decision and propagation applied
-*)
-type conpoly = {imp : Polynome.t; exp : Polynome.t; bound: bound;
-                deps: Deps.t [@printer (fun _ _ -> ())]}
-let pp_conpoly fmt x =
-  Format.fprintf fmt "0 %s@ %a@ (%a)"
-    (match x.bound with | Strict -> "<" | Large -> "<=")
-    Polynome.pp x.imp
-    Polynome.pp x.exp
-let pp_conpoly' fmt x =
-  Format.fprintf fmt "%a@ (%a)@ %s 0"
-    Polynome.pp x.imp
-    Polynome.pp x.exp
-    (match x.bound with | Strict -> "<" | Large -> "<=")
-
-type conpair = {mi: conpoly option; ma:conpoly option}
-(** used as [0 <= x + P = mi /\ x + P = ma <= 0] *)
-let pp_conpair fmt = function
-  | {mi=None; ma=None} -> Format.fprintf fmt "None"
-  | {mi=Some mi;ma=None} -> pp_conpoly fmt mi
-  | {mi=None;ma=Some ma} -> pp_conpoly' fmt ma
-  | {mi=Some mi;ma=Some ma} ->
-    Format.fprintf fmt "%a@,â‹€ %a" pp_conpoly mi pp_conpoly' ma
-
-let interp_conpoly d p =
-  let acc = Node.M.fold_left (fun acc node q ->
-      let v = Opt.get_def D.reals (Egraph.get_dom d dom node) in
-      D.add (D.mult_cst q v) acc
-    ) D.zero p.imp.Polynome.poly in
-  let acc = D.add_cst p.imp.cst acc in
-  let good =
-    if p.bound = Strict then DaemonPropa.gt_zero
-    else DaemonPropa.ge_zero
-  in
-  match D.inter acc good with
-  | None -> Conflict.False
-  | Some i when D.equal i acc -> Conflict.True
-  | Some _ -> Conflict.ToDecide
-
-let condom : conpair Trail.con = Trail.Con.create_key "LRA.dom"
-
-(** Return the corresponding bound *)
-let get_exp_conpoly {exp={Polynome.cst}} = Q.neg cst
-
-let mk_conpoly p = {imp = p; exp = p; bound=Large; deps = Deps.empty}
-let mk_conpair p = let p = mk_conpoly p in {mi = Some p; ma = Some p}
-let zero_conpoly = mk_conpoly Polynome.zero
-let zero_conpair = mk_conpair Polynome.zero
-
-let add_bound b1 b2 =
-  match b1, b2 with
-  | Large, Large -> Large
-  | Strict, _ | _, Strict -> Strict
-
-let switch q b1 b2 =
-  if Q.leq Q.zero q then b1 else b2
-
-let inv_bound = function
-  | Large -> Strict
-  | Strict -> Large
-
-let add_conpoly p1 p2 =
-  if p2 == zero_conpoly then p1
-  else if p1 == zero_conpoly then p2
-  else
-    { imp = Polynome.add p1.imp p2.imp;
-      exp = Polynome.add p1.exp p2.exp;
-      bound = add_bound p1.bound p2.bound;
-      deps = Deps.concat p1.deps p2.deps}
-
-let add_conpair p1 p2 =
-  {mi = Opt.map2 add_conpoly p1.mi p2.mi;
-   ma = Opt.map2 add_conpoly p1.ma p2.ma}
-
-let conpair_is_an_equality p1 =
-  match p1.mi, p1.ma with
-  | Some mi, Some ma ->
-    Polynome.equal mi.exp ma.exp &&
-    Q.equal mi.exp.cst Q.zero
-  | _ -> false
-
-let x_p_cy_conpoly p1 q p2 =
-  if p2 == zero_conpoly then p1
-  else
-    {imp = Polynome.x_p_cy p1.imp q p2.imp;
-     exp = Polynome.x_p_cy p1.exp q p2.exp;
-     bound = add_bound p1.bound p2.bound;
-     deps = Deps.concat p1.deps p2.deps
-    }
-
-let cx_p_cy_conpoly q1 p1 q2 p2 =
-  {imp = Polynome.cx_p_cy q1 p1.imp q2 p2.imp;
-   exp = Polynome.cx_p_cy q1 p1.exp q2 p2.exp;
-   bound = add_bound p1.bound p2.bound;
-   deps = Deps.concat p1.deps p2.deps;
-  }
-
-let cst_mult_conpoly q p =
-  {imp = Polynome.mult_cst q p.imp;
-   exp = Polynome.mult_cst q p.exp;
-   bound = p.bound;
-   deps = p.deps;
-  }
-
-let cst_mult_conpair q p =
-  {mi = Opt.map (cst_mult_conpoly q) (switch q p.mi p.ma);
-   ma = Opt.map (cst_mult_conpoly q) (switch q p.ma p.mi);
-  }
-
-let x_p_cy_conpair p1 q p2 =
-  {mi = Opt.map2 (fun x y -> x_p_cy_conpoly x q y)
-       p1.mi (switch q p2.mi p2.ma);
-   ma = Opt.map2 (fun x y -> x_p_cy_conpoly x q y)
-       p1.ma (switch q p2.ma p2.mi);
-  }
-
-let cx_p_cy_conpair q1 p1 q2 p2 =
-  {mi = Opt.map2 (fun x y -> cx_p_cy_conpoly q1 x q2 y)
-       (switch q1 p1.mi p1.ma)
-       (switch q2 p2.mi p2.ma);
-   ma = Opt.map2 (fun x y -> cx_p_cy_conpoly q1 x q2 y)
-       (switch q1 p1.ma p1.mi)
-       (switch q2 p2.ma p2.mi);
-  }
-
-let implies q p =
-  begin match q.mi, p.mi with
-    | _, None -> true
-    | None, _ -> false
-    | Some q, Some p ->
-      match Polynome.is_cst (Polynome.sub p.exp q.exp) with
-      | None -> false
-      | Some cst ->
-        let c = Q.compare Q.zero cst in
-        if c = 0 then
-          not (p.bound = Strict) || q.bound = Strict
-        else c < 0
-  end
-  &&
-  begin match q.ma, p.ma with
-    | _, None -> true
-    | None, _ -> false
-    | Some q, Some p ->
-      match Polynome.is_cst (Polynome.sub p.exp q.exp) with
-      | None -> false
-      | Some cst ->
-        let c = Q.compare Q.zero cst in
-        if c = 0 then
-          not (p.bound = Strict) || q.bound = Strict
-        else c > 0
-  end
-
-(** cl1 -> cl2 *)
-let dist cl1 cl2 =
-  (* contrary of vectors: here AB = OA - OB
-     It is more instuitive for the distance with a constant:
-     0 <= node - c    node - d <= 0
-  *)
-  Polynome.of_list Q.zero [cl1,Q.one;cl2,Q.minus_one]
-
-let dist_conpoly cl1 cl2 =
-  mk_conpoly (dist cl1 cl2)
-
-let dist_conpair cl1 cl2 =
-  mk_conpair (dist cl1 cl2)
-
-let print_conpoly fmt t =
-  Format.fprintf fmt "{imp=%a;exp=%a}" Polynome.pp t.imp Polynome.pp t.exp
-
-let get_rlist_conpair_deps t cl1 cl2 deps =
-  let r,deps =
-    Conflict.ComputeConflict.Equal.one_equal
-    t ~from:cl1 ~to_:cl2 condom zero_conpair deps
-  in
-  (* Debug.dprintf8 debug "cl1=%a cl2=%a r=%a dist=%a" *)
-  (*   Node.pp cl1 Node.pp cl2 pp_conpair r Polynome.pp (dist cl1 cl2); *)
-  assert (conpair_is_an_equality r);
-  assert (Polynome.equal (Opt.get r.mi).exp (dist cl1 cl2));
-  r,deps
-
-let get_rlist_conpair t cl1 cl2 =
-  let r, deps = get_rlist_conpair_deps t cl1 cl2 Trail.Deps.empty in
-  Conflict.ComputeConflict.add_deps t deps;
-  r
-
-(** Gen Equality and disequality *)
-module GenEquality = struct
-  open Conflict
-
-  let equality t cl1 cl2 =
-    (** cl1 -> cl2 *)
-    let p = get_rlist_conpair t cl1 cl2 in
-    assert (conpair_is_an_equality p);
-    (* Debug.dprintf6 debug "cl1=%a cl2=%a p=%a" *)
-    (*   Node.pp cl1 Node.pp cl2 pp_conpair p; *)
-    (** cl2 -> cl1 *)
-    let p = add_conpair p (dist_conpair cl2 cl1) in
-    (** cl1 -> cl2 -> cl1 = 0 *)
-    assert (conpair_is_an_equality p);
-    assert (Polynome.is_zero (Opt.get p.mi).exp);
-    Debug.dprintf6 debug "[LRA] %a=%a: %a" Node.pp cl1 Node.pp cl2 pp_conpair p;
-    ComputeConflict.unknown_con t condom p
-
-  let expspecial =
-    { Equality.equality = equality;
-      disequality = (fun t _age ~hyp:_ cl1d cl1e cl2e cl2d ->
-          equality t cl1d cl1e;
-          equality t cl2d cl2e);
-      merged = (fun t deps _age cl1d cl1 pexp cl2 cl2d ->
-          let eq_t = ComputeConflict.Equal.init condom
-              zero_conpair deps ~from:cl1d in
-          let eq_t = ComputeConflict.Equal.add_equal t eq_t ~to_:cl1 in
-          let eq_t = ComputeConflict.Equal.add_pexp t eq_t ~to_:cl2 pexp in
-          let eq_t = ComputeConflict.Equal.add_equal t eq_t ~to_:cl2d in
-          let p,deps = ComputeConflict.Equal.close eq_t in
-          (** cl2d -> cl1d *)
-          let pd = dist_conpair cl2d cl1d in
-          let p = add_conpair p pd in
-          (* Debug.dprintf2 debug "sum: %a" pp_conpair p; *)
-          Trail.Deps.add_unknown_con deps condom p);
-      dodec = true (** TODO *);
-      new_true_disequality = (fun _ _ _ -> ());
-    }
-
-  let () = Equality.register_sort Term._Real expspecial
-
-end
-*)
-
 type hypbound =
   | Eq
   | Le
@@ -519,16 +422,19 @@ let pp_hyppoly fmt c =
     Polynome.pp c.poly
 
 module ChoLRA = struct
-  let make_decision node b env =
+  let make_decision node v env =
     Debug.dprintf4 Egraph.print_decision
-      "[LRA] decide %a on %a" Q.pp b Node.pp node;
-    set_dom env node (D.singleton b)
+      "[LRA] decide %a on %a" D.pp v Node.pp node;
+    set_dom env node v
 
   let choose_decision node env =
     let v = Opt.get_def D.reals (Egraph.get_dom env dom node) in
-    match D.is_singleton v with
-    | Some _ -> Egraph.DecNo
-    | None -> DecTodo (make_decision node (D.choose v))
+      match D.split_heuristic v with
+      | `Singleton _ -> Egraph.DecNo
+      | `Splitted (v1,v2) ->
+        DecTodo (List.map (make_decision node) (Shuffle.shufflel [v1;v2]))
+      | `NotSplitted ->
+        DecTodo [make_decision node (D.singleton (D.choose v))]
 
   let choice n = {
     Egraph.prio = 1;
@@ -555,7 +461,7 @@ let sub cl1 cl2 =
 let neg cl2 =
   index (S.Add(Q.one,zero,Q.minus_one,cl2))
 
-let mult _cl1 _cl2 = raise (TODO "mult without constant")
+let mult _node1 _node2 = raise (TODO "mult without constant")
 
 let mult_cst cst node =
   add' cst node Q.one zero
@@ -589,7 +495,7 @@ let converter d (f:Expr.Term.t) =
     Some (add (of_term a) (of_term b))
   | { descr = Expr.App({builtin = Expr.Sub},[],[a;b]); _ } ->
     Some (sub (of_term a) (of_term b))
-  | { descr = Expr.App({builtin = Expr.Neg},[],[a]); _ } ->
+  | { descr = Expr.App({builtin = Expr.Minus},[],[a]); _ } ->
     Some (neg (of_term a))
   | { descr = Expr.App({builtin = Expr.Mul},[],args); _ } -> begin
       let mult_cst c t = Some (mult_cst c (of_term t)) in
@@ -640,7 +546,10 @@ let th_register env =
     (fun d value ->
        let v = RealValue.value value in
        let s = D.singleton v in
-       Egraph.set_dom d dom (RealValue.node value) s
+       Egraph.set_dom d dom (RealValue.node value) s;
+       let cl = RealValue.node value in
+       let p1 = Polynome.of_list v [] in
+       Th.solve_one d cl p1
     ) env;
   ()
 
@@ -686,7 +595,7 @@ let () =
     !< (Q.add !>a !>b)
   | { descr = Expr.App({builtin = Expr.Sub},[],[a;b]); _ } ->
     !< (Q.sub !>a !>b)
-  | { descr = Expr.App({builtin = Expr.Neg},[],[a]); _ } ->
+  | { descr = Expr.App({builtin = Expr.Minus},[],[a]); _ } ->
     !< (Q.neg !>a)
   | { descr = Expr.App({builtin = Expr.Mul},[],[a;b]); _ } ->
     !< (Q.mul !>a !>b)
diff --git a/src_colibri2/theories/LRA/interval.ml b/src_colibri2/theories/LRA/interval.ml
index 3713d6c89073e9770e97a8c212c1c2cca7f6f376..f512a3cc2aca5d58ab239f3b25dfc4433da502e1 100644
--- a/src_colibri2/theories/LRA/interval.ml
+++ b/src_colibri2/theories/LRA/interval.ml
@@ -281,6 +281,27 @@ module Convexe = struct
       if Q.lt q maxv then q
       else Q.add maxv (Q.div_2exp (Q.sub minv maxv) 1)
 
+  let split_heuristic c =
+    match is_singleton c with
+    | Some s -> `Singleton s
+    | None ->
+      let split_at mid =
+        let left,right =
+          if Q.equal mid c.maxv
+          then inter (lt mid) c, inter (ge mid) c
+          else inter (le mid) c, inter (gt mid) c
+        in
+        match left, right with
+        | Some left, Some right ->
+          `Splitted(left,right)
+        | _ -> assert false
+      in
+      if Q.equal Q.minus_inf c.minv || Q.equal Q.inf c.maxv then
+        if mem Q.zero c then split_at Q.zero
+        else `NotSplitted
+      else
+        let mid = Q.div_2exp (Q.add c.minv c.maxv) (-1) in
+        split_at mid
 
   let nb_incr = 100
   let z_nb_incr = Z.of_int nb_incr
@@ -307,6 +328,28 @@ module Convexe = struct
       | Q.UNDEF -> assert false in
     mk e.minv e.minb, mk e.maxv e.maxb
 
+  let is_Large = function
+    | Large -> true
+    | Strict -> false
+
+  let inter_with_integer t =
+    let t = {
+    minb = if Q.equal Q.minus_inf t.minv then Large else Strict;
+    minv =
+      if is_Large t.minb && Q.is_integer t.minv
+      then Q.add t.minv Q.one
+      else Q.ceil t.minv;
+    maxb = if Q.equal Q.inf t.maxv then Large else Strict;
+    maxv =
+      if is_Large t.maxb && Q.is_integer t.maxv
+      then Q.sub t.maxv Q.one
+      else Q.floor t.maxv;
+  } in
+    if Q.lt t.maxv t.minv then None else begin
+      assert (invariant t);
+      Some t
+    end
+
 end
 
 module ConvexeWithExceptions = struct
diff --git a/src_colibri2/theories/LRA/interval.mli b/src_colibri2/theories/LRA/interval.mli
index b6ca6b7b76b82ecb3e05916f32e209dd08a4e694..c6daa364c2470b3d064bdde60e56ad1f6b8e0816 100644
--- a/src_colibri2/theories/LRA/interval.mli
+++ b/src_colibri2/theories/LRA/interval.mli
@@ -28,7 +28,15 @@ val compare_bounds_inf: Q.t * bound -> Q.t * bound -> int
 val compare_bounds_sup: Q.t * bound -> Q.t * bound -> int
 val compare_bounds_inf_sup: Q.t * bound -> Q.t * bound -> int
 
-module Convexe: Interval_sig.S
+module Convexe: sig
+  include Interval_sig.S
+  val split_heuristic: t ->
+    [ `Singleton of Q.t
+    | `Splitted of t * t
+    | `NotSplitted ]
+
+  val inter_with_integer: t -> t option
+end
 
 module ConvexeWithExceptions: Interval_sig.S
 
diff --git a/src_colibri2/theories/bool/boolean.ml b/src_colibri2/theories/bool/boolean.ml
index 51cc5d5798bcf13e854f5934140f80e7b5de06e4..cfe2b0ead5e2481ab62897541c00da604fad3e87 100644
--- a/src_colibri2/theories/bool/boolean.ml
+++ b/src_colibri2/theories/bool/boolean.ml
@@ -442,7 +442,9 @@ module ChoBool = struct
   let choose_decision node env =
     match Egraph.get_value env dom node with
     | Some _ -> Egraph.DecNo
-    | None -> DecTodo (fun env -> make_decision env node true) (** why not true? *)
+    | None -> DecTodo
+                (List.map (fun v env -> make_decision env node v)
+                   (Shuffle.shufflel [true;false]))
 
 end
 
diff --git a/src_colibri2/theories/bool/equality.ml b/src_colibri2/theories/bool/equality.ml
index 925afc195e2c8a48f00224fdfcb8b458aa194d32..e0158476b18dec9b33ce53b357183a4a9eb4526e 100644
--- a/src_colibri2/theories/bool/equality.ml
+++ b/src_colibri2/theories/bool/equality.ml
@@ -248,7 +248,7 @@ let norm_set d the =
     true
 
 module ChoEquals = struct
-  let make_decision the (cl1,cl2) d =
+  let make_equal the (cl1,cl2) d =
     Debug.dprintf6 Egraph.print_decision
       "[Equality] @[decide on merge of %a and %a in %a@]"
       Node.pp cl1 Node.pp cl2 ThE.pp the;
@@ -256,12 +256,23 @@ module ChoEquals = struct
     Egraph.register d cl2;
     Egraph.merge d cl1 cl2
 
+  let make_disequal the (cl1,cl2) d =
+    Debug.dprintf6 Egraph.print_decision
+      "[Equality] @[decide on merge of %a and %a in %a@]"
+      Node.pp cl1 Node.pp cl2 ThE.pp the;
+    Egraph.register d cl1;
+    Egraph.register d cl2;
+    let _dis, stag = new_tag the in
+    List.iter (fun cl -> set_dom d cl (stag ())) [cl1;cl2]
+
   let choose_decision the d =
     let v = ThE.sem the in
     let own = ThE.node the in
       Debug.dprintf4 debug "[Equality] @[dec on %a for %a@]"
         Node.pp own ThE.pp the;
-      if norm_set d the
+      if Boolean.is_false d own
+      then Egraph.DecNo
+      else if norm_set d the
       then Egraph.DecNo
       else
         match find_not_disequal d v with
@@ -269,7 +280,7 @@ module ChoEquals = struct
           Boolean.set_false d own;
           DecNo
         | `Found (cl1,cl2) ->
-          DecTodo (make_decision the (cl1,cl2))
+          DecTodo [make_equal the (cl1,cl2);make_disequal the (cl1,cl2)]
 
   let mk_choice the = {
     Egraph.choice = choose_decision the;