]> matita.cs.unibo.it Git - helm.git/blob - components/tactics/closeCoercionGraph.ml
95b9fd6e04f04a100746d316a95059fe264eae15
[helm.git] / components / tactics / closeCoercionGraph.ml
1 (* Copyright (C) 2005, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://helm.cs.unibo.it/
24  *)
25
26 (* $Id: cicCoercion.ml 7077 2006-12-05 15:44:54Z fguidi $ *)
27
28 let debug = false 
29 let debug_print s = if debug then prerr_endline (Lazy.force s) else ()
30
31 (* given the new coercion uri from src to tgt returns the list 
32  * of new coercions to create. the list elements are
33  * (source, list of coercions to follow, target)
34  *)
35 let get_closure_coercions src tgt uri coercions =
36   let enrich (uri,sat) tgt =
37    let arity = match tgt with CoercDb.Fun n -> n | _ -> 0 in
38     uri,sat,arity
39   in
40   let uri = enrich uri tgt in
41   let eq_carr ?exact s t = 
42     try
43       CoercDb.eq_carr ?exact s t
44     with
45     | CoercDb.EqCarrNotImplemented _ | CoercDb.EqCarrOnNonMetaClosed -> false
46   in
47   match src,tgt with
48   | CoercDb.Uri _, CoercDb.Uri _ ->
49       let c_from_tgt = 
50         List.filter 
51           (fun (f,t,_) -> eq_carr f tgt (*&& not (eq_carr t src)*)) 
52           coercions 
53       in
54       let c_to_src = 
55         List.filter 
56           (fun (f,t,_) -> eq_carr t src (*&& not (eq_carr f tgt)*)) 
57           coercions 
58       in
59         (HExtlib.flatten_map 
60           (fun (_,t,ul) -> 
61              if eq_carr ~exact:true src t then [] else
62              List.map (fun u -> src,[uri; enrich u t],t) ul) c_from_tgt) @
63         (HExtlib.flatten_map 
64           (fun (s,t,ul) -> 
65              if eq_carr ~exact:true s tgt then [] else
66              List.map (fun u -> s,[enrich u t; uri],tgt) ul) c_to_src) @
67         (HExtlib.flatten_map 
68           (fun (s,t1,u1l) ->
69             HExtlib.flatten_map 
70               (fun (_,t,u2l) ->
71                 HExtlib.flatten_map
72                   (fun u1 ->
73                     if  eq_carr ~exact:true s t
74                      || eq_carr ~exact:true s tgt
75                      || eq_carr ~exact:true src t
76                     then [] else
77                     List.map 
78                       (fun u2 -> (s,[enrich u1 t1;uri;enrich u2 t],t)) 
79                       u2l)
80                   u1l) 
81               c_from_tgt) 
82           c_to_src)
83   | _ -> [] (* do not close in case source or target is not an indty ?? *)
84 ;;
85
86 let obj_attrs n = [`Class (`Coercion n); `Generated]
87
88 exception UnableToCompose
89
90 (* generate_composite (c2 (c1 s)) in the universe graph univ
91    both living in the same context and metasenv
92
93     c2 ?p2 (c1 ?p1 ?x ?s1) ?s2
94
95     where:
96      ?pn + 1 + ?sn = count_pi n - arity n
97 *)
98 let generate_composite' (c1,sat1,arity1) (c2,sat2,arity2) context metasenv univ=
99   let original_metasenv = metasenv in 
100   let c1_ty,univ = CicTypeChecker.type_of_aux' metasenv context c1 univ in
101   let c2_ty,univ = CicTypeChecker.type_of_aux' metasenv context c2 univ in
102   let rec mk_implicits = function
103     | 0 -> [] | n -> (Cic.Implicit None) :: mk_implicits (n-1)
104   in
105   let rec mk_lambda_spine c namer = function
106     | 0 -> c
107     | n -> 
108         Cic.Lambda 
109           (namer n,
110            (Cic.Implicit None), 
111            mk_lambda_spine (CicSubstitution.lift 1 c) namer (n-1))
112   in 
113   let count_pis t arity = 
114     let rec aux acc n = function
115       | Cic.Prod (name,src,tgt) -> aux (acc@[name]) (n+1) tgt
116       | _ -> n,acc
117     in
118     let len,names = aux [] 0 t in
119     let len = len - arity in
120     List.fold_left 
121       (fun (n,l) x -> if n < len then n+1,l@[x] else n,l) (0,[]) 
122       names
123   in
124   let compose c1 nc1 c2 nc2 =
125    Cic.Appl (CicSubstitution.lift 1 c2 :: mk_implicits (nc2 - sat2 - 1) @
126      Cic.Appl (CicSubstitution.lift 1 c1 :: mk_implicits nc1 ) ::
127      mk_implicits sat2)
128   in
129   let rec create_subst_from_metas_to_rels n = function 
130     | [] -> []
131     | (metano, ctx, ty)::tl -> 
132         (metano,(ctx,Cic.Rel n,ty)) ::
133           create_subst_from_metas_to_rels (n-1) tl
134   in
135   let split_metasenv metasenv n =
136     List.partition (fun (_,ctx,_) -> List.length ctx >= n) metasenv
137   in
138   let purge_unused_lambdas metasenv t =
139     let rec aux = function
140         | Cic.Lambda (_, Cic.Meta (i,_), t) when  
141           List.exists (fun (j,_,_) -> j = i) metasenv ->
142             aux (CicSubstitution.subst (Cic.Rel ~-100) t)
143         | Cic.Lambda (name, s, t) -> 
144             Cic.Lambda (name, s, aux t)
145         | t -> t
146     in
147     aux t
148   in
149   let order_body_menv term body_metasenv c1_pis c2_pis =
150     let rec purge_lambdas = function
151       | Cic.Lambda (_,_,t) -> purge_lambdas t
152       | t -> t
153     in
154     let skip_appl = function | Cic.Appl l -> List.tl l | _ -> assert false in
155     let rec metas_of_term_and_types t =
156       let metas = CicUtil.metas_of_term t in
157       let types = 
158        List.flatten       
159         (List.map 
160           (fun (i,_) -> try 
161             let _,_,ty = CicUtil.lookup_meta i body_metasenv in metas_of_term_and_types ty
162             with CicUtil.Meta_not_found _ -> []) 
163           metas)
164       in
165       metas @ types
166     in
167     let sorted_metas_of_term world t = 
168       let metas = metas_of_term_and_types t in
169       (* this check should be useless *)
170       let metas = List.filter (fun (i,_)->List.exists (fun (j,_,_) -> j=i) world) metas in
171       let order_metas metasenv metas = 
172         let module OT = struct type t = int let compare = Pervasives.compare end in
173         let module S = HTopoSort.Make (OT) in
174         let dep i = 
175           try 
176             let _,_,ty = List.find (fun (j,_,_) -> j=i) metasenv in
177             let metas = List.map fst (CicUtil.metas_of_term ty) in
178             HExtlib.list_uniq (List.sort Pervasives.compare metas)
179           with Not_found -> []
180         in
181           S.topological_sort (List.map (fun (i,_) -> i) metas) dep 
182       in 
183       order_metas world metas
184     in
185     let metas_that_saturate l =
186       List.fold_left 
187         (fun (acc,n) t ->
188           let metas = sorted_metas_of_term body_metasenv t in
189           let metas = 
190             List.filter (fun i -> List.for_all (fun (j,_) -> j<>i) acc) metas in
191           let metas = List.map (fun i -> i,n) metas in
192           metas @ acc, n+1)
193         ([],0) l
194     in
195     let l_c2 = skip_appl (purge_lambdas term) in
196     let l_c2_b,l_c2_a =
197      try
198       HExtlib.split_nth (c2_pis - sat2 - 1) l_c2
199      with
200       Failure _ -> assert false in
201     let l_c1,l_c2_a =
202      match l_c2_a with
203         Cic.Appl (_::l_c1)::tl -> l_c1,tl
204       | _ -> assert false in
205     let meta_to_be_coerced =
206      try
207       match List.nth l_c1 (c1_pis - sat1 - 1) with
208        | Cic.Meta (i,_) -> i
209        | _ -> assert false
210      with
211       Failure _ -> assert false
212     in
213     (* BIG HACK ORRIBLE:
214      * it should be (l_c2_b @ l_c1 @ l_c2_a), but in this case sym (eq_f) gets
215      *  \A,B,f,x,y,Exy and not \B,A,f,x,y,Exy
216      * as an orrible side effect, the other composites get a type lyke
217      *  \A,x,y,Exy,B,f with 2 saturations
218      *)
219     let meta2no = fst (metas_that_saturate (l_c1 @ l_c2_b @ l_c2_a)) in
220     let sorted =
221      List.sort 
222       (fun (i,ctx1,ty1) (j,ctx1,ty1) -> 
223           try List.assoc i meta2no -  List.assoc j meta2no 
224           with Not_found -> assert false) 
225       body_metasenv
226     in
227     let rec position_of n acc =
228      function
229         [] -> assert false
230       | (i,_,_)::_ when i = n -> acc
231       | _::tl -> position_of n (acc + 1) tl
232     in
233     debug_print
234      (lazy ("META_TO_BE_COERCED: " ^ string_of_int meta_to_be_coerced));
235     let position_of_meta_to_be_coerced =
236      position_of meta_to_be_coerced 0 sorted in
237      debug_print (lazy ("POSITION_OF_META_TO_BE_COERCED: " ^
238       string_of_int position_of_meta_to_be_coerced));
239      debug_print (lazy ("SATURATIONS: " ^
240       string_of_int (List.length sorted - position_of_meta_to_be_coerced - 1)));
241      sorted, List.length sorted - position_of_meta_to_be_coerced - 1
242   in
243   let namer l n = 
244     let l = List.map (function Cic.Name s -> s | _ -> "A") l in
245     let l = List.fold_left
246       (fun acc s -> 
247         let rec add' s =
248           if List.exists ((=) s) acc then add' (s^"'") else s
249         in
250         acc@[add' s])
251       [] l
252     in
253     let l = List.rev l in 
254     Cic.Name (List.nth l (n-1))
255   in 
256   debug_print (lazy ("\nCOMPOSING"));
257   debug_print (lazy (" c1= "^CicPp.ppterm c1 ^"  :  "^ CicPp.ppterm c1_ty));
258   debug_print (lazy (" c2= "^CicPp.ppterm c2 ^"  :  "^ CicPp.ppterm c2_ty));
259   let c1_pis, names_c1 = count_pis c1_ty arity1 in 
260   let c2_pis, names_c2 = count_pis c2_ty arity2 in
261   let c = compose c1 c1_pis c2 c2_pis in
262   let spine_len = c1_pis + c2_pis in
263   let c = mk_lambda_spine c (namer (names_c1 @ names_c2)) spine_len in
264   debug_print (lazy ("COMPOSTA: " ^ CicPp.ppterm c));
265   let old_insert_coercions = !CicRefine.insert_coercions in
266   let c, metasenv, univ, saturationsres =
267     try
268       CicRefine.insert_coercions := false;
269       let term, ty, metasenv, ugraph = 
270         CicRefine.type_of_aux' metasenv context c univ
271       in
272       debug_print(lazy("COMPOSED REFINED: "^CicPp.ppterm term));
273 (*       let metasenv = order_metasenv metasenv in *)
274 (*       debug_print(lazy("ORDERED MENV: "^CicMetaSubst.ppmetasenv [] metasenv)); *)
275       let body_metasenv, lambdas_metasenv = 
276         split_metasenv metasenv (spine_len + List.length context)
277       in
278       debug_print(lazy("B_MENV: "^CicMetaSubst.ppmetasenv [] body_metasenv));
279       debug_print(lazy("L_MENV: "^CicMetaSubst.ppmetasenv [] lambdas_metasenv));
280       let body_metasenv, saturationsres =
281        order_body_menv term body_metasenv c1_pis c2_pis
282       in
283       debug_print(lazy("ORDERED_B_MENV: "^CicMetaSubst.ppmetasenv [] body_metasenv));
284       let subst = create_subst_from_metas_to_rels spine_len body_metasenv in
285       debug_print (lazy("SUBST: "^CicMetaSubst.ppsubst body_metasenv subst));
286       let term = CicMetaSubst.apply_subst subst term in
287       let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
288       debug_print (lazy ("COMPOSED SUBSTITUTED: " ^ CicPp.ppterm term));
289       let term, ty, metasenv, ugraph = 
290         CicRefine.type_of_aux' metasenv context term ugraph
291       in
292       let body_metasenv, lambdas_metasenv = 
293         split_metasenv metasenv (spine_len + List.length context)
294       in
295       let lambdas_metasenv = 
296         List.filter 
297           (fun (i,_,_) -> 
298             List.for_all (fun (j,_,_) -> i <> j) original_metasenv)
299           lambdas_metasenv
300       in
301       let term = purge_unused_lambdas lambdas_metasenv term in
302       let metasenv = 
303         List.filter 
304           (fun (i,_,_) -> 
305             List.for_all 
306               (fun (j,_,_) ->
307                 i <> j || List.exists (fun (j,_,_) -> j=i) original_metasenv) 
308               lambdas_metasenv) 
309           metasenv 
310       in
311       debug_print (lazy ("####################"));
312       debug_print (lazy ("COMPOSED: " ^ CicPp.ppterm term));
313       debug_print (lazy ("SATURATIONS: " ^ string_of_int saturationsres));
314       debug_print (lazy ("MENV: "^CicMetaSubst.ppmetasenv [] metasenv));
315       debug_print (lazy ("####################"));
316       CicRefine.insert_coercions := old_insert_coercions;
317       term, metasenv, ugraph, saturationsres
318     with
319     | CicRefine.RefineFailure s 
320     | CicRefine.Uncertain s -> debug_print s; 
321         CicRefine.insert_coercions := old_insert_coercions;
322         raise UnableToCompose
323     | exn ->
324         CicRefine.insert_coercions := old_insert_coercions;
325         raise exn
326   in
327   c, metasenv, univ, saturationsres, arity2
328 ;;
329
330 let build_obj c univ arity =
331   let c_ty,univ = 
332     try 
333       CicTypeChecker.type_of_aux' [] [] c univ
334     with CicTypeChecker.TypeCheckerFailure s ->
335       debug_print (lazy (Printf.sprintf "Generated composite coercion:\n%s\n%s" 
336         (CicPp.ppterm c) (Lazy.force s)));
337       raise UnableToCompose
338   in
339   let cleaned_ty =
340     FreshNamesGenerator.clean_dummy_dependent_types c_ty 
341   in
342   let obj = Cic.Constant ("xxxx",Some c,cleaned_ty,[],obj_attrs arity) in 
343     obj,univ
344 ;;
345
346 (* removes from l the coercions that are in !coercions *)
347 let filter_duplicates l coercions =
348   List.filter (
349       fun (src,l1,tgt) ->
350         not (List.exists (fun (s,t,l2) -> 
351           CoercDb.eq_carr s src && 
352           CoercDb.eq_carr t tgt &&
353           try 
354             List.for_all2 (fun (u1,_,_) (u2,_) -> UriManager.eq u1 u2) l1 l2
355           with
356           | Invalid_argument "List.for_all2" -> false)
357         coercions))
358   l
359
360 let mangle s t l = 
361   (*List.fold_left
362     (fun s x -> s ^ "_" ^ x)
363     (s ^ "_OF_" ^ t ^ "_BY" ^ string_of_int (List.length l)) l*)
364   s ^ "_OF_" ^ t
365 ;;
366
367 exception ManglingFailed of string 
368
369 let number_if_already_defined buri name l =
370   let err () =
371     raise 
372       (ManglingFailed 
373         ("Unable to give an altenative name to " ^ buri ^ "/" ^ name ^ ".con"))
374   in
375   let rec aux n =
376     let suffix = if n > 0 then string_of_int n else "" in
377     let suri = buri ^ "/" ^ name ^ suffix ^ ".con" in
378     let uri = UriManager.uri_of_string suri in
379     let retry () = 
380       if n < 100 then 
381         begin
382           HLog.warn ("Uri " ^ suri ^ " already exists.");
383           aux (n+1)
384         end
385       else
386         err ()
387     in
388     if List.exists (UriManager.eq uri) l then retry ()
389     else
390       try
391         let _  = Http_getter.resolve' ~local:true ~writable:true uri in
392         if Http_getter.exists' ~local:true uri then retry () else uri
393       with 
394       | Http_getter_types.Key_not_found _ -> uri
395       | Http_getter_types.Unresolvable_URI _ -> assert false
396   in
397   aux 0
398 ;;
399   
400 (* given a new coercion uri from src to tgt returns 
401  * a list of (new coercion uri, coercion obj, universe graph) 
402  *)
403 let close_coercion_graph src tgt uri saturations baseuri =
404   (* check if the coercion already exists *)
405   let coercions = CoercDb.to_list () in
406   let todo_list = get_closure_coercions src tgt (uri,saturations) coercions in
407   let todo_list = filter_duplicates todo_list coercions in
408   try
409     let new_coercions = 
410       List.fold_left 
411         (fun acc (src, l , tgt) ->
412           try 
413             (match l with
414             | [] -> assert false 
415             | (he,saturations1,arity1) :: tl ->
416                 let first_step = 
417                   Cic.Constant ("", 
418                    Some (CoercDb.term_of_carr (CoercDb.Uri he)),
419                     Cic.Sort Cic.Prop, [], obj_attrs arity1),
420                   saturations1,
421                   arity1
422                 in
423                 let o,_ = 
424                   List.fold_left (fun (o,univ) (coer,saturations2,arity2) ->
425                     match o with 
426                     | Cic.Constant (_,Some u,_,[],_),saturations1,arity1 ->
427                         let t, menv, univ, saturationsres, arityres = 
428                           generate_composite' (u,saturations1,arity1) 
429                             (CoercDb.term_of_carr (CoercDb.Uri coer),
430                              saturations2, arity2) [] [] univ
431                         in
432                         if (menv = []) then
433                           HLog.warn "MENV non empty after composing coercions";
434                         let o,univ = build_obj t univ arityres in
435                          (o,saturationsres,arityres),univ
436                     | _ -> assert false 
437                   ) (first_step, CicUniv.empty_ugraph) tl
438                 in
439                 let name_src = CoercDb.name_of_carr src in
440                 let name_tgt = CoercDb.name_of_carr tgt in
441                 let by = List.map (fun u,_,_ -> UriManager.name_of_uri u) l in
442                 let name = mangle name_tgt name_src by in
443                 let c_uri = 
444                   number_if_already_defined baseuri name 
445                     (List.map (fun (_,_,u,_,_,_) -> u) acc) 
446                 in
447                 let named_obj,saturations,arity = 
448                   match o with
449                   | Cic.Constant (_,bo,ty,vl,attrs),saturations,arity ->
450                       Cic.Constant (name,bo,ty,vl,attrs),saturations,arity
451                   | _ -> assert false 
452                 in
453                   (src,tgt,c_uri,saturations,named_obj,arity))::acc
454           with UnableToCompose -> acc
455       ) [] todo_list
456     in
457     new_coercions
458   with ManglingFailed s -> HLog.error s; []
459 ;;
460
461 CicCoercion.set_close_coercion_graph close_coercion_graph;;
462
463 (* generate_composite (c2 (c1 s)) in the universe graph univ
464  * both living in the same context and metasenv *)
465 let generate_composite c1 c2 context metasenv univ sat2 =
466  let a,b,c,_,_ =
467   generate_composite' (c1,0,0) (c2,sat2,0) context metasenv univ
468  in
469   a,b,c
470 ;;