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