From a9605bef464f13c4f6d4f5f464a2d7413c20218b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Bobot?= <francois.bobot@cea.fr>
Date: Fri, 11 Jun 2021 11:08:32 +0200
Subject: [PATCH] Restructure the interface of core

---
 src_colibri2/bin/main.ml                      |    2 +-
 src_colibri2/core/.ocamlformat-ignore         |    1 -
 src_colibri2/core/colibri2_core.ml            |  294 +--
 src_colibri2/core/colibri2_core.mli           | 1615 +++++++++++++++++
 src_colibri2/core/datastructure.ml            |    1 -
 src_colibri2/core/datastructure.mli           |    1 -
 src_colibri2/core/dune                        |   11 +-
 src_colibri2/core/ground.ml                   |   68 +-
 src_colibri2/core/ground.mli                  |   23 +-
 src_colibri2/core/structures/dune             |   13 -
 src_colibri2/core/structures/expr.ml          |   13 +-
 src_colibri2/popop_lib/map_intf.ml            |    2 +-
 src_colibri2/solver/dune                      |    2 +-
 src_colibri2/solver/scheduler.ml              |   75 +-
 src_colibri2/tests/tests_lib.ml               |    8 +-
 src_colibri2/theories/ADT/adt.ml              |   24 +-
 src_colibri2/theories/ADT/dune                |    2 +-
 src_colibri2/theories/FP/dune                 |    1 -
 src_colibri2/theories/FP/float32.ml           |    2 +-
 src_colibri2/theories/FP/float64.ml           |    2 +-
 src_colibri2/theories/FP/fp.ml                |    2 +-
 src_colibri2/theories/LRA/LRA.ml              |    2 +-
 src_colibri2/theories/LRA/dom_interval.ml     |    6 +-
 src_colibri2/theories/LRA/dom_polynome.ml     |    6 +-
 src_colibri2/theories/LRA/dom_product.ml      |    4 +-
 src_colibri2/theories/LRA/dune                |    2 +-
 src_colibri2/theories/LRA/fourier.ml          |   14 +-
 src_colibri2/theories/LRA/stages/stage0/dune  |    2 +-
 src_colibri2/theories/LRA/stages/stage1/dune  |    2 +-
 src_colibri2/theories/bool/boolean.ml         |   18 +-
 src_colibri2/theories/bool/boolean.mli        |    2 +-
 src_colibri2/theories/bool/dune               |    2 +-
 src_colibri2/theories/bool/equality.ml        |   18 +-
 .../theories/quantifier/InvertedPath.ml       |    2 +-
 src_colibri2/theories/quantifier/dune         |    2 +-
 src_colibri2/theories/quantifier/info.ml      |    5 +-
 src_colibri2/theories/quantifier/pattern.ml   |    6 +-
 .../theories/quantifier/quantifier.ml         |   26 +-
 src_colibri2/theories/quantifier/trigger.ml   |   29 +-
 src_colibri2/theories/quantifier/trigger.mli  |    8 +-
 src_colibri2/theories/quantifier/uninterp.ml  |   12 +-
 41 files changed, 1987 insertions(+), 343 deletions(-)
 create mode 100644 src_colibri2/core/colibri2_core.mli

diff --git a/src_colibri2/bin/main.ml b/src_colibri2/bin/main.ml
index 6038d19ee..3d5e6f39f 100644
--- a/src_colibri2/bin/main.ml
+++ b/src_colibri2/bin/main.ml
@@ -35,7 +35,7 @@ let () =
     | None -> "n/a"
     | Some v -> Build_info.V1.Version.to_string v in
   let info = Cmdliner.Term.info ~man ~version "Colibri2" in
-  let theories = Colibri2_core.Egraph.default_theories () in
+  let theories = Colibri2_core.ForSchedulers.default_theories () in
   let st,step_limit,show_steps = match Cmdliner.Term.eval (Options.state theories, info) with
     | `Version | `Help -> exit 0
     | `Error `Parse | `Error `Term | `Error `Exn -> exit 2
diff --git a/src_colibri2/core/.ocamlformat-ignore b/src_colibri2/core/.ocamlformat-ignore
index 2a3c74d09..bdfe1b0b3 100644
--- a/src_colibri2/core/.ocamlformat-ignore
+++ b/src_colibri2/core/.ocamlformat-ignore
@@ -5,7 +5,6 @@ structures/term.ml
 structures/domKind.ml
 structures/dune
 structures/domKind.mli
-structures/expr.ml
 datastructure.mli
 env.mli
 ground.mli
diff --git a/src_colibri2/core/colibri2_core.ml b/src_colibri2/core/colibri2_core.ml
index 021442de6..a3bef017e 100644
--- a/src_colibri2/core/colibri2_core.ml
+++ b/src_colibri2/core/colibri2_core.ml
@@ -18,59 +18,10 @@
 (*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
 (*************************************************************************)
 
-(** Colibri2 core: define basic types and the solver *)
-
-(** {3 Egraph } *)
-
-(** The Egraph contains all the context of a state of the analysis. Moreover it
-    handles:
-     - the consolidation of the unique domain for each equivalence class
-     - registering on which events daemons are waiting
-*)
-
 module Egraph = Egraph
-
-(** {3 Ground terms} *)
-
-(** The main constraints are the ground terms. Each ground terms is associated
-   to a node in the Egraph. The terms are simplified from the input syntax by
-   substituting let bindings and separate the other bindings:
-
-    - {!Ground.Term.t} for the total application of a known symbol {!Builtin.t}
-    - {!Ground.ClosedQuantifier.t} for close quantified formula
-    - {!Ground.NotTotalyApplied.t} for partial applications and anonymous
-   lambdas
-
-   This separation allows to consider most of the time only {!Ground.Term.t} terms.
-
-*)
-
 module Ground = Ground
-
 module Builtin = Dolmen_std.Builtin
-(** All the symbols predefined in the
-   language are defined in the {!Builtin} modules. For example {!Builtin.And}
-   for the conjunction.
-
-*)
-
 module Expr = Expr
-(** The module {!Expr} corresponds to the typed expression
-   parsed and typed by Dolmen. It is generally not useful. *)
-
-(** {3 Different Object } *)
-
-(** The different kind of terms are reunited as {!Node.t} by being indexed into
-   theory terms {!ThTerm.t}. Predefined theory terms are:
-
-    - the theory term of {!Ground.Term.t} is {!Ground.t}; - for
-   {!Ground.ClosedQuantifier.t} is {!Ground.ThClosedQuantifier.t} - for
-   {!Ground.NotTotalyApplied.t} is {!Ground.ThNotTotalyApplied.t}
-
-    The theory terms can be transformed without cost directly as {!Node.t}. New
-   kind of theory terms are obtained by applying the functor {!ThTerm.Register}
-
- *)
 
 module Node = struct
   include Nodes.Node
@@ -80,8 +31,7 @@ end
 module ThTerm = struct
   module Kind : Keys.Key2 with type ('a, 'b) t = ('a, 'b) Nodes.ThTermKind.t =
     Nodes.ThTermKind
-  (** Unique keys associated to each kind
-   of ThTerm *)
+  (** Unique keys associated to each kind of ThTerm *)
 
   module type S = Nodes.RegisteredThTerm
 
@@ -98,6 +48,8 @@ end
    terms. The goal of the solver is to find one {!Value.t} for each expression
    of the input problem. They are registered using {!Value.Register}. *)
 
+(** One {!Value.t} can be associated to an equivalence class and a {!Value.t}
+    is associated to an uniq {!Node.t} *)
 module Value = struct
   module Kind : Keys.Key2 with type ('a, 'b) t = ('a, 'b) Nodes.ValueKind.t =
     Nodes.ValueKind
@@ -115,7 +67,7 @@ end
 
 (** Domains are additional informations associated to each equivalence class
    inside the {!Egraph.t}. They can be registered using {!Dom.register} or
-   {!Dom.register_lattice} when the domain is simple *)
+   when the domain is simple by {!Dom.Lattice} *)
 
 module Dom = struct
   module Kind : Keys.Key with type 'a t = 'a DomKind.t = DomKind
@@ -153,17 +105,24 @@ module Dom = struct
     val key : t Kind.t
 
     val inter : Egraph.t -> t -> t -> t option
-    (** [inter d d1 d2] compute the intersection of
-   [d1] and [d2] return [None] if it is empty *)
+    (** [inter d d1 d2] compute the intersection of [d1] and [d2] return [None]
+       if it is empty. In this last case a contradiction is reported *)
 
     val is_singleton : Egraph.t -> t -> Value.t option
     (** [is_singleton _ d] if [d] is
    restricted to a singleton return the corresponding value *)
   end
 
-  (** [lattice l] register a domain as a lattice. It returns a function for
-   setting the domain which will the value instead in case of singleton *)
-  module Lattice (L : Lattice) = struct
+  (** [Lattice(L)] register a domain as a lattice. It returns useful function
+     for setting and updating the domain *)
+  module Lattice (L : Lattice) : sig
+    val set_dom : Egraph.t -> Node.t -> L.t -> unit
+    (** [set_dom d n l] Set the domain of [n] with [l] and set its value if it is a singleton *)
+
+    val upd_dom : Egraph.t -> Node.t -> L.t -> unit
+    (** [upd_dom d n l] Same than {!set_dom} but set with the intersection of
+        [l] with the current value of the domain. *)
+  end = struct
     module S = struct
       type t = L.t
 
@@ -225,19 +184,18 @@ end
 (** The module {!Interp} handles:
 
     - Checking the model before answering SAT, the interpretation of the
-   application are provided using {!Interp.Register.check} - Enumerating the
-   possible values for each node {!Interp.Register.node} - Otherwise enumerating
-   the possible values of each type {!Interp.Register.ty}
+   application are provided using {!Interp.Register.check}
+    - Enumerating the possible values for each node {!Interp.Register.node}
+    - Otherwise enumerating the possible values of each type
+   {!Interp.Register.ty}
 
 *)
 
 module Interp = Interp
 
-(** {3 Custom Environment } *)
+(** {3 Custom Environment and data-structures } *)
 
 module Env = Env
-(** Environment *)
-
 module Datastructure = Datastructure
 
 (** {3 Events } *)
@@ -246,12 +204,115 @@ module Datastructure = Datastructure
    The modification of the Egraph (events) can be monitored through daemons.
  *)
 
