1 (* Copyright (C) 2005, HELM Team.
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.
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.
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.
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,
22 * For details, see the HELM World-Wide-Web page,
23 * http://cs.unibo.it/helm/.
26 (* let _profiler = <:profiler<_profiler>>;; *)
36 ProofEngineTypes.proof ->
39 ProofEngineTypes.goal list ->
40 Cic.substitution list * AutoTypes.cache * int
42 let debug_print s = prerr_endline (Lazy.force s);;
44 let check_disjoint_invariant subst metasenv msg =
46 (fun (i,_,_) -> (Subst.is_in_subst i subst)) metasenv)
49 prerr_endline ("not disjoint: " ^ msg);
54 let rec check_irl start = function
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
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
68 | Cic.MutInd (_, _, []) -> true
69 | Cic.MutConstruct (_, _, _, []) -> true
74 List.exists (fun (j,_,_) -> i = j) menv
77 let unification_simple locked_menv metasenv context t1 t2 ugraph =
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 =
84 | Cic.Meta(i,_) when i = what -> true
85 | C.Appl l -> List.exists (occurs_check subst what) l
87 let t = lookup where subst in
88 if t <> where then occurs_check subst what t else false
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
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) ->
104 (U.UnificationFailure (lazy "Inference.unification.unif"))
105 | C.Meta (i, _), C.Meta (j, _) when (locked locked_menv i) ->
107 | C.Meta (i, _), C.Meta (j, _) when (i > j) && not (locked locked_menv j) ->
109 | C.Meta (i,_), t when occurs_check subst i t ->
111 (U.UnificationFailure (lazy "Inference.unification.unif"))
112 | C.Meta (i, l), t when (locked locked_menv i) ->
114 (U.UnificationFailure (lazy "Inference.unification.unif"))
115 | C.Meta (i, l), t -> (
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 *)
122 with CicUtil.Meta_not_found m ->
123 let names = names_of_context context in
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));
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) -> (
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"))
143 raise (U.UnificationFailure (lazy "Inference.unification.unif"))
145 let subst, menv = unif Subst.empty_subst metasenv t1 t2 in
146 let menv = Subst.filter subst menv in
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]"
155 let unification_aux b metasenv1 metasenv2 context t1 t2 ugraph =
157 HExtlib.list_uniq (List.sort Pervasives.compare (metasenv1 @ metasenv2))
158 (* metasenv1 @ metasenv2 *)
160 let subst, menv, ug =
161 if not (is_simple_term t1) || not (is_simple_term t2) then (
164 (Printf.sprintf "NOT SIMPLE TERMS: %s %s"
165 (CicPp.ppterm t1) (CicPp.ppterm t2)));
166 raise (CicUnification.UnificationFailure (lazy "Inference.unification.unif"))
169 (* full unification *)
170 unification_simple [] metasenv context t1 t2 ugraph
172 (* matching: metasenv1 is locked *)
173 unification_simple metasenv1 metasenv context t1 t2 ugraph
175 if Utils.debug_res then
176 ignore(check_disjoint_invariant subst menv "unif");
177 (* let flatten subst =
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
185 let flatten subst = profiler.HExtlib.profile flatten subst in
186 let subst = flatten subst in *)
190 exception MatchingFailure;;
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 =
197 unification_aux false metasenv1 metasenv2 context t1 t2 ugraph
199 CicUnification.UnificationFailure _ ->
200 raise MatchingFailure
203 let unification m1 m2 c t1 t2 ug =
205 unification_aux true m1 m2 c t1 t2 ug
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))
224 let default_auto maxm _ _ _ _ _ =
225 [],AutoTypes.cache_empty,maxm
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
233 | (Some (nam, Cic.Decl (term)))::tl -> Cic.Prod(nam,term,aux (j-1) tl)
234 | _ -> assert false (* not implemented *)
236 aux (List.length ctx-1) (List.rev ctx)
239 let lambda_of_ctx t i ctx =
240 let rec aux j = function
242 | (Some (nam, Cic.Decl (term)))::tl -> Cic.Lambda(nam,term,aux (j-1) tl)
243 | _ -> assert false (* not implemented *)
245 aux (List.length ctx -1) (List.rev ctx)
248 let rec skip_lambda t l =
250 | Cic.Lambda (_,_,t), _::((_::_) as tl) -> skip_lambda t tl
251 | Cic.Lambda (_,_,t), _::[] -> t
255 let ty_of_eq = function
256 | Cic.Appl [Cic.MutInd (_, _, _); ty; _; _] -> ty
260 exception UnableToSaturate of AutoTypes.cache * int
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
270 let _,_,mt = CicUtil.lookup_meta i metasenv in
272 CicTypeChecker.type_of_aux' metasenv context mt
276 CicReduction.are_convertible ~metasenv context
277 sort (Cic.Sort Cic.Prop) u
279 if b then Some i else None
280 (* maybe unif or conv should be used instead of = *)
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
290 None,metasenv,term,term (* term non e' significativo *)
294 {AutoTypes.timeout = Unix.gettimeofday() +. 1.0;
295 maxwidth = 2;maxdepth = 2;
296 use_paramod=true;use_only_paramod=false}
298 {AutoTypes.timeout = Unix.gettimeofday() +. 1.0;
299 maxwidth = 3;maxdepth = 3;
300 use_paramod=true;use_only_paramod=false}
302 match auto newmeta flags proof context cache args_for_auto with
303 | [],cache,newmeta -> raise (UnableToSaturate (cache,newmeta))
304 | substs,cache,newmeta ->
308 CicMetaSubst.apply_subst_metasenv subst metasenv
310 let head = CicMetaSubst.apply_subst subst head in
312 List.filter (fun (i,_,_) ->i >= oldnewmeta) metasenv
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
319 results,cache,newmeta
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
329 let build_equality_of_hypothesis bag index head args newmetas maxmeta =
331 | Cic.Appl [Cic.MutInd (uri, _, _); ty; t1; t2] ->
333 if args = [] then Cic.Rel index else Cic.Appl ((Cic.Rel index)::args)
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 *)
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
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
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 ->
371 (Printf.sprintf "Examining: %d (%s)" index (CicPp.ppterm term)));
372 let do_find context term =
374 | C.Prod (name, s, t) when is_an_equality t ->
376 let term = S.lift index term in
377 let saturated,cache,newmeta =
378 saturate_term context metasenv newmeta term
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')
388 equality::acc, newmeta + 1)
389 ([],newmeta) saturated
392 with UnableToSaturate (cache,newmeta) ->
394 | C.Appl [C.MutInd (uri, _, _); ty; t1; t2]
395 when LibraryObjects.is_eq_URI uri ->
396 let term = S.lift index term in
398 build_equality_of_hypothesis bag index term [] [] newmeta
400 [e], (newmeta+1),cache
401 | _ -> [], newmeta, cache
403 let eqs, newmeta, cache = do_find context term in
405 debug_print (lazy "skipped")
407 debug_print (lazy "ok");
408 let rest, newmeta,cache =
409 aux cache (index+1) newmeta tl
411 List.map (fun x -> index,x) eqs @ rest, newmeta, cache
413 aux cache (index+1) newmeta tl
415 let il, maxm, cache =
416 aux cache 1 newmeta context
418 let indexes, equalities = List.split il in
419 (* ignore (List.iter (check_eq context "find") equalities); *)
420 indexes, equalities, maxm, cache
425 let equations_blacklist =
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";
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";
458 let equations_blacklist = UriManager.UriSet.empty;;
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 *)
469 let t,ty = tty_of_u u in
473 let find_library_equalities bag
474 ?(auto = default_auto) caso_strano dbd context status maxmeta cache
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
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 &&
496 Some (mainl,MetadataConstraints.UriManagerSet.union sigl sigr)
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))
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
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)
521 let is_monomorphic_eq (_,term,termty) =
522 let rec last = function
523 | Cic.Prod(_,_,t) -> last t
526 match last termty with
527 | C.Appl [C.MutInd (_, _, []); Cic.Rel _; _; _] -> false
528 | C.Appl [C.MutInd (_, _, []); _; _; _] -> true
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 ->
539 (Printf.sprintf "Examining: %s (%s)"
540 (CicPp.ppterm term) (CicPp.ppterm termty)));
541 let res, newmeta, cache =
543 | C.Prod (name, s, t) ->
545 let saturated,cache,newmeta =
546 saturate_term context metasenv newmeta termty
551 (fun (acc,newmeta) (args,metasenv,newmetas,head,newmeta') ->
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')
561 equality::acc,maxmeta + 1
563 ([],newmeta) saturated
566 with UnableToSaturate (cache,newmeta) ->
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
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
577 let found, maxm, cache =
578 aux cache maxmeta candidates
581 let mceq = Equality.meta_convertibility_eq in
583 (fun (s, l) (u, e) ->
584 if List.exists (mceq e) (List.map snd l) then (
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)
593 uriset, eqlist, maxm, cache
596 let get_stats () = "" (*<:show<Inference.>>*) ;;