diff --git a/src_colibri2/theories/FP/dom_interval.ml b/src_colibri2/theories/FP/dom_interval.ml
new file mode 100644
index 0000000000000000000000000000000000000000..d0bb75203482e4a05d193cec4813295c31e2447d
--- /dev/null
+++ b/src_colibri2/theories/FP/dom_interval.ml
@@ -0,0 +1,285 @@
+(*************************************************************************)
+(*  This file is part of Colibri2.                                       *)
+(*                                                                       *)
+(*  Copyright (C) 2014-2021                                              *)
+(*    CEA   (Commissariat à l'énergie atomique et aux énergies           *)
+(*           alternatives)                                               *)
+(*                                                                       *)
+(*  you can redistribute it and/or modify it under the terms of the GNU  *)
+(*  Lesser General Public License as published by the Free Software      *)
+(*  Foundation, version 2.1.                                             *)
+(*                                                                       *)
+(*  It is distributed in the hope that it will be useful,                *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of       *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *)
+(*  GNU Lesser General Public License for more details.                  *)
+(*                                                                       *)
+(*  See the GNU Lesser General Public License version 2.1                *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
+(*************************************************************************)
+
+open Colibri2_popop_lib
+open Colibri2_core
+open Colibri2_stdlib.Std
+
+let debug = Debug.register_info_flag
+    ~desc:"for intervals for the floating points theory"
+    "FP.interval"
+
+module D = Colibri2_theories_LRA_stages.Interval_domain
+
+let dom = DomKind.create_key (module struct type t = D.t let name = "FP_ARITH" end)
+
+let () = DomKind.register(module struct
+    include D
+    let key = dom
+    let merged i1 i2 =
+      match i1, i2 with
+      | None, None -> true
+      | Some i1, Some i2 -> D.equal i1 i2
+      | _ -> false
+
+    let merge d (i1,cl1) (i2,cl2) _ =
+      assert (not (Egraph.is_equal d cl1 cl2));
+      match i1, cl1, i2, cl2 with
+      | Some i1,_, Some i2,_ ->
+        begin match D.inter i1 i2 with
+          | None ->
+            Debug.dprintf8 Egraph.print_contradiction
+              "[FP/Dom] The intersection of %a and %a is empty when merging %a and %a"
+              D.pp i1 D.pp i2
+              Node.pp cl1
+              Node.pp cl2;
+            Egraph.contradiction d
+          | Some i ->
+            if not (D.equal i i1) then
+              Egraph.set_dom d dom cl1 i;
+            if not (D.equal i i2) then
+              Egraph.set_dom d dom cl2 i
+        end
+      | Some i1, _, _, cl2 | _, cl2, Some i1, _ ->
+        Egraph.set_dom d dom cl2 i1
+      | None,_,None,_ -> raise Impossible
+  end)
+
+let is_zero_or_positive d n =
+  match Egraph.get_dom d dom n with
+  | None -> false
+  | Some p -> match D.is_comparable D.zero p with
+    | D.Le | D.Lt -> true
+    | D.Ge | D.Gt | D.Uncomparable -> false
+
+let is_not_zero d n =
+  match Egraph.get_dom d dom n with
+  | None -> false
+  | Some p -> D.absent Q.zero p
+
+let is_strictly_positive d n =
+  match Egraph.get_dom d dom n with
+  | None -> false
+  | Some p -> match D.is_comparable D.zero p with
+    | D.Lt -> true
+    | D.Le | D.Ge | D.Gt | D.Uncomparable -> false
+
+let is_strictly_negative d n =
+  match Egraph.get_dom d dom n with
+  | None -> false
+  | Some p -> match D.is_comparable D.zero p with
+    | D.Gt -> true
+    | D.Le | D.Ge | D.Lt | D.Uncomparable -> false
+
+let is_integer d n =
+  match Egraph.get_dom d dom n with
+  | None -> false
+  | Some p -> D.is_integer p
+
+let set_dom d node v =
+  match D.is_singleton v with
+  | Some q ->
+    let cst = Float32.cst' (Farith.B32.(of_q NE q)) in
+    Egraph.set_value d node (Float32.nodevalue cst)
+  | None ->
+    (** the pexp must be in the dom *)
+    Egraph.set_dom d dom node v
+
+
+module ChoLRA = struct
+  let make_decision node v env =
+    Debug.dprintf4 Egraph.print_decision
+      "[FP] 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
+    | 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 = choose_decision n;
+  }
+
+end
+
+let choice = ChoLRA.choice
+
+let upd_dom d n' v' =
+  match Egraph.get_dom d dom n' with
+  | None -> Egraph.set_dom d dom n' v'
+  | Some old ->
+    match D.inter old v' with
+    | None ->
+      Debug.dprintf6 Egraph.print_contradiction
+        "[FP/Dom] The intersection of %a with %a is empty when updating %a"
+        D.pp old D.pp v'
+        Node.pp n';
+      Egraph.contradiction d
+    | Some d' ->
+      if not (D.equal old d')
+      then Egraph.set_dom d dom n' d'
+
+module Monad : sig
+  type 'a monad = Egraph.t -> Node.t -> 'a
+  val get: Node.t -> D.t option monad
+  val set: Node.t -> D.t option monad -> unit monad
+  val getb: Node.t -> bool option monad
+  val setb: Node.t -> bool option option monad -> unit monad
+  val (let+): 'b option monad -> ('b -> 'c) -> 'c option monad
+  val (and+): 'b option monad -> 'c option monad -> ('b * 'c) option monad
+  val (&&): unit monad -> unit monad -> unit monad
+end = struct
+  type 'a monad = Egraph.t -> Node.t -> 'a
+  let [@ocaml.always inline] get_dom dom n' = fun d _ ->
+    Egraph.get_dom d dom n'
+  let [@ocaml.always inline] set_dom (type b) (dom:b DomKind.t) n' v' d n =
+    if Node.equal n n' then () else
+      Option.iter
+        (fun (v':b) -> Egraph.set_dom d dom n' v')
+        (v' d n)
+  let [@ocaml.always inline] set n' v' d n =
+    if Node.equal n n' then () else
+      Option.iter
+        (fun v' -> upd_dom d n' v' )
+        (v' d n)
+  let [@ocaml.always inline] get a = get_dom dom a
+  let [@ocaml.always inline] get_value key n' = fun d _ ->
+    let open CCOpt in
+    let* v = Egraph.get_value d n' in
+    Value.value key v
+  let [@ocaml.always inline] set_value (type b)
+      (value:(module ValueKind.Registered with type s = b))
+      n' (v':b option option monad) : unit monad =
+    fun d n ->
+    if Node.equal n n' then () else
+      let module V = (val value) in
+      Option.iter
+        (Option.iter (fun v' -> Egraph.set_value d n' (V.nodevalue (V.index v'))))
+        (v' d n)
+  let getb a = get_value Boolean.dom a
+  let setb a = set_value (module Boolean.BoolValue) a
+  let [@ocaml.always inline] (let+) a (f:'b -> 'a) = fun d n -> Option.map f (a d n)
+  let [@ocaml.always inline] (and+) a b = fun d n -> match a d n, b d n with
+    | Some a, Some b -> Some (a,b) | _ -> None
+  let [@ocaml.always inline] (&&) a b = fun d n -> a d n; b d n
+
+end
+
+let wait =
+  Demon.Fast.register_simply "GotDomInterval"
+
+let neg_cmp = function
+  | `Lt -> `Ge
+  | `Le -> `Gt
+  | `Ge -> `Lt
+  | `Gt -> `Le
+
+let com_cmp = function
+  | `Lt -> `Gt
+  | `Le -> `Ge
+  | `Ge -> `Le
+  | `Gt -> `Lt
+
+let backward = function
+  | `Lt -> D.lt'
+  | `Gt -> D.gt'
+  | `Le -> D.le'
+  | `Ge -> D.ge'
+
+(** {2 Initialization} *)
+let converter d (f:Ground.t) =
+  let r = Ground.node f in
+  let reg n = Egraph.register d n in
+  let open Monad in
+  let cmp test _cmp a b =
+    reg a; reg b;
+    let wakeup =
+      setb r (let+ va = get a and+ vb = get b in
+              test (D.is_comparable va vb))
+      (*&&
+        set b  (let+ va = get a and+ vr = getb r in
+        backward (if vr then (com_cmp cmp) else (com_cmp (neg_cmp cmp))) va) &&
+        set a  (let+ vb = get b and+ vr = getb r in
+        backward (if vr then cmp else (neg_cmp cmp)) vb)
+      *)
+    in
+    List.iter (fun n -> wait.for_dom d dom n wakeup) [a;b];
+    wait.for_value d Boolean.BoolValue.key r wakeup
+  in
+  match Ground.sem f with
+  | { app = {builtin = Expr.Base; _ }; tyargs = _; args = _; ty }
+    when Ground.Ty.equal ty Ground.Ty.real ->
+    (* Egraph.register_decision d (ChoLRA.choice r) *) (* not useful for now *)
+    ()
+  | { app = {builtin = Expr.Base; _ }; tyargs = _; args = _; ty }
+    when Ground.Ty.equal ty Ground.Ty.int ->
+    upd_dom d r D.integers
+  | { app = {builtin = Expr.Add}; tyargs = []; args; _ } ->
+    let (a,b) = IArray.extract2_exn args in
+    reg a; reg b;
+    let wakeup =
+      set r (let+ va = get a and+ vb = get b in D.add va vb)
+    in
+    List.iter (fun n -> wait.for_dom d dom n wakeup) [a; b; r]
+  | { app = {builtin = Expr.Sub}; tyargs = []; args; _ } ->
+    let (a,b) = IArray.extract2_exn args in
+    reg a; reg b;
+    let wakeup =
+      set r (let+ va = get a and+ vb = get b in D.minus va vb)
+    in
+    List.iter (fun n -> wait.for_dom d dom n wakeup) [a; b; r]
+  | { app = {builtin = Expr.Minus}; tyargs = []; args; _ } ->
+    let a = IArray.extract1_exn args in
+    reg a;
+    let wakeup =
+      set r (let+ va = get a in D.mult_cst Q.minus_one va) &&
+      set a (let+ vr = get r in D.mult_cst Q.minus_one vr)
+    in
+    List.iter (fun n -> wait.for_dom d dom n wakeup) [a;r]
+  | { app = {builtin = Expr.Lt}; tyargs = []; args; _ } ->
+    let a,b = IArray.extract2_exn args in
+    cmp (function | Uncomparable | Le -> None | Lt -> Some true | Ge | Gt -> Some false) `Lt a b
+  | { app = {builtin = Expr.Leq}; tyargs = []; args; _ } ->
+    let a,b = IArray.extract2_exn args in
+    cmp (function | Uncomparable | Ge -> None | Lt | Le -> Some true | Gt -> Some false) `Le a b
+  | { app = {builtin = Expr.Geq}; tyargs = []; args; _ } ->
+    let a,b = IArray.extract2_exn args in
+    cmp (function | Uncomparable | Le -> None | Lt -> Some false  | Ge | Gt -> Some true) `Ge a b
+  | { app = {builtin = Expr.Gt}; tyargs = []; args; _ } ->
+    let a,b = IArray.extract2_exn args in
+    cmp (function | Uncomparable | Ge -> None | Lt | Le -> Some false  | Gt -> Some true) `Gt a b
+  | _ -> ()
+
+let init env =
+  Demon.Fast.register_init_daemon_value
+    ~name:"Float32ToDomInterval"
+    (module Float32)
+    (fun d value ->
+       let v = Float32.value value in
+       let s = D.singleton (Farith.B32.to_q v) in
+       Egraph.set_dom d dom (Float32.node value) s
+    ) env;
+  Ground.register_converter env converter
diff --git a/src_colibri2/theories/FP/dune b/src_colibri2/theories/FP/dune
index 60fb4f3eb59c4cbacb84ef17af276482f78d6e54..9c01e3f198496c7de542574af903c7e6a30486d7 100644
--- a/src_colibri2/theories/FP/dune
+++ b/src_colibri2/theories/FP/dune
@@ -10,6 +10,7 @@
   colibri2.theories.helpers
   colibri2.core.structures
   colibri2.theories.bool
+  colibri2.theories.LRA.stages
   colibri2.theories.quantifiers
   colibri2.core)
  (preprocess
diff --git a/src_colibri2/theories/FP/float32.ml b/src_colibri2/theories/FP/float32.ml
index 45591c00f79ea85b1fa61b30e9008f96589e7cb5..d612b15076b68c6e25b15108b266fda90ef6f872 100644
--- a/src_colibri2/theories/FP/float32.ml
+++ b/src_colibri2/theories/FP/float32.ml
@@ -26,6 +26,11 @@ module N32 = struct let name = "Float32" end
 module Float32 = ValueKind.Register(MakeFloat(Farith.B32)(N32))
 
 include Float32
+
+let cst' c = index c
+
+let cst c = node (cst' c)
+
 (** Initialise type interpretation
     TODO : fix bounds (there is a finite set of 32 bits floats)
 *)
diff --git a/src_colibri2/theories/FP/float32.mli b/src_colibri2/theories/FP/float32.mli
index 51b03a489ade1b941073cae6020a125e70e17e85..c3900e1f43c164bbbf2b2b5499b79a55ebeb2c48 100644
--- a/src_colibri2/theories/FP/float32.mli
+++ b/src_colibri2/theories/FP/float32.mli
@@ -20,4 +20,8 @@
 
 include ValueKind.Registered with type s = Farith.B32.t
 
+val cst': Farith.B32.t -> t
+
+val cst:  Farith.B32.t -> Node.t
+
 val init : Egraph.t -> unit
\ No newline at end of file