From 8f4e35488c07140619513b91c38ad364abc182bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Bobot?= <francois.bobot@cea.fr>
Date: Fri, 12 Mar 2021 09:55:31 +0100
Subject: [PATCH] Add a generic part of the model computation

---
 .gitignore                                |   3 -
 colibri2.opam                             |   2 +-
 colibrics.opam                            |   2 +-
 dune-project                              |   2 +-
 src_colibri2/core/.ocamlformat            |   0
 src_colibri2/core/.ocamlformat-ignore     |  24 +++
 src_colibri2/core/datastructure.ml        |   2 +
 src_colibri2/core/datastructure.mli       |   2 +
 src_colibri2/core/demon.ml                |  48 ++++-
 src_colibri2/core/demon.mli               |  14 +-
 src_colibri2/core/egraph.ml               | 189 ++++++++---------
 src_colibri2/core/egraph.mli              |   9 +-
 src_colibri2/core/events.ml               |  15 +-
 src_colibri2/core/events.mli              |   7 +-
 src_colibri2/core/ground.mli              |   2 +-
 src_colibri2/core/interp.ml               | 202 ++++++++++++++----
 src_colibri2/core/interp.mli              |  54 ++++-
 src_colibri2/core/structures/nodes.ml     |  16 +-
 src_colibri2/core/structures/nodes.mli    |  18 +-
 src_colibri2/solver/scheduler.ml          |   4 +
 src_colibri2/stdlib/context.ml            |   2 +
 src_colibri2/stdlib/context.mli           |   2 +
 src_colibri2/stdlib/wto.ml                | 236 ++++++++++++++++++++++
 src_colibri2/stdlib/wto.mli               |  64 ++++++
 src_colibri2/theories/ADT/adt.ml          |  11 +-
 src_colibri2/theories/LRA/LRA.ml          |  70 ++++---
 src_colibri2/theories/LRA/dom_interval.ml |   4 +-
 src_colibri2/theories/LRA/realValue.ml    |   5 +-
 src_colibri2/theories/bool/boolean.ml     | 115 ++++++-----
 src_colibri2/theories/bool/equality.ml    | 121 +++++------
 src_colibri2/theories/bool/equality.mli   |   3 +-
 31 files changed, 909 insertions(+), 339 deletions(-)
 create mode 100644 src_colibri2/core/.ocamlformat
 create mode 100644 src_colibri2/core/.ocamlformat-ignore
 create mode 100644 src_colibri2/stdlib/wto.ml
 create mode 100644 src_colibri2/stdlib/wto.mli

diff --git a/.gitignore b/.gitignore
index e3cddf25f..cf0682e64 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,9 +4,6 @@ _build/
 # executable
 *.exe
 
-# jbuild generated files
-*.merlin
-
 # test result files
 *.res
 
