]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/tactics/paramodulation/inference.ml
9ada6994319818edfec0cbdc0c960327bf03a18a
[helm.git] / helm / software / components / tactics / paramodulation / inference.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://cs.unibo.it/helm/.
24  *)
25
26 (* let _profiler = <:profiler<_profiler>>;; *)
27
28 (* $Id$ *)
29
30 open Utils;;
31 open Printf;;
32
33 type auto_type = 
34   int ->
35   AutoTypes.flags ->
36   ProofEngineTypes.proof -> 
37   Cic.context -> 
38   AutoTypes.cache -> 
39   ProofEngineTypes.goal list ->
40     Cic.substitution list * AutoTypes.cache * int
41
42 let debug_print s = prerr_endline (Lazy.force s);;
43
44 let check_disjoint_invariant subst metasenv msg =
45   if (List.exists 
46         (fun (i,_,_) -> (Subst.is_in_subst i subst)) metasenv)
47   then 
48     begin 
49       prerr_endline ("not disjoint: " ^ msg);
50       assert false
51     end
52 ;;
53
54 let rec check_irl start = function
55   | [] -> true
56   | None::tl -> check_irl (start+1) tl
57   | (Some (Cic.Rel x))::tl ->
58       if x = start then check_irl (start+1) tl else false
59   | _ -> false
60 ;;
61
62 let rec is_simple_term = function
63   | Cic.Appl ((Cic.Meta _)::_) -> false
64   | Cic.Appl l -> List.for_all is_simple_term l
65   | Cic.Meta (i, l) -> let l = [] in check_irl 1 l
66   | Cic.Rel _ -> true
67   | Cic.Const _ -> true
68   | Cic.MutInd (_, _, []) -> true
69   | Cic.MutConstruct (_, _, _, []) -> true
70   | _ -> false
71 ;;
72
73 let locked menv i =
74   List.exists (fun (j,_,_) -> i = j) menv
75 ;;
76
77 let unification_simple locked_menv metasenv context t1 t2 ugraph =
78   let module C = Cic in
79   let module M = CicMetaSubst in
80   let module U = CicUnification in
81   let lookup = Subst.lookup_subst in
82   let rec occurs_check subst what where =
83     match where with
84     | Cic.Meta(i,_) when i = what -> true
85     | C.Appl l -> List.exists (occurs_check subst what) l
86     | C.Meta _ ->
87         let t = lookup where subst in
88         if t <> where then occurs_check subst what t else false
89     | _ -> false
90   in
91   let rec unif subst menv s t =
92     let s = match s with C.Meta _ -> lookup s subst | _ -> s
93     and t = match t with C.Meta _ -> lookup t subst | _ -> t
94     
95     in
96     match s, t with
97     | s, t when s = t -> subst, menv
98     (* sometimes the same meta has different local contexts; this
99        could create "cyclic" substitutions *)
100     | C.Meta (i, _), C.Meta (j, _) when i=j ->  subst, menv
101     | C.Meta (i, _), C.Meta (j, _) 
102         when (locked locked_menv i) &&(locked locked_menv j) ->
103         raise
104           (U.UnificationFailure (lazy "Inference.unification.unif"))
105     | C.Meta (i, _), C.Meta (j, _) when (locked locked_menv i) ->          
106         unif subst menv t s
107     | C.Meta (i, _), C.Meta (j, _) when (i > j) && not (locked locked_menv j) ->
108         unif subst menv t s
109     | C.Meta (i,_), t when occurs_check subst i t ->
110         raise
111           (U.UnificationFailure (lazy "Inference.unification.unif"))
112     | C.Meta (i, l), t when (locked locked_menv i) -> 
113         raise
114           (U.UnificationFailure (lazy "Inference.unification.unif"))
115     | C.Meta (i, l), t -> (
116         try
117           let _, _, ty = CicUtil.lookup_meta i menv in
118           assert (not (Subst.is_in_subst i subst));
119           let subst = Subst.buildsubst i context t ty subst in
120           let menv = menv in (* List.filter (fun (m, _, _) -> i <> m) menv in *)
121           subst, menv
122         with CicUtil.Meta_not_found m ->
123           let names = names_of_context context in
124           (*debug_print
125             (lazy*) prerr_endline 
126                (Printf.sprintf "Meta_not_found %d!: %s %s\n%s\n\n%s" m
127                   (CicPp.pp t1 names) (CicPp.pp t2 names)
128                   (print_metasenv menv) (print_metasenv metasenv));
129           assert false
130       )
131     | _, C.Meta _ -> unif subst menv t s
132     | C.Appl (hds::_), C.Appl (hdt::_) when hds <> hdt ->
133         raise (U.UnificationFailure (lazy "Inference.unification.unif"))
134     | C.Appl (hds::tls), C.Appl (hdt::tlt) -> (
135         try
136           List.fold_left2
137             (fun (subst', menv) s t -> unif subst' menv s t)
138             (subst, menv) tls tlt
139         with Invalid_argument _ ->
140           raise (U.UnificationFailure (lazy "Inference.unification.unif"))
141       )
142     | _, _ ->
143         raise (U.UnificationFailure (lazy "Inference.unification.unif"))
144   in
145   let subst, menv = unif Subst.empty_subst metasenv t1 t2 in
146   let menv = Subst.filter subst menv in
147   subst, menv, ugraph
148 ;;
149
150 let profiler = HExtlib.profile "P/Inference.unif_simple[flatten]"
151 let profiler2 = HExtlib.profile "P/Inference.unif_simple[flatten_fast]"
152 let profiler3 = HExtlib.profile "P/Inference.unif_simple[resolve_meta]"
153 let profiler4 = HExtlib.profile "P/Inference.unif_simple[filter]"
154
155 let unification_aux b metasenv1 metasenv2 context t1 t2 ugraph =
156   let metasenv = 
157     HExtlib.list_uniq (List.sort Pervasives.compare (metasenv1 @ metasenv2)) 
158     (* metasenv1 @ metasenv2 *)
159   in
160   let subst, menv, ug =
161     if not (is_simple_term t1) || not (is_simple_term t2) then (
162       debug_print
163         (lazy
164            (Printf.sprintf "NOT SIMPLE TERMS: %s %s"
165               (CicPp.ppterm t1) (CicPp.ppterm t2)));
166       raise (CicUnification.UnificationFailure (lazy "Inference.unification.unif"))
167     ) else
168       if b then
169         (* full unification *)
170         unification_simple [] metasenv context t1 t2 ugraph
171       else
172         (* matching: metasenv1 is locked *)
173         unification_simple metasenv1 metasenv context t1 t2 ugraph
174   in
175   if Utils.debug_res then
176             ignore(check_disjoint_invariant subst menv "unif");
177   (* let flatten subst = 
178     List.map
179       (fun (i, (context, term, ty)) ->
180          let context = apply_subst_context subst context in
181          let term = apply_subst subst term in
182          let ty = apply_subst subst ty in  
183            (i, (context, term, ty))) subst 
184   in
185   let flatten subst = profiler.HExtlib.profile flatten subst in
186   let subst = flatten subst in *)
187     subst, menv, ug
188 ;;
189
190 exception MatchingFailure;;
191
192 (** matching takes in input the _disjoint_ metasenv of t1 and  t2;
193 it perform unification in the union metasenv, then check that
194 the first metasenv has not changed *)
195 let matching metasenv1 metasenv2 context t1 t2 ugraph = 
196   try 
197     unification_aux false metasenv1 metasenv2 context t1 t2 ugraph
198   with
199     CicUnification.UnificationFailure _ -> 
200       raise MatchingFailure
201 ;;
202
203 let unification m1 m2 c t1 t2 ug = 
204   try 
205     unification_aux true m1 m2 c t1 t2 ug
206   with exn -> 
207     raise exn
208 ;;
209
210
211 let check_eq context msg eq =
212   let w, proof, (eq_ty, left, right, order), metas = eq in
213   if not (fst (CicReduction.are_convertible ~metasenv:metas context eq_ty
214    (fst (CicTypeChecker.type_of_aux' metas context  left CicUniv.empty_ugraph))
215    CicUniv.empty_ugraph))
216   then
217     begin
218       prerr_endline msg;
219       assert false;
220     end
221   else ()
222 ;;
223
224 let default_auto maxm _ _ _ _ _ = 
225   [],AutoTypes.cache_empty,maxm
226 ;;
227
228 (* far sta roba e' un casino perche' bisogna pulire il contesto lasciando solo
229  * la roba che non dipende da i *)
230 let pi_of_ctx t i ctx = 
231   let rec aux j = function 
232     | [] -> t 
233     | (Some (nam, Cic.Decl (term)))::tl -> Cic.Prod(nam,term,aux (j-1) tl)
234     | _ -> assert false (* not implemented *)
235   in
236   aux (List.length ctx-1) (List.rev ctx)
237 ;;
238
239 let lambda_of_ctx t i ctx = 
240   let rec aux j = function
241     | [] -> t 
242     | (Some (nam, Cic.Decl (term)))::tl -> Cic.Lambda(nam,term,aux (j-1) tl)
243     | _ -> assert false (* not implemented *)
244   in 
245   aux (List.length ctx -1) (List.rev ctx)
246 ;;
247
248 let rec skip_lambda t l =
249   match t,l with
250   | Cic.Lambda (_,_,t), _::((_::_) as tl) -> skip_lambda t tl
251   | Cic.Lambda (_,_,t), _::[] -> t
252   | _ -> assert false
253 ;;
254   
255 let ty_of_eq = function
256   | Cic.Appl [Cic.MutInd (_, _, _); ty; _; _] -> ty
257   | _ -> assert false
258 ;;
259
260 exception UnableToSaturate of AutoTypes.cache * int
261
262 let saturate_term context metasenv oldnewmeta term cache auto fast = 
263   let head, metasenv, args, newmeta =
264     ProofEngineHelpers.saturate_term oldnewmeta metasenv context term 0
265   in
266   let args_for_auto = 
267     HExtlib.filter_map
268       (function 
269       | Cic.Meta(i,_) -> 
270           let _,_,mt = CicUtil.lookup_meta i metasenv in
271           let sort,u = 
272             CicTypeChecker.type_of_aux' metasenv context mt 
273               CicUniv.empty_ugraph
274           in
275           let b, _ = 
276             CicReduction.are_convertible ~metasenv context 
277               sort (Cic.Sort Cic.Prop) u
278           in
279           if b then Some i else None 
280           (* maybe unif or conv should be used instead of = *)
281       | _ -> assert false)
282     args
283   in
284   let results,cache,newmeta = 
285     if args_for_auto = [] then 
286       let newmetas = List.filter (fun (i,_,_) -> i >= oldnewmeta) metasenv in
287       [args,metasenv,newmetas,head,newmeta],cache,newmeta
288     else
289       let proof = 
290         None,metasenv,term,term (* term non e' significativo *)
291       in
292       let flags = 
293         if fast then
294           {AutoTypes.timeout = Unix.gettimeofday() +. 1.0;
295            maxwidth = 2;maxdepth = 2;
296            use_paramod=true;use_only_paramod=false}
297         else
298           {AutoTypes.timeout = Unix.gettimeofday() +. 1.0;
299            maxwidth = 3;maxdepth = 3;
300            use_paramod=true;use_only_paramod=false} 
301       in
302       match auto newmeta flags proof context cache args_for_auto with
303       | [],cache,newmeta -> raise (UnableToSaturate (cache,newmeta))
304       | substs,cache,newmeta ->
305           List.map 
306             (fun subst ->
307               let metasenv = 
308                 CicMetaSubst.apply_subst_metasenv subst metasenv
309               in
310               let head = CicMetaSubst.apply_subst subst head in
311               let newmetas = 
312                 List.filter (fun (i,_,_) ->i >= oldnewmeta) metasenv 
313               in
314               let args = List.map (CicMetaSubst.apply_subst subst) args in
315               let newm = CicMkImplicit.new_meta metasenv subst in
316               args,metasenv,newmetas,head,max newm newmeta)
317             substs, cache, newmeta
318   in
319   results,cache,newmeta
320 ;;
321
322 let rec is_an_equality = function
323   | Cic.Appl [Cic.MutInd (uri, _, _); ty; t1; t2] 
324     when (LibraryObjects.is_eq_URI uri) -> true
325   | Cic.Prod (name, s, t) -> is_an_equality t
326   | _ -> false
327 ;;
328
329 let build_equality_of_hypothesis bag index head args newmetas maxmeta = 
330   match head with
331   | Cic.Appl [Cic.MutInd (uri, _, _); ty; t1; t2] ->
332       let p =
333         if args = [] then Cic.Rel index else Cic.Appl ((Cic.Rel index)::args)
334       in 
335       debug_print
336         (lazy
337            (Printf.sprintf "OK: %s" (CicPp.ppterm p)));
338       let o = !Utils.compare_terms t1 t2 in
339       let stat = (ty,t1,t2,o) in
340       (* let w = compute_equality_weight stat in *)
341       let w = 0 in 
342       let proof = Equality.Exact p in
343       let e = Equality.mk_equality bag (w, proof, stat, newmetas) in
344       (* to clean the local context of metas *)
345       Equality.fix_metas bag maxmeta e
346   | _ -> assert false
347 ;;
348  
349 let build_equality bag ty t1 t2 proof menv maxmeta =
350   let o = !Utils.compare_terms t1 t2 in
351   let stat = (ty,t1,t2,o) in
352   let w = compute_equality_weight stat in
353   let proof = Equality.Exact proof in
354   let e = Equality.mk_equality bag (w, proof, stat, menv) in
355   (* to clean the local context of metas *)
356   Equality.fix_metas bag maxmeta e
357 ;;
358
359 let find_equalities maxmeta bag ?(auto = default_auto) context proof cache =
360   prerr_endline "find_equalities";
361   let module C = Cic in
362   let module S = CicSubstitution in
363   let module T = CicTypeChecker in
364   let _,metasenv,_,_ = proof in
365   let newmeta = max (ProofEngineHelpers.new_meta_of_proof ~proof) maxmeta in
366   let rec aux cache index newmeta = function
367     | [] -> [], newmeta,cache
368     | (Some (_, C.Decl (term)))::tl ->
369         debug_print
370           (lazy
371              (Printf.sprintf "Examining: %d (%s)" index (CicPp.ppterm term)));
372         let do_find context term =
373           match term with
374           | C.Prod (name, s, t) when is_an_equality t ->
375               (try 
376                 let term = S.lift index term in
377                 let saturated,cache,newmeta = 
378                   saturate_term context metasenv newmeta term 
379                     cache auto false
380                 in
381                 let eqs,newmeta = 
382                   List.fold_left 
383                    (fun (acc,newmeta) (args,metasenv,newmetas,head,newmeta') ->
384                      let newmeta, equality = 
385                        build_equality_of_hypothesis 
386                          bag index head args newmetas (max newmeta newmeta')
387                      in
388                      equality::acc, newmeta + 1)
389                    ([],newmeta) saturated
390                 in
391                  eqs, newmeta, cache
392               with UnableToSaturate (cache,newmeta) ->
393                 [],newmeta,cache)
394           | C.Appl [C.MutInd (uri, _, _); ty; t1; t2]
395               when LibraryObjects.is_eq_URI uri ->
396               let term = S.lift index term in
397               let newmeta, e = 
398                 build_equality_of_hypothesis bag index term [] [] newmeta
399               in
400               [e], (newmeta+1),cache
401           | _ -> [], newmeta, cache
402         in 
403         let eqs, newmeta, cache = do_find context term in
404         if eqs = [] then 
405           debug_print (lazy "skipped")
406         else 
407           debug_print (lazy "ok");
408         let rest, newmeta,cache = 
409           aux cache (index+1) newmeta tl
410         in
411         List.map (fun x -> index,x) eqs @ rest, newmeta, cache
412     | _::tl ->
413         aux cache (index+1) newmeta tl
414   in
415   let il, maxm, cache = 
416     aux cache 1 newmeta context 
417   in
418   let indexes, equalities = List.split il in
419   (* ignore (List.iter (check_eq context "find") equalities); *)
420   indexes, equalities, maxm, cache
421 ;;
422
423
424 (*
425 let equations_blacklist =
426   List.fold_left
427     (fun s u -> UriManager.UriSet.add (UriManager.uri_of_string u) s)
428     UriManager.UriSet.empty [
429       "cic:/Coq/Init/Logic/eq.ind#xpointer(1/1/1)";
430       "cic:/Coq/Init/Logic/trans_eq.con";
431       "cic:/Coq/Init/Logic/f_equal.con";
432       "cic:/Coq/Init/Logic/f_equal2.con";
433       "cic:/Coq/Init/Logic/f_equal3.con";
434       "cic:/Coq/Init/Logic/f_equal4.con";
435       "cic:/Coq/Init/Logic/f_equal5.con";
436       "cic:/Coq/Init/Logic/sym_eq.con";
437       "cic:/Coq/Init/Logic/eq_ind.con";
438       "cic:/Coq/Init/Logic/eq_ind_r.con";
439       "cic:/Coq/Init/Logic/eq_rec.con";
440       "cic:/Coq/Init/Logic/eq_rec_r.con";
441       "cic:/Coq/Init/Logic/eq_rect.con";
442       "cic:/Coq/Init/Logic/eq_rect_r.con";
443       "cic:/Coq/Logic/Eqdep/UIP.con";
444       "cic:/Coq/Logic/Eqdep/UIP_refl.con";
445       "cic:/Coq/Logic/Eqdep_dec/eq2eqT.con";
446       "cic:/Coq/ZArith/Zcompare/rename.con";
447       (* ALB !!!! questo e` imbrogliare, ma x ora lo lasciamo cosi`...
448          perche' questo cacchio di teorema rompe le scatole :'( *)
449       "cic:/Rocq/SUBST/comparith/mult_n_2.con";
450
451       "cic:/matita/logic/equality/eq_f.con";
452       "cic:/matita/logic/equality/eq_f2.con";
453       "cic:/matita/logic/equality/eq_rec.con";
454       "cic:/matita/logic/equality/eq_rect.con";
455     ]
456 ;;
457 *)
458 let equations_blacklist = UriManager.UriSet.empty;;
459
460 let tty_of_u u = 
461 (*   let _ = <:start<tty_of_u>> in *)
462   let t = CicUtil.term_of_uri u in
463   let ty, _ = CicTypeChecker.type_of_aux' [] [] t CicUniv.empty_ugraph in
464 (*   let _ = <:stop<tty_of_u>> in *)
465   t, ty
466 ;;
467
468 let utty_of_u u =
469   let t,ty = tty_of_u u in
470   u, t, ty
471 ;;
472
473 let find_library_equalities bag
474   ?(auto = default_auto) caso_strano dbd context status maxmeta cache 
475
476   prerr_endline "find_library_equalities";
477   let module C = Cic in
478   let module S = CicSubstitution in
479   let module T = CicTypeChecker in
480 (*   let _ = <:start<equations_for_goal>> in *)
481   let proof, goalno = status in
482   let _,metasenv,_,_ = proof in
483   let metano,context,ty = CicUtil.lookup_meta goalno metasenv in
484   let signature = 
485     if caso_strano then
486       begin
487         match ty with
488         | Cic.Appl[Cic.MutInd(u,0,_);eq_ty;l;r] ->
489             (let mainl, sigl = MetadataConstraints.signature_of l in
490             let mainr, sigr = MetadataConstraints.signature_of r in
491             match mainl,mainr with
492             | Some (uril,tyl), Some (urir, tyr) 
493                 when LibraryObjects.is_eq_URI uril && 
494                      LibraryObjects.is_eq_URI urir && 
495                      tyl = tyr ->
496                   Some (mainl,MetadataConstraints.UriManagerSet.union sigl sigr)
497             | _ -> 
498                 let u = (UriManager.uri_of_string
499                   (UriManager.string_of_uri u ^ "#xpointer(1/1)")) in
500                 let main = Some (u, []) in
501                 Some (main,MetadataConstraints.UriManagerSet.union sigl sigr))
502         | _ -> assert false
503       end
504     else
505       None
506   in
507   prerr_endline "find_library_equalities.1";
508   let eqs = MetadataQuery.equations_for_goal ~dbd ?signature status in
509 (*   let _ = <:stop<equations_for_goal>> in *)
510   prerr_endline "find_library_equalities.2";
511   let is_var_free (_,term,_ty) =
512     let rec is_var_free = function
513       | C.Var _ -> false
514       | C.Appl l -> List.for_all is_var_free l
515       | C.Prod (_, s, t) | C.Lambda (_, s, t)
516       | C.LetIn (_, s, t) | C.Cast (s, t) -> (is_var_free s) && (is_var_free t)
517       | _ -> true
518    in
519    is_var_free term
520  in
521  let is_monomorphic_eq (_,term,termty) = 
522    let rec last = function
523      | Cic.Prod(_,_,t) -> last t
524      | t -> t
525    in
526    match last termty with
527    | C.Appl [C.MutInd (_, _, []); Cic.Rel _; _; _] -> false
528    | C.Appl [C.MutInd (_, _, []); _; _; _] -> true
529    | _ -> false
530  in
531  let candidates = List.map utty_of_u eqs in
532  let candidates = List.filter is_monomorphic_eq candidates in
533  let candidates = List.filter is_var_free candidates in
534  let rec aux cache newmeta = function
535     | [] -> [], newmeta, cache
536     | (uri, term, termty)::tl ->
537         debug_print
538           (lazy
539              (Printf.sprintf "Examining: %s (%s)"
540                 (CicPp.ppterm term) (CicPp.ppterm termty)));
541         let res, newmeta, cache = 
542           match termty with
543           | C.Prod (name, s, t) ->
544               (try
545                 let saturated,cache,newmeta = 
546                   saturate_term context metasenv newmeta termty 
547                     cache auto true
548                 in
549                 let eqs,newmeta = 
550                   List.fold_left 
551                    (fun (acc,newmeta) (args,metasenv,newmetas,head,newmeta') ->
552                      match head with
553                      | C.Appl [C.MutInd (uri, _, _); ty; t1; t2]
554                        when LibraryObjects.is_eq_URI uri ->
555                          let proof = C.Appl (term::args) in
556                          prerr_endline ("PROVA: " ^ CicPp.ppterm proof);
557                          let maxmeta, equality = 
558                            build_equality bag ty t1 t2 proof newmetas 
559                              (max newmeta newmeta')
560                          in
561                          equality::acc,maxmeta + 1
562                      | _ -> assert false)
563                    ([],newmeta) saturated
564                 in
565                  eqs, newmeta , cache
566               with UnableToSaturate (cache,newmeta) ->
567                 [], newmeta , cache)
568           | C.Appl [C.MutInd (uri, _, _); ty; t1; t2] -> 
569               let newmeta, e = build_equality bag ty t1 t2 term [] newmeta in
570               [e], newmeta+1, cache
571           | _ -> assert false
572         in
573         let res = List.map (fun e -> uri, e) res in
574         let tl, newmeta, cache = aux cache newmeta tl in
575         res @ tl, newmeta, cache
576   in
577   let found, maxm, cache = 
578     aux cache maxmeta candidates 
579   in
580   let uriset, eqlist = 
581     let mceq = Equality.meta_convertibility_eq in
582     (List.fold_left
583        (fun (s, l) (u, e) ->
584           if List.exists (mceq e) (List.map snd l) then (
585             debug_print
586               (lazy
587                  (Printf.sprintf "NO!! %s already there!"
588                     (Equality.string_of_equality e)));
589             (UriManager.UriSet.add u s, l)
590           ) else (UriManager.UriSet.add u s, (u, e)::l))
591        (UriManager.UriSet.empty, []) found)
592   in
593   uriset, eqlist, maxm, cache
594 ;;
595
596 let get_stats () = "" (*<:show<Inference.>>*) ;;