-module Daemon = Demon.Simple
+module Daemon : sig
+  (** Attach a callback executed when different modifications of the Egraph happens *)
+
+  (** The callback are not interrupted by other callbacks. They are scheduled to
+     run as soon as possible during the propagation phase *)
+
+  val attach_dom :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    'a DomKind.t ->
+    (Egraph.t -> Node.t -> unit) ->
+    unit
+  (** [attach_dom d ?direct n dom callback] The callback is scheduled when the
+     domain [dom] of the equivalence class of [n] is modified. If direct is true
+     (default) the callback is scheduled immediately if the domain is already
+     set. *)
+
+  val attach_any_dom :
+    Egraph.t -> 'a DomKind.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_value :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    ('a, 'b) Nodes.ValueKind.t ->
+    (Egraph.t -> Node.t -> 'b -> unit) ->
+    unit
+
+  val attach_any_value :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    (Egraph.t -> Node.t -> Value.t -> unit) ->
+    unit
+
+  val attach_reg_any : Egraph.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_reg_node :
+    Egraph.t -> Node.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_reg_sem :
+    Egraph.t -> ('a, 'b) Nodes.ThTermKind.t -> (Egraph.t -> 'b -> unit) -> unit
+
+  val attach_reg_value :
+    Egraph.t -> ('a, 'b) Nodes.ValueKind.t -> (Egraph.t -> 'b -> unit) -> unit
+
+  val attach_repr : Egraph.t -> Node.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_any_repr : Egraph.t -> (Egraph.t -> Node.t -> unit) -> unit
+end =
+  Demon.Simple
+
+module DaemonFixingModel : sig
+  (** Attach a callback executed when different modifications of the Egraph happens *)
+
+  (** Same as {!Daemon} but they are scheduled to run as soon as possible during
+     the FixingModel phase *)
+
+  val attach_dom :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    'a DomKind.t ->
+    (Egraph.t -> Node.t -> unit) ->
+    unit
+  (** [attach_dom d ?direct n dom callback] The callback is *)
+
+  val attach_any_dom :
+    Egraph.t -> 'a DomKind.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_value :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    ('a, 'b) Nodes.ValueKind.t ->
+    (Egraph.t -> Node.t -> 'b -> unit) ->
+    unit
+
+  val attach_any_value :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    (Egraph.t -> Node.t -> Value.t -> unit) ->
+    unit
+
+  val attach_reg_any : Egraph.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_reg_node :
+    Egraph.t -> Node.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_reg_sem :
+    Egraph.t -> ('a, 'b) Nodes.ThTermKind.t -> (Egraph.t -> 'b -> unit) -> unit
+
+  val attach_reg_value :
+    Egraph.t -> ('a, 'b) Nodes.ValueKind.t -> (Egraph.t -> 'b -> unit) -> unit
+
+  val attach_repr : Egraph.t -> Node.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_any_repr : Egraph.t -> (Egraph.t -> Node.t -> unit) -> unit
+end =
+  Demon.Simple.FixingModel
+
 module DaemonWithFilter = Demon.WithFilter
 module DaemonWithKey = Demon.Key
 module Monad = Demon.Monad
 
 module Events = struct
+  include Egraph
   (** Low level API *)
 
   (** {3 Create daemons } *)
@@ -277,84 +338,14 @@ module Events = struct
   type daemon_key = Events.Wait.daemon_key =
     | DaemonKey : 'runable Dem.t * 'runable -> daemon_key
 
+  module type T = Egraph.Wait.Dem
   (** Basic daemons *)
-  module Basic = struct
-    module type T = Egraph.Wait.Dem
 
-    let register (s : (module T)) =
-      let module S = (val s) in
-      Egraph.Wait.register_dem (module S)
-  end
+  let register (s : (module T)) =
+    let module S = (val s) in
+    Egraph.Wait.register_dem (module S)
 
-  (** {3 Attach daemons } *)
-
-  (** wakeup when the dom of the node change *)
-  let attach_dom :
-      Egraph.t ->
-      ?direct:bool ->
-      Node.t ->
-      'a DomKind.t ->
-      (Egraph.Ro.t -> Node.t -> enqueue) ->
-      unit =
-    Egraph.attach_dom
-
-  (** wakeup when the dom of any node change *)
-  let attach_any_dom :
-      Egraph.t -> 'a DomKind.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit =
-    Egraph.attach_any_dom
-
-  (** wakeup when a value is attached to this equivalence class *)
-  let attach_value :
-      Egraph.t ->
-      ?direct:bool ->
-      Node.t ->
-      ('a, 'b) Value.Kind.t ->
-      (Egraph.Ro.t -> Node.t -> 'b -> enqueue) ->
-      unit =
-    Egraph.attach_value
-
-  (** wakeup when any kind of value is attached to this equivalence class *)
-  let attach_any_value :
-      Egraph.t ->
-      ?direct:bool ->
-      Node.t ->
-      (Egraph.Ro.t -> Node.t -> Value.t -> enqueue) ->
-      unit =
-    Egraph.attach_any_value
-
-  (** wakeup when any node is registered *)
-  let attach_reg_any : Egraph.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit =
-    Egraph.attach_reg_any
-
-  (** wakeup when this node is registered *)
-  let attach_reg_node :
-      Egraph.t -> Node.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit =
-    Egraph.attach_reg_node
-
-  (** wakeup when a new semantical class is registered *)
-  let attach_reg_sem :
-      Egraph.t ->
-      ('a, 'b) ThTerm.Kind.t ->
-      (Egraph.Ro.t -> 'b -> enqueue) ->
-      unit =
-    Egraph.attach_reg_sem
-
-  (** wakeup when a new value is registered *)
-  let attach_reg_value :
-      Egraph.t ->
-      ('a, 'b) Value.Kind.t ->
-      (Egraph.Ro.t -> 'b -> enqueue) ->
-      unit =
-    Egraph.attach_reg_value
-
-  (** wakeup when it is not anymore the representative class *)
-  let attach_repr :
-      Egraph.t -> Node.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit =
-    Egraph.attach_repr
-
-  (** wakeup when a node is not its representative class anymore *)
-  let attach_any_repr : Egraph.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit =
-    Egraph.attach_any_repr
+  let new_pending_daemon = Egraph.new_pending_daemon
 end
 
 (** {3 Helpers } *)
@@ -371,11 +362,6 @@ module Debug = struct
   let contradiction = Egraph.print_contradiction
 end
 
-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 *)
-
 (** {3 For schedulers} *)
 
 (** The following functions are necessary only to the scheduler *)
@@ -384,6 +370,24 @@ module ForSchedulers = struct
   module Backtrackable = Egraph.Backtrackable
 
   let default_theories = Egraph.default_theories
+
+  let ground_init = Ground.init
+
+  let interp_init = Interp.init
+
+  module Fix_model = Interp.Fix_model
+
+  let get_event_priority = Events.Wait.get_priority
+
+  let flush_internal = Egraph.flush_internal
 end
 
-module Demon = Demon
+module Choice = struct
+  type choice_state = Egraph.choice_state =
+    | DecNo
+    | DecTodo of (Egraph.t -> unit) list
+
+  and t = Egraph.choice = { choice : Egraph.t -> choice_state; prio : int }
+
+  let register = Egraph.register_decision
+end
diff --git a/src_colibri2/core/colibri2_core.mli b/src_colibri2/core/colibri2_core.mli
new file mode 100644
index 000000000..2b00d22c4
--- /dev/null
+++ b/src_colibri2/core/colibri2_core.mli
@@ -0,0 +1,1615 @@
+(*************************************************************************)
+(*  This file is part of Colibri2.                                       *)
+(*                                                                       *)
+(*  Copyright (C) 2014-2021                                              *)
+(*    CEA   (Commissariat à l'énergie atomique et aux énergies           *)
+(*           alternatives)                                               *)
+(*                                                                       *)
+(*  you can redistribute it and/or modify it under the terms of the GNU  *)
+(*  Lesser General Public License as published by the Free Software      *)
+(*  Foundation, version 2.1.                                             *)
+(*                                                                       *)
+(*  It is distributed in the hope that it will be useful,                *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of       *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *)
+(*  GNU Lesser General Public License for more details.                  *)
+(*                                                                       *)
+(*  See the GNU Lesser General Public License version 2.1                *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
+(*************************************************************************)
+
+(** Colibri2 core: define basic types and the solver *)
+
+(** {3 Egraph } *)
+
+(** The Egraph contains all the context of a state of the analysis. Moreover it
+    handles:
+     - the consolidation of the unique domain for each equivalence class
+     - execute callbacks when some events happens
+
+    The Egraph is piloted by a scheduler which distinguished four different phases:
+     + Propagation phase
+     + Decision phase
+     + LastEffort phase
+     + FixingModel phase
+
+    Each phase starts when there is nothing more to do in the previous phase,
+    but a later phase can add work to a previous phase. A decision adds new
+    possible propagations
+
+*)
+
+module rec Egraph : sig
+  module Ro : sig
+    type t
+
+    val is_equal : t -> Node.t -> Node.t -> bool
+
+    val find_def : t -> Node.t -> Node.t
+
+    val get_dom : t -> 'a Dom.Kind.t -> Node.t -> 'a option
+    (** 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} *)
+
+    val find : t -> Node.t -> Node.t
+
+    val is_repr : t -> Node.t -> bool
+
+    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
+
+    val context : t -> Context.creator
+
+    val register : t -> Node.t -> unit
+    (** Add a new node to register *)
+  end
+
+  type t = private Ro.t
+
+  val is_equal : t -> Node.t -> Node.t -> bool
+
+  val find_def : t -> Node.t -> Node.t
+
+  val get_dom : t -> 'a Dom.Kind.t -> Node.t -> 'a option
+  (** 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} *)
+
+  val find : t -> Node.t -> Node.t
+
+  val is_repr : t -> Node.t -> bool
+
+  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
+
+  val context : t -> Context.creator
+
+  val contradiction : t -> 'a
+
+  val register : t -> Node.t -> unit
+  (** Add a new node to register *)
+
+  (** {3 Immediate modifications} *)
+  val set_dom : t -> 'a Dom.Kind.t -> Node.t -> 'a -> unit
+  (** change the dom of the equivalence class *)
+
+  val unset_dom : t -> 'a Dom.Kind.t -> Node.t -> unit
+  (** remove the dom of the equivalence class *)
+
+  (** {3 Delayed modifications} *)
+  val set_thterm : t -> Node.t -> ThTerm.t -> unit
+  (** attach a theory term to an equivalence class *)
+
+  val set_value : t -> Node.t -> Value.t -> unit
+  (** attach value to an equivalence class *)
+
+  val merge : t -> Node.t -> Node.t -> unit
+
+  exception Contradiction
+end
+
+(** {3 Ground terms} *)
+(** The main representations of constraints are the ground terms. Each ground
+    terms is associated to a node in the Egraph. The terms are simplified from
+    the input syntax by substituting let bindings and separate the other bindings:
+
+    - {!Ground.Term.t} for the total application of a known symbol {!Builtin.t}
+    - {!Ground.ClosedQuantifier.t} for close quantified formula
+    - {!Ground.NotTotalyApplied.t} for partial applications and anonymous
+   lambdas
+
+   This separation allows to consider most of the time only {!Ground.Term.t} terms.
+
+*)
+
+and Ground : sig
+  module rec Subst : sig
+    type ty = Ty.t Expr.Ty.Var.M.t [@@deriving show, hash, ord, eq]
+
+    type t = { term : Node.t Expr.Term.Var.M.t; ty : ty }
+
+    include Colibri2_popop_lib.Popop_stdlib.Datatype with type t := t
+
+    val empty : t
+
+    val distinct_union : t -> t -> t
+  end
+
+  and Ty : sig
+    type t = { app : Expr.Ty.Const.t; args : t list }
+
+    include Colibri2_popop_lib.Popop_stdlib.Datatype with type t := t
+
+    val convert : Subst.ty -> Expr.Ty.t -> t
+
+    val prop : t
+    (** The type of propositions *)
+
+    val bool : t
+    (** Alias for {!prop}. *)
+
+    val unit : t
+    (** The unit type. *)
+
+    val base : t
+    (** An arbitrary type. *)
+
+    val int : t
+    (** The type of integers *)
+
+    val rat : t
+    (** The type of rationals *)
+
+    val real : t
+    (** The type of reals. *)
+
+    val string : t
+    (** The type of strings *)
+
+    val string_reg_lang : t
+    (** The type of regular language over strings. *)
+
+    val definition : Expr.Ty.Const.t -> Expr.Ty.def
+  end
+
+  type s = {
+    app : Expr.Term.Const.t;
+    tyargs : Ty.t list;
+    args : Node.t Colibri2_popop_lib.IArray.t;
+    ty : Ty.t;
+  }
+
+  module Term : Colibri2_popop_lib.Popop_stdlib.Datatype with type t = s
+
+  include Colibri2_popop_lib.Popop_stdlib.Datatype
+
+  val node : t -> Node.t
+  (** Return a class from a thterm *)
+
+  val sem : t -> s
+  (** Return the sem from a thterm *)
+
+  val index : s -> t
+  (** Return a theory term from the user type *)
+
+  val thterm : t -> ThTerm.t
+
+  val of_thterm : ThTerm.t -> t option
+  (** Return the user type if the ThTerm belongs to this module *)
+
+  val coerce_thterm : ThTerm.t -> t
+  (** Return the user type. Raise if the ThTerm does not belong to this
+        module *)
+
+  val convert : ?subst:Subst.t -> Expr.Term.t -> Node.t
+
+  val apply :
+    Expr.Term.Const.t -> Ty.t list -> Node.t Colibri2_popop_lib.IArray.t -> s
+
+  val init : Egraph.t -> unit
+
+  val register_converter : Egraph.t -> (Egraph.t -> t -> unit) -> unit
+  (** register callback called for each new ground term registered *)
+
+  val tys : Egraph.t -> Node.t -> Ty.S.t
+
+  module Defs : sig
+    val add :
+      Egraph.t ->
+      Dolmen_std.Expr.term_cst ->
+      Dolmen_std.Expr.ty_var list ->
+      Dolmen_std.Expr.term_var list ->
+      Expr.term ->
+      unit
+  end
+
+  module ClosedQuantifier : sig
+    type binder = Forall | Exists
+
+    type s = {
+      binder : binder;
+      subst : Subst.t;
+      ty_vars : Expr.Ty.Var.t list;
+      term_vars : Expr.Term.Var.t list;
+      body : Expr.Term.t;
+    }
+
+    include Colibri2_popop_lib.Popop_stdlib.Datatype
+
+    val key : (s, t) ThTerm.Kind.t
+
+    val node : t -> Node.t
+    (** Return a class from a thterm *)
+
+    val sem : t -> s
+    (** Return the sem from a thterm *)
+
+    val thterm : t -> ThTerm.t
+
+    val of_thterm : ThTerm.t -> t option
+    (** Return the user type if the ThTerm belongs to this module *)
+
+    val coerce_thterm : ThTerm.t -> t
+    (** Return the user type. Raise if the ThTerm does not belong to this
+        module *)
+  end
+
+  module NotTotalyApplied : sig
+    type s =
+      | Lambda of {
+          subst : Subst.t;
+          ty_vars : Expr.Ty.Var.t list;
+          term_vars : Expr.Term.Var.t list;
+          body : Expr.Term.t;
+          ty : Ty.t;
+        }
+      | Cst of Expr.Term.Const.t
+      | App of {
+          app : Node.t;
+          tyargs : Ty.t list;
+          args : Node.t Colibri2_popop_lib.IArray.t;
+          ty : Ty.t;
+        }
+
+    type t
+
+    val key : (s, t) ThTerm.Kind.t
+
+    val node : t -> Node.t
+    (** Return a class from a thterm *)
+
+    val sem : t -> s
+    (** Return the sem from a thterm *)
+
+    val thterm : t -> ThTerm.t
+
+    val of_thterm : ThTerm.t -> t option
+    (** Return the user type if the ThTerm belongs to this module *)
+
+    val coerce_thterm : ThTerm.t -> t
+    (** Return the user type. Raise if the ThTerm does not belong to this
+        module *)
+  end
+end
+
+(** {3 Different Object } *)
+(** The different kind of terms are reunited as {!Node.t} by being indexed into
+   theory terms {!ThTerm.t}. Predefined theory terms are:
+
+    - the theory term of {!Ground.s} is {!Ground.t};
+    - for {!Ground.ClosedQuantifier.s} is {!Ground.ClosedQuantifier.t}
+    - for {!Ground.NotTotalyApplied.s} is {!Ground.NotTotalyApplied.t}
+
+    The theory terms can be transformed without cost directly as {!Node.t}. New
+   kind of theory terms are obtained by applying the functor {!ThTerm.Register}
+
+ *)
+
+(** The nodes form equivalence class inside the Egraph *)
+and Node : sig
+  include Colibri2_popop_lib.Popop_stdlib.Datatype
+
+  val rename : t -> string -> unit
+  (** Change the pretty printed string for this node, to use with care
+      preferably at the start *)
+
+  val index_sem : ('a, _) ThTerm.Kind.t -> 'a -> t
+  (** Return the corresponding node from a theory term *)
+
+  val index_value : ('a, _) Value.Kind.t -> 'a -> t
+  (** Return the corresponding node from a value *)
+
+  module HC : 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 find_opt : 'a t -> Egraph.t -> key -> 'a option
+
+    val mem : 'a t -> Egraph.t -> key -> bool
+
+    val change : ('a option -> 'a option) -> 'a t -> Egraph.t -> key -> unit
+
+    module Ro : sig
+      val find : 'a t -> Egraph.Ro.t -> key -> 'a
+
+      val find_opt : 'a t -> Egraph.Ro.t -> key -> 'a option
+
+      val mem : 'a t -> Egraph.Ro.t -> key -> bool
+    end
+  end
+  with type key := t
+end
+
+(** ThTerm allows to associates an OCaml type to a uniq {!Node.t} using an
+   indexing table *)
+and ThTerm : sig
+  module Kind : Keys.Key2
+  (** Unique keys associated to each kind of ThTerm *)
+
+  module type S = sig
+    type s
+    (** the user given type *)
+
+    module SD : Colibri2_popop_lib.Popop_stdlib.NamedDatatype with type t = s
+
+    include Colibri2_popop_lib.Popop_stdlib.Datatype
+    (** thterm *)
+
+    val key : (s, t) Kind.t
+
+    val index : s -> t
+    (** Return a theory term from the user type *)
+
+    val node : t -> Node.t
+    (** Return a class from a thterm *)
+
+    val sem : t -> s
+    (** Return the sem from a thterm *)
+
+    val thterm : t -> ThTerm.t
+
+    val of_thterm : ThTerm.t -> t option
+    (** Return the user type if the ThTerm belongs to this module *)
+
+    val coerce_thterm : ThTerm.t -> t
+    (** Return the user type. Raise if the ThTerm does not belong to this
+        module *)
+  end
+
+  module Register (T : Colibri2_popop_lib.Popop_stdlib.NamedDatatype) :
+    S with type s = T.t
+
+  include Colibri2_popop_lib.Popop_stdlib.Datatype
+  (** {3 Generic value which units all the theory terms } *)
+
+  val index : ('a, _) Kind.t -> 'a -> t
+  (** Return the corresponding node from a theory term *)
+
+  val node : t -> Node.t
+  (** Returns the node associated to this theory term *)
+end
+
+(** Another kind of nodes are values. They are disjoint but similar to theory
+   terms. The goal of the solver is to find one {!Value.t} for each expression
+   of the input problem. They are registered using {!Value.Register}. *)
+
+(** One {!Value.t} can be associated to an equivalence class and a {!Value.t}
+    is associated to an uniq {!Node.t} *)
+and Value : sig
+  module Kind : Keys.Key2
+
+  (** {3 Generic value which unit all the values } *)
+
+  include Colibri2_popop_lib.Popop_stdlib.Datatype
+
+  val index : ('a, _) Value.Kind.t -> 'a -> t
+  (** Return the corresponding node from a value *)
+
+  val node : t -> Node.t
+
+  val value : ('a, _) Kind.t -> t -> 'a option
+
+  type kind = Value : (_, 'b) Kind.t * 'b -> kind
+
+  val kind : t -> kind
+  (** unpack a value *)
+
+  module type S = sig
+    type s
+
+    module SD : Colibri2_popop_lib.Popop_stdlib.NamedDatatype with type t = s
+
+    include Colibri2_popop_lib.Popop_stdlib.Datatype
+    (** nodevalue *)
+
+    val key : (s, t) Kind.t
+
+    val index : ?basename:string -> s -> t
+    (** Return a nodevalue from a valueantical term.
+      Basename is used only for debug
+  *)
+
+    val node : t -> Node.t
+    (** Return a class from a nodevalue *)
+
+    val value : t -> s
+    (** Return the value from a nodevalue *)
+
+    val nodevalue : t -> Value.t
+
+    val of_nodevalue : Value.t -> t option
+
+    val coerce_nodevalue : Value.t -> t
+  end
+
+  module Register (T : Colibri2_popop_lib.Popop_stdlib.NamedDatatype) :
+    S with type s = T.t
+end
+
+(** Domains are additional informations associated to each equivalence class
+   inside the {!Egraph.t}. They can be registered using {!Dom.register} or
+   when the domain is simple by {!Dom.Lattice} *)
+
+and Dom : sig
+  module Kind : Keys.Key
+
+  module type S = sig
+    type t
+
+    val merged : t option -> t option -> bool
+    (** [merged d1 d2] indicates if
+   the [d1] and [d2] are the same and doesn't need to be merged *)
+
+    val merge :
+      Egraph.t -> t option * Node.t -> t option * Node.t -> bool -> unit
+    (** [merge d (dom1,cl1) (dom2,cl2) inv] called when [cl1] and [cl2] are
+   going to be merged in the same equivalence class. - 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 Kind.t
+  end
+
+  val register : (module S) -> unit
+
+  module type Lattice = sig
+    type t
+
+    val equal : t -> t -> bool
+
+    val pp : Format.formatter -> t -> unit
+
+    val key : t Kind.t
+
+    val inter : Egraph.t -> t -> t -> t option
+    (** [inter d d1 d2] compute the intersection of [d1] and [d2] return [None]
+       if it is empty. In this last case a contradiction is reported *)
+
+    val is_singleton : Egraph.t -> t -> Value.t option
+    (** [is_singleton _ d] if [d] is
+        restricted to a singleton return the corresponding value *)
+  end
+
+  (** [Lattice(L)] register a domain as a lattice. It returns useful function
+     for setting and updating the domain *)
+  module Lattice (L : Lattice) : sig
+    val set_dom : Egraph.t -> Node.t -> L.t -> unit
+    (** [set_dom d n l] Set the domain of [n] with [l] and set its value if it is a singleton *)
+
+    val upd_dom : Egraph.t -> Node.t -> L.t -> unit
+    (** [upd_dom d n l] Same than {!set_dom} but set with the intersection of
+        [l] with the current value of the domain. *)
+  end
+end
+
+module Expr = Expr
+(** The module {!Expr} corresponds to the typed expression
+   parsed and typed by Dolmen. It is generally not useful. *)
+
+module Builtin = Dolmen_std.Builtin
+
+(** {3 Fix the models} *)
+
+(** The module {!Interp} handles:
+
+    - Checking the model before answering SAT, the interpretation of the
+   application are provided using {!Interp.Register.check}
+    - Enumerating the possible values for each node {!Interp.Register.node}
+    - Otherwise enumerating the possible values of each type
+   {!Interp.Register.ty}
+
+*)
+
+module Interp : sig
+  module SeqLim : sig
+    type 'a t
+    (** Sequence, finite during module fixing *)
+
+    val of_seq : Egraph.t -> 'a Base.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 ( 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
+
+    val map : 'a t -> f:('a -> 'b) -> 'b t
+
+    val unfold_with :
+      'a t -> init:'b -> f:('b -> 'a -> ('c, 'b) Base.Sequence.Step.t) -> 'c t
+  end
+
+  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 -> Node.t -> Value.t SeqLim.t) ->
+      Egraph.t ->
+      Node.t ->
+      Value.t SeqLim.t option) ->
+      unit
+    (** Register the computation of possible values for a node using the
+      information on the domains. It could ask the computation of other nodes *)
+
+    val ty :
+      Egraph.t -> (Egraph.t -> Ground.Ty.t -> 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 ty : Egraph.t -> Ground.Ty.t -> Value.t SeqLim.t
+  (** Iterate on all the possible value of the given type, usually all the values
+    will be reached eventually *)
+
+  module WatchArgs : sig
+    val create : Egraph.t -> (Egraph.t -> Ground.t -> unit) -> Ground.t -> unit
+    (** call the given function when all the arguments of the ground term have a value *)
+  end
+end
+
+(** {3 Custom Environment and data-structures } *)
+
+module Env : sig
+  (** Theory specific environment *)
+
+  module Saved : sig
+    (** Environment should currently be persistent data-structure in order
+      to be backtracked correctly *)
+
+    include Keys.Key
+
+    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 check_is_registered : 'a t -> unit
+    (** Check if all the keys created have been registered *)
+  end
+
+  module Unsaved : sig
+    (** These environment are not saved automatically *)
+
+    include Keys.Key
+
+    val register :
+      init:(Context.creator -> '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 : Context.creator -> 'a t -> 'a
+    (** Create the initial value *)
+  end
+end
+
+module Datastructure : sig
+  (** {2 An hashtable context aware } *)
+
+  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 find_opt : 'a t -> Egraph.t -> key -> 'a option
+
+    val mem : 'a t -> Egraph.t -> key -> bool
+
+    val change : ('a option -> 'a option) -> 'a t -> Egraph.t -> key -> unit
+
+    module Ro : sig
+      val find : 'a t -> Egraph.Ro.t -> key -> 'a
+
+      val find_opt : 'a t -> Egraph.Ro.t -> key -> 'a option
+
+      val mem : 'a t -> Egraph.Ro.t -> key -> bool
+    end
+  end
+
+  module Hashtbl (S : Colibri2_popop_lib.Popop_stdlib.Datatype) :
+    Sig with type key := S.t
+
+  (** {2 An hashtable context aware, where data are automatically initialized } *)
+
+  module type Sig2 = sig
+    type 'a t
+
+    type key
+
+    val create : 'a Format.printer -> string -> (Context.creator -> 'a) -> 'a t
+
+    val set : 'a t -> Egraph.t -> key -> 'a -> unit
+
+    val find : 'a t -> Egraph.t -> key -> 'a
+
+    val change : ('a -> 'a) -> 'a t -> Egraph.t -> key -> unit
+
+    module Ro : sig
+      val set : 'a t -> Egraph.Ro.t -> key -> 'a -> unit
+
+      val find : 'a t -> Egraph.Ro.t -> key -> 'a
+
+      val change : ('a -> 'a) -> 'a t -> Egraph.Ro.t -> key -> unit
+    end
+  end
+
+  module Hashtbl2 (S : Colibri2_popop_lib.Popop_stdlib.Datatype) :
+    Sig2 with type key := S.t
+
+  (** {2 A table where data are initialized on the fly, and can't be modified. It
+   is used with other context aware mutable data-structure as data } *)
+
+  module type Memo = sig
+    type 'a t
+
+    type key
+
+    val create :
+      'a Format.printer -> string -> (Context.creator -> key -> 'a) -> 'a t
+
+    val find : 'a t -> Egraph.t -> key -> 'a
+
+    val iter : (key -> 'a -> unit) -> 'a t -> Egraph.t -> unit
+
+    val fold : (key -> 'a -> 'acc -> 'acc) -> 'a t -> Egraph.t -> 'acc -> 'acc
+  end
+
+  module Memo (S : Colibri2_popop_lib.Popop_stdlib.Datatype) :
+    Memo with type key := S.t
+
+  module Push : sig
+    type 'a t
+
+    val create : 'a Format.printer -> string -> 'a t
+
+    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
+
+  module Ref : sig
+    type 'a t
+
+    val create : 'a Fmt.t -> string -> 'a -> 'a t
+
+    val get : 'a t -> Egraph.t -> 'a
+
+    val set : 'a t -> Egraph.t -> 'a -> unit
+
+    module Ro : sig
+      val get : 'a t -> Egraph.Ro.t -> 'a
+
+      val set : 'a t -> Egraph.Ro.t -> 'a -> unit
+    end
+  end
+end
+
+(** {3 Events } *)
+
+(**
+   The modification of the Egraph (events) can be monitored through daemons.
+ *)
+
+module Daemon : sig
+  (** Attach a callback executed when different modifications of the Egraph happens *)
+
+  (** The callback are not interrupted by other callbacks. They are scheduled to
+     run as soon as possible during the propagation phase *)
+
+  val attach_dom :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    'a Dom.Kind.t ->
+    (Egraph.t -> Node.t -> unit) ->
+    unit
+  (** [attach_dom d ?direct n dom callback] The callback is scheduled when the
+     domain [dom] of the equivalence class of [n] is modified. If direct is true
+     (default) the callback is scheduled immediately if the domain is already
+     set. *)
+
+  val attach_any_dom :
+    Egraph.t -> 'a Dom.Kind.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_value :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    ('a, 'b) Value.Kind.t ->
+    (Egraph.t -> Node.t -> 'b -> unit) ->
+    unit
+
+  val attach_any_value :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    (Egraph.t -> Node.t -> Value.t -> unit) ->
+    unit
+
+  val attach_reg_any : Egraph.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_reg_node :
+    Egraph.t -> Node.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_reg_sem :
+    Egraph.t -> ('a, 'b) ThTerm.Kind.t -> (Egraph.t -> 'b -> unit) -> unit
+
+  val attach_reg_value :
+    Egraph.t -> ('a, 'b) Value.Kind.t -> (Egraph.t -> 'b -> unit) -> unit
+
+  val attach_repr : Egraph.t -> Node.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_any_repr : Egraph.t -> (Egraph.t -> Node.t -> unit) -> unit
+end
+
+module DaemonFixingModel : sig
+  (** Attach a callback executed when different modifications of the Egraph happens *)
+
+  (** Same as {!Daemon} but they are scheduled to run as soon as possible during
+     the FixingModel phase *)
+
+  val attach_dom :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    'a Dom.Kind.t ->
+    (Egraph.t -> Node.t -> unit) ->
+    unit
+  (** [attach_dom d ?direct n dom callback] The callback is *)
+
+  val attach_any_dom :
+    Egraph.t -> 'a Dom.Kind.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_value :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    ('a, 'b) Value.Kind.t ->
+    (Egraph.t -> Node.t -> 'b -> unit) ->
+    unit
+
+  val attach_any_value :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    (Egraph.t -> Node.t -> Value.t -> unit) ->
+    unit
+
+  val attach_reg_any : Egraph.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_reg_node :
+    Egraph.t -> Node.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_reg_sem :
+    Egraph.t -> ('a, 'b) ThTerm.Kind.t -> (Egraph.t -> 'b -> unit) -> unit
+
+  val attach_reg_value :
+    Egraph.t -> ('a, 'b) Value.Kind.t -> (Egraph.t -> 'b -> unit) -> unit
+
+  val attach_repr : Egraph.t -> Node.t -> (Egraph.t -> Node.t -> unit) -> unit
+
+  val attach_any_repr : Egraph.t -> (Egraph.t -> Node.t -> unit) -> unit
+end
+
+module DaemonWithFilter : sig
+  (** Attach a callback executed when different modifications of the Egraph happens *)
+
+  (** Same as {!Daemon} but they are scheduled to run as soon as possible during
+     the FixingModel phase *)
+
+  val attach_dom :
+    Egraph.Ro.t ->
+    ?direct:bool ->
+    Node.t ->
+    'a Dom.Kind.t ->
+    (Egraph.Ro.t -> Node.t -> (Egraph.t -> unit) option) ->
+    unit
+  (** [attach_dom d ?direct n dom callback] The callback is *)
+
+  val attach_any_dom :
+    Egraph.Ro.t ->
+    'a Dom.Kind.t ->
+    (Egraph.Ro.t -> Node.t -> (Egraph.t -> unit) option) ->
+    unit
+
+  val attach_value :
+    Egraph.Ro.t ->
+    ?direct:bool ->
+    Node.t ->
+    ('a, 'b) Value.Kind.t ->
+    (Egraph.Ro.t -> Node.t -> 'b -> (Egraph.t -> unit) option) ->
+    unit
+
+  val attach_any_value :
+    Egraph.Ro.t ->
+    ?direct:bool ->
+    Node.t ->
+    (Egraph.Ro.t -> Node.t -> Value.t -> (Egraph.t -> unit) option) ->
+    unit
+
+  val attach_reg_any :
+    Egraph.Ro.t -> (Egraph.Ro.t -> Node.t -> (Egraph.t -> unit) option) -> unit
+
+  val attach_reg_node :
+    Egraph.Ro.t ->
+    Node.t ->
+    (Egraph.Ro.t -> Node.t -> (Egraph.t -> unit) option) ->
+    unit
+
+  val attach_reg_sem :
+    Egraph.Ro.t ->
+    ('a, 'b) ThTerm.Kind.t ->
+    (Egraph.Ro.t -> 'b -> (Egraph.t -> unit) option) ->
+    unit
+
+  val attach_reg_value :
+    Egraph.Ro.t ->
+    ('a, 'b) Value.Kind.t ->
+    (Egraph.Ro.t -> 'b -> (Egraph.t -> unit) option) ->
+    unit
+
+  val attach_repr :
+    Egraph.Ro.t ->
+    Node.t ->
+    (Egraph.Ro.t -> Node.t -> (Egraph.t -> unit) option) ->
+    unit
+
+  val attach_any_repr :
+    Egraph.Ro.t -> (Egraph.Ro.t -> Node.t -> (Egraph.t -> unit) option) -> unit
+end
+
+module Monad : sig
+  type 'a monad
+
+  type sequence
+
+  val getd : 'a Dom.Kind.t -> Node.t -> 'a option monad
+
+  val setd : 'a Dom.Kind.t -> Node.t -> 'a option monad -> sequence
+
+  val updd :
+    (Egraph.t -> Node.t -> 'a -> unit) -> Node.t -> 'a option monad -> sequence
+
+  val getv : ('a, _) Value.Kind.t -> Node.t -> 'a option monad
+
+  val setv : ('a, _) Value.Kind.t -> Node.t -> 'a option monad -> sequence
+
+  val ( let+ ) : 'a option monad -> ('a -> 'c) -> 'c option monad
+
+  val ( let* ) : 'a option monad -> ('a -> 'c option) -> 'c option monad
+
+  val ( and+ ) : 'a option monad -> 'b option monad -> ('a * 'b) option monad
+
+  val ( && ) : sequence -> sequence -> sequence
+
+  val attach : Egraph.t -> sequence -> unit
+end
+
+module rec DaemonWithKey : sig
+  type state = Wait | Stop
+
+  module type S = sig
+    module Key : Colibri2_popop_lib.Popop_stdlib.Datatype
+
+    val delay : Events.delay
+
+    val run : Egraph.t -> Key.t -> state
+
+    val name : string
+  end
+
+  module Register (S : S) : sig
+    val attach_dom :
+      Egraph.t -> ?direct:bool -> Node.t -> 'a Dom.Kind.t -> S.Key.t -> unit
+
+    val attach_any_dom : Egraph.t -> 'a Dom.Kind.t -> S.Key.t -> unit
+
+    val attach_value :
+      Egraph.t ->
+      ?direct:bool ->
+      Node.t ->
+      ('a, 'b) Value.Kind.t ->
+      S.Key.t ->
+      unit
+
+    val attach_any_value : Egraph.t -> ?direct:bool -> Node.t -> S.Key.t -> unit
+
+    val attach_reg_any : Egraph.t -> S.Key.t -> unit
+
+    val attach_reg_node : Egraph.t -> Node.t -> S.Key.t -> unit
+
+    val attach_reg_sem : Egraph.t -> ('a, 'b) ThTerm.Kind.t -> S.Key.t -> unit
+
+    val attach_reg_value : Egraph.t -> ('a, 'b) Value.Kind.t -> S.Key.t -> unit
+
+    val attach_repr : Egraph.t -> Node.t -> S.Key.t -> unit
+
+    val attach_any_repr : Egraph.t -> S.Key.t -> unit
+  end
+end
+
+and Events : sig
+  (** Low level API *)
+
+  (** {3 Create daemons } *)
+
+  module Dem : Keys.Key
+
+  (** {3 Register daemons } *)
+
+  type delay =
+    | Immediate
+    | Delayed_by of int  (** Must be strictly positive *)
+    | LastEffort of int
+        (** Should try to ensure that a model exists, must be strictly positive *)
+    | FixingModel
+
+  type enqueue =
+    | EnqRun : 'r Dem.t * 'r -> enqueue  (** Schedule a daemon run *)
+    | EnqLast : 'r Dem.t * 'r -> enqueue
+        (** Same as EnqRun but remove the waiting event *)
+    | EnqAlready : enqueue  (** Don't run but keep the waiting event *)
+    | EnqStopped : enqueue  (** Stop and don't run *)
+
+  type daemon_key = DaemonKey : 'runable Dem.t * 'runable -> daemon_key
+
+  (** {3 Basic daemons} *)
+  module type T = sig
+    type runable
+
+    val print_runable : runable Format.printer
+
+    val run : Egraph.t -> runable -> unit
+    (** The function run after the delay *)
+
+    val key : runable Dem.t
+
+    val delay : delay
+  end
+
+  val register : (module T) -> unit
+
+  (** {3 Attach daemons } *)
+
+  val attach_dom :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    'a Dom.Kind.t ->
+    (Egraph.Ro.t -> Node.t -> enqueue) ->
+    unit
+  (** wakeup when the dom of the node change *)
+
+  val attach_any_dom :
+    Egraph.t -> 'a Dom.Kind.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit
+  (** wakeup when the dom of any node change *)
+
+  val attach_value :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    ('a, 'b) Value.Kind.t ->
+    (Egraph.Ro.t -> Node.t -> 'b -> enqueue) ->
+    unit
+  (** wakeup when a value is attached to this equivalence class *)
+
+  val attach_any_value :
+    Egraph.t ->
+    ?direct:bool ->
+    Node.t ->
+    (Egraph.Ro.t -> Node.t -> Value.t -> enqueue) ->
+    unit
+  (** wakeup when any kind of value is attached to this equivalence class *)
+
+  val attach_reg_any : Egraph.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit
+  (** wakeup when any node is registered *)
+
+  val attach_reg_node :
+    Egraph.t -> Node.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit
+  (** wakeup when this node is registered *)
+
+  val attach_reg_sem :
+    Egraph.t -> ('a, 'b) ThTerm.Kind.t -> (Egraph.Ro.t -> 'b -> enqueue) -> unit
+  (** wakeup when a new semantical class is registered *)
+
+  val attach_reg_value :
+    Egraph.t -> ('a, 'b) Value.Kind.t -> (Egraph.Ro.t -> 'b -> enqueue) -> unit
+  (** wakeup when a new value is registered *)
+
+  val attach_repr :
+    Egraph.t -> Node.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit
+  (** wakeup when it is not anymore the representative class *)
+
+  val attach_any_repr : Egraph.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit
+  (** wakeup when a node is not its representative class anymore *)
+
+  module Ro : sig
+    val attach_dom :
+      Egraph.Ro.t ->
+      ?direct:bool ->
+      Node.t ->
+      'a Dom.Kind.t ->
+      (Egraph.Ro.t -> Node.t -> enqueue) ->
+      unit
+    (** wakeup when the dom of the node change *)
+
+    val attach_any_dom :
+      Egraph.Ro.t -> 'a Dom.Kind.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit
+    (** wakeup when the dom of any node change *)
+
+    val attach_value :
+      Egraph.Ro.t ->
+      ?direct:bool ->
+      Node.t ->
+      ('a, 'b) Value.Kind.t ->
+      (Egraph.Ro.t -> Node.t -> 'b -> enqueue) ->
+      unit
+    (** wakeup when a value is attached to this equivalence class *)
+
+    val attach_any_value :
+      Egraph.Ro.t ->
+      ?direct:bool ->
+      Node.t ->
+      (Egraph.Ro.t -> Node.t -> Value.t -> enqueue) ->
+      unit
+    (** wakeup when any kind of value is attached to this equivalence class *)
+
+    val attach_reg_any :
+      Egraph.Ro.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit
+    (** wakeup when any node is registered *)
+
+    val attach_reg_node :
+      Egraph.Ro.t -> Node.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit
+    (** wakeup when this node is registered *)
+
+    val attach_reg_sem :
+      Egraph.Ro.t ->
+      ('a, 'b) ThTerm.Kind.t ->
+      (Egraph.Ro.t -> 'b -> enqueue) ->
+      unit
+    (** wakeup when a new semantical class is registered *)
+
+    val attach_reg_value :
+      Egraph.Ro.t ->
+      ('a, 'b) Value.Kind.t ->
+      (Egraph.Ro.t -> 'b -> enqueue) ->
+      unit
+    (** wakeup when a new value is registered *)
+
+    val attach_repr :
+      Egraph.Ro.t -> Node.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit
+    (** wakeup when it is not anymore the representative class *)
+
+    val attach_any_repr :
+      Egraph.Ro.t -> (Egraph.Ro.t -> Node.t -> enqueue) -> unit
+    (** wakeup when a node is not its representative class anymore *)
+  end
+
+  val new_pending_daemon : Egraph.t -> 'a Dem.t -> 'a -> unit
+  (** register an event for later (immediate or not). *)
+end
+
+(** {3 Choices } *)
+
+module Choice : sig
+  type choice_state = DecNo | DecTodo of (Egraph.t -> unit) list
+
+  and t = { choice : Egraph.t -> choice_state; prio : int }
+
+  val register : Egraph.t -> t -> unit
+  (** register a decision that would be scheduled later. The
+      [choose_decision] of the [Cho] will be called at that time to know
+      if the decision is still needed. *)
+end
+
+(** {3 Helpers } *)
+
+module Init : sig
+  val add_default_theory : (Egraph.t -> unit) -> unit
+end
+
+module Debug : sig
+  type flag = Colibri2_popop_lib.Debug.flag
+
+  val register_flag : desc:Colibri2_popop_lib.Pp.formatted -> string -> flag
+  (** Register a new flag. It is allowed to register twice the same flag *)
+
+  val register_info_flag :
+    desc:Colibri2_popop_lib.Pp.formatted -> string -> flag
+  (** Register a new info flag. It is allowed to register twice the same flag.
+    Info flags are set by --debug-all and must not change the behaviour. *)
+
+  val dprintf0 :
+    ?nobox:unit -> flag -> (unit, Format.formatter, unit) format -> unit
+  (** Print only if the flag is set *)
+
+  val dprintf1 :
+    ?nobox:unit ->
+    flag ->
+    ('a -> unit, Format.formatter, unit) format ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf2 :
+    ?nobox:unit ->
+    flag ->
+    ('b -> 'a -> unit, Format.formatter, unit) format ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf3 :
+    ?nobox:unit ->
+    flag ->
+    ('c -> 'b -> 'a -> unit, Format.formatter, unit) format ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf4 :
+    ?nobox:unit ->
+    flag ->
+    ('d -> 'c -> 'b -> 'a -> unit, Format.formatter, unit) format ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf5 :
+    ?nobox:unit ->
+    flag ->
+    ('e -> 'd -> 'c -> 'b -> 'a -> unit, Format.formatter, unit) format ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf6 :
+    ?nobox:unit ->
+    flag ->
+    ('f -> 'e -> 'd -> 'c -> 'b -> 'a -> unit, Format.formatter, unit) format ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf7 :
+    ?nobox:unit ->
+    flag ->
+    ( 'g -> 'f -> 'e -> 'd -> 'c -> 'b -> 'a -> unit,
+      Format.formatter,
+      unit )
+    format ->
+    'g ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf8 :
+    ?nobox:unit ->
+    flag ->
+    ( 'h -> 'g -> 'f -> 'e -> 'd -> 'c -> 'b -> 'a -> unit,
+      Format.formatter,
+      unit )
+    format ->
+    'h ->
+    'g ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf9 :
+    ?nobox:unit ->
+    flag ->
+    ( 'i -> 'h -> 'g -> 'f -> 'e -> 'd -> 'c -> 'b -> 'a -> unit,
+      Format.formatter,
+      unit )
+    format ->
+    'i ->
+    'h ->
+    'g ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf10 :
+    ?nobox:unit ->
+    flag ->
+    ( 'j -> 'i -> 'h -> 'g -> 'f -> 'e -> 'd -> 'c -> 'b -> 'a -> unit,
+      Format.formatter,
+      unit )
+    format ->
+    'j ->
+    'i ->
+    'h ->
+    'g ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf11 :
+    ?nobox:unit ->
+    flag ->
+    ( 'k -> 'j -> 'i -> 'h -> 'g -> 'f -> 'e -> 'd -> 'c -> 'b -> 'a -> unit,
+      Format.formatter,
+      unit )
+    format ->
+    'k ->
+    'j ->
+    'i ->
+    'h ->
+    'g ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf12 :
+    ?nobox:unit ->
+    flag ->
+    ( 'l ->
+      'k ->
+      'j ->
+      'i ->
+      'h ->
+      'g ->
+      'f ->
+      'e ->
+      'd ->
+      'c ->
+      'b ->
+      'a ->
+      unit,
+      Format.formatter,
+      unit )
+    format ->
+    'l ->
+    'k ->
+    'j ->
+    'i ->
+    'h ->
+    'g ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf13 :
+    ?nobox:unit ->
+    flag ->
+    ( 'm ->
+      'l ->
+      'k ->
+      'j ->
+      'i ->
+      'h ->
+      'g ->
+      'f ->
+      'e ->
+      'd ->
+      'c ->
+      'b ->
+      'a ->
+      unit,
+      Format.formatter,
+      unit )
+    format ->
+    'm ->
+    'l ->
+    'k ->
+    'j ->
+    'i ->
+    'h ->
+    'g ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf14 :
+    ?nobox:unit ->
+    flag ->
+    ( 'n ->
+      'm ->
+      'l ->
+      'k ->
+      'j ->
+      'i ->
+      'h ->
+      'g ->
+      'f ->
+      'e ->
+      'd ->
+      'c ->
+      'b ->
+      'a ->
+      unit,
+      Format.formatter,
+      unit )
+    format ->
+    'n ->
+    'm ->
+    'l ->
+    'k ->
+    'j ->
+    'i ->
+    'h ->
+    'g ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintf15 :
+    ?nobox:unit ->
+    flag ->
+    ( 'o ->
+      'n ->
+      'm ->
+      'l ->
+      'k ->
+      'j ->
+      'i ->
+      'h ->
+      'g ->
+      'f ->
+      'e ->
+      'd ->
+      'c ->
+      'b ->
+      'a ->
+      unit,
+      Format.formatter,
+      unit )
+    format ->
+    'o ->
+    'n ->
+    'm ->
+    'l ->
+    'k ->
+    'j ->
+    'i ->
+    'h ->
+    'g ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    unit
+  (** Print only if the flag is set *)
+
+  val dprintfn :
+    ?nobox:unit ->
+    flag ->
+    ( 'o ->
+      'n ->
+      'm ->
+      'l ->
+      'k ->
+      'j ->
+      'i ->
+      'h ->
+      'g ->
+      'f ->
+      'e ->
+      'd ->
+      'c ->
+      'b ->
+      'a ->
+      'z,
+      Format.formatter,
+      unit )
+    format ->
+    'o ->
+    'n ->
+    'm ->
+    'l ->
+    'k ->
+    'j ->
+    'i ->
+    'h ->
+    'g ->
+    'f ->
+    'e ->
+    'd ->
+    'c ->
+    'b ->
+    'a ->
+    'z
+  (** Print only if the flag is set *)
+
+  val decision : flag
+
+  val contradiction : flag
+
+  type 'a stat
+
+  val register_stats_int : name:string -> init:int -> int stat
+
+  val incr : int stat -> unit
+
+  val decr : int stat -> unit
+end
+
+(** {3 For schedulers} *)
+
+(** The following functions are necessary only to the scheduler *)
+
+module ForSchedulers : sig
+  module Backtrackable : sig
+    type t
+
+    val new_t : Context.creator -> t
+
+    val set_sched :
+      sched_daemon:(Events.daemon_key -> unit) ->
+      sched_decision:(Choice.t -> unit) ->
+      t ->
+      unit
+
+    val get_delayed : t -> Egraph.t
+
+    val run_daemon : Egraph.t -> Events.daemon_key -> unit
+    (** schedule the run of a deamon *)
+
+    val delayed_stop : t -> unit
+    (** Check that not work need to be done. *)
+
+    val flush : t -> unit
+    (** Apply all the modifications and direct consequences. *)
+
+    val draw_graph : ?force:bool -> t -> unit
+    (** Debug *)
+
+    val output_graph : string -> t -> unit
+  end
+
+  val default_theories : unit -> (Egraph.t -> unit) list
+
+  val ground_init : Egraph.t -> unit
+  (** Initialize the module ground for later use *)
+
+  val interp_init : Egraph.t -> unit
+  (** Initialize the module interp for later use *)
+
+  val get_event_priority : Events.daemon_key -> Events.delay
+
+  val flush_internal : Egraph.t -> unit
+
+  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) Base.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
+end
diff --git a/src_colibri2/core/datastructure.ml b/src_colibri2/core/datastructure.ml
index 685c97647..7eac0a818 100644
--- a/src_colibri2/core/datastructure.ml
+++ b/src_colibri2/core/datastructure.ml
@@ -247,7 +247,6 @@ end
 
 
 module HNode = Hashtbl(Nodes.Node)
-module HTermConst = Hashtbl(Expr.Term.Const)
 
 module Push = struct
 
diff --git a/src_colibri2/core/datastructure.mli b/src_colibri2/core/datastructure.mli
index d64124ca0..c5101b8b1 100644
--- a/src_colibri2/core/datastructure.mli
+++ b/src_colibri2/core/datastructure.mli
@@ -79,7 +79,6 @@ module Memo (S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Memo with type key :=
 
 
 module HNode : Sig with type key := Nodes.Node.t
-module HTermConst : Sig with type key := Expr.Term.Const.t
 
 module Push: sig
   type 'a t
diff --git a/src_colibri2/core/dune b/src_colibri2/core/dune
index 12453f2f4..2709e1eb3 100644
--- a/src_colibri2/core/dune
+++ b/src_colibri2/core/dune
@@ -2,11 +2,14 @@
  (name colibri2_core)
  (public_name colibri2.core)
  (synopsis "core for colibri2, e.g. trail, egraph")
- (libraries containers ocamlgraph str colibri2.stdlib colibri2.popop_lib
-   colibri2_core_structures)
+ (libraries containers ocamlgraph str colibri2.stdlib colibri2.popop_lib dolmen.std)
  (preprocess
   (pps ppx_deriving.std ppx_hash))
  (flags :standard -w +a-4-42-44-48-50-58-60-40-9@8 -color always -open
-   Containers -open Colibri2_stdlib -open Std -open Colibri2_core_structures)
+   Containers -open Colibri2_stdlib -open Std)
  (ocamlopt_flags :standard -O3 -bin-annot -unbox-closures
-   -unbox-closures-factor 20))
+                 -unbox-closures-factor 20)
+ (private_modules nodes egraph domKind demon events datastructure)
+)
+
+(copy_files structures/*.ml*)
diff --git a/src_colibri2/core/ground.ml b/src_colibri2/core/ground.ml
index 28dd54fe5..63c38331d 100644
--- a/src_colibri2/core/ground.ml
+++ b/src_colibri2/core/ground.ml
@@ -214,11 +214,18 @@ module Term = struct
 
 end
 
+type s = All.term = {
+  app: Expr.Term.Const.t;
+  tyargs : Ty.t list;
+  args : Node.t IArray.t;
+  ty:Ty.t
+}
+
 
 module ThTerm = RegisterThTerm(Term)
 
 
-module ClosedQuantifier = struct
+module ClosedQuantifier0 = struct
 
   module T = struct
     open! Base
@@ -248,10 +255,19 @@ module ClosedQuantifier = struct
 
 end
 
-module ThClosedQuantifier = RegisterThTerm(ClosedQuantifier)
-
+module ClosedQuantifier = struct
+  type binder = ClosedQuantifier0.binder = Forall | Exists
+    type s = ClosedQuantifier0.t = {
+      binder: binder;
+      subst: Subst.t;
+      ty_vars: Expr.Ty.Var.t list;
+      term_vars: Expr.Term.Var.t list;
+      body: Expr.Term.t;
+    }
+  include (RegisterThTerm(ClosedQuantifier0): RegisteredThTerm with type s := s)
+end
 
-module NotTotalyApplied = struct
+module NotTotalyApplied0 = struct
 
   module T = struct
     open! Base
@@ -293,8 +309,24 @@ module NotTotalyApplied = struct
 
 end
 
-module ThNotTotalyApplied = RegisterThTerm(NotTotalyApplied)
-
+module NotTotalyApplied = struct
+    type s = NotTotalyApplied0.t =
+      | Lambda of {
+        subst: Subst.t;
+        ty_vars: Expr.Ty.Var.t list;
+        term_vars: Expr.Term.Var.t list;
+        body: Expr.Term.t;
+        ty: Ty.t;
+      }
+      | Cst of Expr.Term.Const.t
+      | App of {
+          app: Node.t;
+          tyargs : Ty.t list;
+          args : Node.t IArray.t;
+          ty: Ty.t;
+        }
+  include (RegisterThTerm(NotTotalyApplied0):RegisteredThTerm with type s := s)
+end
 
 let rec convert ?(subst=Subst.empty) (t : Expr.Term.t) =
   match t.term_descr with
@@ -308,7 +340,7 @@ let rec convert ?(subst=Subst.empty) (t : Expr.Term.t) =
     begin match ty.app.builtin, f.term_descr with
       | (Ty.Arrow, _) | (_, (Match _ | App _ | Var _ | Binder _))
         ->
-        ThNotTotalyApplied.node @@ ThNotTotalyApplied.index @@
+        NotTotalyApplied.node @@ NotTotalyApplied.index @@
         App { app = convert ~subst f;
               tyargs = List.map (Ty.convert subst.ty) tyargs;
               args = IArray.of_list_map ~f:(convert ~subst) args;
@@ -330,19 +362,19 @@ let rec convert ?(subst=Subst.empty) (t : Expr.Term.t) =
       { Term.app = f; tyargs = []; args = IArray.empty;
         ty = Ty.convert subst.ty ty }
     end else
-      ThNotTotalyApplied.node @@ ThNotTotalyApplied.index @@
+      NotTotalyApplied.node @@ NotTotalyApplied.index @@
       Cst f
   | Expr.Binder (Exists(ty_vars,term_vars) as b, body)
   | Expr.Binder (Forall(ty_vars,term_vars) as b, body) ->
     let binder = match b with
-      | Exists _ -> ClosedQuantifier.Exists
-      | Forall _ -> ClosedQuantifier.Forall
+      | Exists _ -> ClosedQuantifier0.Exists
+      | Forall _ -> ClosedQuantifier0.Forall
       | Let_seq _ | Let_par _ | Lambda _ -> assert false
     in
-    ThClosedQuantifier.node @@ ThClosedQuantifier.index @@
+    ClosedQuantifier.node @@ ClosedQuantifier.index @@
     { binder; ty_vars; term_vars; body; subst }
   | Expr.Binder (Lambda(ty_vars,term_vars), body) ->
-    ThNotTotalyApplied.node @@ ThNotTotalyApplied.index @@
+    NotTotalyApplied.node @@ NotTotalyApplied.index @@
     (Lambda { ty_vars; term_vars; body; subst;
               ty = Ty.convert subst.ty t.term_ty; })
   | Expr.Binder (Let_seq l, body) ->
@@ -395,16 +427,16 @@ module Defs = struct
 
   let pp_fundef _ _ = ()
 
-  let fundefs = Datastructure.HTermConst.create pp_fundef "SynTerm.fundefs"
+  let fundefs = Expr.Term.Const.HC.create pp_fundef "SynTerm.fundefs"
 
   let add d tc tyl tvl body =
-    Datastructure.HTermConst.set fundefs d tc {tyl;tvl;body}
+    Expr.Term.Const.HC.set fundefs d tc {tyl;tvl;body}
 
   let converter d (v:ThTerm.t) =
     let cl = ThTerm.node v in
     match ThTerm.sem v with
     | { app = tc; tyargs = tyl; args = tvl; ty = _ } ->
-      begin match Datastructure.HTermConst.find fundefs d tc with
+      begin match Expr.Term.Const.HC.find fundefs d tc with
         | exception Not_found -> ()
         | fundef ->
           let subst = {
@@ -467,10 +499,10 @@ let init d =
        Defs.converter d g;
        Datastructure.Push.iter registered_converter d ~f:(fun f -> f d g));
   Demon.Simple.attach_reg_sem d
-    ThClosedQuantifier.key
+    ClosedQuantifier.key
     (fun d g ->
-       let n = ThClosedQuantifier.node g in
+       let n = ClosedQuantifier.node g in
        add_ty d n Ty.bool
     )
 
-include ThTerm
+include (ThTerm : RegisteredThTerm with type s := s and type t = ThTerm.t)
diff --git a/src_colibri2/core/ground.mli b/src_colibri2/core/ground.mli
index cefc6c277..dc081f0d5 100644
--- a/src_colibri2/core/ground.mli
+++ b/src_colibri2/core/ground.mli
@@ -104,6 +104,13 @@ module Term: sig
   include Colibri2_popop_lib.Popop_stdlib.Datatype with type t := t
 end
 
+type s = All.term = {
+  app: Expr.Term.Const.t;
+  tyargs : Ty.t list;
+  args : Node.t IArray.t;
+  ty:Ty.t
+}
+
 include RegisteredThTerm with type s := Term.t
 
 val convert : ?subst:Subst.t -> Expr.Term.t -> Node.t
@@ -129,23 +136,20 @@ module Defs : sig
 module ClosedQuantifier : sig
 
     type binder = Forall | Exists
-    [@@deriving eq, ord, hash]
 
-    type t = {
+    type s = {
       binder: binder;
       subst: Subst.t;
       ty_vars: Expr.Ty.Var.t list;
       term_vars: Expr.Term.Var.t list;
       body: Expr.Term.t;
     }
-    [@@deriving eq, ord, hash]
-
-  end
 
-module ThClosedQuantifier : RegisteredThTerm with type s = ClosedQuantifier.t
+    include RegisteredThTerm with type s := s
+end
 
 module NotTotalyApplied : sig
-    type t =
+    type s =
       | Lambda of {
         subst: Subst.t;
         ty_vars: Expr.Ty.Var.t list;
@@ -160,8 +164,7 @@ module NotTotalyApplied : sig
           args : Node.t IArray.t;
           ty: Ty.t;
         }
-    [@@deriving eq, ord, hash]
 
-end
+    include RegisteredThTerm with type s := s
 
-module ThNotTotalyApplied : RegisteredThTerm with type s = NotTotalyApplied.t
+end
diff --git a/src_colibri2/core/structures/dune b/src_colibri2/core/structures/dune
index 92ee09425..e69de29bb 100644
--- a/src_colibri2/core/structures/dune
+++ b/src_colibri2/core/structures/dune
@@ -1,13 +0,0 @@
-(library
- (name colibri2_core_structures)
- (public_name colibri2.core.structures)
- (synopsis
-   "core structures for colibri2, e.g. terms, semantic terms, values, etc")
- (libraries containers ocamlgraph colibri2.stdlib colibri2.popop_lib str
-   dolmen.std)
- (preprocess
-  (pps ppx_deriving.std))
- (flags :standard -w +a-4-42-44-48-50-58-60-40-9@8 -color always -open
-   Containers -open Colibri2_stdlib -open Std)
- (ocamlopt_flags :standard -O3 -bin-annot -unbox-closures
-   -unbox-closures-factor 20))
diff --git a/src_colibri2/core/structures/expr.ml b/src_colibri2/core/structures/expr.ml
index 7982d431a..b5c34015f 100644
--- a/src_colibri2/core/structures/expr.ml
+++ b/src_colibri2/core/structures/expr.ml
@@ -90,17 +90,24 @@ module Term = struct
     end)
 
   module Const = struct
+
+    module D = struct
     include Dolmen_std.Expr.Term.Const
     let pp fmt (t:t) = Dolmen_std.Expr.Id.print fmt t
-
-    include Colibri2_popop_lib.Popop_stdlib.MkDatatype(struct
+      include Colibri2_popop_lib.Popop_stdlib.MkDatatype(struct
         type nonrec t = t
         let equal = equal
         let compare = compare
         let hash = hash
         let pp = pp
         let hash_fold_t s t = Base.Hash.fold_int s (hash t)
-    end)
+      end)
+    end
+
+    include D
+
+    module HC = Datastructure.Hashtbl(D)
+
   end
 
   module Var = struct
diff --git a/src_colibri2/popop_lib/map_intf.ml b/src_colibri2/popop_lib/map_intf.ml
index fd296c728..d0d2ae68b 100644
--- a/src_colibri2/popop_lib/map_intf.ml
+++ b/src_colibri2/popop_lib/map_intf.ml
@@ -176,7 +176,7 @@ module type Map =
     (** Same as {!Extmap.S.map}, but the function receives as arguments both
         the key and the associated value for each binding of the map. *)
 
-    (** @Added in Why3 *)
+    (** Added in Why3 *)
 
     val change :
       ('a data option -> 'a data option) -> key -> 'a data t -> 'a data t
diff --git a/src_colibri2/solver/dune b/src_colibri2/solver/dune
index f8ee1077e..b58f23fde 100644
--- a/src_colibri2/solver/dune
+++ b/src_colibri2/solver/dune
@@ -3,7 +3,7 @@
  (public_name colibri2.solver)
  (synopsis "colibri2's solver")
  (libraries containers zarith ocamlgraph gen dolmen spelll colibri2.stdlib
-   colibri2.popop_lib str colibri2.core colibri2.core.structures dolmen_loop
+   colibri2.popop_lib str colibri2.core dolmen_loop
    dolmen_type)
  (preprocess
   (pps ppx_deriving.std))
diff --git a/src_colibri2/solver/scheduler.ml b/src_colibri2/solver/scheduler.ml
index d892f816a..efd423d21 100644
--- a/src_colibri2/solver/scheduler.ml
+++ b/src_colibri2/solver/scheduler.ml
@@ -20,6 +20,7 @@
 
 open Colibri2_popop_lib
 open Colibri2_core
+open ForSchedulers
 
 let debug = Debug.register_info_flag
   ~desc:"for the scheduler in the simple version"
@@ -47,7 +48,7 @@ exception Contradiction
 
 module Att = struct
   type t =
-    | Decision of int * Egraph.choice
+    | Decision of int * Choice.t
   type prio = float
   type db = float Node.H.t
 
@@ -83,7 +84,7 @@ type t =
     lasteffort : Events.daemon_key Context.TimeWheel.t;
     fixing_model : Events.daemon_key list Context.Ref.t;
     mutable prev_scheduler_state : bp option;
-            solver_state      : Egraph.Backtrackable.t;
+            solver_state      : Backtrackable.t;
     (* global *)
     decprio : Att.db;
     var_inc  : float ref;
@@ -123,7 +124,7 @@ let new_solver () =
       lasteffort = Context.TimeWheel.create (Context.creator context);
       fixing_model = Context.Ref.create (Context.creator context) [];
       prev_scheduler_state = None;
-      solver_state = Egraph.Backtrackable.new_t (Context.creator context);
+      solver_state = Backtrackable.new_t (Context.creator context);
       context;
       decprio = Node.H.create 100;
       var_inc = ref 1.;
@@ -135,7 +136,7 @@ let new_solver () =
   let sched_daemon att =
     incr daemon_count;
     Debug.dprintf0 debug "[Scheduler] New waiting daemon";
-    match Egraph.Wait.get_priority att with
+    match get_event_priority att with
     | Immediate -> assert false (* absurd *)
     | Delayed_by offset -> Context.TimeWheel.add t.daemons att offset
     | LastEffort offset ->
@@ -148,13 +149,13 @@ let new_solver () =
       !dec_count;
     t.choices <- Prio.insert t.decprio (Att.Decision (!dec_count,dec))
         t.choices in
-  Egraph.Backtrackable.set_sched ~sched_daemon ~sched_decision t.solver_state;
+  Backtrackable.set_sched ~sched_daemon ~sched_decision t.solver_state;
   t
 
 
 let push kind t =
-  if Debug.test_flag debug_dotgui then
-    Egraph.Backtrackable.draw_graph ~force:true t.solver_state;
+  if Colibri2_popop_lib.Debug.test_flag debug_dotgui then
+    Backtrackable.draw_graph ~force:true t.solver_state;
   Debug.dprintf2 debug_pushpop "[Scheduler] push from %a" print_level t;
   let prev =
     { pre_choices    = t.choices;
@@ -175,7 +176,7 @@ let pop_to t prev =
   t.prev_scheduler_state <- prev.pre_prev_scheduler_state;
   t.level <- prev.pre_level;
   Context.pop prev.pre_backtrack_point;
-  Egraph.Backtrackable.draw_graph t.solver_state;
+  Backtrackable.draw_graph t.solver_state;
   Debug.dprintf2 debug_pushpop "[Scheduler] pop to %a"
     print_level t
 
@@ -224,8 +225,8 @@ let pop_to t prev =
 *)
 
 let rec conflict_analysis t =
-  if Debug.test_flag debug_dotgui then
-    Egraph.Backtrackable.draw_graph ~force:true t.solver_state;
+  if Colibri2_popop_lib.Debug.test_flag debug_dotgui then
+    Backtrackable.draw_graph ~force:true t.solver_state;
   Debug.incr stats_con;
   t.var_inc := !(t.var_inc) *. var_decay;
   let rec rewind () =
@@ -248,25 +249,25 @@ let rec conflict_analysis t =
   rewind ()
 
 and try_run_dec:
-  t -> Prio.t -> Egraph.choice -> unit = fun t prio choice ->
+  t -> Prio.t -> Choice.t -> unit = fun t prio choice ->
   (** First we verify its the decision is at this point needed *)
-  let d = Egraph.Backtrackable.get_delayed t.solver_state in
+  let d = Backtrackable.get_delayed t.solver_state in
   match choice.choice d with
-  | Egraph.DecNo | Egraph.DecTodo [] ->
+  | Choice.DecNo | Choice.DecTodo [] ->
     t.choices <- prio
-  | Egraph.DecTodo (todo::todos) ->
+  | Choice.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.choices <- prio;
     Debug.incr stats_dec;
-    Egraph.Backtrackable.delayed_stop t.solver_state;
+    Backtrackable.delayed_stop t.solver_state;
     make_choice t todo (Base.Sequence.of_list todos)
 
 and make_choice t todo todos =
   ignore (push (Choices todos) t);
   try
-    todo (Egraph.Backtrackable.get_delayed t.solver_state)
+    todo (Backtrackable.get_delayed t.solver_state)
   with Egraph.Contradiction ->
     conflict_analysis t
 
@@ -278,8 +279,8 @@ and make_choice t todo todos =
  *       let _, prio = Prio.extract_min t.choices in
  *       Debug.incr stats_propa;
  *       t.choices <- prio;
- *       Egraph.Backtrackable.run_daemon d att;
- *       Egraph.Backtrackable.flush d;
+ *       Backtrackable.run_daemon d att;
+ *       Backtrackable.flush d;
  *       run_until_dec t d
  *     end
  *   | Some (Att.Decision (_,_)) | None -> () *)
@@ -298,8 +299,8 @@ let run_one_step_propagation ~nodec t =
   | Some att -> begin
       Debug.incr stats_propa;
       protect_against_contradiction t (fun () ->
-          let d = Egraph.Backtrackable.get_delayed t.solver_state in
-          Egraph.Backtrackable.run_daemon d att
+          let d = Backtrackable.get_delayed t.solver_state in
+          Backtrackable.run_daemon d att
         ) (fun () -> true)
     end
   | None when nodec -> false
@@ -310,8 +311,8 @@ let run_one_step_propagation ~nodec t =
           (fun fmt -> Fmt.int fmt (Context.TimeWheel.size_at_current_time t.lasteffort));
         Debug.incr stats_lasteffort;
         protect_against_contradiction t (fun () ->
-            let d = Egraph.Backtrackable.get_delayed t.solver_state in
-            Egraph.Backtrackable.run_daemon d att
+            let d = Backtrackable.get_delayed t.solver_state in
+            Backtrackable.run_daemon d att
           ) (fun () -> true)
       end
     | None ->
@@ -326,8 +327,8 @@ let run_one_step_propagation ~nodec t =
         | Some att -> begin
             Debug.incr stats_lasteffort;
             protect_against_contradiction t (fun () ->
-                let d = Egraph.Backtrackable.get_delayed t.solver_state in
-                Egraph.Backtrackable.run_daemon d att
+                let d = Backtrackable.get_delayed t.solver_state in
+                Backtrackable.run_daemon d att
           ) (fun () -> true)
           end
         | None ->
@@ -339,19 +340,19 @@ let run_one_step_fix_model t =
   | att::l -> begin
       Context.Ref.set t.fixing_model l;
       protect_against_contradiction t (fun () ->
-          let d = Egraph.Backtrackable.get_delayed t.solver_state in
-          Egraph.Backtrackable.run_daemon d att
+          let d = Backtrackable.get_delayed t.solver_state in
+          Backtrackable.run_daemon d att
         ) (fun () -> true)
     end
   | [] ->
     protect_against_contradiction t (fun () ->
-        let d = Egraph.Backtrackable.get_delayed t.solver_state in
-        Interp.Fix_model.next_dec d
+        let d = Backtrackable.get_delayed t.solver_state in
+        Fix_model.next_dec d
       ) (fun seq ->
         match Base.Sequence.next seq with
         | None -> false
         | Some (todo,todos) ->
-          Egraph.Backtrackable.delayed_stop t.solver_state;
+          Backtrackable.delayed_stop t.solver_state;
           make_choice t todo todos;
           true
       )
@@ -372,7 +373,7 @@ let run_one_step ~nodec t =
 
 let rec flush t =
   try
-    Egraph.Backtrackable.flush t.solver_state
+    Backtrackable.flush t.solver_state
   with Egraph.Contradiction ->
     Debug.dprintf0 debug "[Scheduler] Contradiction";
     conflict_analysis t;
@@ -387,7 +388,7 @@ let rec run_inf_step ~limit ~nodec t =
   | true ->
     run_inf_step ~limit ~nodec t
   | false ->
-    Egraph.Backtrackable.delayed_stop t.solver_state
+    Backtrackable.delayed_stop t.solver_state
 
 let run_inf_step ?(limit=(-1)) ?(nodec=false) t =
   try
@@ -399,9 +400,9 @@ let run_inf_step ?(limit=(-1)) ?(nodec=false) t =
 
 let init_theories ~theories t =
   try
-    let d = Egraph.Backtrackable.get_delayed t.solver_state in
-    List.iter (fun f -> f d) (Ground.init::Interp.init::theories);
-    Egraph.Backtrackable.flush t.solver_state
+    let d = Backtrackable.get_delayed t.solver_state in
+    List.iter (fun f -> f d) (ground_init::interp_init::theories);
+    Backtrackable.flush t.solver_state
   with Egraph.Contradiction ->
     Debug.dprintf0 debug
       "[Scheduler] Contradiction during theory initialization";
@@ -410,7 +411,7 @@ let init_theories ~theories t =
 
 let add_assertion t f =
   try
-    let d = Egraph.Backtrackable.get_delayed t.solver_state in
+    let d = Backtrackable.get_delayed t.solver_state in
     f d;
     flush t
   with Egraph.Contradiction ->
@@ -422,7 +423,7 @@ let check_sat ?limit t =
   try
     flush t;
     run_inf_step ?limit t;
-    `Sat (Egraph.Backtrackable.get_delayed t.solver_state)
+    `Sat (Backtrackable.get_delayed t.solver_state)
   with Contradiction ->
     `Unsat
 
@@ -432,7 +433,7 @@ let run_exn ?nodec ?limit ~theories f =
   add_assertion t f;
   flush t;
   run_inf_step ~nodec:(nodec=Some ()) ?limit t;
-  let d = Egraph.Backtrackable.get_delayed t.solver_state in
+  let d = Backtrackable.get_delayed t.solver_state in
   d
 
 let run ?nodec ?limit ~theories f =
diff --git a/src_colibri2/tests/tests_lib.ml b/src_colibri2/tests/tests_lib.ml
index 227017ec4..965b54a53 100644
--- a/src_colibri2/tests/tests_lib.ml
+++ b/src_colibri2/tests/tests_lib.ml
@@ -31,18 +31,18 @@ let (&:) s l = s >::: (List.map (fun f -> OUnit2.test_case f) l)
 
 let register d cl =
   Egraph.register d cl;
-  Egraph.flush_internal d
+  ForSchedulers.flush_internal d
 
 let merge d cl1 cl2 =
   Egraph.merge d cl1 cl2;
-  Egraph.flush_internal d
+  ForSchedulers.flush_internal d
 
 let is_equal = Egraph.is_equal
 
 (** without decisions *)
 type t =
   { wakeup_daemons    : Events.daemon_key Queue.t;
-    solver_state      : Egraph.Backtrackable.t;
+    solver_state      : ForSchedulers.Backtrackable.t;
     context : Colibri2_stdlib.Context.context;
   }
 
@@ -51,7 +51,7 @@ let new_solver () =
   let context = Colibri2_stdlib.Context.create () in
   {
     wakeup_daemons = Queue.create ();
-    solver_state = Egraph.Backtrackable.new_t (Colibri2_stdlib.Context.creator context);
+    solver_state = ForSchedulers.Backtrackable.new_t (Colibri2_stdlib.Context.creator context);
     context;
   }
 
diff --git a/src_colibri2/theories/ADT/adt.ml b/src_colibri2/theories/ADT/adt.ml
index f7b48140a..af77dcd1b 100644
--- a/src_colibri2/theories/ADT/adt.ml
+++ b/src_colibri2/theories/ADT/adt.ml
@@ -18,7 +18,7 @@
 (*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
 (*************************************************************************)
 
-open Colibri2_popop_lib
+module IArray = Colibri2_popop_lib.IArray
 open Colibri2_popop_lib.Popop_stdlib
 module Case = DInt
 module Field = DInt
@@ -117,26 +117,26 @@ let case_of_adt adt =
 (** Decide for destructors *)
 module Decide = struct
   let make_decision n adt cases d =
-    Colibri2_popop_lib.Debug.dprintf4 Egraph.print_decision
-      "[ADT] decide %a on %a" Case.S.pp cases Node.pp n;
+    Debug.dprintf4 Debug.decision "[ADT] decide %a on %a" Case.S.pp cases
+      Node.pp n;
     upd_dom d n (Unk { adt; cases })
 
   let new_decision n adt c =
     {
-      Egraph.prio = 1;
+      Choice.prio = 1;
       choice =
         (fun d ->
           let decisions s =
-            Egraph.DecTodo
+            Choice.DecTodo
               [
                 make_decision n adt (Case.S.singleton c);
                 make_decision n adt (Case.S.remove c s);
               ]
           in
           match Egraph.get_dom d D.key n with
-          | Some (One _) -> Egraph.DecNo
-          | Some (Unk s) when Case.S.is_num_elt 1 s.cases -> Egraph.DecNo
-          | Some (Unk s) when not (Case.S.mem c s.cases) -> Egraph.DecNo
+          | Some (One _) -> Choice.DecNo
+          | Some (Unk s) when Case.S.is_num_elt 1 s.cases -> Choice.DecNo
+          | Some (Unk s) when not (Case.S.mem c s.cases) -> Choice.DecNo
           | Some (Unk s) -> decisions s.cases
           | None -> decisions (case_of_adt adt));
     }
@@ -151,7 +151,7 @@ let converter d (f : Ground.t) =
   let setb = setv Boolean.dom in
   let getb = getv Boolean.dom in
   let set = updd upd_dom in
-  let get = getd key in
+  let get = getd D.key in
   match Ground.sem f with
   | { app = { builtin = Expr.Tester { adt; case; _ }; _ }; args; tyargs; _ } ->
       let adt = Option.get_exn (Adt_value.MonoAdt.index adt tyargs) in
@@ -164,7 +164,7 @@ let converter d (f : Ground.t) =
             else
               let cases = Case.S.remove case (case_of_adt adt) in
               if Case.S.is_empty cases then (
-                Debug.dprintf4 Egraph.print_contradiction
+                Debug.dprintf4 Debug.contradiction
                   "[ADT] tester %a removed the only case %a of the type" Node.pp
                   r Case.pp case;
                 Egraph.contradiction d)
@@ -199,7 +199,7 @@ let converter d (f : Ground.t) =
       let adt = Option.get_exn (Adt_value.MonoAdt.index adt tyargs) in
       let e = IArray.extract1_exn args in
       reg e;
-      Egraph.register_decision d (Decide.new_decision e adt case);
+      Choice.register d (Decide.new_decision e adt case);
       attach d
         (set e
            (let* ve = get e in
@@ -272,4 +272,4 @@ let init env : unit =
   Ground.register_converter env converter;
   init_node env
 
-let () = Egraph.add_default_theory init
+let () = Init.add_default_theory init
diff --git a/src_colibri2/theories/ADT/dune b/src_colibri2/theories/ADT/dune
index ecb846e0b..bd987f5ba 100644
--- a/src_colibri2/theories/ADT/dune
+++ b/src_colibri2/theories/ADT/dune
@@ -3,7 +3,7 @@
  (public_name colibri2.theories.adt)
  (synopsis "theory of algebraic datatype for colibri2")
  (libraries containers ocamlgraph colibri2.stdlib colibri2.popop_lib
-            colibri2.core.structures colibri2.core colibri2.theories.bool
+            colibri2.core colibri2.theories.bool
             colibri2.theories.quantifiers
  )
  (preprocess
diff --git a/src_colibri2/theories/FP/dune b/src_colibri2/theories/FP/dune
index f409932f1..dc4d996e9 100644
--- a/src_colibri2/theories/FP/dune
+++ b/src_colibri2/theories/FP/dune
@@ -7,7 +7,6 @@
   farith
   colibri2.stdlib
   colibri2.popop_lib
-  colibri2.core.structures
   colibri2.core)
  (preprocess
   (pps ppx_deriving.std ppx_hash))
diff --git a/src_colibri2/theories/FP/float32.ml b/src_colibri2/theories/FP/float32.ml
index 7da6179fb..74b3dfd93 100644
--- a/src_colibri2/theories/FP/float32.ml
+++ b/src_colibri2/theories/FP/float32.ml
@@ -31,7 +31,7 @@ include Float32
 let init_ty d =
   Interp.Register.ty d (fun d ty ->
       match ty with
-      | {app={builtin = Expr.Float(8, 24);_};_} ->
+      | {app={builtin = Builtin.Float(8, 24);_};_} ->
         let seq =
           let open Interp.SeqLim in
           let+ e = of_seq d posint_sequence in
diff --git a/src_colibri2/theories/FP/float64.ml b/src_colibri2/theories/FP/float64.ml
index eb1d80dce..803b353b0 100644
--- a/src_colibri2/theories/FP/float64.ml
+++ b/src_colibri2/theories/FP/float64.ml
@@ -30,7 +30,7 @@ include Float64
 let init_ty d =
   Interp.Register.ty d (fun d ty ->
       match ty with
-      | {app={builtin = Expr.Float(11, 53);_};_} ->
+      | {app={builtin = Builtin.Float(11, 53);_};_} ->
         let seq =
           let open Interp.SeqLim in
           let+ e = of_seq d posint_sequence in
diff --git a/src_colibri2/theories/FP/fp.ml b/src_colibri2/theories/FP/fp.ml
index b43e48302..aa65f4931 100644
--- a/src_colibri2/theories/FP/fp.ml
+++ b/src_colibri2/theories/FP/fp.ml
@@ -23,4 +23,4 @@ let th_register env =
 
 (* Add the theory to defaults *)
 let () =
-  Egraph.add_default_theory th_register
+  Init.add_default_theory th_register
diff --git a/src_colibri2/theories/LRA/LRA.ml b/src_colibri2/theories/LRA/LRA.ml
index b9f35ca93..d92e352e1 100644
--- a/src_colibri2/theories/LRA/LRA.ml
+++ b/src_colibri2/theories/LRA/LRA.ml
@@ -34,7 +34,7 @@ let th_register env =
   Dom_product.init env;
   ()
 
-let () = Egraph.add_default_theory th_register
+let () = Init.add_default_theory th_register
 
 
 (** Helpers to remove *)
diff --git a/src_colibri2/theories/LRA/dom_interval.ml b/src_colibri2/theories/LRA/dom_interval.ml
index a727f38c2..0ffb6fd6f 100644
--- a/src_colibri2/theories/LRA/dom_interval.ml
+++ b/src_colibri2/theories/LRA/dom_interval.ml
@@ -73,21 +73,21 @@ let is_integer d n =
 
 module ChoLRA = struct
   let make_decision node v env =
-    Debug.dprintf4 Egraph.print_decision
+    Debug.dprintf4 Debug.decision
       "[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.split_heuristic v with
-      | Singleton _ -> Egraph.DecNo
+      | Singleton _ -> Choice.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;
+    Choice.prio = 1;
     choice = choose_decision n;
   }
 
diff --git a/src_colibri2/theories/LRA/dom_polynome.ml b/src_colibri2/theories/LRA/dom_polynome.ml
index 243272c3b..4ee192231 100644
--- a/src_colibri2/theories/LRA/dom_polynome.ml
+++ b/src_colibri2/theories/LRA/dom_polynome.ml
@@ -127,7 +127,7 @@ module Th = struct
         end
       | Cst c ->
         (* 0 = cst <> 0 *)
-        Debug.dprintf6 Egraph.print_contradiction
+        Debug.dprintf6 Debug.contradiction
           "[LRA/Poly] Found 0 = %a when merging %a and %a"
           Q.pp c
           Node.pp cl1 Node.pp cl2;
@@ -162,7 +162,7 @@ module Th = struct
           | Zero -> ()
           | Cst c ->
             (* 0 = cst <> 0 *)
-            Debug.dprintf4 Egraph.print_contradiction
+            Debug.dprintf4 Debug.contradiction
               "[LRA/Poly] Found 0 = %a when updating %a"
               Q.pp c
               Node.pp cl;
@@ -177,7 +177,7 @@ module Th = struct
     let key = dom
 end
 
-let () = Egraph.register_dom(module Th)
+let () = Dom.register(module Th)
 
 let norm d (p:Polynome.t) =
   let add acc cl c =
diff --git a/src_colibri2/theories/LRA/dom_product.ml b/src_colibri2/theories/LRA/dom_product.ml
index 9ca609428..5d10dbc5e 100644
--- a/src_colibri2/theories/LRA/dom_product.ml
+++ b/src_colibri2/theories/LRA/dom_product.ml
@@ -282,7 +282,7 @@ module Th = struct
     let pp = pp
 end
 
-let () = Egraph.register_dom(module Th)
+let () = Dom.register(module Th)
 
 let get_repr d n =
   let open CCOpt in
@@ -319,7 +319,7 @@ module ChangePos = struct
 
 end
 
-let () = Egraph.Wait.register_dem (module ChangePos)
+let () = Events.register (module ChangePos)
 
 let factorize res a coef b d _ =
   match Egraph.get_dom d dom a, Egraph.get_dom d dom b with
diff --git a/src_colibri2/theories/LRA/dune b/src_colibri2/theories/LRA/dune
index 6fe40e43d..4b7875743 100644
--- a/src_colibri2/theories/LRA/dune
+++ b/src_colibri2/theories/LRA/dune
@@ -3,7 +3,7 @@
  (public_name colibri2.theories.LRA)
  (synopsis "theories for colibri2")
  (libraries containers ocamlgraph colibri2.stdlib colibri2.popop_lib
-            colibri2.core.structures colibri2.core colibri2.theories.bool
+            colibri2.core colibri2.theories.bool
             colibri2.theories.quantifiers
             colibri2.theories.LRA.stages )
  (preprocess
diff --git a/src_colibri2/theories/LRA/fourier.ml b/src_colibri2/theories/LRA/fourier.ml
index 2dfec3e4b..ebb907c57 100644
--- a/src_colibri2/theories/LRA/fourier.ml
+++ b/src_colibri2/theories/LRA/fourier.ml
@@ -138,7 +138,7 @@ let add_eq d eqs p bound origins =
     Debug.dprintf2 debug "[Fourier] discard %a" Ground.S.pp origins;
     eqs
   | Some p, bound ->
-    Debug.dprintf4 Egraph.print_contradiction
+    Debug.dprintf4 Debug.contradiction
       "[LRA/Fourier] Found %a%a0"
       Q.pp p Bound.pp bound;
     Egraph.contradiction d
@@ -244,7 +244,7 @@ module Daemon = struct
   let run d () = fm d
 end
 
-let () = Egraph.Wait.register_dem (module Daemon)
+let () = Events.register (module Daemon)
 
 
 (** {2 Initialization} *)
@@ -252,14 +252,14 @@ let converter d (f:Ground.t) =
   match Ground.sem f with
   | { app = {builtin = (Expr.Lt|Expr.Leq|Expr.Geq|Expr.Gt)}; tyargs = []; args } ->
     let attach n =
-      Egraph.attach_dom d n Dom_polynome.dom Daemon.enqueue;
-      Egraph.attach_repr d n Daemon.enqueue;
+      Events.attach_dom d n Dom_polynome.dom Daemon.enqueue;
+      Events.attach_repr d n Daemon.enqueue;
     in
     IArray.iter ~f:attach args;
-    Egraph.attach_value d (Ground.node f) Boolean.dom (fun d n _ -> Daemon.enqueue d n);
+    Events.attach_value d (Ground.node f) Boolean.dom (fun d n _ -> Daemon.enqueue d n);
     Datastructure.Push.push comparisons d f;
-    Egraph.new_pending_daemon d Daemon.key ();
-    Egraph.register_decision d (Boolean.chobool (Ground.node f))
+    Events.new_pending_daemon d Daemon.key ();
+    Choice.register d (Boolean.chobool (Ground.node f))
   | _ -> ()
 
 let init env =
diff --git a/src_colibri2/theories/LRA/stages/stage0/dune b/src_colibri2/theories/LRA/stages/stage0/dune
index a84e03e54..f3c33491d 100644
--- a/src_colibri2/theories/LRA/stages/stage0/dune
+++ b/src_colibri2/theories/LRA/stages/stage0/dune
@@ -2,7 +2,7 @@
  (name        colibri2_theories_LRA_stages_stage0_sign_domain)
  (public_name colibri2.theories.LRA.stages.stage0.sign_domain)
  (libraries containers ocamlgraph colibri2.stdlib colibri2.popop_lib
-            colibri2.core.structures colibri2.core colibri2.theories.bool
+            colibri2.core colibri2.theories.bool
             colibri2.theories.quantifiers colibri2.theories.LRA.stages.def)
  (preprocess
   (pps ppx_deriving.std ppx_hash))
diff --git a/src_colibri2/theories/LRA/stages/stage1/dune b/src_colibri2/theories/LRA/stages/stage1/dune
index 89ee0c1fb..b5c5dfed1 100644
--- a/src_colibri2/theories/LRA/stages/stage1/dune
+++ b/src_colibri2/theories/LRA/stages/stage1/dune
@@ -2,7 +2,7 @@
  (name        colibri2_theories_LRA_stages_stage1_interval_domain)
  (public_name colibri2.theories.LRA.stages.stage1.interval_domain)
  (libraries containers ocamlgraph colibri2.stdlib colibri2.popop_lib
-            colibri2.core.structures colibri2.core colibri2.theories.bool
+            colibri2.core colibri2.theories.bool
             colibri2.theories.quantifiers colibri2.theories.LRA.stages.def
             colibrics.lib
  )
diff --git a/src_colibri2/theories/bool/boolean.ml b/src_colibri2/theories/bool/boolean.ml
index ea064fe48..ef869aaf5 100644
--- a/src_colibri2/theories/bool/boolean.ml
+++ b/src_colibri2/theories/bool/boolean.ml
@@ -100,14 +100,14 @@ let _or = _gen Expr.Term._or
 
 module ChoBool = struct
   let make_decision env node b =
-    Debug.dprintf3 Egraph.print_decision "[Bool] decide %b on %a" b Node.pp node;
+    Debug.dprintf3 Debug.decision "[Bool] decide %b on %a" b Node.pp node;
     set_bool env node b
 
   let choose_decision node env =
     match is env node with
     | Some _ ->
-      Debug.dprintf2 Egraph.print_decision "[Bool] No decision for %a" Node.pp node;
-      Egraph.DecNo
+      Debug.dprintf2 Debug.decision "[Bool] No decision for %a" Node.pp node;
+      Choice.DecNo
     | None -> DecTodo
                 (List.map (fun v env -> make_decision env node v)
                    (Shuffle.shufflel [true;false]))
@@ -115,7 +115,7 @@ module ChoBool = struct
 end
 
 let chobool n = {
-  Egraph.prio = 1;
+  Choice.prio = 1;
   choice = ChoBool.choose_decision n;
 }
 
@@ -173,9 +173,9 @@ module TwoWatchLiteral = struct
     let run d r = r d
 
     let rec attach d r i =
-      Egraph.Ro.attach_value d
+      Events.Ro.attach_value d
         (IArray.get (Ground.sem r.ground).args i) BoolValue.key (fun d _ _ -> enqueue d r);
-      Egraph.Ro.attach_repr d (IArray.get (Ground.sem r.ground).args i) (fun d _ -> enqueue d r);
+      Events.Ro.attach_repr d (IArray.get (Ground.sem r.ground).args i) (fun d _ -> enqueue d r);
 
     and enqueue d r =
       let o_from_start = Context.Ref.get r.from_start in
@@ -255,7 +255,7 @@ module TwoWatchLiteral = struct
               attach (d :> Egraph.Ro.t) r from_end
   end
 
-  let () = Egraph.Wait.register_dem (module Daemon)
+  let () = Events.register (module Daemon)
 
   let create = Daemon.create
 end
@@ -270,7 +270,7 @@ let converter d (f:Ground.t) =
   match Ground.sem f with
   | { app = {builtin = Expr.Base; _ }; ty; _ }
     when Ground.Ty.equal ty Ground.Ty.bool  ->
-    Egraph.register_decision d (chobool res)
+    Choice.register d (chobool res)
   | { app = {builtin = Expr.Or}; tyargs = []; args; _ } ->
     reg_args args;
     TwoWatchLiteral.create d values_true f
@@ -347,4 +347,4 @@ let th_register env =
   init_check env;
   ()
 
-let () = Egraph.add_default_theory th_register
+let () = Init.add_default_theory th_register
diff --git a/src_colibri2/theories/bool/boolean.mli b/src_colibri2/theories/bool/boolean.mli
index 44ec950a8..defd19ec0 100644
--- a/src_colibri2/theories/bool/boolean.mli
+++ b/src_colibri2/theories/bool/boolean.mli
@@ -38,7 +38,7 @@ val is_unknown : Egraph.t -> Node.t -> bool
 
 val th_register: Egraph.t -> unit
 
-val chobool: Node.t -> Egraph.choice
+val chobool: Node.t -> Choice.t
 
 (* val make_dec: Variable.make_dec *)
 
diff --git a/src_colibri2/theories/bool/dune b/src_colibri2/theories/bool/dune
index 1b294acbe..41ff0647b 100644
--- a/src_colibri2/theories/bool/dune
+++ b/src_colibri2/theories/bool/dune
@@ -4,7 +4,7 @@
  (synopsis "theories for colibri2")
  (modules Boolean Equality)
  (libraries containers ocamlgraph colibri2.stdlib colibri2.popop_lib
-   colibri2.core.structures colibri2.core dolmen.std)
+  colibri2.core dolmen.std)
  (preprocess
   (pps ppx_deriving.std ppx_hash))
  (flags :standard -w +a-4-42-44-48-50-58-32-60-40-9@8 -color always -open
diff --git a/src_colibri2/theories/bool/equality.ml b/src_colibri2/theories/bool/equality.ml
index 0819e5929..b8a6cf32c 100644
--- a/src_colibri2/theories/bool/equality.ml
+++ b/src_colibri2/theories/bool/equality.ml
@@ -169,7 +169,7 @@ module D = struct
         let s =
           Dis.test_disjoint
             (fun c ->
-              Debug.dprintf6 Egraph.print_contradiction
+              Debug.dprintf6 Debug.contradiction
                 "[Equality] The currently merged %a and %a are different since \
                  %a"
                 Node.pp cl1 Node.pp cl2 Dis.pp_elt c;
@@ -294,7 +294,7 @@ let norm_set d the =
 
 module ChoEquals = struct
   let make_equal the (cl1, cl2) d =
-    Debug.dprintf6 Egraph.print_decision
+    Debug.dprintf6 Debug.decision
       "[Equality] @[decide on merge of %a and %a in %a@]" Node.pp cl1 Node.pp
       cl2 ThE.pp the;
     Egraph.register d cl1;
@@ -302,7 +302,7 @@ module ChoEquals = struct
     Egraph.merge d cl1 cl2
 
   let make_disequal the (cl1, cl2) d =
-    Debug.dprintf6 Egraph.print_decision
+    Debug.dprintf6 Debug.decision
       "[Equality] @[decide on merge of %a and %a in %a@]" Node.pp cl1 Node.pp
       cl2 ThE.pp the;
     Egraph.register d cl1;
@@ -315,8 +315,8 @@ module ChoEquals = struct
     let own = ThE.node the in
     Debug.dprintf4 debug "[Equality] @[dec on %a for %a@]" Node.pp own ThE.pp
       the;
-    if Boolean.is_false d own then Egraph.DecNo
-    else if norm_set d the then Egraph.DecNo
+    if Boolean.is_false d own then Choice.DecNo
+    else if norm_set d the then Choice.DecNo
     else
       match find_not_disequal d v with
       | `AllDiff _ ->
@@ -325,7 +325,7 @@ module ChoEquals = struct
       | `Found (cl1, cl2) ->
           DecTodo [ make_equal the (cl1, cl2); make_disequal the (cl1, cl2) ]
 
-  let mk_choice the = { Egraph.choice = choose_decision the; prio = 1 }
+  let mk_choice the = { Choice.choice = choose_decision the; prio = 1 }
 end
 
 let norm_dom d the =
@@ -363,7 +363,7 @@ let norm_dom d the =
 
 (** Propagation *)
 
-module DaemonPropa = Demon.Key.Register (struct
+module DaemonPropa = DaemonWithKey.Register (struct
   module Key = ThE
 
   let delay = Events.Delayed_by 1
@@ -391,7 +391,7 @@ let attach_new_equalities d =
           if true (* GenEquality.dodec (Th.get_ty v) *) then (
             Debug.dprintf4 debug "[Equality] @[ask_dec on %a for %a@]" Node.pp
               own Th.pp v;
-            Egraph.register_decision d (ChoEquals.mk_choice clsem))
+            Choice.register d (ChoEquals.mk_choice clsem))
       | _ -> ())
 
 (** ITE *)
@@ -527,4 +527,4 @@ let th_register env =
   init_check env;
   ()
 
-let () = Egraph.add_default_theory th_register
+let () = Init.add_default_theory th_register
diff --git a/src_colibri2/theories/quantifier/InvertedPath.ml b/src_colibri2/theories/quantifier/InvertedPath.ml
index 6d5c02821..124dc033c 100644
--- a/src_colibri2/theories/quantifier/InvertedPath.ml
+++ b/src_colibri2/theories/quantifier/InvertedPath.ml
@@ -70,7 +70,7 @@ let rec exec d acc substs n ip =
     in
     let acc =
       let match_one_app (ptyl, pargs, pos, t) acc g =
-        let { Ground.Term.tyargs = tyl; args; _ } = Ground.sem g in
+        let { Ground.tyargs = tyl; args; _ } = Ground.sem g in
         let substs = List.fold_left2 Pattern.match_ty substs tyl ptyl in
         let substs =
           if Ground.Subst.S.is_empty substs then substs
diff --git a/src_colibri2/theories/quantifier/dune b/src_colibri2/theories/quantifier/dune
index 279a2d266..747afb861 100644
--- a/src_colibri2/theories/quantifier/dune
+++ b/src_colibri2/theories/quantifier/dune
@@ -3,7 +3,7 @@
  (public_name colibri2.theories.quantifiers)
  (synopsis "theories for colibri2")
  (libraries containers base ocamlgraph colibri2.stdlib colibri2.popop_lib
-   colibri2.core.structures colibri2.core colibri2.theories.bool)
+  colibri2.core colibri2.theories.bool)
  (preprocess
   (pps ppx_deriving.std ppx_hash))
  (flags :standard -open Colibri2_stdlib -open Std -open
diff --git a/src_colibri2/theories/quantifier/info.ml b/src_colibri2/theories/quantifier/info.ml
index c8e4a7c39..53755873b 100644
--- a/src_colibri2/theories/quantifier/info.ml
+++ b/src_colibri2/theories/quantifier/info.ml
@@ -45,10 +45,7 @@ let congruence_closure d ~other parent0 ~repr parent1 =
       let h = Ground.Term.H.create 10 in
       let norm g =
         let g = Ground.sem g in
-        {
-          g with
-          Ground.Term.args = IArray.map ~f:find_as_if g.Ground.Term.args;
-        }
+        { g with Ground.args = IArray.map ~f:find_as_if g.Ground.args }
       in
       let s = ref (Ground.S.union g1 g2) in
       let not_first g = s := Ground.S.remove g !s in
diff --git a/src_colibri2/theories/quantifier/pattern.ml b/src_colibri2/theories/quantifier/pattern.ml
index dc5d72ea1..ebe4baf21 100644
--- a/src_colibri2/theories/quantifier/pattern.ml
+++ b/src_colibri2/theories/quantifier/pattern.ml
@@ -149,7 +149,7 @@ let rec match_term d (substs : Ground.Subst.S.t) (n : Node.t) (p : t) :
         in
         Ground.S.fold_left
           (fun acc n ->
-            let { Ground.Term.app = f; tyargs = tyl; args; _ } = Ground.sem n in
+            let { Ground.app = f; tyargs = tyl; args; _ } = Ground.sem n in
             assert (Expr.Term.Const.equal f pf);
             let substs = List.fold_left2 match_ty substs tyl ptyl in
             if Ground.Subst.S.is_empty substs then acc
@@ -192,7 +192,7 @@ let rec check_term d (subst : Ground.Subst.t) (n : Node.t) (p : t) : bool =
       in
       Ground.S.exists
         (fun n ->
-          let { Ground.Term.app = f; tyargs = tyl; args; _ } = Ground.sem n in
+          let { Ground.app = f; tyargs = tyl; args; _ } = Ground.sem n in
           assert (Expr.Term.Const.equal f pf);
           List.for_all2 (check_ty subst) tyl ptyl
           && IArray.for_all2_exn ~f:(check_term d subst) args pargs)
@@ -321,7 +321,7 @@ let match_any_term d subst (p : t) : Ground.Subst.S.t =
   | App (pf, ptyl, pargs) ->
       Context.Push.fold
         (fun acc n ->
-          let { Ground.Term.app = f; tyargs = tyl; args; _ } = Ground.sem n in
+          let { Ground.app = f; tyargs = tyl; args; _ } = Ground.sem n in
           assert (Expr.Term.Const.equal f pf);
           let substs = List.fold_left2 match_ty subst tyl ptyl in
           let substs =
diff --git a/src_colibri2/theories/quantifier/quantifier.ml b/src_colibri2/theories/quantifier/quantifier.ml
index 8d0af561b..658f3c4d3 100644
--- a/src_colibri2/theories/quantifier/quantifier.ml
+++ b/src_colibri2/theories/quantifier/quantifier.ml
@@ -155,7 +155,7 @@ module Delayed_find_new_event = struct
   let run d (n, ips) = process_inverted_path d n ips
 end
 
-let () = Egraph.Wait.register_dem (module Delayed_find_new_event)
+let () = Events.register (module Delayed_find_new_event)
 
 let () =
   Dom.register
@@ -185,10 +185,10 @@ let () =
             Egraph.set_dom d Info.dom cl1 info;
             let ips = find_new_event d cl0 info0 cl1 info1 in
             if not (Base.List.is_empty ips) then
-              Egraph.new_pending_daemon d Delayed_find_new_event.key (repr, ips)
+              Events.new_pending_daemon d Delayed_find_new_event.key (repr, ips)
     end)
 
-let skolemize d (e : Ground.ClosedQuantifier.t) =
+let skolemize d (e : Ground.ClosedQuantifier.s) =
   if not (Base.List.is_empty e.ty_vars) then
     invalid_arg "False type quantification";
   let subst_term =
@@ -205,13 +205,13 @@ let skolemize d (e : Ground.ClosedQuantifier.t) =
   n
 
 let attach d th =
-  Daemon.attach_value d (Ground.ThClosedQuantifier.node th)
-    Boolean.BoolValue.key (fun d n b ->
-      match (Ground.ThClosedQuantifier.sem th, Boolean.BoolValue.value b) with
+  Daemon.attach_value d (Ground.ClosedQuantifier.node th) Boolean.BoolValue.key
+    (fun d n b ->
+      match (Ground.ClosedQuantifier.sem th, Boolean.BoolValue.value b) with
       | ({ binder = Exists; _ } as e), true
       | ({ binder = Forall; _ } as e), false ->
-          Debug.dprintf2 debug "[Quant] Skolemize %a"
-            Ground.ThClosedQuantifier.pp th;
+          Debug.dprintf2 debug "[Quant] Skolemize %a" Ground.ClosedQuantifier.pp
+            th;
           Egraph.merge d (skolemize d e) n
       | { binder = Exists; _ }, false | { binder = Forall; _ }, true ->
           let triggers =
@@ -220,15 +220,15 @@ let attach d th =
             | triggers -> triggers
           in
           Debug.dprintf4 debug "[Quant] For %a adds %a"
-            Ground.ThClosedQuantifier.pp th
+            Ground.ClosedQuantifier.pp th
             Fmt.(list ~sep:semi (Fmt.using (fun t -> t.Trigger.pat) Pattern.pp))
             triggers;
           List.iter (add_trigger d) triggers
       (* Todo match with current terms *))
 
 let quantifier_registered d th =
-  let n = Ground.ThClosedQuantifier.node th in
-  if Boolean.is_unknown d n then Egraph.register_decision d (Boolean.chobool n);
+  let n = Ground.ClosedQuantifier.node th in
+  if Boolean.is_unknown d n then Choice.register d (Boolean.chobool n);
   attach d th
 
 (** Verify that this term is congruent closure to another already existing term
@@ -289,8 +289,8 @@ let add_info_on_ground_terms d thg =
 
 let th_register d =
   (* let delay = Events.Delayed_by 10 in *)
-  Daemon.attach_reg_sem d Ground.ThClosedQuantifier.key quantifier_registered;
+  Daemon.attach_reg_sem d Ground.ClosedQuantifier.key quantifier_registered;
   Ground.register_converter d (fun d g ->
       if not (application_useless d g) then add_info_on_ground_terms d g)
 
-let () = Egraph.add_default_theory th_register
+let () = Init.add_default_theory th_register
diff --git a/src_colibri2/theories/quantifier/trigger.ml b/src_colibri2/theories/quantifier/trigger.ml
index 9d0eadb6c..a160ee268 100644
--- a/src_colibri2/theories/quantifier/trigger.ml
+++ b/src_colibri2/theories/quantifier/trigger.ml
@@ -27,7 +27,7 @@ module T = struct
   type t = {
     pat : Pattern.t;
     checks : Pattern.t list;
-    form : Ground.ThClosedQuantifier.t;
+    form : Ground.ClosedQuantifier.t;
     eager : bool;
   }
   [@@deriving eq, ord, hash]
@@ -35,14 +35,14 @@ module T = struct
   let pp fmt t =
     Fmt.pf fmt "[%a, %a -> %a]" Pattern.pp t.pat
       Fmt.(list ~sep:comma Pattern.pp)
-      t.checks Ground.ThClosedQuantifier.pp t.form
+      t.checks Ground.ClosedQuantifier.pp t.form
 end
 
 include T
 include Popop_stdlib.MkDatatype (T)
 
-let compute_top_triggers (cq : Ground.ThClosedQuantifier.t) =
-  let cq' = Ground.ThClosedQuantifier.sem cq in
+let compute_top_triggers (cq : Ground.ClosedQuantifier.t) =
+  let cq' = Ground.ClosedQuantifier.sem cq in
   let tyvs = cq'.ty_vars in
   let tvs = cq'.term_vars in
   let t = cq'.body in
@@ -106,8 +106,8 @@ let compute_top_triggers (cq : Ground.ThClosedQuantifier.t) =
     multi_pats;
   multi_pats
 
-let compute_all_triggers (cq : Ground.ThClosedQuantifier.t) =
-  let cq' = Ground.ThClosedQuantifier.sem cq in
+let compute_all_triggers (cq : Ground.ClosedQuantifier.t) =
+  let cq' = Ground.ClosedQuantifier.sem cq in
   let tyvs = cq'.ty_vars in
   let tvs = cq'.term_vars in
   let t = cq'.body in
@@ -162,8 +162,8 @@ let compute_all_triggers (cq : Ground.ThClosedQuantifier.t) =
   in
   pats
 
-let get_user_triggers (cq : Ground.ThClosedQuantifier.t) =
-  let cq' = Ground.ThClosedQuantifier.sem cq in
+let get_user_triggers (cq : Ground.ClosedQuantifier.t) =
+  let cq' = Ground.ClosedQuantifier.sem cq in
   let pats = Expr.Term.get_tag_list cq'.body Expr.Tags.triggers in
   let tyvs = Expr.Ty.Var.S.of_list cq'.ty_vars in
   let tvs = Expr.Term.Var.S.of_list cq'.term_vars in
@@ -204,14 +204,14 @@ let add_trigger d t =
   | Node _ -> ()
 
 let instantiate_aux d tri subst =
-  let form = Ground.ThClosedQuantifier.sem tri.form in
+  let form = Ground.ClosedQuantifier.sem tri.form in
   Debug.incr nb_instantiation;
   let subst = Ground.Subst.distinct_union subst form.subst in
   let n = Ground.convert ~subst form.body in
   if Debug.test_flag Debug.stats && not (Egraph.is_registered d n) then
     Debug.incr nb_new_instantiation;
   Egraph.register d n;
-  Egraph.merge d n (Ground.ThClosedQuantifier.node tri.form)
+  Egraph.merge d n (Ground.ClosedQuantifier.node tri.form)
 
 module Delayed_instantiation = struct
   let key =
@@ -231,13 +231,13 @@ module Delayed_instantiation = struct
   let run d (tri, subst) =
     Debug.dprintf8 debug
       "[Quant] %a delayed instantiation %a, pat %a, checks:%a" Ground.Subst.pp
-      subst Ground.ThClosedQuantifier.pp tri.form Pattern.pp tri.pat
+      subst Ground.ClosedQuantifier.pp tri.form Pattern.pp tri.pat
       Fmt.(list ~sep:comma Pattern.pp)
       tri.checks;
     instantiate_aux d tri subst
 end
 
-let () = Egraph.Wait.register_dem (module Delayed_instantiation)
+let () = Events.register (module Delayed_instantiation)
 
 let instantiate d tri subst =
   let subst =
@@ -248,8 +248,7 @@ let instantiate d tri subst =
     }
   in
   Debug.dprintf8 debug "[Quant] %a instantiation found %a, pat %a, checks:%a"
-    Ground.Subst.pp subst Ground.ThClosedQuantifier.pp tri.form Pattern.pp
-    tri.pat
+    Ground.Subst.pp subst Ground.ClosedQuantifier.pp tri.form Pattern.pp tri.pat
     Fmt.(list ~sep:comma Pattern.pp)
     tri.checks;
   if
@@ -261,7 +260,7 @@ let instantiate d tri subst =
   then instantiate_aux d tri subst
   else (
     Debug.dprintf0 debug "[Quant] Delayed";
-    Egraph.new_pending_daemon d Delayed_instantiation.key (tri, subst))
+    Events.new_pending_daemon d Delayed_instantiation.key (tri, subst))
 
 let match_ d tri n =
   Debug.dprintf4 debug "[Quant] match %a %a" pp tri Node.pp n;
diff --git a/src_colibri2/theories/quantifier/trigger.mli b/src_colibri2/theories/quantifier/trigger.mli
index 395c16e7d..df743fb59 100644
--- a/src_colibri2/theories/quantifier/trigger.mli
+++ b/src_colibri2/theories/quantifier/trigger.mli
@@ -25,21 +25,21 @@ type t = {
       (** The main pattern, the one matched to obtain a complete
                      substitution *)
   checks : Pattern.t list;  (** Guards for the existence of terms *)
-  form : Ground.ThClosedQuantifier.t;  (** the body of the formula *)
+  form : Ground.ClosedQuantifier.t;  (** the body of the formula *)
   eager : bool;
       (** If it should be eagerly applied, otherwise wait for LastEffort *)
 }
 
 include Colibri2_popop_lib.Popop_stdlib.Datatype with type t := t
 
-val compute_top_triggers : Ground.ThClosedQuantifier.t -> t list
+val compute_top_triggers : Ground.ClosedQuantifier.t -> t list
 (** Compute triggers, that should only add logical connective or equalities are
    new terms *)
 
-val compute_all_triggers : Ground.ThClosedQuantifier.t -> t list
+val compute_all_triggers : Ground.ClosedQuantifier.t -> t list
 (** Compute all the triggers whose patterns contain all the variables of the formula *)
 
-val get_user_triggers : Ground.ThClosedQuantifier.t -> t list
+val get_user_triggers : Ground.ClosedQuantifier.t -> t list
 (** return the triggers given by the user *)
 
 val env_vars : t Datastructure.Push.t
diff --git a/src_colibri2/theories/quantifier/uninterp.ml b/src_colibri2/theories/quantifier/uninterp.ml
index 490978b08..1ab005b7a 100644
--- a/src_colibri2/theories/quantifier/uninterp.ml
+++ b/src_colibri2/theories/quantifier/uninterp.ml
@@ -286,11 +286,11 @@ module UFModel = struct
   let env =
     HConst.create Fmt.nop "Uninterp.UFModel.env" (fun c _ -> Hargs.create c)
 
-  let find d (g : Ground.Term.t) lv =
+  let find d (g : Ground.s) lv =
     let h = HConst.find env d { tc = g.app; ta = g.tyargs } in
     Hargs.find_opt h lv
 
-  let set d (g : Ground.Term.t) lv v =
+  let set d (g : Ground.s) lv v =
     let h = HConst.find env d { tc = g.app; ta = g.tyargs } in
     Hargs.set h lv v
 
@@ -303,14 +303,14 @@ module UFModel = struct
       match find d s lv with
       | Some v' ->
           if not (Value.equal v v') then (
-            Debug.dprintf8 Egraph.print_contradiction
+            Debug.dprintf8 Debug.contradiction
               "[Uninterp] The model of %a (%a) is %a and not %a" Ground.pp g
-              Ground.Term.pp s Value.pp v' Value.pp v;
+              Ground.pp g Value.pp v' Value.pp v;
             Egraph.contradiction d)
       | None -> set d s lv v
     in
     let f d g =
-      Daemon.FixingModel.attach_any_value d (Ground.node g) (check_or_update g)
+      DaemonFixingModel.attach_any_value d (Ground.node g) (check_or_update g)
     in
     f d g
 
@@ -350,4 +350,4 @@ let th_register env =
   init_check env;
   init_ty env
 
-let () = Egraph.add_default_theory th_register
+let () = Init.add_default_theory th_register
-- 
GitLab