diff --git a/colibri2.opam b/colibri2.opam
index a58a31c1a..fb3eb7e18 100644
--- a/colibri2.opam
+++ b/colibri2.opam
@@ -20,7 +20,7 @@ depends: [
   "dolmen_loop" {>= "0.5~dev"}
   "cmdliner"
   "gen"
-  "dune" {>= "2.7"}
+  "dune" {>= "2.8"}
   "zarith"
   "ppx_deriving" {> "4.1.5"}
   "ppx_optcomp"
diff --git a/colibrics.opam b/colibrics.opam
index 7cf296b71..09cd7ff21 100644
--- a/colibrics.opam
+++ b/colibrics.opam
@@ -7,7 +7,7 @@ depends: [
   "dolmen" {>= "0.5~dev"}
   "dolmen_type" {>= "0.5~dev"}
   "dolmen_loop" {>= "0.5~dev"}
-  "dune" {>= "2.7"}
+  "dune" {>= "2.8"}
   "zarith"
   "cmdliner"
   "ocaml" {>= "4.08"}
diff --git a/dune-project b/dune-project
index b758b5f52..65842d36c 100644
--- a/dune-project
+++ b/dune-project
@@ -1,4 +1,4 @@
-(lang dune 2.7)
+(lang dune 2.8)
 
 (cram enable)
 (generate_opam_files true)
diff --git a/src_colibri2/core/.ocamlformat b/src_colibri2/core/.ocamlformat
new file mode 100644
index 000000000..e69de29bb
diff --git a/src_colibri2/core/.ocamlformat-ignore b/src_colibri2/core/.ocamlformat-ignore
new file mode 100644
index 000000000..19b3d4c70
--- /dev/null
+++ b/src_colibri2/core/.ocamlformat-ignore
@@ -0,0 +1,24 @@
+env.ml
+events.ml
+theory.ml
+structures
+structures/nodes.mli
+structures/term.ml
+structures/domKind.ml
+structures/dune
+structures/domKind.mli
+structures/expr.ml
+structures/nodes.ml
+structures/.merlin
+datastructure.mli
+colibri2_core.ml
+demon.mli
+env.mli
+ground.mli
+dune
+datastructure.ml
+egraph.ml
+egraph.mli
+events.mli
+demon.ml
+ground.ml
diff --git a/src_colibri2/core/datastructure.ml b/src_colibri2/core/datastructure.ml
index 123535639..9731f2494 100644
--- a/src_colibri2/core/datastructure.ml
+++ b/src_colibri2/core/datastructure.ml
@@ -242,6 +242,8 @@ module Queue = struct
   let fold ~f ~init t d =
     Context.Queue.fold f init (Egraph.get_unsaved_env d t)
 
+  let length t d = Context.Queue.length (Egraph.get_unsaved_env d t)
+  let get t d i = Context.Queue.get (Egraph.get_unsaved_env d t) i
 
 end
 
diff --git a/src_colibri2/core/datastructure.mli b/src_colibri2/core/datastructure.mli
index 89dd3b015..be6adf803 100644
--- a/src_colibri2/core/datastructure.mli
+++ b/src_colibri2/core/datastructure.mli
@@ -75,6 +75,8 @@ module Queue: 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 length: 'a t -> Egraph.t -> int
+  val get: 'a t -> Egraph.t -> int -> 'a
 
 end
 
diff --git a/src_colibri2/core/demon.ml b/src_colibri2/core/demon.ml
index 587ce8593..b2358dda6 100644
--- a/src_colibri2/core/demon.ml
+++ b/src_colibri2/core/demon.ml
@@ -32,6 +32,7 @@ module Create = struct
     | EventAnyDom   : 'a DomKind.t  * 'b -> 'b event
     | EventValue    : Node.t * 'a ValueKind.t * 'b -> 'b event
     | EventAnyValue : Node.t  * 'b -> 'b event
+    | EventRegAny   : 'b -> 'b event
     | EventRegCl    : Node.t           * 'b -> 'b event
     | EventChange   : Node.t           * 'b -> 'b event
     | EventChangeAny: 'b -> 'b event
@@ -50,6 +51,8 @@ module Create = struct
         Format.fprintf fmt "any value of %a" Node.pp node
       | EventRegCl  (node, _)    ->
         Format.fprintf fmt "registration of %a" Node.pp node
+      | EventRegAny  (_)    ->
+        Format.fprintf fmt "any registration"
       | EventChange   (node, _)    ->
         Format.fprintf fmt "changeNode of %a" Node.pp node
       | EventChangeAny   (_)    ->
@@ -230,7 +233,7 @@ module Key = struct
         let open Events.Fired in
         match event with
         | EventDom      (a, b , (k,d))   -> k, EventDom(a, b, d)
-        | EventValue    (a, b , c, (k,d))   -> k, EventValue(a, b, c, d)
+        | EventValue    (a, c, (k,d))   -> k, EventValue(a, c, d)
         | EventSem      (a, b, c, (k,d)) -> k, EventSem(a, b, c, d)
         | EventReg      (a, (k,d))       -> k, EventReg(a, d)
         | EventRegNode  (a, (k,d))       -> k, EventRegNode(a, d)
@@ -298,6 +301,8 @@ module Key = struct
           Egraph.attach_any_node t dem.dk_id (k,data)
         | Create.EventRegCl (node,data) ->
           Egraph.attach_reg_node t node dem.dk_id (k,data)
+        | Create.EventRegAny (data) ->
+          Egraph.attach_reg_any t dem.dk_id (k,data)
         | Create.EventRegSem (sem,data) ->
           Egraph.attach_reg_sem t sem dem.dk_id (k,data)
         | Create.EventRegValue (value,data) ->
@@ -428,7 +433,7 @@ module Fast = struct
           Debug.dprintf0 debug "[Demon] @[Done@]";
           (match D.delay with
            | Immediate -> ()
-           | Delayed_by _ | LastEffort _ -> Egraph.flush_internal d);
+           | Delayed_by _ | LastEffort _ | FixingModel -> Egraph.flush_internal d);
           run_one () in
       try
         run_one ();
@@ -500,6 +505,8 @@ module Fast = struct
           Egraph.attach_any_value d node dem.dk_id data
         | EventRegCl  (node,data) ->
           Egraph.attach_reg_node d node dem.dk_id data
+        | EventRegAny  (data) ->
+          Egraph.attach_reg_any d dem.dk_id data
         | EventChange   (node,data) ->
           Egraph.attach_node d node dem.dk_id data
         | EventChangeAny   (data) ->
@@ -582,6 +589,27 @@ module Fast = struct
     RDaemonInit.init init_d;
     attach init_d DaemonInit.key [Create.EventChangeAny(())]
 
+  let register_any_new_node_daemon
+      ~name
+      ?(delay=Events.Delayed_by 1)
+      ?(throttle=100)
+      (f:Egraph.t -> Node.t -> unit)
+      (init_d:Egraph.t)
+    =
+    let module DaemonInit = struct
+      let key = create name
+      module Data = Popop_stdlib.DUnit
+      let delay = delay
+      let throttle = throttle
+      let wakeup d = function
+        | Events.Fired.EventReg(node,()) ->
+          f d node
+        | _ -> raise UnwaitedEvent
+    end in
+    let module RDaemonInit = Register(DaemonInit) in
+    RDaemonInit.init init_d;
+    attach init_d DaemonInit.key [Create.EventRegAny(())]
+
   let register_change_domain_daemon
     (type a) (type b)
     ~name
@@ -657,16 +685,20 @@ module Fast = struct
       let delay = delay
       let throttle = throttle
       let wakeup d = function
-        | Events.Fired.EventValue(node,value,v,data) ->
-          let v = ValueKind.Eq.coerce value Val.key v in
+        | Events.Fired.EventValue(node,value,data) ->
+          let v = Opt.get_exn Impossible (Value.value Val.key value) in
           f d node v data
         | _ -> raise UnwaitedEvent
     end in
     let module RDaemonInit = Register(DaemonInit) in
     let attach d n data =
-      match Egraph.get_value d Val.key n with
+      match Egraph.get_value d n with
       | None -> attach d DaemonInit.key [Create.EventValue(n,Val.key,data)]
-      | Some v -> f d n v data
+      | Some v ->
+        match Value.value Val.key  v with
+        | None -> attach d DaemonInit.key [Create.EventValue(n,Val.key,data)]
+        | Some v ->
+          f d n v data
     in
     RDaemonInit.init, attach
 
@@ -691,7 +723,7 @@ module Fast = struct
       let wakeup d = function
         | Events.Fired.EventDom(node,_,f) ->
           f d node
-        | Events.Fired.EventValue(node,_,_,f) ->
+        | Events.Fired.EventValue(node,_,f) ->
           f d node
         | _ -> raise UnwaitedEvent
     end in
@@ -704,7 +736,7 @@ module Fast = struct
     in
     let for_value d value n f =
       attach d DaemonInit.key [Create.EventValue(n,value,f)];
-      match Egraph.get_value d value n with
+      match Egraph.get_value d n with
       | None -> ()
       | Some _ -> f d n
     in
diff --git a/src_colibri2/core/demon.mli b/src_colibri2/core/demon.mli
index 901e3b296..7c4dbde8b 100644
--- a/src_colibri2/core/demon.mli
+++ b/src_colibri2/core/demon.mli
@@ -31,7 +31,9 @@ module Create : sig
     | EventValue    : Node.t * 'a ValueKind.t  * 'b -> 'b event
     (** the values of the class is watched *)
     | EventAnyValue    : Node.t  * 'b -> 'b event
-    (** we want to register this class *)
+    (** Warn when any class registered *)
+    | EventRegAny    : 'b -> 'b event
+    (** Warn when this class is registered *)
     | EventRegCl    : Node.t           * 'b -> 'b event
     (** Warn when the class is not the representant of its eq-class anymore *)
     | EventChange   : Node.t           * 'b -> 'b event
@@ -161,6 +163,16 @@ module Fast: sig
     unit
     (** *)
 
+    (** helper *)
+  val register_any_new_node_daemon:
+    name:string ->
+    ?delay:Events.delay ->
+    ?throttle:int ->
+    (Egraph.t -> Node.t -> unit) ->
+    Egraph.t ->
+    unit
+    (** *)
+
   (** helper *)
   val register_change_domain_daemon:
     name:string ->
diff --git a/src_colibri2/core/egraph.ml b/src_colibri2/core/egraph.ml
index ae0ac0652..505ac7314 100644
--- a/src_colibri2/core/egraph.ml
+++ b/src_colibri2/core/egraph.ml
@@ -50,12 +50,11 @@ module VDomTable = DomKind.MkVector (struct type ('a,'unused) t = 'a domtable en
 
 module VSemTable = ThTermKind.Vector
 
-type 'a valuetable = {
-  table : 'a Node.M.t;
-  events : Events.Wait.t Bag.t Node.M.t;
-  reg_events : Events.Wait.t list;
+type valuetable = {
+  values : Value.t Node.M.t;
+  events : Events.Wait.t Bag.t Node.M.t ValueKind.M.t;
+  reg_events : Events.Wait.t list ValueKind.M.t;
 }
-module VValueTable = ValueKind.MkVector (struct type ('a,'unit) t = 'a valuetable end)
 
 (** Environnement *)
 
@@ -73,7 +72,7 @@ module Def = struct
       saved_event_any_reg : Events.Wait.t list;
       saved_dom   : delayed_t VDomTable.t;
       saved_sem   : semtable VSemTable.t;
-      saved_value : unit VValueTable.t;
+      saved_value : valuetable;
       saved_envs  : Env.Saved.VectorH.t;
     }
 
@@ -89,7 +88,7 @@ module Def = struct
       (** extensible "number of fields" *)
       dom   : delayed_t VDomTable.t;
       sem   : semtable VSemTable.t;
-      value : unit VValueTable.t;
+      mutable value : valuetable;
       envs  : Env.Saved.VectorH.t;
       mutable current_delayed  : delayed_t; (** For assert-check *)
       unsaved_envs: Env.Unsaved.VectorH.t;
@@ -189,7 +188,7 @@ module Hidden = Context.Make(struct
         saved_event_any_reg = t.event_any_reg;
         saved_dom = VDomTable.copy t.dom;
         saved_sem = VSemTable.copy t.sem;
-        saved_value = VValueTable.copy t.value;
+        saved_value = t.value;
         saved_envs = Env.Saved.VectorH.copy t.envs;
       }
 
@@ -200,9 +199,9 @@ module Hidden = Context.Make(struct
       t.event_value <- s.saved_event_value ;
       t.event_reg <- s.saved_event_reg ;
       t.event_any_reg <- s.saved_event_any_reg;
+      t.value <- s.saved_value;
       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.Saved.VectorH.move ~from:s.saved_envs ~to_:t.envs;
       t.current_delayed <- dumb_delayed
 
@@ -222,13 +221,6 @@ let get_table_sem t k =
   Nodes.check_thterm_registered k;
   ThTermKind.Vector.get_def t.sem k []
 
-let get_table_value t k =
-  Nodes.check_value_registered k;
-  VValueTable.get_def t.value k
-    { table = Node.M.empty;
-      events = Node.M.empty;
-      reg_events = [] }
-
 exception UninitializedEnv of string
 
 exception NotRegistered
@@ -265,12 +257,12 @@ module T = struct
     let node = find_def t node in
     get_direct_dom t dom node
 
-  let get_direct_value t value node =
-    Node.M.find_opt node (get_table_value t value).table
+  let get_direct_value t node =
+    Node.M.find_opt node t.value.values
 
-  let get_value t value node =
+  let get_value t node =
     let node = find_def t node in
-    get_direct_value t value node
+    get_direct_value t node
 
   let get_env : type a. t -> a Env.Saved.t -> a
     = fun t k ->
@@ -339,11 +331,13 @@ let output_graph filename t =
             DomKind.pp dom (escape_for_dot (VDom.print_dom dom) s);
         with Not_found -> ()
       in
-      let iter_value value fmt (valuetable: _ valuetable) =
+      let print_value fmt valuetable =
         try
-          let s = Node.M.find node valuetable.table in
+          let s = Node.M.find node valuetable.values in
+          (match Value.kind s with
+           | Value.Value (kind, value) ->
           Format.fprintf fmt "| {%a | %s}"
-            ValueKind.pp value (escape_for_dot (print_value value) s);
+            ValueKind.pp kind (escape_for_dot (print_value kind) value))
         with Not_found -> ()
       in
       let print_sem fmt node =
@@ -366,9 +360,7 @@ let output_graph filename t =
          else Format.silent)
         t.dom
         (if is_repr t node
-         then VValueTable.pp Format.silent Format.silent
-             {VValueTable.printk=Format.silent}
-             {VValueTable.printd=iter_value}
+         then print_value
          else Format.silent)
         t.value
 
@@ -435,9 +427,9 @@ module Delayed = struct
     assert (is_current_env t);
     get_dom t.env dom node
 
-  let get_value t value node =
+  let get_value t node =
     assert (is_current_env t);
-    get_value t.env value node
+    get_value t.env node
 
   let get_env t env =
     assert (is_current_env t);
@@ -455,19 +447,26 @@ module Delayed = struct
     assert (is_current_env t);
     is_registered t.env node
 
-  let set_value_direct (type a) t (value : a ValueKind.t) node0 new_v =
+  let set_value_direct t node0 new_v =
     Debug.incr stats_set_value;
     let node = find t node0 in
-    let valuetable = get_table_value t.env value in
+    let valuetable = t.env.value in
     let valuetable = {
       valuetable with
-      table = Node.M.add node new_v valuetable.table;
+      values = Node.M.add node new_v valuetable.values;
     } in
-    VValueTable.set t.env.value value valuetable;
-    let events = Node.M.find_opt node valuetable.events in
-    Wait.wakeup_events_bag Events.Wait.translate_value t events (node,value,new_v);
+    t.env.value <- valuetable;
+    (match Value.kind new_v with
+     | Value.Value(valuekind,_) ->
+       let events =
+         let open Option in
+         let* events = ValueKind.M.find_opt valuekind valuetable.events in
+         Node.M.find_opt node events
+       in
+       Wait.wakeup_events_bag Events.Wait.translate_value t events (node,new_v)
+    );
     let events = Node.M.find_opt node t.env.event_value in
-    Wait.wakeup_events_bag Events.Wait.translate_value t events (node,value,new_v)
+    Wait.wakeup_events_bag Events.Wait.translate_value t events (node,new_v)
 
   let add_pending_merge (t : t) node node' =
     Debug.dprintf4 debug "[Egraph] @[add_pending_merge for %a and %a@]"
@@ -515,13 +514,13 @@ module Delayed = struct
               t (Some reg_events) (thterm)
         end
       | Only_for_solver.Value nodevalue ->
-        begin match Only_for_solver.value_of_node nodevalue with
-          | Only_for_solver.Value(value,v) ->
-            let valuetable = get_table_value t.env value in
-            let reg_events = valuetable.reg_events in
+        begin match Value.kind nodevalue with
+          | Value(value,_) ->
+            let valuetable = t.env.value in
+            let reg_events = ValueKind.M.find_opt value valuetable.reg_events in
             Wait.wakeup_events_list Events.Wait.translate_regvalue
-              t (Some reg_events) (nodevalue);
-            set_value_direct t value node v
+              t reg_events (nodevalue);
+            set_value_direct t node nodevalue
         end
     end
 
@@ -545,9 +544,7 @@ module Delayed = struct
         match Nodes.Only_for_solver.nodevalue node0' with
         | None -> ()
         | Some value ->
-          match Nodes.Only_for_solver.value_of_node value with
-          | Nodes.Only_for_solver.Value(value,v) ->
-            set_value_direct t value node0 v
+            set_value_direct t node0 value
       end
       (** node' is already registered *)
       else if Node.equal node (find t node0') then
@@ -662,32 +659,28 @@ module Delayed = struct
   let merge_values t node0 node0' =
     let node  = find t node0 in
     let node' = find t node0'  in
-    let iteri (type a) (value:a ValueKind.t) (valuetable:a valuetable) =
-      let old_s   = Node.M.find_opt node  valuetable.table in
-      let old_s'  = Node.M.find_opt node' valuetable.table in
-      let (module V) = Nodes.get_value value in
-      Debug.dprintf14 debug
-        "[Egraph] @[merge value %a (%a(%a),%a)@ and (%a(%a),%a)@]"
-        ValueKind.pp value
-        Node.pp node Node.pp node0
-        (Format.opt (print_value value)) old_s
-        Node.pp node' Node.pp node0'
-        (Format.opt (print_value value)) old_s';
-      match old_s, old_s' with
-      | None, None   -> ()
-      | Some v, None ->
-        set_value_direct t value node0' v
-      | None, Some v' ->
-        set_value_direct t value node0  v'
-      | Some v, Some v' ->
-        if V.equal v v'
-        then
-          (* already same value. Does that really happen? *)
-          ()
-        else
-          raise Contradiction
-    in
-    VValueTable.iter_initializedi {VValueTable.iteri} t.env.value
+    let valuetable = t.env.value in
+    let old_s   = Node.M.find_opt node  valuetable.values in
+    let old_s'  = Node.M.find_opt node' valuetable.values in
+    Debug.dprintf12 debug
+      "[Egraph] @[merge value (%a(%a),%a)@ and (%a(%a),%a)@]"
+      Node.pp node Node.pp node0
+      (Format.opt Value.pp) old_s
+      Node.pp node' Node.pp node0'
+      (Format.opt Value.pp) old_s';
+    match old_s, old_s' with
+    | None, None   -> ()
+    | Some v, None ->
+      set_value_direct t node0' v
+    | None, Some v' ->
+      set_value_direct t node0  v'
+    | Some v, Some v' ->
+      if Value.equal v v'
+      then
+        (* already same value. Does that really happen? *)
+        ()
+      else
+        raise Contradiction
 
   let finalize_merge t node1_0 node2_0 inv =
     let node1 = find t node1_0 in
@@ -726,17 +719,16 @@ module Delayed = struct
     VDomTable.iter_initializedi {VDomTable.iteri} t.env.dom;
 
     (** move value events  *)
-    let iteri (type a) (value : a ValueKind.t) (valuetable: a valuetable) =
-      match Node.M.find_opt other_node valuetable.events with
-      | None -> ()
+    let mapi _ events =
+      match Node.M.find_opt other_node events with
+      | None -> events
       | Some other_events ->
-        let new_events =
-          Node.M.add_change (fun x -> x) Bag.concat repr_node other_events
-            valuetable.events in
-        let valuetable = { valuetable with events = new_events } in
-        VValueTable.set t.env.value value valuetable
+        Node.M.add_change (fun x -> x) Bag.concat repr_node other_events
+            events
     in
-    VValueTable.iter_initializedi {VValueTable.iteri} t.env.value;
+    t.env.value <- { t.env.value with events =
+                                        ValueKind.M.mapi {mapi} t.env.value.events
+                   };
 
     (** wakeup the daemons *)
     Wait.wakeup_events_bag
@@ -931,12 +923,16 @@ module Delayed = struct
   let attach_value (type a) t node (value : a ValueKind.t) dem event =
     let node = find_def t node in
     let event = Events.Wait.Event (dem,event) in
-    let valuetable = (get_table_value t.env value) in
+    let valuetable = t.env.value in
     let valuetable = {
       valuetable with
-      events = Node.M.add_change Bag.elt Bag.add node event valuetable.events
+      events =
+        ValueKind.M.add_change
+          (fun event -> Node.M.singleton node (Bag.elt event))
+          (Node.M.add_change Bag.elt Bag.add node)
+          value event valuetable.events
     } in
-    VValueTable.set t.env.value value valuetable
+    t.env.value <- valuetable
 
   let attach_node t node dem event =
     let node = find_def t node in
@@ -961,6 +957,15 @@ module Delayed = struct
       t.env.event_reg <-
         Node.M.add_change Lists.singleton Lists.add node event t.env.event_reg
 
+  let attach_reg_any t dem event =
+    let event = Events.Wait.Event (dem,event) in
+    (* todo already registered ? *)
+    (* match find t node with
+     * | node -> (\** already registered *\)
+     *   Wait.wakeup_events_list Events.Wait.translate_regnode t (Some [event]) node
+     * | exception NotRegistered -> *)
+      t.env.event_any_reg <- event::t.env.event_any_reg
+
   let attach_reg_sem (type a) t (sem : a ThTermKind.t) dem event =
     let event = Events.Wait.Event (dem,event) in
     let reg_events = get_table_sem t.env sem in
@@ -969,9 +974,11 @@ module Delayed = struct
 
   let attach_reg_value (type a) t (value : a ValueKind.t) dem event =
     let event = Events.Wait.Event (dem,event) in
-    let value_table = get_table_value t.env value in
-    let reg_events = event::value_table.reg_events in
-    VValueTable.set t.env.value value {value_table with reg_events}
+    let value_table = t.env.value in
+    let reg_events = event::(ValueKind.M.find_def [] value value_table.reg_events) in
+    t.env.value <-
+      {value_table with reg_events =
+                          ValueKind.M.add value reg_events value_table.reg_events}
 
   let attach_any_dom (type a) t (dom : a DomKind.t) dem event =
     let event = Events.Wait.Event (dem,event) in
@@ -1024,7 +1031,10 @@ module Backtrackable = struct
     event_any_reg = [];
     dom = VDomTable.create 5;
     sem = VSemTable.create 5;
-    value = VValueTable.create 5;
+    value = { reg_events = ValueKind.M.empty;
+              values = Node.M.empty;
+              events = ValueKind.M.empty;
+            };
     envs = Env.Saved.VectorH.create 5;
     unsaved_envs = Env.Unsaved.VectorH.create 5;
     current_delayed = dumb_delayed;
@@ -1101,10 +1111,10 @@ module Backtrackable = struct
     let t = Hidden.rw t in
     T.get_dom t dom node
 
-  let get_value t value node =
+  let get_value t node =
     let t = Hidden.rw t in
     assert (check_disabled_delayed t);
-    T.get_value t value node
+    T.get_value t node
 
   let get_env t env =
     let t = Hidden.rw t in
@@ -1150,8 +1160,7 @@ module type Getter = sig
   val find_def  : t -> Node.t -> Node.t
   val get_dom   : t -> 'a DomKind.t -> Node.t -> 'a option
   (** dom of the nodeass *)
-  val get_value : t -> 'a ValueKind.t -> Node.t -> 'a option
-  (** value of the nodeass *)
+  val get_value : t -> Node.t -> Value.t option
 
   (** {4 The nodeasses must have been marked has registered} *)
 
diff --git a/src_colibri2/core/egraph.mli b/src_colibri2/core/egraph.mli
index 71f6418a0..a964f1b73 100644
--- a/src_colibri2/core/egraph.mli
+++ b/src_colibri2/core/egraph.mli
@@ -38,9 +38,9 @@ module type Getter = sig
   val is_equal  : t -> Node.t -> Node.t -> bool
   val find_def  : t -> Node.t -> Node.t
   val get_dom   : t -> 'a DomKind.t -> Node.t -> 'a option
-    (** dom of the class *)
-  val get_value : t -> 'a ValueKind.t -> Node.t -> 'a option
-    (** value of the class *)
+  (** dom of the class *)
+  val get_value : t -> Node.t -> Value.t option
+  (** one of the value of the class *)
 
   (** {4 The classes must have been registered} *)
 
@@ -50,6 +50,7 @@ module type Getter = sig
   val is_registered : t -> Node.t -> bool
 
   val get_env : t -> 'a Env.Saved.t -> 'a
+  (** Can raise UninitializedEnv *)
   val set_env : t -> 'a Env.Saved.t -> 'a -> unit
 
   val get_unsaved_env : t -> 'a Env.Unsaved.t -> 'a
@@ -103,6 +104,8 @@ val attach_value: t -> Node.t -> 'a ValueKind.t -> ('event,'r) Events.Dem.t -> '
 (** wakeup when a value is attached to this equivalence class *)
 val attach_any_value: t -> Node.t -> ('event,'r) Events.Dem.t -> 'event -> unit
 (** wakeup when any kind of value is attached to this equivalence class *)
+val attach_reg_any: t -> ('event,'r) Events.Dem.t -> 'event -> unit
+(** wakeup when any node is registered *)
 val attach_reg_node: t -> Node.t -> ('event,'r) Events.Dem.t -> 'event -> unit
 (** wakeup when this node is registered *)
 val attach_reg_sem: t -> 'a ThTermKind.t -> ('event,'r) Events.Dem.t -> 'event -> unit
diff --git a/src_colibri2/core/events.ml b/src_colibri2/core/events.ml
index 6c67f5657..d6182f65a 100644
--- a/src_colibri2/core/events.ml
+++ b/src_colibri2/core/events.ml
@@ -52,7 +52,7 @@ module Fired = struct
     (** the domain dom of the class change *)
     | EventDom    : Node.t * 'a DomKind.t  *      'b -> 'b event
     (** the value of the class has been set *)
-    | EventValue    : Node.t * 'a ValueKind.t * 'a * 'b -> 'b event
+    | EventValue    : Node.t * Value.t * 'b -> 'b event
     (** a new theory term 'a point to this class (not complete) *)
     | EventSem    : Node.t * 'a ThTermKind.t * 'a * 'b -> 'b event
     (** we want to register a class *)
@@ -69,8 +69,8 @@ module Fired = struct
   let pp fmt = function
     | EventDom      (node, dom, _) ->
       Format.fprintf fmt "dom:%a of %a" DomKind.pp dom Node.pp node
-    | EventValue    (node, value, _, _) ->
-      Format.fprintf fmt "value:%a of %a" ValueKind.pp value Node.pp node
+    | EventValue    (node, value, _) ->
+      Format.fprintf fmt "value:%a of %a" Value.pp value Node.pp node
     | EventSem      (node, sem, v, _) ->
       Format.fprintf fmt "sem:%a of %a with %a"
         ThTermKind.pp sem Node.pp node (print_thterm sem) v
@@ -89,15 +89,15 @@ module Fired = struct
       end
     | EventRegValue (nodevalue, _) ->
       let node = Only_for_solver.node_of_nodevalue nodevalue in
-      begin match Only_for_solver.value_of_node nodevalue with
-        | Only_for_solver.Value(value,v) ->
+      begin match Value.kind nodevalue with
+        | Value(value,v) ->
           Format.fprintf fmt "registration of value:%a of %a with %a"
             ValueKind.pp value Node.pp node (print_value value) v
       end
 
   let get_data = function
     | EventDom      (_, _ , d)   -> d
-    | EventValue    (_, _ , _, d)   -> d
+    | EventValue    (_, _ , d)   -> d
     | EventSem      (_, _, _, d) -> d
     | EventReg    (_, d)       -> d
     | EventRegNode  (_, d)       -> d
@@ -112,6 +112,7 @@ type delay =
   | Immediate
   | Delayed_by of int
   | LastEffort of int
+  | FixingModel
 
 module Wait = struct
   type t =
@@ -140,7 +141,7 @@ module Wait = struct
   let translate_dom =
     {translate = fun (node,dom) data -> EventDom(node,dom,data)}
   let translate_value =
-    {translate = fun (node,value,v) data -> EventValue(node,value,v,data)}
+    {translate = fun (node,value) data -> EventValue(node,value,data)}
   let translate_sem =
     {translate = fun (node,sem,s) data -> EventSem(node,sem,s,data)}
   let translate_reg =
diff --git a/src_colibri2/core/events.mli b/src_colibri2/core/events.mli
index dc5415241..5bd66017a 100644
--- a/src_colibri2/core/events.mli
+++ b/src_colibri2/core/events.mli
@@ -26,7 +26,7 @@ module Fired : sig
     (** the domain dom of the class change *)
     | EventDom      : Node.t * 'a DomKind.t  *      'b -> 'b event
     (** the value of the node has been set *)
-    | EventValue    : Node.t * 'a ValueKind.t * 'a * 'b -> 'b event
+    | EventValue    : Node.t * Value.t * 'b -> 'b event
     (** a new semantical term 'a point to this class (not complete) *)
     | EventSem      : Node.t * 'a ThTermKind.t * 'a * 'b -> 'b event
     (** we want to register a class *)
@@ -54,7 +54,8 @@ type delay =
   | Delayed_by of int
   (** Must be strictly positive *)
   | LastEffort of int
-  (** When no decisions remains, must be strictly positive *)
+  (** Should try to ensure that a model exists, must be strictly positive *)
+  | FixingModel
 
 module Wait : sig
   type t =
@@ -75,7 +76,7 @@ module Wait : sig
   type 'a translate = { translate : 'd. 'a -> 'd -> 'd Fired.event}
 
   val translate_dom      : (Node.t * 'a DomKind.t) translate
-  val translate_value    : (Node.t * 'a ValueKind.t * 'a) translate
+  val translate_value    : (Node.t * Value.t) translate
   val translate_reg      : Node.t translate
   val translate_regnode  : Node.t translate
   val translate_change   : Node.t translate
diff --git a/src_colibri2/core/ground.mli b/src_colibri2/core/ground.mli
index 8badd2227..4f9d94f0d 100644
--- a/src_colibri2/core/ground.mli
+++ b/src_colibri2/core/ground.mli
@@ -92,7 +92,7 @@ val init: Egraph.t -> unit
 
 val register_converter:
   Egraph.t -> (Egraph.t -> t -> unit) -> unit
-(** register converters between syntactic terms *)
+(** register callback called for each new ground term registered *)
 
 module Defs : sig
     val add:
diff --git a/src_colibri2/core/interp.ml b/src_colibri2/core/interp.ml
index 7c8ee2713..7b0fd0764 100644
--- a/src_colibri2/core/interp.ml
+++ b/src_colibri2/core/interp.ml
@@ -18,55 +18,171 @@
 (*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
 (*************************************************************************)
 
+open Base
 open Colibri2_popop_lib
 
+type env =
+  | Before  (** fixing model *)
+  | During of { limitreached : bool ref; limit : int; nextnode : int }
+[@@deriving show]
+
+module Data = struct
+  let ground = Datastructure.Queue.create Fmt.nop "Interp.ground"
+
+  let check = Datastructure.Queue.create Fmt.nop "Interp.check"
+
+  let node = Datastructure.Queue.create Fmt.nop "Interp.node"
+
+  let ty = Datastructure.Queue.create Fmt.nop "Interp.ty"
+
+  let reg_ground = Datastructure.Queue.create Fmt.nop "Interp.reg_ground"
+
+  let reg_node = Datastructure.Queue.create Fmt.nop "Interp.reg_node"
+
+  let env =
+    Env.Saved.create_key
+      (module struct
+        type t = env
+
+        let name = "Interp.name"
+      end)
+
+  let () = Env.Saved.register pp_env env
+end
+
+module SeqLim = struct
+  type 'a t = 'a Sequence.t
+
+  let of_seq d s =
+    match Egraph.get_env d Data.env with
+    | Before -> s
+    | During d ->
+        Sequence.unfold_with s ~init:0 ~f:(fun i x ->
+            if i <= d.limit then Sequence.Step.Yield (x, i + 1)
+            else (
+              d.limitreached := true;
+              Sequence.Step.Done))
+
+  let ( let+ ) = Sequence.( >>| )
+
+  let ( let* ) t f = Sequence.bind t ~f
+
+  let ( and* ) = Sequence.cartesian_product
+end
+
 module Register = struct
-  type interp_term = Expr.Term.t -> Nodes.Value.t
-  let ids : (interp_term -> Expr.Term.t -> Nodes.Value.t option) list ref = ref []
-  let id f = ids := f::!ids
+  open Data
+
+  let check d f = Datastructure.Queue.push check d f
+
+  let node d f = Datastructure.Queue.push node d f
+
+  let ty d f = Datastructure.Queue.push ty d f
+end
+
+let get_registered (type a) exn db d x =
+  let exception Found of a in
+  match
+    Datastructure.Queue.iter
+      ~f:(fun f -> Option.iter (f d x) ~f:(fun s -> raise (Found s)))
+      db d
+  with
+  | exception Found s -> s
+  | () -> exn x
+  [@@inline always]
+
+exception CantInterpretTy of Ground.Ty.t
+
+let ty d ty = get_registered (fun ty -> raise (CantInterpretTy ty)) Data.ty d ty
+
+exception CantInterpretNode of Nodes.Node.t
+
+let node d n =
+  get_registered (fun n -> raise (CantInterpretNode n)) Data.node d n
+
+exception CantCheckGround of Ground.t
+
+let ground d n =
+  get_registered (fun n -> raise (CantCheckGround n)) Data.ground d n
+
+let check_ground_terms d =
+  Datastructure.Queue.iter Data.reg_ground d ~f:(fun g ->
+      if not (ground d g) then Egraph.contradiction d)
+
+(* module WTO = Colibri2_stdlib.Wto.Make (Ground) *)
 
-  module ThInterp = Nodes.ThTermKind.MkVector(struct
-      type ('a,_) t = (interp:(Nodes.Node.t -> Nodes.Value.t) -> 'a -> Nodes.Value.t)
-    end)
+(* let compute_wto d =
+ *   let g = Nodes.Node.H.create 100 in *)
 
-  let thterms = ThInterp.create 10
-  let thterm sem f =
-    if not (ThInterp.is_uninitialized thterms sem)
-    then invalid_arg (Format.asprintf "Interpretation for semantic value %a already done" Nodes.ThTermKind.pp sem);
-    ThInterp.set thterms sem f
+let init d =
+  Egraph.set_env d Data.env Before;
+  Demon.Fast.register_any_new_node_daemon ~name:"Interp.new_node"
+    (fun d g -> Datastructure.Queue.push Data.reg_node d g)
+    d;
+  Ground.register_converter d (fun d g ->
+      Datastructure.Queue.push Data.reg_ground d g)
 
-  let models = Expr.Ty.H.create 16
-  let model ty (f:Egraph.t -> Nodes.Node.t -> Nodes.Value.t) =
-    Expr.Ty.H.add models ty f
+module Fix_model = struct
+  let init d =
+    let env =
+      During
+        {
+          limitreached =
+            (* true because we want to continue (i.e start) *)
+            ref true;
+          nextnode = Datastructure.Queue.length Data.reg_node d - 1;
+          limit = 1;
+        }
+    in
+    Egraph.set_env d Data.env env
 
+  let next_dec d =
+    match Egraph.get_env d Data.env with
+    | Before ->
+        (* The first branching is about the limit *)
+        init d;
+        Sequence.unfold ~init:(1, d) ~f:(fun (i, d) ->
+            match Egraph.get_env d Data.env with
+            | Before -> assert false
+            | During r ->
+                if !(r.limitreached) then
+                  let limit = i * 2 in
+                  let dec d =
+                    match Egraph.get_env d Data.env with
+                    | Before -> assert false
+                    | During r ->
+                        Egraph.set_env d Data.env (During { r with limit })
+                  in
+                  Some (dec, (limit, d))
+                else None)
+    | During r ->
+        let rec aux nextnode =
+          if nextnode < 0 then (
+            check_ground_terms d;
+            Egraph.set_env d Data.env Before;
+            Sequence.empty)
+          else
+            (* The others are about the values *)
+            let n = Datastructure.Queue.get Data.reg_node d r.nextnode in
+            match Egraph.get_value d n with
+            | Some _ -> aux (nextnode - 1)
+            | None ->
+                let seq = node d n in
+                Sequence.map seq ~f:(fun v d ->
+                    Egraph.set_env d Data.env
+                      (During { r with nextnode = nextnode - 1 });
+                    Egraph.set_value d n v)
+        in
+        aux r.nextnode
 end
 
-exception CantInterpretTerm of Expr.Term.t
-
-type leaf = Expr.Term.t -> Nodes.Value.t option
-
-let term ?(leaf=(fun _ -> None)) t =
-  let rec interp regl t =
-      let rec aux t = function
-        | [] -> raise (CantInterpretTerm t)
-        | a::l ->
-          match a (interp regl) t with
-          | Some v -> v
-          | None -> aux t l
-      in
-      aux t regl
-  in
-  interp ((fun _ -> leaf)::!Register.ids) t
-
-(* let model d n =
- *   match Ty.H.find_opt Register.models (Nodes.Node.ty n) with
- *   | None -> invalid_arg "Uninterpreted type"
- *   | Some f -> f d n *)
-
-let () = Exn_printer.register (fun fmt exn ->
-    match exn with
-    | CantInterpretTerm t ->
-      Format.fprintf fmt "Can't interpret the term %a."
-        Expr.Term.pp t
-    | exn -> raise exn
-  )
+let () =
+  Exn_printer.register (fun fmt exn ->
+      match exn with
+      | CantInterpretNode t ->
+          Fmt.pf fmt "Can't interpret the node %a." Nodes.Node.pp t
+      | CantCheckGround t ->
+          Fmt.pf fmt "Can't check ground term %a." Ground.pp t
+      | CantInterpretTy t ->
+          Fmt.pf fmt "Can't interpret the type %a." Ground.Ty.pp t
+      | exn -> raise exn)
diff --git a/src_colibri2/core/interp.mli b/src_colibri2/core/interp.mli
index da52e484b..e2df2c8e1 100644
--- a/src_colibri2/core/interp.mli
+++ b/src_colibri2/core/interp.mli
@@ -18,18 +18,58 @@
 (*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
 (*************************************************************************)
 
+open Base
 
-module Register: sig
-  val id: ((Expr.Term.t -> Nodes.Value.t) -> (Expr.Term.t -> Nodes.Value.t option)) -> unit
+module SeqLim : sig
+  type 'a t
+  (** Sequence, finite during module fixing *)
 
-  val thterm: 'a Nodes.ThTermKind.t -> (interp:(Nodes.Node.t -> Nodes.Value.t) -> 'a -> Nodes.Value.t) -> unit
+  val of_seq : Egraph.t -> 'a Sequence.t -> 'a t
+  (** Limit the sequence to the given bound of the iterative deepening.
+      Sequence used for enumerating the values should be limited for ensuring
+      fairness. If the sequence contained more elements than limited the top
+      decision will restart with a bigger limit
+  *)
 
-  (* val model: Ty.t -> (Egraph.t -> Nodes.Node.t -> Nodes.Value.t) -> unit *)
+  val ( let+ ) : 'a t -> ('a -> 'b) -> 'b t
 
+  val ( and* ) : 'a t -> 'b t -> ('a * 'b) t
+  (** cartesian product {!Base.Sequence.cartesian_product} *)
+
+  val ( let* ) : 'a t -> ('a -> 'b t) -> 'b t
 end
 
-type leaf = Expr.Term.t -> Nodes.Value.t option
+module Register : sig
+  val check : Egraph.t -> (Egraph.t -> Ground.t -> bool option) -> unit
+  (** Check the value of the arguments corresponds to the the one of the of the term *)
+
+  val node :
+    Egraph.t ->
+    (Egraph.t -> Nodes.Node.t -> Nodes.Value.t SeqLim.t option) ->
+    unit
+  (** Register the computation of possible values for a node using the
+      information on the domains *)
+
+  val ty :
+    Egraph.t ->
+    (Egraph.t -> Ground.Ty.t -> Nodes.Value.t SeqLim.t option) ->
+    unit
+  (** Register iterators on all the possible value of some types, all the values
+      must be reached eventually *)
+end
 
-val term   : ?leaf:leaf -> Expr.Term.t -> Nodes.Value.t
+val ty : Egraph.t -> Ground.Ty.t -> Nodes.Value.t SeqLim.t
+(** Iterate on all the possible value of the given type, usually all the values
+    will be reached eventually *)
 
-(* val model : Egraph.t -> Nodes.Node.t -> Nodes.Value.t *)
+val init : Egraph.t -> unit
+(** Initialize the module for later use *)
+
+module Fix_model : sig
+  (** The model is search using iterative deepening depth-first search for
+     ensuring optimality even in presence of infinite choice *)
+
+  val next_dec : Egraph.t -> (Egraph.t -> unit) Sequence.t
+  (** Add a level of decision for fixing the model, another level could be
+      needed. Could raise unsatisfiable if all the model have been tried *)
+end
diff --git a/src_colibri2/core/structures/nodes.ml b/src_colibri2/core/structures/nodes.ml
index ad82ca99c..7c455376f 100644
--- a/src_colibri2/core/structures/nodes.ml
+++ b/src_colibri2/core/structures/nodes.ml
@@ -261,11 +261,11 @@ module Value = struct
       | Poly.Neq -> None
       | Poly.Eq  -> Some v
 
-  let semantic_equal (x:t) (y:t) : [ `Uncomparable | `Equal | `Disequal ] =
-    match x, y with
-    | Node.Value(_,xk,_), Node.Value(_,yk,_) when not (ValueKind.equal xk yk) ->
-      `Uncomparable
-    | _ -> if equal x y then `Equal else `Disequal
+  type kind =
+    | Value: 'a ValueKind.t * 'a  -> kind
+
+  let kind: t -> kind = function
+    | Node.Value (_,value,v) -> Value(value,v)
 
 end
 
@@ -403,16 +403,10 @@ module Only_for_solver = struct
   let sem_of_node: ThTerm.t -> sem_of_node = function
     | Node.ThTerm (_,sem,v) -> ThTerm(sem,v)
 
-  type value_of_node =
-    | Value: 'a ValueKind.t * 'a  -> value_of_node
-
   let nodevalue: Node.t -> Value.t option = function
     | Node.All Node.ThTerm _ -> None
     | Node.All (Node.Value _ as x) -> Some x
 
-  let value_of_node: Value.t -> value_of_node = function
-    | Node.Value (_,value,v) -> Value(value,v)
-
   let node_of_thterm : ThTerm.t -> Node.t = ThTerm.node
   let node_of_nodevalue : Value.t -> Node.t = Value.node
 
diff --git a/src_colibri2/core/structures/nodes.mli b/src_colibri2/core/structures/nodes.mli
index 45ca30607..6ab60caa3 100644
--- a/src_colibri2/core/structures/nodes.mli
+++ b/src_colibri2/core/structures/nodes.mli
@@ -140,8 +140,13 @@ module Value: sig
 
   val value: 'a ValueKind.t -> t -> 'a option
 
-  val semantic_equal: t -> t -> [ `Uncomparable | `Equal | `Disequal ]
-    (** Test semantic equality of comparable value (same value kind) *)
+  type kind =
+  | Value: 'a ValueKind.t * 'a -> kind
+
+  val kind: t -> kind
+    (** give the value associated with a node, make sense only for not merged
+        class. So only the module solver can use it *)
+
 end
 
 (** {3 For building a particular value} *)
@@ -179,6 +184,7 @@ val get_registered_value: 'a ValueKind.t -> (module RegisteredValue with type s
 val check_initialization: unit -> bool
 (** Check if the initialization of all the sem and value have been done *)
 
+
 (** {2 Only for the solver } *)
 module Only_for_solver: sig
   type sem_of_node =
@@ -194,19 +200,11 @@ module Only_for_solver: sig
     (** give the sem associated with a node, make sense only for not merged
         class. So only the module solver can use it *)
 
-  type value_of_node =
-    | Value: 'a ValueKind.t * 'a -> value_of_node
-
   val nodevalue:
     Node.t -> Value.t option
     (** give the value associated with a node, make sense only for not merged
         class. So only the module solver can use it *)
 
-  val value_of_node:
-    Value.t -> value_of_node
-    (** give the value associated with a node, make sense only for not merged
-        class. So only the module solver can use it *)
-
   val node_of_thterm: ThTerm.t -> Node.t
   val node_of_nodevalue: Value.t -> Node.t
 
diff --git a/src_colibri2/solver/scheduler.ml b/src_colibri2/solver/scheduler.ml
index 756617357..572aadd85 100644
--- a/src_colibri2/solver/scheduler.ml
+++ b/src_colibri2/solver/scheduler.ml
@@ -80,6 +80,7 @@ type t =
   { mutable choices    : Prio.t;
     daemons : Events.Wait.daemon_key Context.TimeWheel.t;
     lasteffort : Events.Wait.daemon_key Context.TimeWheel.t;
+    mutable fixing_model : Events.Wait.daemon_key list;
     mutable prev_scheduler_state : bp option;
             solver_state      : Egraph.Backtrackable.t;
     mutable delayed           : Egraph.t option;
@@ -115,6 +116,7 @@ let new_solver () =
   { choices = Prio.empty;
     daemons = Context.TimeWheel.create (Context.creator context);
     lasteffort = Context.TimeWheel.create (Context.creator context);
+    fixing_model = [];
     prev_scheduler_state = None;
     solver_state = Egraph.Backtrackable.new_t (Context.creator context);
     context;
@@ -169,6 +171,8 @@ let new_delayed =
     | Delayed_by offset -> Context.TimeWheel.add t.daemons att offset
     | LastEffort offset ->
       Context.TimeWheel.add t.lasteffort att offset
+    | FixingModel ->
+      t.fixing_model <- att :: t.fixing_model
     in
     let sched_decision dec =
       incr dec_count;
diff --git a/src_colibri2/stdlib/context.ml b/src_colibri2/stdlib/context.ml
index c93ee2f71..8e2bfdf0c 100644
--- a/src_colibri2/stdlib/context.ml
+++ b/src_colibri2/stdlib/context.ml
@@ -324,6 +324,8 @@ module Queue = struct
   let push t v = save t; Vector.push t.v v
   let iter f t = refresh t; Vector.iter f t.v
   let fold f acc t = refresh t; Vector.fold f acc t.v
+  let length t = refresh t; Vector.length t.v
+  let get t i = refresh t; Vector.get t.v i
 
   let pp ?sep pp fmt v = Vector.pp ?pp_sep:sep pp fmt v.v
 end
diff --git a/src_colibri2/stdlib/context.mli b/src_colibri2/stdlib/context.mli
index 40bf9a974..17b6ca326 100644
--- a/src_colibri2/stdlib/context.mli
+++ b/src_colibri2/stdlib/context.mli
@@ -176,6 +176,8 @@ module Queue: sig
   val push: 'a t -> 'a -> unit
   val iter: ('a -> unit) -> 'a t -> unit
   val fold: ('acc -> 'a -> 'acc) -> 'acc -> 'a t -> 'acc
+  val length: 'a t -> int
+  val get: 'a t -> int -> 'a
 
   val pp: ?sep:unit Fmt.t -> 'a Fmt.t -> 'a t Fmt.t
 end
diff --git a/src_colibri2/stdlib/wto.ml b/src_colibri2/stdlib/wto.ml
new file mode 100644
index 000000000..defb3ba99
--- /dev/null
+++ b/src_colibri2/stdlib/wto.ml
@@ -0,0 +1,236 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2020                                               *)
+(*    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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(** Each component of the graph is either an individual node of the graph
+    (without) self loop, or a strongly connected component where a node is
+    designed as the head of the component and the remaining nodes are given
+    by a list of components topologically ordered. *)
+type 'n component =
+  | Component of 'n * 'n partition
+    (** A strongly connected component, described by its head node and the
+        remaining sub-components topologically ordered *)
+  | Node of 'n
+    (** A single node without self loop *)
+
+(** A list of strongly connected components, sorted topologically *)
+and 'n partition = 'n component list
+
+
+let rec pp_partition pp_node fmt part =
+  List.iter (fun x -> Format.fprintf fmt "@ %a" (pp_component pp_node) x) part
+and pp_component pp_node fmt : 'a component -> unit = function
+  | Node n -> pp_node fmt n
+  | Component(head,part) ->
+    Format.fprintf fmt "@[<hov 1>(%a%a)@]"
+      pp_node head (pp_partition pp_node) part
+
+let fold_heads f acc l =
+  let rec partition acc l =
+    List.fold_left component acc l
+  and component acc = function
+    | Node _ -> acc
+    | Component (h,l) ->
+      partition (f acc h) l
+  in
+  partition acc l
+
+
+let flatten wto =
+  let rec f acc = function
+    | [] -> acc
+    | Node v :: l -> f (v :: acc) l
+    | Component (v,w) :: l -> f (f (v :: acc) w) l
+  in
+  List.rev (f [] wto)
+
+(* Bourdoncle's WTO algorithm builds on Tarjan's SCC algorithm. In Tarjan:
+
+   - We visit every node once, starting from root, by following the
+     successors; this creates a spanning tree of the graph. SCCs are
+     subtrees of this spanning tree, whose root is the head of the SCC
+     (although in non-natural SCCs, it is possible to enter into a SCC
+     without going through the head).
+
+   - This spanning tree is obtained using DFS. What DFS guarantees is
+     that there is no path from a child c of a node n to other
+     children of n, provided that there is no path from c to an
+     ancestor of n. Thus when we visit other children of n, we know
+     that they are no path to them from the descendants of c.
+
+   - We assign consecutive numbers to each node in the order in which
+     they have been visited. As the iteration is depth-first search,
+     this gives a depth-first numbering (DFN).
+
+   - Each time we visit a node n, we push it on a stack. After the
+     visit, n is popped, unless a path exists from n to an element
+     earlier on the stack. So the stack contains elements currently
+     visited or that belongs to a non-trivial scc. Moreover, they 
+     are in topological order.
+
+   About the proof of Tarjan:
+   http://ls2-www.cs.uni-dortmund.de/~wegener/papers/connected.pdf
+*)
+
+module Make(N:sig
+    type t (* = int *)
+    val equal: t -> t -> bool
+    val hash: t -> int
+    val pp: Format.formatter -> t -> unit
+    (* val succ: t -> t list *)
+  end) = struct
+
+  let rec equal_component (x:N.t component) (y:N.t component) =
+    match x,y with
+    | Node x, Node y -> N.equal x y
+    | Component (x,cx), Component (y,cy) -> N.equal x y && equal_partition cx cy
+    | _ -> false
+
+  and equal_partition x y =
+    (try List.for_all2 equal_component x y with Invalid_argument _ -> false)
+
+  module DFN = Hashtbl.Make(N);;
+
+  type level = int
+
+  (** Status of a visited vertex during the algorithm. *)
+  type status =
+    | Invisible (** The vertex have already been added into the partition and
+                    is hidden until the end of the search. *)
+    | Parent of level (** The vertex have been visited and given a [level]. For
+                          the algorithm, this implies that there is a path
+                          between this vertex and the current vertex. *)
+
+  (** Result of one [visit]  *)
+  type loop =
+    | NoLoop (** The vertex is not in a loop *)
+    | Loop of N.t * level (** The vertex is inside at least one loop, and
+                              level is the smallest level of all these loops *)
+
+  let min_loop x y =
+    match x, y with
+    | NoLoop, z | z, NoLoop -> z
+    | Loop(_,xi), Loop(_,yi) ->
+      if xi <= yi then x else y
+
+  let is_no_loop = function
+    | NoLoop -> true | Loop _ -> false
+
+  type state =
+    { dfn: status DFN.t; (* Mapping from nodes to its dfn, depth-first
+                            numbering.  Note that we replaced the DFN=0
+                            test by presence in the Hashtable. *)
+      mutable num: level;          (* Number of visited nodes. *)
+      succs: N.t -> (N.t list);    (* Successors transition. *)
+      stack: N.t Stack.t
+    }
+
+  (** Visit [vertex], and all the vertices reachable from [vertex]
+      which have not been explored yet (this is a depth-first search).
+      Also gives [partition], which is the partition built so far
+
+      Returns a pair (loop,partition) where
+      - [loop] tells whether we are in a loop or not and gives the vertex of
+        this loop with the lowest level. This vertex is also the deepest in the
+        stack and the neareast vertex from the root that is below [vertex] in
+        the spanning tree built by the DFS);
+      - [partition] is returned completed. *)
+  let rec visit ~pref state vertex partition =
+    match DFN.find state.dfn vertex with
+    (* The vertex is already in the partition *)
+    | Invisible -> NoLoop, partition (* skip it *)
+    (* The vertex have been visited but is not yet in the partition *)
+    | Parent i -> Loop (vertex,i), partition (* we are in a loop *)
+    (* The vertex have not been visited yet *)
+    | exception Not_found ->
+      (* Put the current vertex into the stack *)
+      Stack.push vertex state.stack;
+      (* Number it and mark it as visited *)
+      let n = state.num + 1 in
+      state.num <- n;
+      DFN.replace state.dfn vertex (Parent n);
+      (* Visit all its successors *)
+      let succs = state.succs vertex in
+      let (loop,partition) = List.fold_left (fun (loop,partition) succ ->
+          let (loop',partition) = visit ~pref state succ partition in
+          let loop = min_loop loop loop' in
+          (loop,partition)
+        ) (NoLoop,partition) succs
+      in
+      match loop with
+      (* We are not in a loop. Add the vertex to the partition *)
+      | NoLoop ->
+        let _ = Stack.pop state.stack in
+        DFN.replace state.dfn vertex Invisible;
+        (NoLoop,Node(vertex)::partition)
+      (* We are in a loop and the current vertex is the head of this loop *)
+      | Loop(head,_) when N.equal head vertex ->
+        (* Unmark all vertices in the loop, and, if pref is given, try to
+           return a better head *)
+        let rec reset_SCC best_head =
+          (** pop until vertex *)
+          let element = Stack.pop state.stack in
+          DFN.remove state.dfn element;
+          if not (N.equal element vertex) then begin
+            let best_head = match pref with
+              (** the strict is important because we are conservative *)
+              | Some cmp when cmp best_head element < 0 -> element
+              | _ -> best_head
+            in
+            reset_SCC best_head
+          end
+          else
+            best_head
+        in
+        let best_head = reset_SCC vertex in
+        let vertex, succs =
+          if N.equal best_head vertex
+          then vertex,succs
+          else best_head, state.succs best_head
+        in
+        (* Makes [vertex] invisible in the subsequents visits. *)
+        DFN.replace state.dfn vertex Invisible;
+        (* Restart the component analysis *)
+        let component = List.fold_left
+            (fun component succ ->
+               let (loop,component) = visit ~pref state succ component in
+               (* Since we reset the component we should have no loop *)
+               assert (is_no_loop loop);
+               component
+            ) [] succs
+        in
+        (NoLoop,Component(vertex,component)::partition)
+      | _ ->
+        (* [vertex] is part of a strongly connected component but is not the
+           head. Do not update partition; the vertex will
+           be added during the second visit of the SCC. *)
+        (loop,partition)
+
+  type pref = N.t -> N.t -> int
+
+  let partition ?pref ~init ~succs =
+    let state = {dfn = DFN.create 17; num = 0; succs;
+                 stack = Stack.create () } in
+    let loop,component = visit ~pref state init [] in
+    assert (is_no_loop loop);
+    component
+
+end
diff --git a/src_colibri2/stdlib/wto.mli b/src_colibri2/stdlib/wto.mli
new file mode 100644
index 000000000..82d6f5b19
--- /dev/null
+++ b/src_colibri2/stdlib/wto.mli
@@ -0,0 +1,64 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2020                                               *)
+(*    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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(** Weak topological orderings (WTOs) are a hierarchical decomposition of the
+    a graph where each layer is topologically ordered and strongly connected
+    components are aggregated and ordered recursively. This is a very
+    convenient representation to describe an evaluation order to reach a
+    fixpoint. *)
+
+(** Each component of the graph is either an individual node of the graph
+    (without) self loop, or a strongly connected component where a node is
+    designed as the head of the component and the remaining nodes are given
+    by a list of components topologically ordered. *)
+type 'n component =
+  | Component of 'n * 'n partition
+    (** A strongly connected component, described by its head node and the
+        remaining sub-components topologically ordered *)
+  | Node of 'n
+    (** A single node without self loop *)
+
+(** A list of strongly connected components, sorted topologically *)
+and 'n partition = 'n component list
+
+val flatten: 'n partition -> 'n list
+
+val fold_heads: ('a -> 'n -> 'a) -> 'a -> 'n partition -> 'a
+
+(** This functor provides the partitioning algorithm constructing a WTO. *)
+module Make(Node:sig
+    type t
+    val equal: t -> t -> bool
+    val hash: t -> int
+    val pp: Format.formatter -> t -> unit
+  end):sig
+
+  type pref = Node.t -> Node.t -> int
+  (** partial order of preference for the choice of the head of a loop *)
+
+  (** Implements Bourdoncle "Efficient chaotic iteration strategies with
+  widenings" algorithm to compute a WTO. *)
+  val partition: ?pref:pref -> init:Node.t -> succs:(Node.t -> Node.t list) -> Node.t partition
+
+  val equal_component: Node.t component -> Node.t component -> bool
+  val equal_partition: Node.t partition -> Node.t partition -> bool
+end
diff --git a/src_colibri2/theories/ADT/adt.ml b/src_colibri2/theories/ADT/adt.ml
index 44f5c3fc8..f77b2dcfb 100644
--- a/src_colibri2/theories/ADT/adt.ml
+++ b/src_colibri2/theories/ADT/adt.ml
@@ -10,11 +10,11 @@ module D = struct
 
   let key =
     DomKind.create_key
-      ( module struct
+      (module struct
         type nonrec t = t
 
         let name = "adt"
-      end )
+      end)
 
   let merged d1 d2 = Option.equal equal d1 d2
 
@@ -36,8 +36,8 @@ module D = struct
                   f1 f2;
             }
         else Egraph.contradiction d
-    | (One { case = c1; _ } as d1), Unk c2 | Unk c2, (One { case = c1; _ } as d1)
-      ->
+    | (One { case = c1; _ } as d1), Unk c2
+    | Unk c2, (One { case = c1; _ } as d1) ->
         if Case.S.mem c1 c2 then d1 else Egraph.contradiction d
 
   let merge d (d1, n1) (d2, n2) _ =
@@ -121,7 +121,8 @@ end = struct
 
   let[@ocaml.always inline] get a = get_dom D.key a
 
-  let[@ocaml.always inline] get_value key n' d _ = Egraph.get_value d key n'
+  let[@ocaml.always inline] get_value key n' d _ =
+    Option.bind (Egraph.get_value d n') (Value.value key)
 
   let[@ocaml.always inline] set_value (type b)
       (value : (module ValueKind.Registered with type s = b)) n'
diff --git a/src_colibri2/theories/LRA/LRA.ml b/src_colibri2/theories/LRA/LRA.ml
index df5b98b0a..4c2480f44 100644
--- a/src_colibri2/theories/LRA/LRA.ml
+++ b/src_colibri2/theories/LRA/LRA.ml
@@ -19,39 +19,50 @@
 (*************************************************************************)
 
 open Colibri2_core
+open Colibri2_popop_lib
 open Colibri2_stdlib.Std
 
 let default_value = Q.zero
 
-let () =
-  Interp.Register.id (fun interp t ->
-      let (!>) t = RealValue.value (RealValue.coerce_nodevalue (interp t)) in
-      let (!<) v = Some (RealValue.nodevalue (RealValue.index v)) in
-      let (!<<) b = Some (if b then Boolean.values_true else Boolean.values_false) in
-  match t with
-  | { descr = Expr.App({builtin = Expr.Integer s},[],[]); _ } ->
-    !< (Q.of_string s)
-  | { descr = Expr.App({builtin = Expr.Decimal s},[],[]); _ } ->
-    !< (Q.of_string_decimal s)
-  | { descr = Expr.App({builtin = Expr.Rational s},[],[]); _ } ->
-    !< (Q.of_string_decimal s)
-  | { descr = Expr.App({builtin = Expr.Add},[],[a;b]); _ } ->
-    !< (Q.add !>a !>b)
-  | { descr = Expr.App({builtin = Expr.Sub},[],[a;b]); _ } ->
-    !< (Q.sub !>a !>b)
-  | { descr = Expr.App({builtin = Expr.Minus},[],[a]); _ } ->
-    !< (Q.neg !>a)
-  | { descr = Expr.App({builtin = Expr.Mul},[],[a;b]); _ } ->
-    !< (Q.mul !>a !>b)
-  | { descr = Expr.App({builtin = Expr.Lt},[],[arg1;arg2]); _ } ->
-    !<< (Q.lt !>arg1 !>arg2)
-  | { descr = Expr.App({builtin = Expr.Leq},[],[arg1;arg2]); _ } ->
-    !<< (Q.leq !>arg1 !>arg2)
-  | { descr = Expr.App({builtin = Expr.Gt},[],[arg1;arg2]); _ } ->
-    !<< (Q.gt !>arg1 !>arg2)
-  | { descr = Expr.App({builtin = Expr.Geq},[],[arg1;arg2]); _ } ->
-    !<< (Q.geq !>arg1 !>arg2)
-  | _ -> None
+let init_check d =
+  Interp.Register.check d (fun d t ->
+      let exception False in
+      try
+        let interp n = Opt.get_exn False (Egraph.get_value d n) in
+        let (!>) t = RealValue.value (RealValue.coerce_nodevalue (interp t)) in
+        let check r =
+          Some (Value.equal r (interp (Ground.node t)))
+        in
+        let (!<) v = check (RealValue.nodevalue (RealValue.index v)) in
+        let (!<<) b =
+          let r = if b then Boolean.values_true else Boolean.values_false in
+          check r
+        in
+        match Ground.sem t with
+        | { app = {builtin = Expr.Integer s}; tyargs = []; args = []; ty = _ } ->
+          !< (Q.of_string s)
+        | { app = {builtin = Expr.Decimal s}; tyargs = []; args = []; ty = _ } ->
+          !< (Q.of_string_decimal s)
+        | { app = {builtin = Expr.Rational s}; tyargs = []; args = []; ty = _ } ->
+          !< (Q.of_string_decimal s)
+        | { app = {builtin = Expr.Add}; tyargs = []; args = [a;b]; ty = _ } ->
+          !< (Q.add !>a !>b)
+        | { app = {builtin = Expr.Sub}; tyargs = []; args = [a;b]; ty = _ } ->
+          !< (Q.sub !>a !>b)
+        | { app = {builtin = Expr.Minus}; tyargs = []; args = [a]; ty = _ } ->
+          !< (Q.neg !>a)
+        | { app = {builtin = Expr.Mul}; tyargs = []; args = [a;b]; ty = _ } ->
+          !< (Q.mul !>a !>b)
+        | { app = {builtin = Expr.Lt}; tyargs = []; args = [arg1;arg2]; ty = _ } ->
+          !<< (Q.lt !>arg1 !>arg2)
+        | { app = {builtin = Expr.Leq}; tyargs = []; args = [arg1;arg2]; ty = _ } ->
+          !<< (Q.leq !>arg1 !>arg2)
+        | { app = {builtin = Expr.Gt}; tyargs = []; args = [arg1;arg2]; ty = _ } ->
+          !<< (Q.gt !>arg1 !>arg2)
+        | { app = {builtin = Expr.Geq}; tyargs = []; args = [arg1;arg2]; ty = _ } ->
+          !<< (Q.geq !>arg1 !>arg2)
+        | _ -> None
+      with False -> Some false
     )
 
 module RealValue = RealValue
@@ -63,6 +74,7 @@ let th_register env =
   Fourier.init env;
   Mul.init env;
   Dom_product.init env;
+  init_check env;
   ()
 
 let () = Egraph.add_default_theory th_register
diff --git a/src_colibri2/theories/LRA/dom_interval.ml b/src_colibri2/theories/LRA/dom_interval.ml
index 994f70fa1..cbb5f1848 100644
--- a/src_colibri2/theories/LRA/dom_interval.ml
+++ b/src_colibri2/theories/LRA/dom_interval.ml
@@ -160,7 +160,9 @@ end = struct
         (v' d n)
   let [@ocaml.always inline] get a = get_dom dom a
   let [@ocaml.always inline] get_value key n' = fun d _ ->
-    Egraph.get_value d key n'
+    let open Option in
+    let* v = Egraph.get_value d n' in
+    Value.value key v
   let [@ocaml.always inline] set_value (type b)
       (value:(module ValueKind.Registered with type s = b))
       n' (v':b option option monad) : unit monad =
diff --git a/src_colibri2/theories/LRA/realValue.ml b/src_colibri2/theories/LRA/realValue.ml
index 18b57f2bc..c6a2e8f33 100644
--- a/src_colibri2/theories/LRA/realValue.ml
+++ b/src_colibri2/theories/LRA/realValue.ml
@@ -61,7 +61,10 @@ module Monad : sig
 end = struct
   type ('a,'b) monad = Egraph.t -> Node.t -> 'a -> 'b
   let [@ocaml.always inline] get' key n' = fun d n v ->
-    if Node.equal n n' then Some v else Egraph.get_value d key n'
+    if Node.equal n n' then Some v else
+      let open Option in
+      let* v = Egraph.get_value d n' in
+      Value.value key v
   let [@ocaml.always inline] set' : type b.
       (module ValueKind.Registered with type s = b) ->
     Node.t -> ('a,b option) monad -> ('a, unit) monad =
diff --git a/src_colibri2/theories/bool/boolean.ml b/src_colibri2/theories/bool/boolean.ml
index 1ed567891..4492b29a5 100644
--- a/src_colibri2/theories/bool/boolean.ml
+++ b/src_colibri2/theories/bool/boolean.ml
@@ -50,7 +50,11 @@ let node_false = BoolValue.node value_false
 
 let index sem v = Node.index_sem sem v
 
-let is env node = Egraph.get_value env dom node
+let is env node =
+    let open Option in
+    let+ v = Egraph.get_value env node in
+    Opt.get_exn Impossible (Value.value dom v)
+
 let is_true  env node = Node.equal node node_true
                         || Equal.option Equal.bool (is env node) (Some true)
 let is_false env node = Node.equal node node_false
@@ -124,7 +128,7 @@ module Th = struct
   exception Found of Node.t * bool
   let find_not_known d l =
     IArray.iter (fun (node,b) ->
-      match Egraph.get_value d dom node with
+      match Egraph.get_value d node with
       | Some _ -> ()
       | None -> raise (Found (node,b))
     ) l
@@ -132,8 +136,8 @@ module Th = struct
   let _bcp d l absorbent =
     try
       let res = IArray.fold (fun acc node ->
-        match Egraph.get_value d dom node, acc with
-        | Some b, _ when Equal.bool b absorbent -> raise (TopKnown absorbent)
+        match is d node, acc with
+        | Some b, _ when Bool.equal b absorbent -> raise (TopKnown absorbent)
         | Some _, _ -> acc
         | None, Some _ -> raise Exit
         | None, None -> Some node)
@@ -160,9 +164,8 @@ module DaemonPropaNot = struct
   let throttle = 100
   let wakeup d =
     function
-    | Events.Fired.EventValue(_,dom',_,((_,node,ncl))) ->
-      assert (ValueKind.equal dom dom');
-      begin match Egraph.get_value d dom node with
+    | Events.Fired.EventValue(_,_,((_,node,ncl))) ->
+      begin match is d node with
         | None -> raise Impossible
         | Some b ->
           set_bool d ncl (not b)
@@ -215,17 +218,17 @@ module DaemonPropa = struct
     let own = ThE.node thterm in
     let set_dom_up_true d own _ _ =
       let b = (not v.topnot) in
-      match Egraph.get_value d dom own with
+      match is d own with
       | Some b' when Equal.bool b' b -> ()
       | _ -> set_bool d own b in
     let merge_bcp node sign =
       Debug.dprintf2 debug "[Bool] @[merge_bcp %a@]" Node.pp node;
-      match Egraph.get_value d dom own with
+      match is d own with
       | Some b' ->
         let b = mulbool sign (mulbool b' v.topnot) in
         set_bool d node b
       | None -> (** merge *)
-        match Egraph.get_value d dom node with
+        match is d node with
         | Some b' ->
           let b = mulbool sign (mulbool b' v.topnot) in
           set_bool d own b
@@ -241,7 +244,7 @@ module DaemonPropa = struct
         (merge_bcp node sign; raise Exit)
       else
         let node,sign = IArray.get v.lits pos in
-        match Egraph.get_value d dom node with
+        match is d node with
         | None -> node,pos
         | Some b when mulbool b sign (** true absorbent of or *) ->
           set_dom_up_true d own node b; raise Exit
@@ -271,7 +274,7 @@ module DaemonPropa = struct
   let wakeup_own d thterm =
     let v = ThE.sem thterm in
     let own = ThE.node thterm in
-    begin match Egraph.get_value d dom own with
+    begin match is d own with
     | None -> (* only during init *)
       Demon.Fast.attach d key
         [Demon.Create.EventValue(own, dom, All thterm)];
@@ -295,11 +298,9 @@ module DaemonPropa = struct
     wakeup_lit d thterm last watcher
 
   let wakeup d = function
-    | Events.Fired.EventValue(_,dom',_,Lit(thterm,watched,next)) ->
-      assert( ValueKind.equal dom dom' );
+    | Events.Fired.EventValue(_,_,Lit(thterm,watched,next)) ->
       ignore (wakeup_lit d thterm watched next)
-    | Events.Fired.EventValue(_ownr,dom',_,All thterm) ->
-      assert( ValueKind.equal dom dom' );
+    | Events.Fired.EventValue(_ownr,_,All thterm) ->
       (** use this own because the other is the representant *)
       ignore (wakeup_own d thterm)
     | _ -> raise UnwaitedEvent
@@ -401,7 +402,7 @@ module ChoBool = struct
     set_bool env node b
 
   let choose_decision node env =
-    match Egraph.get_value env dom node with
+    match is env node with
     | Some _ ->
       Debug.dprintf2 Egraph.print_decision "[Bool] No decision for %a" Node.pp node;
       Egraph.DecNo
@@ -442,6 +443,37 @@ let converter d (f:Ground.t) =
     reg _false
   | _ -> ()
 
+
+let init_check d =
+  Interp.Register.check d (fun d t ->
+      let exception False in
+      try
+        let interp n = Opt.get_exn False (Egraph.get_value d n) in
+        let (!>) t = BoolValue.value (BoolValue.coerce_nodevalue (interp t)) in
+        let check r =
+          Some (Value.equal r (interp (Ground.node t)))
+        in
+        let (!<) b =
+          let r = if b then values_true else values_false in
+          check r
+        in
+        match Ground.sem t with
+        | { app = {builtin = Expr.Or}; tyargs = []; args = args; ty = _ } ->
+          !< (List.fold_left (||) false (List.map (!>) args))
+        | { app = {builtin = Expr.And}; tyargs = []; args = args; ty = _ } ->
+          !< (List.fold_left (&&) true (List.map (!>) args))
+        | { app = {builtin = Expr.Imply}; tyargs = []; args = [arg1;arg2]; ty = _ } ->
+          !< ( not (!> arg1) || !> arg2 )
+        | { app = {builtin = Expr.Neg}; tyargs = []; args = [arg]; ty = _ } ->
+          !< (not (!> arg))
+        | { app = {builtin = Expr.True}; tyargs = []; args = []; ty = _ } ->
+          check values_true
+        | { app = {builtin = Expr.False}; tyargs = []; args = []; ty = _ } ->
+          check values_false
+        | _ -> None
+      with False -> Some false
+    )
+
 let th_register env =
   RDaemonPropaNot.init env;
   RDaemonPropa.init env;
@@ -451,30 +483,31 @@ let th_register env =
   Egraph.register env node_true;
   Egraph.register env node_false;
   Ground.register_converter env converter;
+  init_check env;
   ()
 
 let () = Egraph.add_default_theory th_register
 
 (** {2 Interpretations} *)
-let () =
-  let interp ~interp t =
-    let v =
-      IArray.fold (fun acc (n,b) ->
-          acc ||
-          let v = BoolValue.value (BoolValue.coerce_nodevalue (interp n)) in
-          if b then not v else v
-        ) false t.T.lits
-    in
-    let v = if t.T.topnot then not v else v in
-    BoolValue.nodevalue (if v then value_true else value_false)
-  in
-  Interp.Register.thterm sem interp
+(* let () =
+ *   let interp ~interp t =
+ *     let v =
+ *       IArray.fold (fun acc (n,b) ->
+ *           acc ||
+ *           let v = BoolValue.value (BoolValue.coerce_nodevalue (interp n)) in
+ *           if b then not v else v
+ *         ) false t.T.lits
+ *     in
+ *     let v = if t.T.topnot then not v else v in
+ *     BoolValue.nodevalue (if v then value_true else value_false)
+ *   in
+ *   Interp.Register.thterm sem interp *)
 
 let default_value = true
 
 (* let () =
  *   Interp.Register.model ty (fun d n ->
- *       let v = Egraph.get_value d dom n in
+ *       let v = is d n in
  *       let v = Colibri2_popop_lib.Opt.get_def default_value v in
  *       let v = if v then values_true else values_false in
  *       v) *)
@@ -482,24 +515,4 @@ let default_value = true
 
 
 
-let () =
-  Interp.Register.id (fun interp t ->
-      let (!>) t = BoolValue.value (BoolValue.coerce_nodevalue (interp t)) in
-      let (!<) b = Some (if b then values_true else values_false) in
-      match t with
-      | { descr = Expr.App({builtin = Expr.Or},[],args); _ } ->
-        !< (List.fold_left (||) false (List.map (!>) args))
-      | { descr = Expr.App({builtin = Expr.And},[],args); _ } ->
-        !< (List.fold_left (&&) true (List.map (!>) args))
-      | { descr = Expr.App({builtin = Expr.Imply},[],[arg1;arg2]); _ } ->
-        !< ( not (!> arg1) || !> arg2 )
-      | { descr = Expr.App({builtin = Expr.Neg},[],[arg]); _ } ->
-        !< (not (!> arg))
-      | { descr = Expr.App({builtin = Expr.True},[],[]); _ } ->
-        Some values_true
-      | { descr = Expr.App({builtin = Expr.False},[],[]); _ } ->
-        Some values_false
-      | _ -> None
-    )
-
 type t = T.t
diff --git a/src_colibri2/theories/bool/equality.ml b/src_colibri2/theories/bool/equality.ml
index 553bf87e5..3a26d4635 100644
--- a/src_colibri2/theories/bool/equality.ml
+++ b/src_colibri2/theories/bool/equality.ml
@@ -191,22 +191,13 @@ let find_not_disequal d s =
     (match dis1, dis2 with
      | Some dis1, Some dis2 when not (Dis.disjoint dis1 dis2) -> true
      | _ -> false) ||
-    (try
-       let fold2_inter (type a) (k:a ValueKind.t) v1 v2 () =
-         let (module V) = ValueKind.get k in
-            if not (V.equal v1 v2) then raise Exit
-        in
-        MValues.fold2_inter {fold2_inter} values1 values2 ();
-        false
-     with Exit -> true)
+    (match values1, values2 with
+     | Some v1, Some v2 -> not (Value.equal v1 v2)
+     | _ -> false)
   in
   let get_dis_and_values cl =
     Egraph.get_dom d dom cl,
-    ValueKind.fold {fold=(fun k acc ->
-        match Egraph.get_value d k cl with
-        | None -> acc
-        | Some v -> MValues.add k v acc)}
-      MValues.empty
+    Egraph.get_value d cl
   in
   assert (Th.inv s);
   let rec inner_loop cl1 s1 enum2 =
@@ -428,8 +419,7 @@ module DaemonPropaITE = struct
   let delay = Events.Delayed_by 1
   let throttle = 100
   let wakeup d = function
-    | Events.Fired.EventValue(cond,dom,_,clsem) ->
-      assert (ValueKind.equal dom Boolean.dom);
+    | Events.Fired.EventValue(cond,_,clsem) ->
       let v = EITE.sem clsem in
       assert (Egraph.is_equal d cond v.cond);
       begin match Boolean.is d v.cond with
@@ -480,9 +470,6 @@ module RDaemonInitITE = Demon.Fast.Register(DaemonInitITE)
 
 (** Give for a node the values that are different *)
 let iter_on_value_different
-    (type a)
-    (type b)
-    ((module Val): (module Colibri2_core.ValueKind.Registered with type s = a and type t = b))
     ~they_are_different
     (d:Egraph.t)
     (own:Node.t) =
@@ -490,10 +477,10 @@ let iter_on_value_different
   let iter elt =
     let iter n =
       if not (Egraph.is_equal d own n) then
-        match Egraph.get_value d Val.key n with
+        match Egraph.get_value d n with
         | None -> ()
         | Some v ->
-        they_are_different n v
+          they_are_different n v
     in
     Node.S.iter iter (ThE.sem (Dis.to_node elt))
   in
@@ -558,46 +545,59 @@ let bool_init_diff_to_value d =
     ~already_registered:[Boolean.value_true;Boolean.value_false]
 
 (** {2 Interpretations} *)
-let () =
-  let interp ~interp t =
-    try
-      let fold acc e = Value.S.add_new Exit (interp e) acc in
-      let _ = Node.S.fold_left fold Value.S.empty t in
-      Boolean.values_false
-    with Exit ->
-      Boolean.values_true
-  in
-  Interp.Register.thterm sem interp
-
-let () =
-  let interp ~interp (t:ITE.t) =
-    let c = Boolean.BoolValue.value (Boolean.BoolValue.coerce_nodevalue (interp t.cond)) in
-    if c then interp t.then_ else interp t.else_
-  in
-  Interp.Register.thterm ITE.key interp
-
-let () =
-  Interp.Register.id (fun interp t ->
-      let (!>) n = Boolean.BoolValue.value (Boolean.BoolValue.coerce_nodevalue (interp n)) in
-      let (!<) b = Some (if b then Boolean.values_true else Boolean.values_false) in
-      match t with
-      | { descr = Expr.App({builtin = Expr.Equal},[_],a::l); _ } ->
-        let a = interp a in
-        !< (List.for_all (fun t -> Value.equal a (interp t)) l)
-      | { descr = Expr.App({builtin = Expr.Equiv},[_],[a;b]); _ } ->
-        !< (Value.equal (interp a) (interp b))
-      | { descr = Expr.App({builtin = Expr.Distinct},[_],args); _ } ->
-         begin
-          try
-            let fold acc v = Value.S.add_new Exit (interp v) acc in
-            let _ = List.fold_left fold Value.S.empty args in
-            Some Boolean.values_false
-          with Exit ->
-            Some Boolean.values_true
-        end
-      | { descr = Expr.App({builtin = Expr.Ite},[_],[c;a;b]); _ } ->
-        Some (if (!> c) then interp a else interp b)
-      | _ -> None
+(* let () =
+ *   let interp ~interp t =
+ *     try
+ *       let fold acc e = Value.S.add_new Exit (interp e) acc in
+ *       let _ = Node.S.fold_left fold Value.S.empty t in
+ *       Boolean.values_false
+ *     with Exit ->
+ *       Boolean.values_true
+ *   in
+ *   Interp.Register.thterm sem interp
+ * 
+ * let () =
+ *   let interp ~interp (t:ITE.t) =
+ *     let c = Boolean.BoolValue.value (Boolean.BoolValue.coerce_nodevalue (interp t.cond)) in
+ *     if c then interp t.then_ else interp t.else_
+ *   in
+ *   Interp.Register.thterm ITE.key interp *)
+
+let init_check d =
+  Interp.Register.check d (fun d t ->
+      let exception False in
+      try
+        let interp n = Opt.get_exn False (Egraph.get_value d n) in
+        let (!>) n =
+          Boolean.BoolValue.value
+            (Boolean.BoolValue.coerce_nodevalue (interp n))
+        in
+        let check r =
+          Some (Value.equal r (interp (Ground.node t)))
+        in
+        let (!<) b =
+          let r = if b then Boolean.values_true else Boolean.values_false in
+          check r
+        in
+        match Ground.sem t with
+        | { app = {builtin = Expr.Equal}; tyargs = [_]; args = a::l; ty = _ } ->
+          let a = interp a in
+          !< (List.for_all (fun t -> Value.equal a (interp t)) l)
+        | { app = {builtin = Expr.Equiv}; tyargs = [_]; args = [a;b]; ty = _ } ->
+          !< (Value.equal (interp a) (interp b))
+        | { app = {builtin = Expr.Distinct}; tyargs = [_]; args = args; ty = _ } ->
+          begin
+            try
+              let fold acc v = Value.S.add_new Exit (interp v) acc in
+              let _ = List.fold_left fold Value.S.empty args in
+              check Boolean.values_false
+            with Exit ->
+              check Boolean.values_true
+          end
+        | { app = {builtin = Expr.Ite}; tyargs = [_]; args = [c;a;b]; ty = _ } ->
+          check (if (!> c) then interp a else interp b)
+        | _ -> None
+      with False -> Some false
     )
 
 
@@ -635,6 +635,7 @@ let th_register env =
     DaemonInitITE.key [Demon.Create.EventRegSem(ITE.key,())];
   Ground.register_converter env converter;
   bool_init_diff_to_value env;
+  init_check env;
   ()
 
 let () = Egraph.add_default_theory th_register
diff --git a/src_colibri2/theories/bool/equality.mli b/src_colibri2/theories/bool/equality.mli
index 1352f9a6d..9cabfdec5 100644
--- a/src_colibri2/theories/bool/equality.mli
+++ b/src_colibri2/theories/bool/equality.mli
@@ -27,8 +27,7 @@ val is_disequal : Egraph.t -> Node.t -> Node.t -> bool
 val ite : Node.t -> Node.t -> Node.t -> Node.t
 
 val iter_on_value_different:
-  (module ValueKind.Registered with type s = 'a and type t = 'b) ->
-  they_are_different:(Node.t -> 'a -> unit) ->
+  they_are_different:(Node.t -> Value.t -> unit) ->
   Egraph.t -> Node.t -> unit
 
 
-- 
GitLab