diff --git a/colibri2/core/colibri2_core.mli b/colibri2/core/colibri2_core.mli
index b3cca4eec2d3270d4ba7723b6a2fe7350dd1cb1e..54edf8848d5b3eb8f632d7044fa6bf95b1aab817 100644
--- a/colibri2/core/colibri2_core.mli
+++ b/colibri2/core/colibri2_core.mli
@@ -769,6 +769,9 @@ module Datastructure : sig
     val change : ('a option -> 'a option) -> 'a t -> _ Egraph.t -> key -> unit
     val iter : f:(key -> 'a -> unit) -> 'a t -> _ Egraph.t -> unit
     val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> _ Egraph.t -> 'b -> 'b
+
+    val filter_map_inplace :
+      (key -> 'a -> 'a option) -> 'a t -> _ Egraph.t -> unit
   end
 
   module Hashtbl (S : Colibri2_popop_lib.Popop_stdlib.Datatype) :
diff --git a/colibri2/core/datastructure.ml b/colibri2/core/datastructure.ml
index cdddee3d52d867b3129b547b3f5cefa81bb0d478..155a9298f898fe4f42558b4964d106989dad7a16 100644
--- a/colibri2/core/datastructure.ml
+++ b/colibri2/core/datastructure.ml
@@ -32,6 +32,7 @@ module type Sig =  sig
   val change : ('a option -> 'a option) -> 'a t -> _ Egraph.t -> key -> unit
   val iter :  f:(key -> 'a -> unit) -> 'a t -> _ Egraph.t -> unit
   val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> _ Egraph.t -> 'b -> 'b
+  val filter_map_inplace: (key -> 'a -> 'a option) -> 'a t -> _ Egraph.t -> unit
 end
 
 module Hashtbl(S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Sig with type key := S.t = struct
@@ -112,6 +113,13 @@ module Hashtbl(S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Sig with type key :
         | Some r -> f k r acc
     ) h acc
 
+  let filter_map_inplace (f : S.t -> 'a -> 'a option)
+    (t : 'a option Context.Ref.t S.H.t Env.Unsaved.t) (d : _ Egraph.t) =
+  let h = Egraph.get_unsaved_env d t in
+  S.H.iter
+    (fun k _ -> change (function Some v -> f k v | None -> None) t d k)
+    h
+
 end
 
 module type Sig2 =  sig
diff --git a/colibri2/core/datastructure.mli b/colibri2/core/datastructure.mli
index 0f7320de07c6b1497af4a4742eddca5ee6c025bb..323a3e53dab8c204832731f9ec00cf65ab8a00fa 100644
--- a/colibri2/core/datastructure.mli
+++ b/colibri2/core/datastructure.mli
@@ -34,6 +34,7 @@ module type Sig =  sig
   val change : ('a option -> 'a option) -> 'a t -> _ Egraph.t -> key -> unit
   val iter :  f:(key -> 'a -> unit) -> 'a t -> _ Egraph.t -> unit
   val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> _ Egraph.t -> 'b -> 'b
+  val filter_map_inplace: (key -> 'a -> 'a option) -> 'a t -> _ Egraph.t -> unit
 end
 
 module Hashtbl (S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Sig with type key := S.t
diff --git a/colibri2/theories/array/Array_Id_dom.mli b/colibri2/theories/array/Array_Id_dom.mli
index 5c580537e680ae6ec1c16c4dfbb4362c1e0de068..438f2ca30fc18e2b273e75c03e0bf2f4bbc8f44c 100644
--- a/colibri2/theories/array/Array_Id_dom.mli
+++ b/colibri2/theories/array/Array_Id_dom.mli
@@ -19,13 +19,4 @@
 (*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
 (*************************************************************************)
 
-val register_merge_hook :
-  Egraph.wt ->
-  (Egraph.wt -> Node.t * int -> Node.t * int -> bool -> unit) ->
-  unit
-
-val register_new_id_hook :
-  Egraph.wt -> (Egraph.wt -> int -> Node.t -> unit) -> unit
-
-val set_id : Egraph.wt -> Node.t -> unit
-val get_id : Egraph.wt -> Node.t -> int
+include Common.IdDomSig
diff --git a/colibri2/theories/array/Index_Id_dom.mli b/colibri2/theories/array/Index_Id_dom.mli
index 5c580537e680ae6ec1c16c4dfbb4362c1e0de068..438f2ca30fc18e2b273e75c03e0bf2f4bbc8f44c 100644
--- a/colibri2/theories/array/Index_Id_dom.mli
+++ b/colibri2/theories/array/Index_Id_dom.mli
@@ -19,13 +19,4 @@
 (*  for more details (enclosed in the file licenses/LGPLv2.1).           *)
 (*************************************************************************)
 
-val register_merge_hook :
-  Egraph.wt ->
-  (Egraph.wt -> Node.t * int -> Node.t * int -> bool -> unit) ->
-  unit
-
-val register_new_id_hook :
-  Egraph.wt -> (Egraph.wt -> int -> Node.t -> unit) -> unit
-
-val set_id : Egraph.wt -> Node.t -> unit
-val get_id : Egraph.wt -> Node.t -> int
+include Common.IdDomSig
diff --git a/colibri2/theories/array/RWRules.ml b/colibri2/theories/array/RWRules.ml
index a7a60b5054a68dc6d833c4ef78955cefee5b7354..ab7ced4ba272617b05a589fec742bce01d7af3fa 100644
--- a/colibri2/theories/array/RWRules.ml
+++ b/colibri2/theories/array/RWRules.ml
@@ -316,21 +316,21 @@ let new_array =
     (* Extensionality rule ext: a, b ⇒ (a = b) ⋁ (a[k] ≠ b[k]) *)
     let agty = Ground.Ty.array ind_gty val_gty in
     (if not (Options.get env restrict_ext) then
-      match GHT.find_opt db_gty env agty with
-      | Some s ->
-          Ground.S.iter
-            (fun f2 ->
-              let a = Ground.node f in
-              let b = Ground.node f2 in
-              let adist = mk_distinct_arrays env a b ind_gty val_gty in
-              let aeq = mk_eq env a b (Ground.Ty.array ind_gty val_gty) in
-              let n = mk_or env adist aeq in
-              Debug.dprintf4 debug "Found ext with %a and %a" Ground.pp f2
-                Ground.pp f;
-              Egraph.register env n;
-              Boolean.set_true env n)
-            s
-      | None -> ());
+     match GHT.find_opt db_gty env agty with
+     | Some s ->
+         Ground.S.iter
+           (fun f2 ->
+             let a = Ground.node f in
+             let b = Ground.node f2 in
+             let adist = mk_distinct_arrays env a b ind_gty val_gty in
+             let aeq = mk_eq env a b (Ground.Ty.array ind_gty val_gty) in
+             let n = mk_or env adist aeq in
+             Debug.dprintf4 debug "Found ext with %a and %a" Ground.pp f2
+               Ground.pp f;
+             Egraph.register env n;
+             Boolean.set_true env n)
+           s
+     | None -> ());
     GHT.change
       (function
         | Some s -> Some (Ground.S.add f s)
diff --git a/colibri2/theories/array/WEGraph.ml b/colibri2/theories/array/WEGraph.ml
index e1a76711e284efdf1ecd91e7b192bc85ec2372a9..120ff94321549cddbd40b819e66031e781a8db60 100644
--- a/colibri2/theories/array/WEGraph.ml
+++ b/colibri2/theories/array/WEGraph.ml
@@ -38,6 +38,16 @@ module VHT = MkIHT (struct
   let name = "wegraph_indices"
 end)
 
+let pp_eid env fmt i =
+  match EHT.find_opt env i with
+  | Some n -> Format.fprintf fmt "%a{id = %d}" Node.pp n i
+  | None -> Format.fprintf fmt "Not_found{id = %d}" i
+
+let pp_vid env fmt i =
+  match VHT.find_opt env i with
+  | Some n -> Format.fprintf fmt "%a{id = %d}" Node.pp n i
+  | None -> Format.fprintf fmt "Not_found{id = %d}" i
+
 module Vertex = struct
   let sort (a, b) = if DInt.compare a b <= 0 then (a, b) else (b, a)
 
@@ -157,17 +167,106 @@ module WEG = struct
         Fmt.pf fmt "%d{%a;%a}" id (DInt.M.pp DInt.S.pp) m1 (DInt.M.pp DInt.pp)
           m2
     | None -> Fmt.pf fmt "%d{}" id
+
+  let width_first_fold env curr ~f acc =
+    let rec aux env ?(seen = DInt.S.empty) ~curr f acc =
+      let tosee, nseen, nacc =
+        DInt.M.fold
+          (fun next next_ind (tosee, seen, acc) ->
+            if DInt.S.mem next seen then (tosee, seen, acc)
+            else
+              let b, nacc = f env ~curr ~next_ind ~next acc in
+              let nseen = DInt.S.add next seen in
+              if b then (DInt.S.add next tosee, nseen, nacc)
+              else (tosee, nseen, nacc))
+          (snd (find env curr))
+          (DInt.S.empty, DInt.S.add curr seen, acc)
+      in
+      DInt.S.fold
+        (fun curr (seen, acc) -> aux env ~seen ~curr f acc)
+        tosee (nseen, nacc)
+    in
+    snd (aux env ~curr f acc)
+
+  let breadth_first_fold env curr ~f acc =
+    let rec aux env ?(seen = DInt.S.empty) ~curr f acc =
+      DInt.M.fold
+        (fun next next_ind (seen, acc) ->
+          if DInt.S.mem next seen then (seen, acc)
+          else
+            let b, nacc = f env ~curr ~next_ind ~next acc in
+            let nseen = DInt.S.add next seen in
+            if b then aux env ~seen:nseen ~curr:next f nacc else (nseen, nacc))
+        (snd (find env curr))
+        (DInt.S.add curr seen, acc)
+    in
+    snd (aux env ~curr f acc)
 end
 
-let pp_eid env fmt i =
-  match EHT.find_opt env i with
-  | Some n -> Format.fprintf fmt "%a{id = %d}" Node.pp n i
-  | None -> Format.fprintf fmt "Not_found{id = %d}" i
+module KnownValues = struct
+  type t = { value : Node.t; propag : DInt.S.t; nopropag : DInt.S.t }
+  [@@deriving show]
 
-let pp_vid env fmt i =
-  match VHT.find_opt env i with
-  | Some n -> Format.fprintf fmt "%a{id = %d}" Node.pp n i
-  | None -> Format.fprintf fmt "Not_found{id = %d}" i
+  module HT = MkIHT (struct
+    type nonrec t = t DInt.M.t
+
+    let pp = DInt.M.pp pp
+    let name = "KnownValues.HT"
+  end)
+
+  let add env array_id ind_id value =
+    let rec aux env ?(seen = DInt.S.empty) array_id ind_id value =
+      if
+        match HT.find env array_id with
+        | exception Not_found -> true
+        | m -> (
+            match DInt.M.find ind_id m with
+            | exception Not_found -> true
+            | { value = v; _ } -> not (Egraph.is_equal env v value))
+      then (
+        let ind = VHT.find env ind_id in
+        let propag, nopropag, seen =
+          DInt.M.fold
+            (fun next next_ind (propag, nopropag, seen) ->
+              if DInt.S.mem next seen then (propag, nopropag, seen)
+              else if Equality.is_disequal env (VHT.find env next_ind) ind then
+                (DInt.S.add next propag, nopropag, DInt.S.add next seen)
+              else (propag, DInt.S.add next nopropag, DInt.S.add next seen))
+            (snd (WEG.find env array_id))
+            (DInt.S.empty, DInt.S.empty, DInt.S.add array_id seen)
+        in
+        HT.change env array_id ~f:(function
+          | None -> Some (DInt.M.singleton ind_id { value; propag; nopropag })
+          | Some m ->
+              Some
+                (DInt.M.change
+                   (function
+                     | None -> Some { value; propag; nopropag }
+                     | Some { value = fvalue; propag = p1; nopropag = p2 } ->
+                         let _, val_gty =
+                           get_array_gty_args env (EHT.find env array_id)
+                         in
+                         let eq = mk_eq env value fvalue val_gty in
+                         Egraph.register env eq;
+                         Boolean.set_true env eq;
+                         (* ? *)
+                         let propag = DInt.S.union p1 propag in
+                         let nopropag =
+                           DInt.S.filter
+                             (fun i -> not (DInt.S.mem i propag))
+                             (DInt.S.union p2 nopropag)
+                         in
+                         Some { value; propag; nopropag })
+                   ind_id m));
+        ();
+        DInt.S.fold
+          (fun a_id seen ->
+            aux env ~seen:(DInt.S.add a_id seen) a_id ind_id value)
+          propag seen)
+      else seen
+    in
+    ignore (aux env array_id ind_id value)
+end
 
 let s_remove_opt s_opt v =
   match s_opt with
@@ -321,9 +420,9 @@ let are_k_neibnours env aid bid iid =
   match WEG.find_opt env aid with
   | None -> false
   | Some (_, m2) -> (
-      match DInt.M.find_opt iid m2 with
+      match DInt.M.find_opt bid m2 with
       | None -> false
-      | Some bid' -> bid = bid')
+      | Some iid' -> iid = iid')
 
 let add_edge env aid bid iid =
   (* when adding a node dest as a neighbour to a node src, dest is also added
@@ -509,11 +608,10 @@ let update env a b ind _v =
   let aid = Array_Id_dom.get_id env a in
   let bid = Array_Id_dom.get_id env b in
   let iid = Index_Id_dom.get_id env ind in
-  Debug.dprintf9 debug "WEGraph.update: %a(%d) %a(%d) %a(%d)" Node.pp a aid
-    Node.pp b bid Node.pp ind iid;
   Debug.dprintf6 debug "WEGraph.update: %a %a %a" (pp_eid env) aid (pp_eid env)
     bid (pp_vid env) iid;
   add_edge env aid bid iid;
+  KnownValues.add env aid iid _v;
   if Debug.test_flag WEG.wegraph_opt then
     WEG.pp_dot_wegraph
       ~msg:
diff --git a/colibri2/theories/array/array.ml b/colibri2/theories/array/array.ml
index 486f7e4da2f325e88b1ded5fbbc33762b8838df4..c975e4fdf899386ec774bef75d53a16857d8fac4 100644
--- a/colibri2/theories/array/array.ml
+++ b/colibri2/theories/array/array.ml
@@ -74,6 +74,7 @@ let converter env (f : Ground.t) =
             let gty = Ground.Ty.convert subst (List.nth arg_tys i) in
             match gty with
             | { app = { builtin = Expr.Array; _ }; _ } ->
+                Array_Id_dom.set_id env n;
                 Ground.add_ty env n gty;
                 Foreign_dom.set_dom env gty n IsForeign
             | _ -> ())
@@ -91,9 +92,9 @@ let converter env (f : Ground.t) =
       add_array_gty env a ind_gty val_gty;
       Array_Id_dom.set_id env a;
       (* update of the Foreign domain *)
-      if Options.get env restrict_ext && ind_gty.app.builtin == Expr.Array then (
-        Ground.add_ty env i ind_gty;
-        Foreign_dom.set_dom env (Ground.Ty.array ind_gty val_gty) i IsForeign);
+      if Options.get env restrict_ext && ind_gty.app.builtin == Expr.Array then
+        (* id and ground type are set during registration *)
+        Foreign_dom.set_dom env (Ground.Ty.array ind_gty val_gty) i IsForeign;
       if Options.get env extended_comb then (
         (* when a new read is encountered, check if map⇑ can be applied *)
         Array_dom.add_read env a i;
@@ -238,7 +239,6 @@ let init env =
       Foreign_dom.register_hook_new_foreign_array env (apply_res_ext_2_2 env))
     else (
       (* (a = b) ≡ false |> (a[k] ≠ b[k]) *)
-      (* TODO: Are a and b always of the same type? *)
       Equality.register_hook_new_disequality env (apply_res_ext_1_1 env);
       (* a, b, {a,b} ⊆ foreign |> (a = b) ⋁ (a[k] ≠ b[k]) *)
       Foreign_dom.register_hook_new_foreign_array env (apply_res_ext_2_1 env));
diff --git a/colibri2/theories/array/common.ml b/colibri2/theories/array/common.ml
index e08f6fe7dccf3e644cf2706097349c42bd0ca82e..b7575ec3d52e732ccff138a849934792043a6c4e 100644
--- a/colibri2/theories/array/common.ml
+++ b/colibri2/theories/array/common.ml
@@ -126,7 +126,6 @@ let array_gty_args : Ground.Ty.t -> Ground.Ty.t * Ground.Ty.t = function
   | ty -> failwith (Fmt.str "'%a' is not an array ground type!" Ground.Ty.pp ty)
 
 let get_node_ty env n =
-  (* TODO: fix somehow *)
   match Ground.Ty.S.elements (Ground.tys env n) with
   | h :: _ -> h
   | [] -> failwith (Fmt.str "The type of the node %a was not set" Node.pp n)
@@ -348,6 +347,7 @@ module type HTS = sig
   val remove : Egraph.wt -> int -> unit
   val iter : f:(int -> t -> unit) -> Egraph.wt -> unit
   val fold : (int -> t -> 'a -> 'a) -> Egraph.wt -> 'a -> 'a
+  val filter_map_inplace : (int -> t -> t option) -> 'a Egraph.t -> unit
 end
 
 module MkIHT (V : sig
@@ -366,14 +366,27 @@ end) : HTS with type t = V.t = struct
   let remove (env : Egraph.wt) = HT.remove db env
   let iter = HT.iter db
   let fold f env acc = HT.fold f db env acc
+  let filter_map_inplace f env = HT.filter_map_inplace f db env
+end
+
+module type IdDomSig = sig
+  val register_merge_hook :
+    Egraph.wt ->
+    (Egraph.wt -> Node.t * int -> Node.t * int -> bool -> unit) ->
+    unit
+
+  val register_new_id_hook :
+    Egraph.wt -> (Egraph.wt -> int -> Node.t -> unit) -> unit
+
+  val set_id : Egraph.wt -> Node.t -> unit
+  val get_id : Egraph.wt -> Node.t -> int
 end
 
 module MkIdDom (N : sig
   val n1 : string
   val n2 : string
   val n3 : string
-end) =
-struct
+end) : IdDomSig = struct
   let merge_hooks = Datastructure.Push.create Fmt.nop N.n1
 
   let register_merge_hook env (f : Egraph.wt -> 'a -> 'a -> bool -> unit) =
@@ -424,28 +437,18 @@ struct
       match Egraph.get_dom env D.key n with
       | None ->
           incr id_counter;
-          Debug.dprintf1 debug "set_id:\n%s@."
-            (Printexc.raw_backtrace_to_string @@ Printexc.get_callstack 1000);
           Debug.dprintf4 debug "set_id(%s) of %a: none -> %d" N.n2 Node.pp n
             !id_counter;
           D.set_dom env n !id_counter;
           Datastructure.Push.iter new_id_hooks env ~f:(fun new_id_hook ->
-              Debug.dprintf4 debug "apply new_id_hooks(%s) on %d %a@." N.n2
-                (Datastructure.Push.length new_id_hooks env)
-                Node.pp n;
               new_id_hook env !id_counter n)
-      | Some id -> Debug.dprintf3 debug "set_id of %a: %d" Node.pp n id
+      | Some id -> Debug.dprintf4 debug "set_id(%s) of %a: %d" N.n2 Node.pp n id
     in
     let get_id env n =
-      (* is this a good idea?
-         TODO: Find out why it crashes occasionally with
-         restricted extensionality *)
       match Egraph.get_dom env D.key n with
       | Some id -> id
       | None ->
-          Debug.dprintf3 debug "get_id(%s) of %a: No Id found!" N.n2 Node.pp n;
-          set_id env n;
-          !id_counter
+          failwith (Fmt.str "get_id(%s) of %a: No Id found!" N.n2 Node.pp n)
     in
     (set_id, get_id)
 end
diff --git a/colibri2/theories/array/common.mli b/colibri2/theories/array/common.mli
index fe0f8e472647d496075284351805c57f6a9bcf7b..bd4609c9b44ae5008ab001affb877958ae2b79a1 100644
--- a/colibri2/theories/array/common.mli
+++ b/colibri2/theories/array/common.mli
@@ -144,6 +144,7 @@ module type HTS = sig
   val remove : Egraph.wt -> int -> unit
   val iter : f:(int -> t -> unit) -> Egraph.wt -> unit
   val fold : (int -> t -> 'a -> 'a) -> Egraph.wt -> 'a -> 'a
+  val filter_map_inplace : (int -> t -> t option) -> 'a Egraph.t -> unit
 end
 
 module MkIHT (V : sig
@@ -153,21 +154,21 @@ module MkIHT (V : sig
   val name : string
 end) : HTS with type t = V.t
 
-module MkIdDom (_ : sig
-  val n1 : string
-  val n2 : string
-  val n3 : string
-end) : sig
+module type IdDomSig = sig
   val register_merge_hook :
     Egraph.wt ->
     (Egraph.wt -> Node.t * int -> Node.t * int -> bool -> unit) ->
     unit
 
-  module D : Dom.DS with type t = int
-
   val register_new_id_hook :
     Egraph.wt -> (Egraph.wt -> int -> Node.t -> unit) -> unit
 
   val set_id : Egraph.wt -> Node.t -> unit
   val get_id : Egraph.wt -> Node.t -> int
 end
+
+module MkIdDom (_ : sig
+  val n1 : string
+  val n2 : string
+  val n3 : string
+end) : IdDomSig