(* Copyright (C) 2005, HELM Team. * * This file is part of HELM, an Hypertextual, Electronic * Library of Mathematics, developed at the Computer Science * Department, University of Bologna, Italy. * * HELM is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * HELM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HELM; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. * * For details, see the HELM World-Wide-Web page, * http://cs.unibo.it/helm/. *) let _profiler = <:profiler<_profiler>>;; (* $Id$ *) open Utils;; open Printf;; let check_disjoint_invariant subst metasenv msg = if (List.exists (fun (i,_,_) -> (Subst.is_in_subst i subst)) metasenv) then begin prerr_endline ("not disjoint: " ^ msg); assert false end ;; let rec check_irl start = function | [] -> true | None::tl -> check_irl (start+1) tl | (Some (Cic.Rel x))::tl -> if x = start then check_irl (start+1) tl else false | _ -> false ;; let rec is_simple_term = function | Cic.Appl ((Cic.Meta _)::_) -> false | Cic.Appl l -> List.for_all is_simple_term l | Cic.Meta (i, l) -> let l = [] in check_irl 1 l | Cic.Rel _ -> true | Cic.Const _ -> true | Cic.MutInd (_, _, []) -> true | Cic.MutConstruct (_, _, _, []) -> true | _ -> false ;; let locked menv i = List.exists (fun (j,_,_) -> i = j) menv ;; let unification_simple locked_menv metasenv context t1 t2 ugraph = let module C = Cic in let module M = CicMetaSubst in let module U = CicUnification in let lookup = Subst.lookup_subst in let rec occurs_check subst what where = match where with | Cic.Meta(i,_) when i = what -> true | C.Appl l -> List.exists (occurs_check subst what) l | C.Meta _ -> let t = lookup where subst in if t <> where then occurs_check subst what t else false | _ -> false in let rec unif subst menv s t = let s = match s with C.Meta _ -> lookup s subst | _ -> s and t = match t with C.Meta _ -> lookup t subst | _ -> t in match s, t with | s, t when s = t -> subst, menv (* sometimes the same meta has different local contexts; this could create "cyclic" substitutions *) | C.Meta (i, _), C.Meta (j, _) when i=j -> subst, menv | C.Meta (i, _), C.Meta (j, _) when (locked locked_menv i) &&(locked locked_menv j) -> raise (U.UnificationFailure (lazy "Inference.unification.unif")) | C.Meta (i, _), C.Meta (j, _) when (locked locked_menv i) -> unif subst menv t s | C.Meta (i, _), C.Meta (j, _) when (i > j) && not (locked locked_menv j) -> unif subst menv t s | C.Meta (i,_), t when occurs_check subst i t -> raise (U.UnificationFailure (lazy "Inference.unification.unif")) | C.Meta (i, l), t when (locked locked_menv i) -> raise (U.UnificationFailure (lazy "Inference.unification.unif")) | C.Meta (i, l), t -> ( try let _, _, ty = CicUtil.lookup_meta i menv in assert (not (Subst.is_in_subst i subst)); let subst = Subst.buildsubst i context t ty subst in let menv = menv in (* List.filter (fun (m, _, _) -> i <> m) menv in *) subst, menv with CicUtil.Meta_not_found m -> let names = names_of_context context in (*debug_print (lazy*) prerr_endline (Printf.sprintf "Meta_not_found %d!: %s %s\n%s\n\n%s" m (CicPp.pp t1 names) (CicPp.pp t2 names) (print_metasenv menv) (print_metasenv metasenv)); assert false ) | _, C.Meta _ -> unif subst menv t s | C.Appl (hds::_), C.Appl (hdt::_) when hds <> hdt -> raise (U.UnificationFailure (lazy "Inference.unification.unif")) | C.Appl (hds::tls), C.Appl (hdt::tlt) -> ( try List.fold_left2 (fun (subst', menv) s t -> unif subst' menv s t) (subst, menv) tls tlt with Invalid_argument _ -> raise (U.UnificationFailure (lazy "Inference.unification.unif")) ) | _, _ -> raise (U.UnificationFailure (lazy "Inference.unification.unif")) in let subst, menv = unif Subst.empty_subst metasenv t1 t2 in let menv = Subst.filter subst menv in subst, menv, ugraph ;; let profiler = HExtlib.profile "P/Inference.unif_simple[flatten]" let profiler2 = HExtlib.profile "P/Inference.unif_simple[flatten_fast]" let profiler3 = HExtlib.profile "P/Inference.unif_simple[resolve_meta]" let profiler4 = HExtlib.profile "P/Inference.unif_simple[filter]" let unification_aux b metasenv1 metasenv2 context t1 t2 ugraph = let metasenv = HExtlib.list_uniq (List.sort Pervasives.compare (metasenv1 @ metasenv2)) (* metasenv1 @ metasenv2 *) in let subst, menv, ug = if not (is_simple_term t1) || not (is_simple_term t2) then ( debug_print (lazy (Printf.sprintf "NOT SIMPLE TERMS: %s %s" (CicPp.ppterm t1) (CicPp.ppterm t2))); raise (CicUnification.UnificationFailure (lazy "Inference.unification.unif")) ) else if b then (* full unification *) unification_simple [] metasenv context t1 t2 ugraph else (* matching: metasenv1 is locked *) unification_simple metasenv1 metasenv context t1 t2 ugraph in if Utils.debug_res then ignore(check_disjoint_invariant subst menv "unif"); (* let flatten subst = List.map (fun (i, (context, term, ty)) -> let context = apply_subst_context subst context in let term = apply_subst subst term in let ty = apply_subst subst ty in (i, (context, term, ty))) subst in let flatten subst = profiler.HExtlib.profile flatten subst in let subst = flatten subst in *) subst, menv, ug ;; exception MatchingFailure;; (** matching takes in input the _disjoint_ metasenv of t1 and t2; it perform unification in the union metasenv, then check that the first metasenv has not changed *) let matching metasenv1 metasenv2 context t1 t2 ugraph = try unification_aux false metasenv1 metasenv2 context t1 t2 ugraph with CicUnification.UnificationFailure _ -> raise MatchingFailure ;; let unification m1 m2 c t1 t2 ug = try unification_aux true m1 m2 c t1 t2 ug with exn -> raise exn ;; let check_eq context msg eq = let w, proof, (eq_ty, left, right, order), metas = eq in if not (fst (CicReduction.are_convertible ~metasenv:metas context eq_ty (fst (CicTypeChecker.type_of_aux' metas context left CicUniv.empty_ugraph)) CicUniv.empty_ugraph)) then begin prerr_endline msg; assert false; end else () ;; let find_equalities context proof = let module C = Cic in let module S = CicSubstitution in let module T = CicTypeChecker in let newmeta = ProofEngineHelpers.new_meta_of_proof ~proof in let ok_types ty menv = List.for_all (fun (_, _, mt) -> mt = ty) menv in let rec aux index newmeta = function | [] -> [], newmeta | (Some (_, C.Decl (term)))::tl -> let do_find context term = match term with | C.Prod (name, s, t) -> let (head, newmetas, args, newmeta) = ProofEngineHelpers.saturate_term newmeta [] context (S.lift index term) 0 in let p = if List.length args = 0 then C.Rel index else C.Appl ((C.Rel index)::args) in ( match head with | C.Appl [C.MutInd (uri, _, _); ty; t1; t2] when (LibraryObjects.is_eq_URI uri) && (ok_types ty newmetas) -> debug_print (lazy (Printf.sprintf "OK: %s" (CicPp.ppterm term))); let o = !Utils.compare_terms t1 t2 in let stat = (ty,t1,t2,o) in let w = compute_equality_weight stat in let proof = Equality.Exact p in let e = Equality.mk_equality (w, proof, stat, newmetas) in Some e, (newmeta+1) | _ -> None, newmeta ) | C.Appl [C.MutInd (uri, _, _); ty; t1; t2] when LibraryObjects.is_eq_URI uri -> let ty = S.lift index ty in let t1 = S.lift index t1 in let t2 = S.lift index t2 in let o = !Utils.compare_terms t1 t2 in let stat = (ty,t1,t2,o) in let w = compute_equality_weight stat in let p = C.Rel index in let proof = Equality.Exact p in let e = Equality.mk_equality (w, proof,stat,[]) in Some e, (newmeta+1) | _ -> None, newmeta in ( match do_find context term with | Some p, newmeta -> let tl, newmeta' = (aux (index+1) newmeta tl) in if newmeta' < newmeta then prerr_endline "big trouble"; (index, p)::tl, newmeta' (* max???? *) | None, _ -> aux (index+1) newmeta tl ) | _::tl -> aux (index+1) newmeta tl in let il, maxm = aux 1 newmeta context in let indexes, equalities = List.split il in (* ignore (List.iter (check_eq context "find") equalities); *) indexes, equalities, maxm ;; (* let equations_blacklist = List.fold_left (fun s u -> UriManager.UriSet.add (UriManager.uri_of_string u) s) UriManager.UriSet.empty [ "cic:/Coq/Init/Logic/eq.ind#xpointer(1/1/1)"; "cic:/Coq/Init/Logic/trans_eq.con"; "cic:/Coq/Init/Logic/f_equal.con"; "cic:/Coq/Init/Logic/f_equal2.con"; "cic:/Coq/Init/Logic/f_equal3.con"; "cic:/Coq/Init/Logic/f_equal4.con"; "cic:/Coq/Init/Logic/f_equal5.con"; "cic:/Coq/Init/Logic/sym_eq.con"; "cic:/Coq/Init/Logic/eq_ind.con"; "cic:/Coq/Init/Logic/eq_ind_r.con"; "cic:/Coq/Init/Logic/eq_rec.con"; "cic:/Coq/Init/Logic/eq_rec_r.con"; "cic:/Coq/Init/Logic/eq_rect.con"; "cic:/Coq/Init/Logic/eq_rect_r.con"; "cic:/Coq/Logic/Eqdep/UIP.con"; "cic:/Coq/Logic/Eqdep/UIP_refl.con"; "cic:/Coq/Logic/Eqdep_dec/eq2eqT.con"; "cic:/Coq/ZArith/Zcompare/rename.con"; (* ALB !!!! questo e` imbrogliare, ma x ora lo lasciamo cosi`... perche' questo cacchio di teorema rompe le scatole :'( *) "cic:/Rocq/SUBST/comparith/mult_n_2.con"; "cic:/matita/logic/equality/eq_f.con"; "cic:/matita/logic/equality/eq_f2.con"; "cic:/matita/logic/equality/eq_rec.con"; "cic:/matita/logic/equality/eq_rect.con"; ] ;; *) let equations_blacklist = UriManager.UriSet.empty;; let tty_of_u u = let _ = <:start> in let t = CicUtil.term_of_uri u in let ty, _ = CicTypeChecker.type_of_aux' [] [] t CicUniv.empty_ugraph in let _ = <:stop> in t, ty ;; let utty_of_u u = let t,ty = tty_of_u u in u, t, ty ;; let find_library_equalities dbd context status maxmeta = let module C = Cic in let module S = CicSubstitution in let module T = CicTypeChecker in let _ = <:start> in let eqs = (MetadataQuery.equations_for_goal ~dbd status) in let _ = <:stop> in let candidates = List.fold_left (fun l uri -> if LibraryObjects.is_eq_refl_URI uri || LibraryObjects.is_sym_eq_URI uri || LibraryObjects.is_trans_eq_URI uri || LibraryObjects.is_eq_ind_URI uri || LibraryObjects.is_eq_ind_r_URI uri then l else (utty_of_u uri)::l) [] eqs in let ok_types ty menv = List.for_all (fun (_, _, mt) -> mt = ty) menv in let rec has_vars = function | C.Meta _ | C.Rel _ | C.Const _ -> false | C.Var _ -> true | C.Appl l -> List.exists has_vars l | C.Prod (_, s, t) | C.Lambda (_, s, t) | C.LetIn (_, s, t) | C.Cast (s, t) -> (has_vars s) || (has_vars t) | _ -> false in let rec aux newmeta = function | [] -> [], newmeta | (uri, term, termty)::tl -> debug_print (lazy (Printf.sprintf "Examining: %s (%s)" (CicPp.ppterm term) (CicPp.ppterm termty))); let res, newmeta = match termty with | C.Prod (name, s, t) when not (has_vars termty) -> let head, newmetas, args, newmeta = ProofEngineHelpers.saturate_term newmeta [] context termty 0 in let p = if List.length args = 0 then term else C.Appl (term::args) in ( match head with | C.Appl [C.MutInd (uri, _, _); ty; t1; t2] when (LibraryObjects.is_eq_URI uri || LibraryObjects.is_eq_refl_URI uri) && (ok_types ty newmetas) -> debug_print (lazy (Printf.sprintf "OK: %s" (CicPp.ppterm term))); let o = !Utils.compare_terms t1 t2 in let stat = (ty,t1,t2,o) in let w = compute_equality_weight stat in let proof = Equality.Exact p in let e = Equality.mk_equality (w, proof, stat, newmetas) in Some e, (newmeta+1) | _ -> None, newmeta ) | C.Appl [C.MutInd (uri, _, _); ty; t1; t2] when (LibraryObjects.is_eq_URI uri || LibraryObjects.is_eq_refl_URI uri) && not (has_vars termty) -> let o = !Utils.compare_terms t1 t2 in let stat = (ty,t1,t2,o) in let w = compute_equality_weight stat in let proof = Equality.Exact term in let e = Equality.mk_equality (w, proof, stat, []) in Some e, (newmeta+1) | _ -> None, newmeta in match res with | Some e -> let tl, newmeta' = aux newmeta tl in if newmeta' < newmeta then prerr_endline "big trouble"; (uri, e)::tl, newmeta' (* max???? *) | None -> aux newmeta tl in let found, maxm = aux maxmeta candidates in let uriset, eqlist = let mceq = Equality.meta_convertibility_eq in (List.fold_left (fun (s, l) (u, e) -> if List.exists (mceq e) (List.map snd l) then ( debug_print (lazy (Printf.sprintf "NO!! %s already there!" (Equality.string_of_equality e))); (UriManager.UriSet.add u s, l) ) else (UriManager.UriSet.add u s, (u, e)::l)) (UriManager.UriSet.empty, []) found) in uriset, eqlist, maxm ;; let find_library_theorems dbd env status equalities_uris = let module C = Cic in let module S = CicSubstitution in let module T = CicTypeChecker in let candidates = List.fold_left (fun l uri -> if LibraryObjects.is_sym_eq_URI uri || LibraryObjects.is_trans_eq_URI uri || LibraryObjects.is_eq_ind_URI uri || LibraryObjects.is_eq_ind_r_URI uri then l else (let t,ty = tty_of_u uri in t, ty, [] )::l) [] (MetadataQuery.signature_of_goal ~dbd status) in let refl_equal = let eq = match LibraryObjects.eq_URI () with | Some u -> u | None -> raise (ProofEngineTypes.Fail (lazy "No default eq defined when running find_library_theorems")) in let t = CicUtil.term_of_uri (LibraryObjects.eq_refl_URI ~eq) in let ty, _ = CicTypeChecker.type_of_aux' [] [] t CicUniv.empty_ugraph in (t, ty, []) in let res = refl_equal::candidates in res ;; let find_context_hypotheses env equalities_indexes = let metasenv, context, ugraph = env in let _, res = List.fold_left (fun (n, l) entry -> match entry with | None -> (n+1, l) | Some _ -> if List.mem n equalities_indexes then (n+1, l) else let t = Cic.Rel n in let ty, _ = CicTypeChecker.type_of_aux' metasenv context t ugraph in (n+1, (t, ty, [])::l)) (1, []) context in res ;; let get_stats () = <:show> ;;