From 79b56fe599d486c5247a23112ddee8508feb80e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Bobot?= <francois.bobot@cea.fr>
Date: Thu, 12 Nov 2020 11:36:14 +0100
Subject: [PATCH] Add tests for UF and simplify synTerm

---
 src_colibri2/core/synTerm.ml                  |  42 ++---
 src_colibri2/core/synTerm.mli                 |   9 +-
 src_colibri2/solver/scheduler.ml              | 178 ++++++++----------
 src_colibri2/tests/solve/smt_uf/sat/dune      |   8 +
 src_colibri2/tests/solve/smt_uf/sat/dune.inc  |   3 +
 src_colibri2/tests/solve/smt_uf/unsat/dune    |   8 +
 .../tests/solve/smt_uf/unsat/dune.inc         |  21 +++
 src_colibri2/tests/tests_uf.ml                | 141 +++++++-------
 src_colibri2/theories/LRA/LRA.ml              |  42 ++---
 src_colibri2/theories/bool/boolean.ml         |  58 +++---
 src_colibri2/theories/bool/equality.ml        |  18 +-
 src_colibri2/theories/bool/uninterp.ml        |  13 +-
 src_colibri2/theories/bool/uninterp.mli       |  10 +-
 13 files changed, 282 insertions(+), 269 deletions(-)
 create mode 100644 src_colibri2/tests/solve/smt_uf/sat/dune
 create mode 100644 src_colibri2/tests/solve/smt_uf/sat/dune.inc
 create mode 100644 src_colibri2/tests/solve/smt_uf/unsat/dune
 create mode 100644 src_colibri2/tests/solve/smt_uf/unsat/dune.inc

