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