]> matita.cs.unibo.it Git - helm.git/blob - helm/ocaml/cic_disambiguation/disambiguate.ml
disabled debugging info
[helm.git] / helm / ocaml / cic_disambiguation / disambiguate.ml
1 (* Copyright (C) 2004, 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 open Printf
27
28 open DisambiguateTypes
29 open UriManager
30
31 exception No_choices of domain_item
32 exception NoWellTypedInterpretation
33
34   (** raised when an environment is not enough informative to decide *)
35 exception Try_again
36
37 let debug = false
38 let debug_print = if debug then prerr_endline else ignore
39
40 (*
41   (** print benchmark information *)
42 let benchmark = true
43 let max_refinements = ref 0       (* benchmarking is not thread safe *)
44 let actual_refinements = ref 0
45 let domain_size = ref 0
46 let choices_avg = ref 0.
47 *)
48
49 let descr_of_domain_item = function
50  | Id s -> s
51  | Symbol (s, _) -> s
52  | Num i -> string_of_int i
53
54 type test_result =
55   | Ok of Cic.term * Cic.metasenv
56   | Ko
57   | Uncertain
58
59 let refine metasenv context term =
60 (*   if benchmark then incr actual_refinements; *)
61   let metasenv, term = CicMkImplicit.expand_implicits metasenv [] context term in
62   debug_print (sprintf "TEST_INTERPRETATION: %s" (CicPp.ppterm term));
63   try
64     let term', _, metasenv' = CicRefine.type_of_aux' metasenv context term in
65     Ok (term', metasenv')
66   with
67     | CicRefine.Uncertain _ ->
68         debug_print ("%%% UNCERTAIN!!! " ^ CicPp.ppterm term) ;
69         Uncertain
70     | CicRefine.RefineFailure _ ->
71         debug_print ("%%% PRUNED!!! " ^ CicPp.ppterm term) ;
72         Ko
73
74 let resolve (env: environment) (item: domain_item) ?(num = "") ?(args = []) () =
75   try
76     snd (Environment.find item env) env num args
77   with Not_found -> assert false
78
79   (* TODO move it to Cic *)
80 let find_in_environment name context =
81   let rec aux acc = function
82     | [] -> raise Not_found
83     | Cic.Name hd :: tl when hd = name -> acc
84     | _ :: tl ->  aux (acc + 1) tl
85   in
86   aux 1 context
87
88 let interpretate ~context ~env ast =
89   let rec aux loc context = function
90     | CicAst.AttributedTerm (`Loc loc, term) ->
91         aux loc context term
92     | CicAst.AttributedTerm (_, term) -> aux loc context term
93     | CicAst.Appl (CicAst.Symbol (symb, i) :: args) ->
94         let cic_args = List.map (aux loc context) args in
95         resolve env (Symbol (symb, i)) ~args:cic_args ()
96     | CicAst.Appl terms -> Cic.Appl (List.map (aux loc context) terms)
97     | CicAst.Binder (binder_kind, (var, typ), body) ->
98         let cic_type = aux_option loc context typ in
99         let cic_body = aux loc (var :: context) body in
100         (match binder_kind with
101         | `Lambda -> Cic.Lambda (var, cic_type, cic_body)
102         | `Pi | `Forall -> Cic.Prod (var, cic_type, cic_body)
103         | `Exists ->
104             resolve env (Symbol ("exists", 0))
105               ~args:[ cic_type; Cic.Lambda (var, cic_type, cic_body) ] ())
106     | CicAst.Case (term, indty_ident, outtype, branches) ->
107         let cic_term = aux loc context term in
108         let cic_outtype = aux_option loc context outtype in
109         let do_branch ((head, args), term) =
110           let rec do_branch' context = function
111             | [] -> aux loc context term
112             | (name, typ) :: tl ->
113                 let cic_body = do_branch' (name :: context) tl in
114                 let typ =
115                   match typ with
116                   | None -> Cic.Implicit (Some `Type)
117                   | Some typ -> aux loc context typ
118                 in
119                 Cic.Lambda (name, typ, cic_body)
120           in
121           do_branch' context args
122         in
123         let (indtype_uri, indtype_no) =
124           match indty_ident with
125           | Some indty_ident ->
126               (match resolve env (Id indty_ident) () with
127               | Cic.MutInd (uri, tyno, _) -> (uri, tyno)
128               | Cic.Implicit _ -> raise Try_again
129               | _ -> raise DisambiguateChoices.Invalid_choice)
130           | None ->
131               let fst_constructor =
132                 match branches with
133                 | ((head, _), _) :: _ -> head
134                 | [] -> raise DisambiguateChoices.Invalid_choice
135               in
136               (match resolve env (Id fst_constructor) () with
137               | Cic.MutConstruct (indtype_uri, indtype_no, _, _) ->
138                   (indtype_uri, indtype_no)
139               | Cic.Implicit _ -> raise Try_again
140               | _ -> raise DisambiguateChoices.Invalid_choice)
141         in
142         Cic.MutCase (indtype_uri, indtype_no, cic_outtype, cic_term,
143           (List.map do_branch branches))
144     | CicAst.LetIn ((name, typ), def, body) ->
145         let cic_def = aux loc context def in
146         let cic_def =
147           match typ with
148           | None -> cic_def
149           | Some t -> Cic.Cast (cic_def, aux loc context t)
150         in
151         let cic_body = aux loc (name :: context) body in
152         Cic.LetIn (name, cic_def, cic_body)
153     | CicAst.LetRec (kind, defs, body) ->
154         let context' =
155           List.fold_left (fun acc ((name, _), _, _) -> name :: acc)
156             context defs
157         in
158         let cic_body = aux loc context' body in
159         let inductiveFuns =
160           List.map
161             (fun ((name, typ), body, decr_idx) ->
162               let cic_body = aux loc context' body in
163               let cic_type = aux_option loc context typ in
164               let name =
165                 match name with
166                 | Cic.Anonymous ->
167                     CicTextualParser2.fail loc
168                       "Recursive functions cannot be anonymous"
169                 | Cic.Name name -> name
170               in
171               (name, decr_idx, cic_type, cic_body))
172             defs
173         in
174         let counter = ref ~-1 in
175         let build_term funs =
176           (* this is the body of the fold_right function below. Rationale: Fix
177            * and CoFix cases differs only in an additional index in the
178            * inductiveFun list, see Cic.term *)
179           match kind with
180           | `Inductive ->
181               (fun (var, _, _, _) cic ->
182                 incr counter;
183                 Cic.LetIn (Cic.Name var, Cic.Fix (!counter, funs), cic))
184           | `CoInductive ->
185               let funs =
186                 List.map (fun (name, _, typ, body) -> (name, typ, body)) funs
187               in
188               (fun (var, _, _, _) cic ->
189                 incr counter;
190                 Cic.LetIn (Cic.Name var, Cic.CoFix (!counter, funs), cic))
191         in
192         List.fold_right (build_term inductiveFuns) inductiveFuns cic_body
193     | CicAst.Ident (name, subst) ->
194         (try
195           let index = find_in_environment name context in
196           if subst <> None then
197             CicTextualParser2.fail loc
198               "Explicit substitutions not allowed here";
199           Cic.Rel index
200         with Not_found ->
201           let cic = resolve env (Id name) () in
202           let mk_subst uris =
203             let ids_to_uris =
204               List.map (fun uri -> UriManager.name_of_uri uri, uri) uris
205             in
206             (match subst with
207             | Some subst ->
208                 List.map
209                   (fun (s, term) ->
210                     (try
211                       List.assoc s ids_to_uris, aux loc context term
212                      with Not_found ->
213                        raise DisambiguateChoices.Invalid_choice))
214                   subst
215             | None -> List.map (fun uri -> uri, Cic.Implicit None) uris)
216           in
217           (* the try is for CicTypeChecker.typecheck *)
218           (try 
219             match cic with
220             | Cic.Const (uri, []) ->
221                 let uris =
222                   match CicEnvironment.get_obj uri with
223                   (*match CicTypeChecker.typecheck uri with*)
224                   | Cic.Constant (_, _, _, uris) -> uris
225                   | _ -> assert false
226                 in
227                 Cic.Const (uri, mk_subst uris)
228             | Cic.Var (uri, []) ->
229                 let uris =
230                   match CicEnvironment.get_obj uri with
231                   (*match CicTypeChecker.typecheck uri with*)
232                   | Cic.Variable (_, _, _, uris) -> uris
233                   | _ -> assert false
234                 in
235                 Cic.Var (uri, mk_subst uris)
236             | Cic.MutInd (uri, i, []) ->
237                 let uris =
238                   match CicEnvironment.get_obj uri with
239                   (*match CicTypeChecker.typecheck uri with*)
240                   | Cic.InductiveDefinition (_, uris, _) -> uris
241                   | _ -> assert false
242                 in
243                 Cic.MutInd (uri, i, mk_subst uris)
244             | Cic.MutConstruct (uri, i, j, []) ->
245                 let uris =
246                   match CicEnvironment.get_obj uri with
247                   (*match CicTypeChecker.typecheck uri with*)
248                   | Cic.InductiveDefinition (_, uris, _) -> uris
249                   | _ -> assert false
250                 in
251                 Cic.MutConstruct (uri, i, j, mk_subst uris)
252             | Cic.Meta _ | Cic.Implicit _ as t ->
253 (*
254                 prerr_endline (sprintf
255                   "Warning: %s must be instantiated with _[%s] but we do not enforce it"
256                   (CicPp.ppterm t)
257                   (String.concat "; "
258                     (List.map
259                       (fun (s, term) -> s ^ " := " ^ CicAstPp.pp_term term)
260                       subst)));
261 *)
262                 t
263             | _ ->
264               raise DisambiguateChoices.Invalid_choice
265            with 
266              CicEnvironment.CircularDependency _ -> 
267                raise DisambiguateChoices.Invalid_choice))
268     | CicAst.Implicit -> Cic.Implicit None
269     | CicAst.Num (num, i) -> resolve env (Num i) ~num ()
270     | CicAst.Meta (index, subst) ->
271         let cic_subst =
272           List.map
273             (function None -> None | Some term -> Some (aux loc context term))
274             subst
275         in
276         Cic.Meta (index, cic_subst)
277     | CicAst.Sort `Prop -> Cic.Sort Cic.Prop
278     | CicAst.Sort `Set -> Cic.Sort Cic.Set
279     | CicAst.Sort `Type -> Cic.Sort (Cic.Type (CicUniv.fresh())) (* TASSI *)
280     | CicAst.Sort `CProp -> Cic.Sort Cic.CProp
281     | CicAst.Symbol (symbol, instance) ->
282         resolve env (Symbol (symbol, instance)) ()
283   and aux_option loc context = function
284     | None -> Cic.Implicit (Some `Type)
285     | Some term -> aux loc context term
286   in
287   match ast with
288   | CicAst.AttributedTerm (`Loc loc, term) -> aux loc context term
289   | term -> aux CicAst.dummy_floc context term
290
291 let domain_of_term ~context ast =
292     (* "aux" keeps domain in reverse order and doesn't care about duplicates.
293      * Domain item more in deep in the list will be processed first.
294      *)
295   let rec aux loc context = function
296     | CicAst.AttributedTerm (`Loc loc, term) -> aux loc context term
297     | CicAst.AttributedTerm (_, term) -> aux loc context term
298     | CicAst.Appl terms ->
299         List.fold_left (fun dom term -> aux loc context term @ dom) [] terms
300     | CicAst.Binder (kind, (var, typ), body) ->
301         let kind_dom =
302           match kind with
303           | `Exists -> [ Symbol ("exists", 0) ]
304           | _ -> []
305         in
306         let type_dom = aux_option loc context typ in
307         let body_dom = aux loc (var :: context) body in
308         body_dom @ type_dom @ kind_dom
309     | CicAst.Case (term, indty_ident, outtype, branches) ->
310         let term_dom = aux loc context term in
311         let outtype_dom = aux_option loc context outtype in
312         let do_branch ((head, args), term) =
313           let (term_context, args_domain) =
314             List.fold_left
315               (fun (cont, dom) (name, typ) ->
316                 (name :: cont,
317                  (match typ with
318                  | None -> dom
319                  | Some typ -> aux loc cont typ @ dom)))
320               (context, []) args
321           in
322           args_domain @ aux loc term_context term
323         in
324         let branches_dom =
325           List.fold_left (fun dom branch -> do_branch branch @ dom) [] branches
326         in
327         branches_dom @ outtype_dom @ term_dom @
328         (match indty_ident with None -> [] | Some ident -> [ Id ident ])
329     | CicAst.LetIn ((var, typ), body, where) ->
330         let body_dom = aux loc context body in
331         let type_dom = aux_option loc context typ in
332         let where_dom = aux loc (var :: context) where in
333         where_dom @ type_dom @ body_dom
334     | CicAst.LetRec (kind, defs, where) ->
335         let context' =
336           List.fold_left (fun acc ((var, typ), _, _) -> var :: acc)
337             context defs
338         in
339         let where_dom = aux loc context' where in
340         let defs_dom =
341           List.fold_left
342             (fun dom ((_, typ), body, _) ->
343               aux loc context' body @ aux_option loc context typ)
344             [] defs
345         in
346         where_dom @ defs_dom
347     | CicAst.Ident (name, subst) ->
348         (try
349           let index = find_in_environment name context in
350           if subst <> None then
351             CicTextualParser2.fail loc
352               "Explicit substitutions not allowed here"
353           else
354             []
355         with Not_found ->
356           (match subst with
357           | None -> [Id name]
358           | Some subst ->
359               List.fold_left
360                 (fun dom (_, term) ->
361                   let dom' = aux loc context term in
362                   dom' @ dom)
363                 [Id name] subst))
364     | CicAst.Implicit -> []
365     | CicAst.Num (num, i) -> [ Num i ]
366     | CicAst.Meta (index, local_context) ->
367         List.fold_left (fun dom term -> aux_option loc context term @ dom) []
368           local_context
369     | CicAst.Sort _ -> []
370     | CicAst.Symbol (symbol, instance) -> [ Symbol (symbol, instance) ]
371
372   and aux_option loc context = function
373     | None -> []
374     | Some t -> aux loc context t
375   in
376
377     (* e.g. [5;1;1;1;2;3;4;1;2] -> [2;1;4;3;5] *)
378   let rev_uniq =
379     let module SortedItem =
380       struct
381         type t = DisambiguateTypes.domain_item
382         let compare = Pervasives.compare
383       end
384     in
385     let module Set = Set.Make (SortedItem) in
386     fun l ->
387       let rev_l = List.rev l in
388       let (_, uniq_rev_l) =
389         List.fold_left
390           (fun (members, rev_l) elt ->
391             if Set.mem elt members then
392               (members, rev_l)
393             else
394               Set.add elt members, elt :: rev_l)
395           (Set.empty, []) rev_l
396       in
397       List.rev uniq_rev_l
398   in
399             
400   rev_uniq
401     (match ast with
402     | CicAst.AttributedTerm (`Loc loc, term) -> aux loc context term
403     | term -> aux CicAst.dummy_floc context term)
404
405   (* dom1 \ dom2 *)
406 let domain_diff dom1 dom2 =
407 (* let domain_diff = Domain.diff *)
408   let is_in_dom2 =
409     List.fold_left (fun pred elt -> (fun elt' -> elt' = elt || pred elt'))
410       (fun _ -> false) dom2
411   in
412   List.filter (fun elt -> not (is_in_dom2 elt)) dom1
413
414 module Make (C: Callbacks) =
415   struct
416     let choices_of_id dbd id =
417       let uris = MetadataQuery.locate ~dbd id in
418       let uris =
419        match uris with
420         | [] ->
421            [UriManager.string_of_uri (C.input_or_locate_uri
422             ~title:("URI matching \"" ^ id ^ "\" unknown.") ~id ())]
423         | [uri] -> [uri]
424         | _ ->
425             C.interactive_user_uri_choice ~selection_mode:`MULTIPLE
426              ~ok:"Try selected." ~enable_button_for_non_vars:true
427              ~title:"Ambiguous input." ~id
428              ~msg: ("Ambiguous input \"" ^ id ^
429                 "\". Please, choose one or more interpretations:")
430              uris
431       in
432       List.map
433         (fun uri ->
434           (uri,
435            let term =
436              try
437                CicUtil.term_of_uri uri
438              with exn ->
439                prerr_endline uri;
440                prerr_endline (Printexc.to_string exn);
441                assert false
442             in
443            fun _ _ _ -> term))
444         uris
445
446     let disambiguate_term ~(dbd:Mysql.dbd) context metasenv term
447       ~aliases:current_env
448     =
449       debug_print "NEW DISAMBIGUATE INPUT";
450       let disambiguate_context =  (* cic context -> disambiguate context *)
451         List.map
452           (function None -> Cic.Anonymous | Some (name, _) -> name)
453           context
454       in
455       let term_dom = domain_of_term ~context:disambiguate_context term in
456       debug_print (sprintf "DISAMBIGUATION DOMAIN: %s"
457         (string_of_domain term_dom));
458       let current_dom =
459         Environment.fold (fun item _ dom -> item :: dom) current_env []
460       in
461       let todo_dom = domain_diff term_dom current_dom in
462       (* (2) lookup function for any item (Id/Symbol/Num) *)
463       let lookup_choices =
464         let id_choices = Hashtbl.create 1023 in
465         fun item ->
466         let choices =
467           match item with
468           | Id id ->
469               (try
470                 Hashtbl.find id_choices id
471               with Not_found ->
472                 let choices = choices_of_id dbd id in
473                 Hashtbl.add id_choices id choices;
474                 choices)
475           | Symbol (symb, _) -> DisambiguateChoices.lookup_symbol_choices symb
476           | Num instance -> DisambiguateChoices.lookup_num_choices ()
477         in
478         if choices = [] then raise (No_choices item);
479         choices
480       in
481
482 (*
483       (* <benchmark> *)
484       let _ =
485         if benchmark then begin
486           let per_item_choices =
487             List.map
488               (fun dom_item ->
489                 try
490                   let len = List.length (lookup_choices dom_item) in
491                   prerr_endline (sprintf "BENCHMARK %s: %d"
492                     (string_of_domain_item dom_item) len);
493                   len
494                 with No_choices _ -> 0)
495               term_dom
496           in
497           max_refinements := List.fold_left ( * ) 1 per_item_choices;
498           actual_refinements := 0;
499           domain_size := List.length term_dom;
500           choices_avg :=
501             (float_of_int !max_refinements) ** (1. /. float_of_int !domain_size)
502         end
503       in
504       (* </benchmark> *)
505 *)
506
507       (* (3) test an interpretation filling with meta uninterpreted identifiers
508        *)
509       let test_env current_env todo_dom univ = 
510         let filled_env =
511           List.fold_left
512             (fun env item ->
513               Environment.add item
514                 ("Implicit",
515                  (match item with
516                  | Id _ | Num _ -> (fun _ _ _ -> Cic.Implicit (Some `Closed))
517                  | Symbol _ -> (fun _ _ _ -> Cic.Implicit None))) env)
518             current_env todo_dom 
519         in
520         try
521           CicUniv.set_working univ; 
522           let cic_term =
523             interpretate ~context:disambiguate_context ~env:filled_env term
524           in
525            let k = refine metasenv context cic_term in
526            let new_univ = CicUniv.get_working () in
527             (k , new_univ )
528         with
529         | Try_again -> Uncertain,univ 
530         | DisambiguateChoices.Invalid_choice -> Ko,univ 
531       in
532       (* (4) build all possible interpretations *)
533       let rec aux current_env todo_dom base_univ =
534         match todo_dom with
535         | [] ->
536             (match test_env current_env [] base_univ with
537             | Ok (term, metasenv),new_univ -> 
538                                [ current_env, metasenv, term, new_univ ]
539             | Ko,_ | Uncertain,_ -> [])
540         | item :: remaining_dom ->
541             debug_print (sprintf "CHOOSED ITEM: %s"
542              (string_of_domain_item item));
543             let choices = lookup_choices item in
544             let rec filter univ = function 
545               | [] -> []
546               | codomain_item :: tl ->
547                   debug_print (sprintf "%s CHOSEN" (fst codomain_item)) ;
548                   let new_env =
549                     Environment.add item codomain_item current_env
550                   in
551                   (match test_env new_env remaining_dom univ with
552                   | Ok (term, metasenv),new_univ ->
553                       (match remaining_dom with
554                       | [] -> [ new_env, metasenv, term, new_univ ]
555                       | _ -> aux new_env remaining_dom new_univ )@ 
556                         filter univ tl
557                   | Uncertain,new_univ ->
558                       (match remaining_dom with
559                       | [] -> []
560                       | _ -> aux new_env remaining_dom new_univ )@ 
561                         filter univ tl
562                   | Ko,_ -> filter univ tl)
563             in
564             filter base_univ choices 
565       in
566        let base_univ = CicUniv.get_working () in
567       try
568         let res =
569          match aux current_env todo_dom base_univ with
570          | [] -> raise NoWellTypedInterpretation
571          | [ e,me,t,u ] as l ->
572              debug_print "UNA SOLA SCELTA";
573              CicUniv.set_working u;
574              [ e,me,t ]
575          | l ->
576              debug_print (sprintf "PIU' SCELTE (%d)" (List.length l));
577              let choices =
578                List.map
579                  (fun (env, _, _, _) ->
580                    List.map
581                      (fun domain_item ->
582                        let description =
583                          fst (Environment.find domain_item env)
584                        in
585                        (descr_of_domain_item domain_item, description))
586                      term_dom)
587                  l
588              in
589              let choosed = C.interactive_interpretation_choice choices in
590              let l' = List.map (List.nth l) choosed in
591              match l' with
592                [] -> assert false
593              | [e,me,t,u] -> 
594                  CicUniv.set_working u;
595                  (*CicUniv.print_working_graph ();*)
596                  [e,me,t]
597              | hd::tl -> (* ok, testlibrary... cosi' stampa MANY... bah *)
598                  List.map (fun (e,me,t,u) -> (e,me,t)) l'
599         in
600 (*
601         (if benchmark then
602           let res_size = List.length res in
603           prerr_endline (sprintf
604             ("BENCHMARK: %d/%d refinements performed, domain size %d, interps %d, k %.2f\n" ^^
605             "BENCHMARK:   estimated %.2f")
606             !actual_refinements !max_refinements !domain_size res_size
607             !choices_avg
608             (float_of_int (!domain_size - 1) *. !choices_avg *. (float_of_int res_size) +. !choices_avg)));
609 *)
610         res
611      with
612       CicEnvironment.CircularDependency s -> 
613         raise (Failure "e chi la becca sta CircularDependency?");
614   end
615