diff --git a/src_colibri2/core/synTerm.ml b/src_colibri2/core/synTerm.ml
index 17550576e..9a053bfc1 100644
--- a/src_colibri2/core/synTerm.ml
+++ b/src_colibri2/core/synTerm.ml
@@ -35,8 +35,7 @@ let node_of_term x = ThTerm.node (ThTerm.index x)
 
 
 type env = {
-  converters: (Egraph.t -> Expr.Term.t -> Node.t option) list;
-  decvars: (Expr.Term.t -> Node.t -> Egraph.choice option) list;
+  converters: (Egraph.t -> Expr.Term.t -> Node.t -> unit) list;
 }
 
 let converters = Env.Saved.create_key (module struct
@@ -46,11 +45,7 @@ let converters = Env.Saved.create_key (module struct
 
 let register_converter env r =
   let e = Egraph.get_env env converters in
-  Egraph.set_env env converters {e with converters = r::e.converters}
-
-let register_decvars env r =
-  let e = Egraph.get_env env converters in
-  Egraph.set_env env converters {e with decvars = r::e.decvars}
+  Egraph.set_env env converters {converters = r::e.converters}
 
 let () = Env.Saved.register (fun _ _ -> ()) converters
 
@@ -67,24 +62,21 @@ module DaemonConvertTerm = struct
         let e = Egraph.get_env d converters in
         let thterm = ThTerm.coerce_thterm thterm in
         let v = ThTerm.sem thterm in
-        begin match v with
-          | { descr = App({builtin = Dolmen_std.Expr.Base; _ },_,[]); _ } ->
-            let n = ThTerm.node thterm in
-            List.iter (fun f ->
-                Opt.iter
-                  (Egraph.register_decision d)
-                  (f v n)
-              ) e.decvars
-          | _ -> ()
-        end;
-        let iter conv =
-          match conv d v with
-          | None -> ()
-          | Some node ->
-            Egraph.register d node;
-            Egraph.merge d (ThTerm.node thterm) node
+        let rec handle (v:Expr.Term.t) =
+          match v with
+            | { descr = Binder(Letin l,t); _ } ->
+              let subst = List.fold_left
+                  (fun acc (v,t) -> Expr.Subst.Var.bind acc v t)
+                  Expr.Subst.empty l
+              in
+              (** todo subst with cache for not blowing-up memory *)
+              handle (Expr.Term.subst Expr.Subst.empty subst t)
+            | _ ->
+              let cl = ThTerm.node thterm in
+              let iter conv = conv d v cl in
+              List.iter iter e.converters
         in
-        List.iter iter e.converters
+        handle v
       end with Exit -> () end
     | _ -> raise UnwaitedEvent
 
@@ -93,7 +85,7 @@ end
 module RDaemonConvertTerm = Demon.Fast.Register(DaemonConvertTerm)
 
 let init env =
-  Egraph.set_env env converters {converters=[]; decvars = []};
+  Egraph.set_env env converters {converters=[]};
   RDaemonConvertTerm.init env;
   Demon.Fast.attach env
     DaemonConvertTerm.key [Demon.Create.EventRegSem(ThTerm.key,())];
diff --git a/src_colibri2/core/synTerm.mli b/src_colibri2/core/synTerm.mli
index 60f4fda96..7645b601a 100644
--- a/src_colibri2/core/synTerm.mli
+++ b/src_colibri2/core/synTerm.mli
@@ -33,13 +33,6 @@ val init: Egraph.t -> unit
 
 val register_converter:
   Egraph.t ->
-  (Egraph.t -> Expr.Term.t -> Node.t option) ->
+  (Egraph.t -> Expr.Term.t -> Node.t -> unit) ->
   unit
 (** register converters between syntactic terms *)
-
-
-val register_decvars:
-  Egraph.t ->
-  (Expr.Term.t -> Node.t -> Egraph.choice option) ->
-  unit
-(** register decision adder on variables *)
diff --git a/src_colibri2/solver/scheduler.ml b/src_colibri2/solver/scheduler.ml
index f0d3824a9..0c809dcd2 100644
--- a/src_colibri2/solver/scheduler.ml
+++ b/src_colibri2/solver/scheduler.ml
@@ -41,6 +41,7 @@ let stats_dec = Debug.register_stats_int ~name:"Scheduler.decision" ~init:0
 let stats_con = Debug.register_stats_int ~name:"Scheduler.conflict" ~init:0
 
 exception NeedStopDelayed
+exception Contradiction
 
 module Att = struct
   type t =
@@ -64,22 +65,23 @@ module Att = struct
     | Decision (_,choice) -> float_of_int choice.prio
 end
 
-exception Contradiction = Egraph.Contradiction
-
 module Prio = Leftistheap.Make(Att)
 
+type bp_kind =
+  | Choices of (Egraph.t -> unit) list
+  | External
+
 type bp =
   { pre_wakeup_daemons    : Prio.t;
     pre_prev_scheduler_state : bp option;
     pre_backtrack_point      : Context.bp;
-    pre_choices              : (Egraph.t -> unit) list;
+    kind                     : bp_kind;
     pre_level                : int;
   }
 
 type t =
   { mutable wakeup_daemons    : Prio.t;
     mutable prev_scheduler_state : bp option;
-    mutable choices              : (Egraph.t -> unit) list;
             solver_state      : Egraph.Backtrackable.t;
     mutable delayed           : Egraph.t option;
     (* global *)
@@ -113,7 +115,6 @@ let new_solver () =
   let context = Context.create () in
   { wakeup_daemons = Prio.empty;
     prev_scheduler_state = None;
-    choices = [];
     solver_state = Egraph.Backtrackable.new_t (Context.creator context);
     context;
     delayed    = None;
@@ -122,23 +123,33 @@ let new_solver () =
     level = 0;
   }
 
-let push t =
+let push kind t =
   if Debug.test_flag debug_dotgui then
     Egraph.Backtrackable.draw_graph ~force:true t.solver_state;
-  Debug.dprintf0 debug_pushpop "[Scheduler] push";
+  Debug.dprintf2 debug_pushpop "[Scheduler] push from %a" print_level t;
   let prev =
     { pre_wakeup_daemons    = t.wakeup_daemons;
       pre_prev_scheduler_state = t.prev_scheduler_state;
       pre_backtrack_point      = Context.bp t.context;
-      pre_choices = t.choices;
+      kind;
       pre_level = t.level;
     } in
-  t.choices <- [];
   t.level <- t.level + 1;
   t.prev_scheduler_state <- Some prev;
   ignore (Context.push t.context);
   prev
 
+let pop_to t prev =
+  Debug.dprintf2 debug_pushpop "[Scheduler] pop from %a"
+    print_level t;
+  t.wakeup_daemons <- prev.pre_wakeup_daemons;
+  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;
+  Debug.dprintf2 debug_pushpop "[Scheduler] pop to %a"
+    print_level t
+
 let update_prio t chogen =
   Node.H.change (function
       | None -> Some (!(t.var_inc))
@@ -181,28 +192,6 @@ let new_delayed =
         conflict_analysis t pexp
 *)
 
-let pop_to t prev =
-  Debug.dprintf2 debug_pushpop "[Scheduler] pop from %a"
-    print_level t;
-  t.wakeup_daemons <- prev.pre_wakeup_daemons;
-  t.prev_scheduler_state <- prev.pre_prev_scheduler_state;
-  t.choices <- prev.pre_choices;
-  t.level <- prev.pre_level;
-  Context.pop prev.pre_backtrack_point;
-  let d = new_delayed t in
-  Egraph.Backtrackable.draw_graph t.solver_state;
-  Debug.dprintf2 debug_pushpop "[Scheduler] pop to %a"
-    print_level t;
-  d
-
-
-let rec apply_learnt t d =
-  try
-    run_until_dec t d;
-    d
-  with Egraph.Contradiction ->
-    Debug.dprintf0 debug "[Scheduler] Contradiction during apply learnt";
-    conflict_analysis t
 
 (*
   and conflict_analysis t pexp =
@@ -229,94 +218,82 @@ let rec apply_learnt t d =
     pop_to llearnt t prev
 *)
 
-and conflict_analysis t =
+let rec conflict_analysis t =
   if Debug.test_flag debug_dotgui then
     Egraph.Backtrackable.draw_graph ~force:true t.solver_state;
   Debug.incr stats_con;
   t.var_inc := !(t.var_inc) *. var_decay;
-  (** We look for the level just below the backtrack level *)
-  let rewind t prevo =
-    match prevo with
+  let rec rewind () =
+    match t.prev_scheduler_state with
     | None ->
       Debug.dprintf0 debug "[Scheduler] learnt clause false at level 0";
       raise Contradiction
     | Some prev ->
-      let d = pop_to t prev in
-      d
+      pop_to t prev;
+      t.wakeup_daemons <- Prio.reprio t.decprio t.wakeup_daemons;
+      match prev.kind with
+      | Choices [] -> rewind ()
+      | Choices (choice::choices) ->
+        make_choice t choice choices
+      | External -> raise Contradiction
   in
-  let d =
-    rewind t t.prev_scheduler_state in
-  t.wakeup_daemons <- Prio.reprio t.decprio t.wakeup_daemons;
-  apply_learnt t d
+  rewind ()
 
 and try_run_dec:
   t -> Egraph.t -> Prio.t -> Egraph.choice -> Egraph.t = fun t d prio choice ->
-    (** First we verify its the decision is at this point needed *)
-  assert (t.choices = []);
-  try
-      match choice.choice d with
-      | Egraph.DecNo | Egraph.DecTodo [] ->
-        t.wakeup_daemons <- prio;
-        d (** d can be precised by choose_decision *)
-      | Egraph.DecTodo (todo::todos) ->
-        (** We remove the decision it is replaced by the todos,
-            we can change the interface of choice and in that case
-            we want to keep the decision in the current branch *)
-        t.wakeup_daemons <- prio;
-        Debug.incr stats_dec;
-        make_choice t d todo todos
-    with Egraph.Contradiction ->
-      Debug.dprintf0 debug "[Scheduler] Contradiction";
-      conflict_analysis t
-
-and make_choice t d todo todos =
-  Egraph.Backtrackable.delayed_stop d;
-  t.choices <- todos;
-  begin match todos with
-    | [] -> ()
-    | _ -> ignore (push t)
-  end;
+  (** First we verify its the decision is at this point needed *)
+  match choice.choice d with
+  | Egraph.DecNo | Egraph.DecTodo [] ->
+    t.wakeup_daemons <- prio;
+    d (** d can be precised by choose_decision *)
+  | Egraph.DecTodo (todo::todos) ->
+    (** We remove the decision it is replaced by the todos,
+        we can change the interface of choice and in that case
+        we want to keep the decision in the current branch *)
+    t.wakeup_daemons <- prio;
+    Debug.incr stats_dec;
+    Egraph.Backtrackable.delayed_stop d;
+    make_choice t todo todos
+
+and make_choice t todo todos =
+  ignore (push (Choices todos) t);
   let d = new_delayed t in
-  todo d;
-  d
+  try
+    todo d;
+    d
+  with Egraph.Contradiction ->
+    conflict_analysis t
 
 
-and run_until_dec t d =
-  let act = Prio.min t.wakeup_daemons in
-  match act with
-  | Some (Att.Daemon (_,att)) -> begin
-      let _, prio = Prio.extract_min t.wakeup_daemons in
-      Debug.incr stats_propa;
-      t.wakeup_daemons <- prio;
-      Egraph.Backtrackable.run_daemon d att;
-      Egraph.Backtrackable.flush d;
-      run_until_dec t d
-    end
-  | Some (Att.Decision (_,_)) | None -> ()
+(* let rec run_until_dec t d =
+ *   let act = Prio.min t.wakeup_daemons in
+ *   match act with
+ *   | Some (Att.Daemon (_,att)) -> begin
+ *       let _, prio = Prio.extract_min t.wakeup_daemons in
+ *       Debug.incr stats_propa;
+ *       t.wakeup_daemons <- prio;
+ *       Egraph.Backtrackable.run_daemon d att;
+ *       Egraph.Backtrackable.flush d;
+ *       run_until_dec t d
+ *     end
+ *   | Some (Att.Decision (_,_)) | None -> () *)
 
 
 let run_one_step t d =
-  match t.choices with
-  | [] -> begin
-      let act, prio = Prio.extract_min t.wakeup_daemons in
-      match act with
-      | Att.Daemon (_,att) -> begin
-          Debug.incr stats_propa;
-          t.wakeup_daemons <- prio;
-          try
-            Egraph.Backtrackable.run_daemon d att; d
-          with Egraph.Contradiction ->
-            Debug.dprintf0 debug "[Scheduler] Contradiction";
-            conflict_analysis t
-        end
-      | Att.Decision (_,chogen) -> try_run_dec t d prio chogen
+  let act, prio = Prio.extract_min t.wakeup_daemons in
+  match act with
+  | Att.Daemon (_,att) -> begin
+      Debug.incr stats_propa;
+      t.wakeup_daemons <- prio;
+      try
+        Egraph.Backtrackable.run_daemon d att; d
+      with Egraph.Contradiction ->
+        Debug.dprintf0 debug "[Scheduler] Contradiction";
+        conflict_analysis t
     end
-  | todo::todos ->
-    try
-      make_choice t d todo todos
-    with Egraph.Contradiction ->
-      Debug.dprintf0 debug "[Scheduler] Contradiction";
-      conflict_analysis t
+  | Att.Decision (_,chogen) ->
+    Debug.dprintf0 debug "[Scheduler] decision";
+    try_run_dec t d prio chogen
 
 let rec flush t d =
   try
@@ -428,3 +405,4 @@ let run ?nodec ?limit ~theories f =
     `Contradiction
 
 let pop_to st bp = ignore (pop_to st bp)
+let push st = push External st
diff --git a/src_colibri2/tests/solve/smt_uf/sat/dune b/src_colibri2/tests/solve/smt_uf/sat/dune
new file mode 100644
index 000000000..47c20f59d
--- /dev/null
+++ b/src_colibri2/tests/solve/smt_uf/sat/dune
@@ -0,0 +1,8 @@
+(include dune.inc)
+
+(rule
+ (alias runtest)
+ (deps (glob_files *.cnf) (glob_files *.smt2))
+ (action (with-stdout-to dune.inc (run %{exe:../../../generate_tests/generate_dune_tests.exe} . sat)))
+ (mode promote)
+)
diff --git a/src_colibri2/tests/solve/smt_uf/sat/dune.inc b/src_colibri2/tests/solve/smt_uf/sat/dune.inc
new file mode 100644
index 000000000..0b8d7662a
--- /dev/null
+++ b/src_colibri2/tests/solve/smt_uf/sat/dune.inc
@@ -0,0 +1,3 @@
+(rule (action (with-stdout-to oracle (echo "sat\n"))))
+(rule (action (with-stdout-to bad_conflict.smt2.res (run colibri2 --max-step 1000 bad_conflict.smt2))))
+(rule (alias runtest) (action (diff oracle bad_conflict.smt2.res)))
diff --git a/src_colibri2/tests/solve/smt_uf/unsat/dune b/src_colibri2/tests/solve/smt_uf/unsat/dune
new file mode 100644
index 000000000..9ca94f895
--- /dev/null
+++ b/src_colibri2/tests/solve/smt_uf/unsat/dune
@@ -0,0 +1,8 @@
+(include dune.inc)
+
+(rule
+ (alias runtest)
+ (deps (glob_files *.cnf) (glob_files *.smt2))
+ (action (with-stdout-to dune.inc (run %{exe:../../../generate_tests/generate_dune_tests.exe} . unsat)))
+ (mode promote)
+)
diff --git a/src_colibri2/tests/solve/smt_uf/unsat/dune.inc b/src_colibri2/tests/solve/smt_uf/unsat/dune.inc
new file mode 100644
index 000000000..0fd7accf3
--- /dev/null
+++ b/src_colibri2/tests/solve/smt_uf/unsat/dune.inc
@@ -0,0 +1,21 @@
+(rule (action (with-stdout-to oracle (echo "unsat\n"))))
+(rule (action (with-stdout-to NEQ004_size4__decide_eq_us.smt2.res (run colibri2 --max-step 1000 NEQ004_size4__decide_eq_us.smt2))))
+(rule (alias runtest) (action (diff oracle NEQ004_size4__decide_eq_us.smt2.res)))
+(rule (action (with-stdout-to deltaed0.smt2.res (run colibri2 --max-step 1000 deltaed0.smt2))))
+(rule (alias runtest) (action (diff oracle deltaed0.smt2.res)))
+(rule (action (with-stdout-to diff_to_value_for_bool.smt2.res (run colibri2 --max-step 1000 diff_to_value_for_bool.smt2))))
+(rule (alias runtest) (action (diff oracle diff_to_value_for_bool.smt2.res)))
+(rule (action (with-stdout-to diff_value_substupfalse.smt2.res (run colibri2 --max-step 1000 diff_value_substupfalse.smt2))))
+(rule (alias runtest) (action (diff oracle diff_value_substupfalse.smt2.res)))
+(rule (action (with-stdout-to distinct.smt2.res (run colibri2 --max-step 1000 distinct.smt2))))
+(rule (alias runtest) (action (diff oracle distinct.smt2.res)))
+(rule (action (with-stdout-to eq_diamond2.smt2.res (run colibri2 --max-step 1000 eq_diamond2.smt2))))
+(rule (alias runtest) (action (diff oracle eq_diamond2.smt2.res)))
+(rule (action (with-stdout-to equality_norm_set.smt2.res (run colibri2 --max-step 1000 equality_norm_set.smt2))))
+(rule (alias runtest) (action (diff oracle equality_norm_set.smt2.res)))
+(rule (action (with-stdout-to many_distinct.smt2.res (run colibri2 --max-step 1000 many_distinct.smt2))))
+(rule (alias runtest) (action (diff oracle many_distinct.smt2.res)))
+(rule (action (with-stdout-to polyeq_genequality_deltaed.smt2.res (run colibri2 --max-step 1000 polyeq_genequality_deltaed.smt2))))
+(rule (alias runtest) (action (diff oracle polyeq_genequality_deltaed.smt2.res)))
+(rule (action (with-stdout-to xor.smt2.res (run colibri2 --max-step 1000 xor.smt2))))
+(rule (alias runtest) (action (diff oracle xor.smt2.res)))
diff --git a/src_colibri2/tests/tests_uf.ml b/src_colibri2/tests/tests_uf.ml
index 1d7005b4d..88774546c 100644
--- a/src_colibri2/tests/tests_uf.ml
+++ b/src_colibri2/tests/tests_uf.ml
@@ -30,9 +30,12 @@ let ($$) f x = f x
 
 open Expr
 
-let a = fresh Ty.bool "a"
-let b = fresh Ty.bool "b"
-let c = fresh Ty.bool "c"
+let ta = fresht Ty.bool "a"
+let tb = fresht Ty.bool "b"
+let tc = fresht Ty.bool "c"
+let a = SynTerm.node_of_term ta
+let b = SynTerm.node_of_term tb
+let c = SynTerm.node_of_term tc
 
 let empty _ =
   let env = run $$ fun env ->
@@ -74,12 +77,13 @@ let noteq _ =
 
 let basic = "Uf.Basic" >::: ["empty" >:: empty; "tauto" >:: tauto;
                          "trans" >:: trans; "noteq" >:: noteq]
-(*
-let f  = Uninterp.fun1 ty "f"
-let fa = f a
-let fb = f b
-let ffa = f (f a)
-let ffb = f (f b)
+
+let f  = Expr.Term.Const.mk "f" [] [Ty.bool] Ty.bool
+let f x  = Expr.Term.apply f [] [x]
+let fa = SynTerm.node_of_term @@ f ta
+let fb = SynTerm.node_of_term @@ f tb
+let ffa = SynTerm.node_of_term @@ f (f ta)
+let ffb = SynTerm.node_of_term @@ f (f tb)
 
 let refl _ =
   let env = run $$ fun env ->
@@ -95,7 +99,7 @@ let empty _ =
 
 let congru _ =
   let env = run $$ fun env ->
-      Shuffle.seql [
+      Colibri2_stdlib.Shuffle.seql [
         (fun () -> register env fa);
         (fun () -> register env fb);
         (fun () -> register env a);
@@ -108,7 +112,7 @@ let congru _ =
 
 let _2level _ =
   let env = run $$ fun env ->
-      Shuffle.seql [
+      Colibri2_stdlib.Shuffle.seql [
         (fun () -> register env ffa);
         (fun () -> register env ffb);
         (fun () -> register env a);
@@ -129,36 +133,36 @@ let _2level' _ =
 
 
 let bigger _ =
-  let rec bf n = if n < 1 then a else (f (bf(n-1))) in
-  let fa = bf 1 in
-  let fffa = bf 3 in
-  let fffffa = bf 5 in
+  let rec bf n = if n < 1 then ta else f (bf(n-1)) in
+  let fa = SynTerm.node_of_term @@ bf 1 in
+  let fffa = SynTerm.node_of_term @@ bf 3 in
+  let fffffa = SynTerm.node_of_term @@ bf 5 in
   let env = run $$ fun env ->
-      Shuffle.seql
+      Colibri2_stdlib.Shuffle.seql
         [(fun () -> register env a);
          (fun () -> register env fa);
          (fun () -> register env fffa);
          (fun () -> register env fffffa);
         ];
-      Shuffle.seql
+      Colibri2_stdlib.Shuffle.seql
         [(fun () -> merge env a fffa);
          (fun () -> merge env fffffa a)];
   in
   assert_bool "a = f(f(f(a))) => f(f(f(f(f(a))))) = a => f(a) = a"
     (is_equal env fa a)
 
-
-
-
-let congru1 = "Uf.Congru 1 arg" >::: ["refl" >:: refl; "congru" >:: congru;
+let congru1 = "Uf.Congru 1 arg" >::: ["refl" >:: refl;"congru" >:: congru;
                                    "2level" >:: _2level; "2level'" >:: _2level';
-                                   "bigger" >:: bigger]
-
-
-let g  = Uninterp.fun2 ty "g"
-let gab = g a b
-let gaa = g a a
-let ggabb = g gab b
+                                                         "bigger" >:: bigger]
+let (!!) = SynTerm.node_of_term
+let g = Expr.Term.Const.mk "g" [] [Ty.bool;Ty.bool] Ty.bool
+let g a b = Expr.Term.apply g [] [a;b]
+let gab = g ta tb
+let gaa = g ta ta
+let ggabb = g gab tb
+let gab = !!gab
+let gaa = !!gaa
+let ggabb = !!ggabb
 
 let refl _ =
   let env = run $$ fun env -> register env gab in
@@ -166,7 +170,7 @@ let refl _ =
 
 let congru _ =
   let env = run $$ fun env ->
-      Shuffle.seql [
+      Colibri2_stdlib.Shuffle.seql [
         (fun () -> register env gab);
         (fun () -> register env gaa);
         (fun () -> register env a);
@@ -187,11 +191,11 @@ let notcongru _ =
 
 let _2level _ =
   let env = run $$ fun env ->
-      Shuffle.seql [
+      Colibri2_stdlib.Shuffle.seql [
         (fun () -> register env a);
         (fun () -> register env gab);
       ];
-      Shuffle.seql [
+      Colibri2_stdlib.Shuffle.seql [
         (fun () -> merge env gab a;);
         (fun () -> register env ggabb);
       ];
@@ -207,75 +211,72 @@ let merge env x y =
   register env y;
   merge env x y
 
-let x = Variable.fresh ty "x"
-let y = Variable.fresh ty "y"
+let x = fresht Ty.bool "x"
+let y = fresht Ty.bool "y"
 
 let altergo0 _ =
-  let h = Uninterp.fun1 ty "h" in
-  let g = Uninterp.fun2 ty "g" in
-  let gax = g a x in
+  let h = Expr.Term.Const.mk "h" [] [Ty.bool] Ty.bool in
+  let h x = Expr.Term.apply h [] [x] in
+  let g = Expr.Term.Const.mk "g" [] [Ty.bool;Ty.bool] Ty.bool in
+  let g x y = Expr.Term.apply g [] [x;y] in
+  let gax = g ta x in
   let hx = h x in
-  let gahx = g a hx in
+  let gahx = g ta hx in
   let ggahxx = g gahx x in
   let env = run $$ fun env ->
-      Shuffle.seql
-        [(fun () -> merge env hx x);
-         (fun () -> merge env gax a)];
-      register env ggahxx
+      Colibri2_stdlib.Shuffle.seql
+        [(fun () -> merge env !!hx !!x);
+         (fun () -> merge env !!gax a)];
+      register env !!ggahxx
   in
   assert_bool "h(x)=x and g(a,x)=a ->  g(g(a,h(x)),x)=a"
-    (is_equal env ggahxx a)
+    (is_equal env !!ggahxx a)
 
 let altergo1 _ =
-  let h = Uninterp.fun2 ty "h" in
-  let rec bf n = if n < 1 then a else f (bf (n-1)) in
+  let h = Expr.Term.Const.mk "h" [] [Ty.bool;Ty.bool] Ty.bool in
+  let h x y = Expr.Term.apply h [] [x;y] in
+  let rec bf n = if n < 1 then ta else f (bf (n-1)) in
   let fffa = bf 3 in
   let fffffa = bf 5 in
   let gxy = g x y in
   let ggxyy = g gxy y in
-  let hggxyya = h ggxyy a in
-  let fa = f a in
+  let hggxyya = h ggxyy ta in
+  let fa = f ta in
   let hxfa = h x fa in
   let env = run $$ fun env ->
-      Shuffle.seql
-        [(fun () -> merge env fffa a);
-         (fun () -> merge env fffffa a);
-         (fun () -> merge env gxy x)];
-      register env hggxyya;
-      register env hxfa;
+      Colibri2_stdlib.Shuffle.seql
+        [(fun () -> merge env !!fffa a);
+         (fun () -> merge env !!fffffa a);
+         (fun () -> merge env !!gxy !!x)];
+      register env !!hggxyya;
+      register env !!hxfa;
   in
   assert_bool
     "f(f(f(a)))=a and f(f(f(f(f(a)))))=a and g(x,y)=x -> \
      h(g(g(x,y),y),a)=h(x,f(a))"
-    (is_equal env hggxyya hxfa)
+    (is_equal env !!hggxyya !!hxfa)
 
 let altergo2 _ =
-  let h = Uninterp.fun2 ty "h" in
+  let h = Expr.Term.Const.mk "h" [] [Ty.bool;Ty.bool] Ty.bool in
+  let h x y = Expr.Term.apply h [] [x;y] in
   let gxy = g x y in
-  let fa = f a in
+  let fa = f ta in
   let ggxyy = g gxy y in
-  let hggxyya = h ggxyy a in
+  let hggxyya = h ggxyy ta in
   let hxfa = h x fa in
   let env = run $$ fun env ->
-      Shuffle.seql
-        [(fun () -> merge env fa a);
-         (fun () -> merge env gxy x)];
-      register env hggxyya;
-      register env hxfa;
+      Colibri2_stdlib.Shuffle.seql
+        [(fun () -> merge env !!fa a);
+         (fun () -> merge env !!gxy !!x)];
+      register env !!hggxyya;
+      register env !!hxfa;
   in
   assert_bool
     "f(a) = a -> g(x,y)=x -> h(g(g(x,y),y),a)=h(x,f(a))"
-    (is_equal env hggxyya hxfa)
+    (is_equal env !!hggxyya !!hxfa)
 
 
 
 let altergo = "Uf.altergo tests" &: [altergo0; altergo1; altergo2]
 
-let files = []
-
-let altergo2 = TestList (List.map Tests_lib.test_split files)
-*)
-
-
-let tests = OUnit2.test_list [basic;(* congru1;congru2;altergo;altergo2;*)
-                              ]
+let tests = OUnit2.test_list [basic; congru1;congru2;altergo]
diff --git a/src_colibri2/theories/LRA/LRA.ml b/src_colibri2/theories/LRA/LRA.ml
index f8491a49b..84cdd0fd2 100644
--- a/src_colibri2/theories/LRA/LRA.ml
+++ b/src_colibri2/theories/LRA/LRA.ml
@@ -491,27 +491,34 @@ let gt cl1 cl2 = lt cl2 cl1
 let ge cl1 cl2 = le cl2 cl1
 
 (** {2 Initialization} *)
-let converter d (f:Expr.Term.t) =
+let converter d (f:Expr.Term.t) res =
   let of_term t =
     let n = SynTerm.node_of_term t in
     Egraph.register d n;
     n
   in
+  let reg n =
+    Egraph.register d n;
+    Egraph.merge d res n
+  in
   match f with
+  | { descr = App({builtin = Dolmen_std.Expr.Base; _ },_,_); ty }
+    when Expr.Ty.equal ty Expr.Ty.real  ->
+    Egraph.register_decision d (ChoLRA.choice res)
   | { descr = Expr.App({builtin = Expr.Integer s},[],[]); _ } ->
-    Some (cst (Q.of_string s))
+    reg (cst (Q.of_string s))
   | { descr = Expr.App({builtin = Expr.Decimal s},[],[]); _ } ->
-    Some (cst (Q.of_string_decimal s))
+    reg (cst (Q.of_string_decimal s))
   | { descr = Expr.App({builtin = Expr.Rational s},[],[]); _ } ->
-    Some (cst (Q.of_string_decimal s))
+    reg (cst (Q.of_string_decimal s))
   | { descr = Expr.App({builtin = Expr.Add},[],[a;b]); _ } ->
-    Some (add (of_term a) (of_term b))
+    reg (add (of_term a) (of_term b))
   | { descr = Expr.App({builtin = Expr.Sub},[],[a;b]); _ } ->
-    Some (sub (of_term a) (of_term b))
+    reg (sub (of_term a) (of_term b))
   | { descr = Expr.App({builtin = Expr.Minus},[],[a]); _ } ->
-    Some (neg (of_term a))
+    reg (neg (of_term a))
   | { descr = Expr.App({builtin = Expr.Mul},[],args); _ } -> begin
-      let mult_cst c t = Some (mult_cst c (of_term t)) in
+      let mult_cst c t = reg (mult_cst c (of_term t)) in
       match args with
       | [{descr = Expr.App({builtin = Expr.Integer s; _},[],[])};arg2] ->
         mult_cst (Q.of_string s) arg2
@@ -525,23 +532,17 @@ let converter d (f:Expr.Term.t) =
         mult_cst (Q.of_string_decimal s) arg2
       | [arg2;{descr = Expr.App({builtin = Expr.Rational s; _},[],[])}] ->
         mult_cst (Q.of_string_decimal s) arg2
-      | _ -> None
+      | _ -> ()
     end
   | { descr = Expr.App({builtin = Expr.Lt},[],[arg1;arg2]); _ } ->
-    Some (lt (of_term arg1) (of_term arg2))
+    reg (lt (of_term arg1) (of_term arg2))
   | { descr = Expr.App({builtin = Expr.Leq},[],[arg1;arg2]); _ } ->
-    Some (le (of_term arg1) (of_term arg2))
+    reg (le (of_term arg1) (of_term arg2))
   | { descr = Expr.App({builtin = Expr.Gt},[],[arg1;arg2]); _ } ->
-    Some (gt (of_term arg1) (of_term arg2))
+    reg (gt (of_term arg1) (of_term arg2))
   | { descr = Expr.App({builtin = Expr.Geq},[],[arg1;arg2]); _ } ->
-    Some (ge (of_term arg1) (of_term arg2))
-  | _ -> None
-
-let decvars t n =
-  if Expr.Ty.equal (Expr.Term.ty t) Expr.Ty.real
-  then Some (ChoLRA.choice n)
-  else None
-
+    reg (ge (of_term arg1) (of_term arg2))
+  | _ -> ()
 
 let th_register env =
   RDaemonPropa.init env;
@@ -552,7 +553,6 @@ let th_register env =
     DaemonPropa.init
     env;
   SynTerm.register_converter env converter;
-  SynTerm.register_decvars env decvars;
   Demon.Fast.register_init_daemon_value
     ~name:"RealValueToDom"
     (module RealValue)
diff --git a/src_colibri2/theories/bool/boolean.ml b/src_colibri2/theories/bool/boolean.ml
index cfe2b0ead..28db037b4 100644
--- a/src_colibri2/theories/bool/boolean.ml
+++ b/src_colibri2/theories/bool/boolean.ml
@@ -411,27 +411,6 @@ let _false = node_false
 let set_true env node = set_bool env node true
 let set_false env node = set_bool env node false
 
-let converter d (f:Expr.Term.t) =
-  let of_term t =
-    let n = SynTerm.node_of_term t in
-    Egraph.register d n;
-    n
-  in
-  match f with
-  | { descr = Expr.App({builtin = Expr.Or},[],args); _ } ->
-    Some (_or (List.map of_term args))
-  | { descr = Expr.App({builtin = Expr.And},[],args); _ } ->
-    Some (_and (List.map of_term args))
-  | { descr = Expr.App({builtin = Expr.Imply},[],[arg1;arg2]); _ } ->
-    Some (gen false [of_term arg1,true;of_term arg2,false])
-  | { descr = Expr.App({builtin = Expr.Neg},[],[arg]); _ } ->
-    Some (_not (of_term arg))
-  | { descr = Expr.App({builtin = Expr.True},[],[]); _ } ->
-    Some _true
-  | { descr = Expr.App({builtin = Expr.False},[],[]); _ } ->
-    Some _false
-  | _ -> None
-
 (** {2 Choice on bool} *)
 
 module ChoBool = struct
@@ -441,7 +420,9 @@ module ChoBool = struct
 
   let choose_decision node env =
     match Egraph.get_value env dom node with
-    | Some _ -> Egraph.DecNo
+    | Some _ ->
+      Debug.dprintf2 Egraph.print_decision "[Bool] No decision for %a" Node.pp node;
+      Egraph.DecNo
     | None -> DecTodo
                 (List.map (fun v env -> make_decision env node v)
                    (Shuffle.shufflel [true;false]))
@@ -453,10 +434,34 @@ let chobool n = {
   choice = ChoBool.choose_decision n;
 }
 
-let decvars t n =
-  if Ty.equal (Expr.Term.ty t) Dolmen_std.Expr.Ty.bool
-  then Some (chobool n)
-  else None
+
+let converter d (f:Expr.Term.t) res =
+  let of_term t =
+    let n = SynTerm.node_of_term t in
+    Egraph.register d n;
+    n
+  in
+  let reg n =
+    Egraph.register d n;
+    Egraph.merge d res n
+  in
+  match f with
+  | { descr = App({builtin = Dolmen_std.Expr.Base; _ },_,_); ty }
+    when Expr.Ty.equal ty Expr.Ty.bool  ->
+    Egraph.register_decision d (chobool res)
+  | { descr = Expr.App({builtin = Expr.Or},[],args); _ } ->
+    reg (_or (List.map of_term args))
+  | { descr = Expr.App({builtin = Expr.And},[],args); _ } ->
+    reg (_and (List.map of_term args))
+  | { descr = Expr.App({builtin = Expr.Imply},[],[arg1;arg2]); _ } ->
+    reg (gen false [of_term arg1,true;of_term arg2,false])
+  | { descr = Expr.App({builtin = Expr.Neg},[],[arg]); _ } ->
+    reg (_not (of_term arg))
+  | { descr = Expr.App({builtin = Expr.True},[],[]); _ } ->
+    reg _true
+  | { descr = Expr.App({builtin = Expr.False},[],[]); _ } ->
+    reg _false
+  | _ -> ()
 
 let th_register env =
   RDaemonPropaNot.init env;
@@ -467,7 +472,6 @@ let th_register env =
   Egraph.register env node_true;
   Egraph.register env node_false;
   SynTerm.register_converter env converter;
-  SynTerm.register_decvars env decvars;
   ()
 
 (** {2 Interpretations} *)
diff --git a/src_colibri2/theories/bool/equality.ml b/src_colibri2/theories/bool/equality.ml
index e0158476b..948616fb0 100644
--- a/src_colibri2/theories/bool/equality.ml
+++ b/src_colibri2/theories/bool/equality.ml
@@ -607,22 +607,28 @@ let () =
     )
 
 
-let converter d (t:Expr.Term.t) =
+let converter d (t:Expr.Term.t) res =
   let of_term t =
     let n = SynTerm.node_of_term t in
     Egraph.register d n;
     n
   in
+  let reg n =
+    Egraph.register d n;
+    Egraph.merge d res n
+  in
   match t with
   | { descr = Expr.App({builtin = Expr.Equal},[_],l); _ } ->
-    Some (equality (List.map of_term l))
+    reg (equality (List.map of_term l))
   | { descr = Expr.App({builtin = Expr.Equiv},[_],[a;b]); _ } ->
-    Some (equality [of_term a;of_term b])
+    reg (equality [of_term a;of_term b])
   | { descr = Expr.App({builtin = Expr.Distinct},[_],args); _ } ->
-    Some (disequality (List.map of_term args))
+    reg (disequality (List.map of_term args))
   | { descr = Expr.App({builtin = Expr.Ite},[_],[c;a;b]); _ } ->
-    Some (ite (of_term c) (of_term a) (of_term b))
-  | _ -> None
+    reg (ite (of_term c) (of_term a) (of_term b))
+  | { descr = Expr.App({builtin = Expr.Xor},[],[a;b]); _ } ->
+    reg (disequality ([of_term a;of_term b]))
+  | _ -> ()
 
 let th_register env =
   RDaemonPropa.init env;
diff --git a/src_colibri2/theories/bool/uninterp.ml b/src_colibri2/theories/bool/uninterp.ml
index ddf336ff5..e9f4cba9d 100644
--- a/src_colibri2/theories/bool/uninterp.ml
+++ b/src_colibri2/theories/bool/uninterp.ml
@@ -160,7 +160,7 @@ module DaemonInit = struct
           Debug.dprintf2 debug "[Uninterp] @[init %a@]" Th.pp v;
           if DaemonPropa.is_unborn d nodesem then
             match v with
-            | Fun _ -> assert false (** TODO *)
+            | Fun _ -> ()
             | App(f,g) ->
               Egraph.register d f; Egraph.register d g;
               let f' = Egraph.find d f in
@@ -181,20 +181,19 @@ end
 
 module RDaemonInit = Demon.Key.Register(DaemonInit)
 
-let converter d (t:Term.t) =
+let converter d (t:Term.t) res =
   let of_term t =
     let n = SynTerm.node_of_term t in
     Egraph.register d n;
     n
   in
-  let node = match t with
+  match t with
     | { descr = App({builtin = Dolmen_std.Expr.Base; _ } as f,tyl,((_::_) as l)); _ } ->
       let f = ThE.node (ThE.index (Fun (f,tyl))) in
       let l = List.map of_term l in
-      Some (appl f l)
-    | _ -> None
-  in
-      node
+      let l,a = Lists.chop_last l in
+      Egraph.set_thterm d res (ThE.thterm (ThE.index (App(appl f l,a))))
+    | _ -> ()
 
 let th_register env =
   RDaemonPropa.init env;
diff --git a/src_colibri2/theories/bool/uninterp.mli b/src_colibri2/theories/bool/uninterp.mli
index 0b1398ace..f4befa96f 100644
--- a/src_colibri2/theories/bool/uninterp.mli
+++ b/src_colibri2/theories/bool/uninterp.mli
@@ -31,8 +31,8 @@ val sem: Th.t ThTermKind.t
 
 (* val fun1 :
  *   Ty.t -> string ->
- *   (Node.t -> Node.t)
- * val fun2 :
+ *   (Node.t -> Node.t) *)
+(* val fun2 :
  *   Ty.t -> string ->
  *   (Node.t -> Node.t -> Node.t)
  * val fun3 :
@@ -43,9 +43,9 @@ val sem: Th.t ThTermKind.t
  *   (Node.t -> Node.t -> Node.t -> Node.t -> Node.t)
  * val fun5 :
  *   Ty.t -> string ->
- *   (Node.t -> Node.t -> Node.t -> Node.t -> Node.t -> Node.t)
- * 
- * val fresh_fun: result:Ty.t -> arity:int -> string -> Node.t *)
+ *   (Node.t -> Node.t -> Node.t -> Node.t -> Node.t -> Node.t) *)
+
+(* val fresh_fun: result:Ty.t -> arity:int -> string -> Node.t *)
 
 (* val app_fun: Node.t -> Node.t list -> Node.t *)
 
-- 
GitLab