diff --git a/src/transform/intro_projections_counterexmp.ml b/src/transform/intro_projections_counterexmp.ml
index ea4ddf6c0470d485202292a48aba0d89fdb98aa1..3f94ff1dee08bbb4a20a8ea7d5b14df13c8caea6 100644
--- a/src/transform/intro_projections_counterexmp.ml
+++ b/src/transform/intro_projections_counterexmp.ml
@@ -64,6 +64,178 @@ let intro_const_equal_to_term
   (* Return the declaration of new constant and the axiom *)
   decl_new_constant::decl_axiom::[]
 
+let introduce_constant ls t_rhs proj_name =
+  (* introduce new constant c and axiom stating c = t_rhs  *)
+  let const_label = Slab.add model_label ls.ls_name.id_label in
+  let const_label = append_to_model_element_name ~labels:const_label ~to_append:proj_name in
+  let const_loc = Opt.get ls.ls_name.id_loc in
+  let const_name = ls.ls_name.id_string^"_proj_constant_"^proj_name in
+  let axiom_name = ls.ls_name.id_string^"_proj_axiom_"^proj_name in
+  let id_new = Ident.id_user ~label:const_label const_name const_loc in
+  intro_const_equal_to_term ~term:t_rhs ~id_new:id_new ~axiom_name
+
+let get_record_field_suffix projection =
+  try
+    get_model_element_name ~labels:projection.ls_name.id_label
+  with Not_found -> ""
+
+(* Takes a type of map and returns the list of successive type in the map
+   together with the return type. *)
+let detect_map_types ty =
+  let rec detect_map_types t_froms ty =
+    match ty.ty_node with
+    | Tyapp (ts, [t_from; t_to]) when ts.ts_name.id_string = "map" ->
+        detect_map_types ((ts, t_from) :: t_froms) t_to
+    | _ -> (List.rev t_froms, ty)
+  in
+  detect_map_types [] ty
+
+(* Returns the return type of the last functions of list proj_functions *)
+let rec last_type proj_functions =
+  match proj_functions with
+  | [] -> failwith "Should not happen. Please report."
+  | [pf] -> (Opt.get pf.ls_value)
+  | _pf1 :: pf2 :: tl -> last_type (pf2 :: tl)
+
+(* Recreate type of the composition of projection functions *)
+let recreate_types ty_froms proj_functions =
+  let rec rec_types ty_froms =
+  match ty_froms with
+  | [(ts, ty_from)] ->
+      ty_app ts [ty_from; last_type proj_functions]
+  | (ts, ty_from) :: tl ->
+      let ty_to = rec_types tl in
+      ty_app ts [ty_from; ty_to]
+  | [] -> failwith "Not a correct type application. Please report."
+  in
+  rec_types ty_froms
+
+(* Returns a list of pairs of vsymbol for array axiom definition *)
+let rec create_index_list ty_froms =
+  match ty_froms with
+  | ty :: tl ->
+      let var_i : Term.vsymbol = Term.create_vsymbol (Ident.id_fresh "x") ty in
+      let i : Term.term = Term.t_var var_i in
+      let l = create_index_list tl in
+      (var_i, i) :: l
+  | [] -> []
+
+(* Applying array to indices: term[i][j][k]....[w]...  *)
+let rec recreate_term_applications select term var_l =
+  match var_l with
+  | i :: tl ->
+      let term_x = Term.t_app_infer select [term;i] in
+      recreate_term_applications select term_x tl
+  | [] -> term
+
+(* Generate the list of projections possible for a term where a possible projection is
+   a list of functions that projects the result. *)
+let rec list_projection_until_base_type map_projs t_to : Term.lsymbol list list =
+  let proj_functions = try Some (Ty.Mty.find t_to map_projs)
+  with | Not_found -> None in
+  match proj_functions with
+  | None -> [[]]
+  | Some lpfs ->
+    let lpfs_rec = List.map (fun x -> List.map (fun l -> x :: l)
+        (list_projection_until_base_type map_projs (Opt.get x.ls_value)))
+        lpfs in
+    List.fold_left (fun acc x -> acc @ x) [] lpfs_rec
+
+let rec projections_for_term ls term proj_name applied_projs env map_projs =
+  (* Return declarations for projections of the term.
+     Parameter proj_name is the name of the projection
+     Parameter applied_proj_f is a set of projection functions already applied to the term *)
+  match (Opt.get term.t_ty).ty_node with
+  | Tyapp (ts, [_t_from; _t_to]) when ts.ts_name.id_string = "map" -> begin
+      let (ty_froms, t_to) = detect_map_types (Opt.get term.t_ty) in
+      let pfs =
+        list_projection_until_base_type map_projs t_to
+      in
+      match pfs with
+      | [] | [[]]->
+         (* There is no projection function for the term
+	    -> the projection consists of definition of constant c and axiom  c = p
+	  *)
+	  introduce_constant ls term proj_name
+      | _ ->
+          List.fold_left
+	    (fun ldecls proj_function ->
+	      (* Newly introduced map with projected indices *)
+	      let proj_map_name = ls.ls_name.id_string^"_proj_arr_constant"^proj_name in
+	      let proj_map_id = Ident.id_fresh proj_map_name in
+	      let proj_map_ty = Some (recreate_types ty_froms proj_function) in
+	      let proj_map_ls = Term.create_lsymbol proj_map_id [] proj_map_ty in
+	      let proj_map_decl = Decl.create_param_decl proj_map_ls in
+	      let proj_map_t = Term.t_app proj_map_ls [] proj_map_ty in
+
+              (* The quantified variables i's *)
+              let var_l = create_index_list (List.map snd ty_froms) in
+
+	      let map_theory = Env.read_theory env ["map"] "Map" in
+	      let select = (ns_find_ls map_theory.th_export ["get"]) in
+
+              (* Indices: proj_map[i], term[i]  *)
+	      let term_idx_comp_app = recreate_term_applications select term (List.map snd var_l) in
+              let proj_map_idx_comp_app = recreate_term_applications select proj_map_t (List.map snd var_l) in
+
+	      (* Formula f: forall i : t_from. proj_map[i] = pf_1(term[i]) *)
+	      let term_idx_projected_t : Term.term =
+                List.fold_left (fun term_idx_comp_app proj_function ->
+                 Term.t_app proj_function [term_idx_comp_app] proj_function.ls_value)
+                   term_idx_comp_app proj_function in
+              let fla_to_be_quant = Term.t_equ proj_map_idx_comp_app term_idx_projected_t in
+              let fla_axiom = Term.t_forall_close (List.map fst var_l) [] fla_to_be_quant in
+
+	      (* Axiom about projection: axiom f *)
+	      let proj_axiom_name = ls.ls_name.id_string^"_proj_arr_axiom"^proj_name in
+	      let proj_axiom_id = Decl.create_prsymbol (Ident.id_fresh proj_axiom_name) in
+	      let proj_axiom = Decl.create_prop_decl Decl.Paxiom proj_axiom_id fla_axiom in
+
+	      (* Recursively call projecting of the term proj_map -> proj_map_projections  *)
+	      let proj_name = proj_name^(List.fold_left
+                 (fun acc x -> acc ^ get_record_field_suffix x)
+                    "" proj_function) in
+	      (*let applied_projs = Term.Sls.add proj_function applied_projs in*)
+	      let proj_map_projections_defs =
+                introduce_constant ls proj_map_t proj_name in
+              List.append ldecls (
+                List.append [proj_map_decl;proj_axiom] proj_map_projections_defs)
+            )
+	    []
+	    pfs
+  end
+
+  | _ ->
+   (* Non-map case *)
+      (* Find all projection functions for the term *)
+      let pfs = try (Some (Ty.Mty.find (Opt.get term.t_ty) map_projs)) with
+      | Not_found -> None in
+      match pfs with
+      | None ->
+          (* There is no projection function for the term
+	    -> the projection consists of definition of constant c and axiom  c = p
+	  *)
+	  introduce_constant ls term proj_name
+      | Some pfs ->
+	(* Collect declarations for projections f of the form
+	   f = pf_n .. pf_1 where pf_1 is an element of pfs *)
+	List.fold_left
+	  (fun l pf_1 ->
+	    if Term.Sls.mem pf_1 applied_projs then
+	      (* Do not apply the same projection twice *)
+	      introduce_constant ls term proj_name
+	    else
+	      let t_applied = Term.t_app pf_1 [term] pf_1.ls_value in
+	      let proj_name = proj_name^(get_record_field_suffix pf_1) in
+	      let applied_projs = Term.Sls.add pf_1 applied_projs in
+	      (* Return declarations for projections of t_applied = pf_1 term *)
+	      let t_applied_projs =
+                 projections_for_term ls t_applied proj_name applied_projs env map_projs in
+	      List.append l t_applied_projs
+	  )
+	  []
+	  pfs
+
 let intro_proj_for_ls env map_projs ls_projected =
   (* Returns list of declarations for projection of ls_projected
      if it has a  label "model_projected", otherwise returns [].
@@ -88,141 +260,10 @@ let intro_proj_for_ls env map_projs ls_projected =
     match ls_projected.ls_value with
     | None -> []
     | Some _ ->
-      let introduce_constant t_rhs proj_name =
-	  (* introduce new constant c and axiom stating c = t_rhs  *)
-	  let const_label = Slab.add model_label ls_projected.ls_name.id_label in
-	  let const_label = append_to_model_element_name ~labels:const_label ~to_append:proj_name in
-	  let const_loc = Opt.get ls_projected.ls_name.id_loc in
-	  let const_name = ls_projected.ls_name.id_string^"_proj_constant_"^proj_name in
-	  let axiom_name = ls_projected.ls_name.id_string^"_proj_axiom_"^proj_name in
-	  let id_new = Ident.id_user ~label:const_label const_name const_loc in
-	  intro_const_equal_to_term ~term:t_rhs ~id_new:id_new ~axiom_name in
-
-      let rec projections_for_term term proj_name applied_projs map_projs =
-	(* Return declarations for projections of the term.
-	   Parameter proj_name is the name of the projection
-	   Parameter applied_proj_f is a set of projection functions already applied to the term *)
-
-	let get_record_field_suffix projection =
-	  try
-	    get_model_element_name ~labels:projection.ls_name.id_label
-	  with Not_found -> "" in
-
-	match (Opt.get term.t_ty).ty_node with
-	| Tyapp (ts, [t_from; t_to]) when ts.ts_name.id_string = "map" -> begin
-	  (* If the term is of map type, check whether t_to (and t_from - to be done later) can be projected.
-	     If it is so, for each projection pf_1 from t_to to t_res introduce new map with the elemements
-	     equal to projections of the source map:
-
-	     const proj_map: map t_from t_res
-	     axiom proj_axiom :
-	     (forall i : t_from. proj_map[i] = pf_1(term[i]))
-
-	     -> continue recursively with m2 as a term (see comments for non-map case)
-	     Problem: this introduces too many new constants => TODO: do either:
-
-	     (1)
-	     val proj_map_func (term: map t_from t_to) : map t_from t_res
-	     ensures { forall i: t_from. pf_1(term[i]) = result[i]  }
-
-	     -> apply proj_map_func to term and continue the same way as in the non-map case
-
-	     or
-
-	     (2)
-	     NOT: this does not work
-	     function proj_map_func (term : map t_from t_to) : map t_from t_res
-	     =
-	     let proj_map = ref (Const.const 0) in
-	     problem, cannot do for cycle through all the map proj_map
-	  *)
-	  try
-	    let pfs = Ty.Mty.find t_to map_projs in
-	    List.fold_left
-	      (fun l pf_1 ->
-		if Term.Sls.mem pf_1 applied_projs then
-		  (* Do not apply the same projection twice *)
-		  introduce_constant term proj_name
-		else
-		  (* Newly introduced map with projected indices *)
-		  let proj_map_name = ls_projected.ls_name.id_string^"_proj_arr_constant"^proj_name in
-		  let proj_map_id = Ident.id_fresh proj_map_name in
-		  let proj_map_ty = Some (ty_app ts [t_from; Opt.get pf_1.ls_value]) in
-		  let proj_map_ls = Term.create_lsymbol proj_map_id [] proj_map_ty in
-		  let proj_map_decl = Decl.create_param_decl proj_map_ls in
-		  let proj_map_t = Term.t_app proj_map_ls [] proj_map_ty in
-
-		  (* The quantified variable i *)
-		  let var_i : Term.vsymbol = Term.create_vsymbol (Ident.id_fresh "x") t_from in
-		  let i : Term.term = Term.t_var var_i in
-
-		  let map_theory = Env.read_theory env ["map"] "Map" in
-		  let select = (ns_find_ls map_theory.th_export ["get"]) in
-
-		  (* Indices: proj_map[i], term[i]  *)
-		  let proj_map_idx_t = Term.t_app_infer select [proj_map_t;i] in
-		  let term_idx_t = Term.t_app_infer select [term;i] in
-
-		  (* Formula f: forall i : t_from. proj_map[i] = pf_1(term[i]) *)
-		  let term_idx_projected_t = Term.t_app pf_1 [term_idx_t] pf_1.ls_value in
-		  let fla_to_be_quant = Term.t_equ proj_map_idx_t term_idx_projected_t in
-		  let fla_axiom = Term.t_forall_close [var_i] [] fla_to_be_quant in
-
-		  (* Axiom about projection: axiom f*)
-		  let proj_axiom_name = ls_projected.ls_name.id_string^"_proj_arr_axiom"^proj_name in
-		  let proj_axiom_id = Decl.create_prsymbol (Ident.id_fresh proj_axiom_name) in
-		  let proj_axiom = Decl.create_prop_decl Decl.Paxiom proj_axiom_id fla_axiom in
-
-		  (* Recursively call projecting of the term proj_map -> proj_map_projections  *)
-		  let proj_name = proj_name^(get_record_field_suffix pf_1) in
-		  let applied_projs = Term.Sls.add pf_1 applied_projs in
-		  let proj_map_projections_defs = projections_for_term proj_map_t proj_name applied_projs map_projs in
-
-		  List.append l (List.append [proj_map_decl;proj_axiom] proj_map_projections_defs)
-	      )
-	      []
-	      pfs
-	  with Not_found ->
-	    (* There is no projection function for the term
-	       -> the projection consists of definition of constant c and axiom  c = p
-	    *)
-	    introduce_constant term proj_name
-	end
-
-	| _ ->
-	  (* Non-map case *)
-	  try
-	    (* Find all projection functions for the term *)
-	    let pfs = Ty.Mty.find (Opt.get term.t_ty) map_projs in
-	    (* Collect declarations for projections f of the form
-	       f = pf_n .. pf_1 where pf_1 is an element of pfs *)
-	    List.fold_left
-	      (fun l pf_1 ->
-		if Term.Sls.mem pf_1 applied_projs then
-		  (* Do not apply the same projection twice *)
-		  introduce_constant term proj_name
-		else
-		  let t_applied = Term.t_app pf_1 [term] pf_1.ls_value in
-		  let proj_name = proj_name^(get_record_field_suffix pf_1) in
-		  let applied_projs = Term.Sls.add pf_1 applied_projs in
-		  (* Return declarations for projections of t_applied = pf_1 term *)
-		  let t_applied_projs = projections_for_term t_applied proj_name applied_projs map_projs in
-		  List.append l t_applied_projs
-	      )
-	      []
-	      pfs
-	  with Not_found ->
-	    (* There is no projection function for the term
-	       -> the projection consists of definition of constant c and axiom  c = p
-	    *)
-	    introduce_constant term proj_name
-
-      in
 
       (* Create term from ls_projected *)
       let t_projected = Term.t_app ls_projected [] ls_projected.ls_value in
-
-      projections_for_term t_projected "" Term.Sls.empty map_projs
+      projections_for_term ls_projected t_projected "" Term.Sls.empty env map_projs
 
 let introduce_projs env map_projs decl =
   match decl.d_node with