(* 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/. *) (* $Id$ *) open Utils;; open Printf;; let metas_of_proof_time = ref 0.;; let metas_of_term_time = ref 0.;; (* type substitution = Cic.substitution let apply_subst = CicMetaSubst.apply_subst let apply_subst_metasenv = CicMetaSubst.apply_subst_metasenv let ppsubst = CicMetaSubst.ppsubst let buildsubst n context t ty = (n,(context,t,ty)) let flatten_subst 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 let rec lookup_subst meta subst = match meta with | Cic.Meta (i, _) -> ( try let _, (_, t, _) = List.find (fun (m, _) -> m = i) subst in lookup_subst t subst with Not_found -> meta ) | _ -> meta ;; *) (* naif version of apply subst; the local context of metas is ignored; we assume the substituted term must be lifted according to the nesting depth of the meta. Alternatively, ee could used implicit instead of metas *) type substitution = (int * Cic.term) list let apply_subst subst term = let rec aux k t = match t with Cic.Rel _ -> t | Cic.Var (uri,exp_named_subst) -> let exp_named_subst' = List.map (fun (uri, t) -> (uri, aux k t)) exp_named_subst in Cic.Var (uri, exp_named_subst') | Cic.Meta (i, l) -> (try aux k (CicSubstitution.lift k (List.assoc i subst)) with Not_found -> t) | Cic.Sort _ | Cic.Implicit _ -> t | Cic.Cast (te,ty) -> Cic.Cast (aux k te, aux k ty) | Cic.Prod (n,s,t) -> Cic.Prod (n, aux k s, aux (k+1) t) | Cic.Lambda (n,s,t) -> Cic.Lambda (n, aux k s, aux (k+1) t) | Cic.LetIn (n,s,t) -> Cic.LetIn (n, aux k s, aux (k+1) t) | Cic.Appl [] -> assert false | Cic.Appl l -> Cic.Appl (List.map (aux k) l) | Cic.Const (uri,exp_named_subst) -> let exp_named_subst' = List.map (fun (uri, t) -> (uri, aux k t)) exp_named_subst in if exp_named_subst' != exp_named_subst then Cic.Const (uri, exp_named_subst') else t (* TODO: provare a mantenere il piu' possibile sharing *) | Cic.MutInd (uri,typeno,exp_named_subst) -> let exp_named_subst' = List.map (fun (uri, t) -> (uri, aux k t)) exp_named_subst in Cic.MutInd (uri,typeno,exp_named_subst') | Cic.MutConstruct (uri,typeno,consno,exp_named_subst) -> let exp_named_subst' = List.map (fun (uri, t) -> (uri, aux k t)) exp_named_subst in Cic.MutConstruct (uri,typeno,consno,exp_named_subst') | Cic.MutCase (sp,i,outty,t,pl) -> let pl' = List.map (aux k) pl in Cic.MutCase (sp, i, aux k outty, aux k t, pl') | Cic.Fix (i, fl) -> let len = List.length fl in let fl' = List.map (fun (name, i, ty, bo) -> (name, i, aux k ty, aux (k+len) bo)) fl in Cic.Fix (i, fl') | Cic.CoFix (i, fl) -> let len = List.length fl in let fl' = List.map (fun (name, ty, bo) -> (name, aux k ty, aux (k+len) bo)) fl in Cic.CoFix (i, fl') in aux 0 term ;; (* naif version of apply_subst_metasenv: we do not apply the substitution to the context *) let apply_subst_metasenv subst metasenv = List.map (fun (n, context, ty) -> (n, context, apply_subst subst ty)) (List.filter (fun (i, _, _) -> not (List.mem_assoc i subst)) metasenv) let ppsubst subst = String.concat "\n" (List.map (fun (idx, t) -> sprintf "%d:= %s" idx (CicPp.ppterm t)) subst) ;; let buildsubst n context t ty = (n,t) ;; let flatten_subst subst = List.map (fun (i,t) -> i, apply_subst subst t ) subst ;; let rec lookup_subst meta subst = match meta with | Cic.Meta (i, _) -> (try lookup_subst (List.assoc i subst) subst with Not_found -> meta) | _ -> meta ;; type equality = int * (* weight *) proof * (Cic.term * (* type *) Cic.term * (* left side *) Cic.term * (* right side *) Utils.comparison) * (* ordering *) Cic.metasenv (* environment for metas *) and proof = | NoProof (* term is the goal missing a proof *) | BasicProof of substitution * Cic.term | ProofBlock of substitution * UriManager.uri * (Cic.name * Cic.term) * Cic.term * (Utils.pos * equality) * proof | ProofGoalBlock of proof * proof | ProofSymBlock of Cic.term list * proof | SubProof of Cic.term * int * proof ;; let string_of_equality ?env = match env with | None -> ( function | w, _, (ty, left, right, o), _ -> Printf.sprintf "Weight: %d, {%s}: %s =(%s) %s" w (CicPp.ppterm ty) (CicPp.ppterm left) (string_of_comparison o) (CicPp.ppterm right) ) | Some (_, context, _) -> ( let names = names_of_context context in function | w, _, (ty, left, right, o), _ -> Printf.sprintf "Weight: %d, {%s}: %s =(%s) %s" w (CicPp.pp ty names) (CicPp.pp left names) (string_of_comparison o) (CicPp.pp right names) ) ;; let rec string_of_proof = function | NoProof -> "NoProof " | BasicProof (s, t) -> "BasicProof " ^ (CicPp.ppterm (apply_subst s t)) | SubProof (t, i, p) -> Printf.sprintf "SubProof(%s, %s, %s)" (CicPp.ppterm t) (string_of_int i) (string_of_proof p) | ProofSymBlock _ -> "ProofSymBlock" | ProofBlock (subst, _, _, _ ,_,_) -> "ProofBlock" ^ (ppsubst subst) | ProofGoalBlock (p1, p2) -> Printf.sprintf "ProofGoalBlock(%s, %s)" (string_of_proof p1) (string_of_proof p2) ;; let check_disjoint_invariant subst metasenv msg = if (List.exists (fun (i,_,_) -> (List.exists (fun (j,_) -> i=j) subst)) metasenv) then begin prerr_endline ("not disjoint: " ^ msg); assert false end ;; (* filter out from metasenv the variables in substs *) let filter subst metasenv = List.filter (fun (m, _, _) -> try let _ = List.find (fun (i, _) -> m = i) subst in false with Not_found -> true) metasenv ;; (* returns an explicit named subst and a list of arguments for sym_eq_URI *) let build_ens_for_sym_eq sym_eq_URI termlist = let obj, _ = CicEnvironment.get_obj CicUniv.empty_ugraph sym_eq_URI in match obj with | Cic.Constant (_, _, _, uris, _) -> assert (List.length uris <= List.length termlist); let rec aux = function | [], tl -> [], tl | (uri::uris), (term::tl) -> let ens, args = aux (uris, tl) in (uri, term)::ens, args | _, _ -> assert false in aux (uris, termlist) | _ -> assert false ;; let build_proof_term ?(noproof=Cic.Implicit None) proof = let rec do_build_proof proof = match proof with | NoProof -> Printf.fprintf stderr "WARNING: no proof!\n"; noproof | BasicProof (s,term) -> apply_subst s term | ProofGoalBlock (proofbit, proof) -> print_endline "found ProofGoalBlock, going up..."; do_build_goal_proof proofbit proof | ProofSymBlock (termlist, proof) -> let proof = do_build_proof proof in let ens, args = build_ens_for_sym_eq (Utils.sym_eq_URI ()) termlist in Cic.Appl ([Cic.Const (Utils.sym_eq_URI (), ens)] @ args @ [proof]) | ProofBlock (subst, eq_URI, (name, ty), bo, (pos, eq), eqproof) -> let t' = Cic.Lambda (name, ty, bo) in let proof' = let _, proof', _, _ = eq in do_build_proof proof' in let eqproof = do_build_proof eqproof in let _, _, (ty, what, other, _), menv' = eq in let what, other = if pos = Utils.Left then what, other else other, what in apply_subst subst (Cic.Appl [Cic.Const (eq_URI, []); ty; what; t'; eqproof; other; proof']) | SubProof (term, meta_index, proof) -> let proof = do_build_proof proof in let eq i = function | Cic.Meta (j, _) -> i = j | _ -> false in ProofEngineReduction.replace ~equality:eq ~what:[meta_index] ~with_what:[proof] ~where:term and do_build_goal_proof proofbit proof = match proof with | ProofGoalBlock (pb, p) -> do_build_proof (ProofGoalBlock (replace_proof proofbit pb, p)) | _ -> do_build_proof (replace_proof proofbit proof) and replace_proof newproof = function | ProofBlock (subst, eq_URI, namety, bo, poseq, eqproof) -> let eqproof' = replace_proof newproof eqproof in ProofBlock (subst, eq_URI, namety, bo, poseq, eqproof') | ProofGoalBlock (pb, p) -> let pb' = replace_proof newproof pb in ProofGoalBlock (pb', p) | BasicProof _ -> newproof | SubProof (term, meta_index, p) -> SubProof (term, meta_index, replace_proof newproof p) | p -> p in do_build_proof proof ;; let rec metas_of_term = function | Cic.Meta (i, c) -> [i] | Cic.Var (_, ens) | Cic.Const (_, ens) | Cic.MutInd (_, _, ens) | Cic.MutConstruct (_, _, _, ens) -> List.flatten (List.map (fun (u, t) -> metas_of_term t) ens) | Cic.Cast (s, t) | Cic.Prod (_, s, t) | Cic.Lambda (_, s, t) | Cic.LetIn (_, s, t) -> (metas_of_term s) @ (metas_of_term t) | Cic.Appl l -> List.flatten (List.map metas_of_term l) | Cic.MutCase (uri, i, s, t, l) -> (metas_of_term s) @ (metas_of_term t) @ (List.flatten (List.map metas_of_term l)) | Cic.Fix (i, il) -> List.flatten (List.map (fun (s, i, t1, t2) -> (metas_of_term t1) @ (metas_of_term t2)) il) | Cic.CoFix (i, il) -> List.flatten (List.map (fun (s, t1, t2) -> (metas_of_term t1) @ (metas_of_term t2)) il) | _ -> [] ;; let rec metas_of_proof p = if Utils.debug then let t1 = Unix.gettimeofday () in let res = metas_of_term (build_proof_term p) in let t2 = Unix.gettimeofday () in metas_of_proof_time := !metas_of_proof_time +. (t2 -. t1); res else metas_of_term (build_proof_term p) ;; exception NotMetaConvertible;; let meta_convertibility_aux table t1 t2 = let module C = Cic in let rec aux ((table_l, table_r) as table) t1 t2 = match t1, t2 with | C.Meta (m1, tl1), C.Meta (m2, tl2) -> let m1_binding, table_l = try List.assoc m1 table_l, table_l with Not_found -> m2, (m1, m2)::table_l and m2_binding, table_r = try List.assoc m2 table_r, table_r with Not_found -> m1, (m2, m1)::table_r in if (m1_binding <> m2) || (m2_binding <> m1) then raise NotMetaConvertible else ( try List.fold_left2 (fun res t1 t2 -> match t1, t2 with | None, Some _ | Some _, None -> raise NotMetaConvertible | None, None -> res | Some t1, Some t2 -> (aux res t1 t2)) (table_l, table_r) tl1 tl2 with Invalid_argument _ -> raise NotMetaConvertible ) | C.Var (u1, ens1), C.Var (u2, ens2) | C.Const (u1, ens1), C.Const (u2, ens2) when (UriManager.eq u1 u2) -> aux_ens table ens1 ens2 | C.Cast (s1, t1), C.Cast (s2, t2) | C.Prod (_, s1, t1), C.Prod (_, s2, t2) | C.Lambda (_, s1, t1), C.Lambda (_, s2, t2) | C.LetIn (_, s1, t1), C.LetIn (_, s2, t2) -> let table = aux table s1 s2 in aux table t1 t2 | C.Appl l1, C.Appl l2 -> ( try List.fold_left2 (fun res t1 t2 -> (aux res t1 t2)) table l1 l2 with Invalid_argument _ -> raise NotMetaConvertible ) | C.MutInd (u1, i1, ens1), C.MutInd (u2, i2, ens2) when (UriManager.eq u1 u2) && i1 = i2 -> aux_ens table ens1 ens2 | C.MutConstruct (u1, i1, j1, ens1), C.MutConstruct (u2, i2, j2, ens2) when (UriManager.eq u1 u2) && i1 = i2 && j1 = j2 -> aux_ens table ens1 ens2 | C.MutCase (u1, i1, s1, t1, l1), C.MutCase (u2, i2, s2, t2, l2) when (UriManager.eq u1 u2) && i1 = i2 -> let table = aux table s1 s2 in let table = aux table t1 t2 in ( try List.fold_left2 (fun res t1 t2 -> (aux res t1 t2)) table l1 l2 with Invalid_argument _ -> raise NotMetaConvertible ) | C.Fix (i1, il1), C.Fix (i2, il2) when i1 = i2 -> ( try List.fold_left2 (fun res (n1, i1, s1, t1) (n2, i2, s2, t2) -> if i1 <> i2 then raise NotMetaConvertible else let res = (aux res s1 s2) in aux res t1 t2) table il1 il2 with Invalid_argument _ -> raise NotMetaConvertible ) | C.CoFix (i1, il1), C.CoFix (i2, il2) when i1 = i2 -> ( try List.fold_left2 (fun res (n1, s1, t1) (n2, s2, t2) -> let res = aux res s1 s2 in aux res t1 t2) table il1 il2 with Invalid_argument _ -> raise NotMetaConvertible ) | t1, t2 when t1 = t2 -> table | _, _ -> raise NotMetaConvertible and aux_ens table ens1 ens2 = let cmp (u1, t1) (u2, t2) = compare (UriManager.string_of_uri u1) (UriManager.string_of_uri u2) in let ens1 = List.sort cmp ens1 and ens2 = List.sort cmp ens2 in try List.fold_left2 (fun res (u1, t1) (u2, t2) -> if not (UriManager.eq u1 u2) then raise NotMetaConvertible else aux res t1 t2) table ens1 ens2 with Invalid_argument _ -> raise NotMetaConvertible in aux table t1 t2 ;; let meta_convertibility_eq eq1 eq2 = let _, _, (ty, left, right, _), _ = eq1 and _, _, (ty', left', right', _), _ = eq2 in if ty <> ty' then false else if (left = left') && (right = right') then true else if (left = right') && (right = left') then true else try let table = meta_convertibility_aux ([], []) left left' in let _ = meta_convertibility_aux table right right' in true with NotMetaConvertible -> try let table = meta_convertibility_aux ([], []) left right' in let _ = meta_convertibility_aux table right left' in true with NotMetaConvertible -> false ;; let meta_convertibility t1 t2 = if t1 = t2 then true else try ignore(meta_convertibility_aux ([], []) t1 t2); true with NotMetaConvertible -> false ;; 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) -> 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 debug_print x = prerr_endline (Lazy.force x) in let module C = Cic in let module M = CicMetaSubst in let module U = CicUnification in let lookup = lookup_subst in let rec occurs_check subst what where = match where with | t when what = t -> 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 | 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 _, t when occurs_check subst s 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 (List.mem_assoc i subst)); let 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 [] metasenv t1 t2 in let menv = filter subst menv in List.rev 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 = 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;; let matching1 metasenv1 metasenv2 context t1 t2 ugraph = try unification_aux false metasenv1 metasenv2 context t1 t2 ugraph with CicUnification .UnificationFailure _ -> raise MatchingFailure ;; let unification = unification_aux true ;; (** 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 = matching1;; 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 eq_uri = LibraryObjects.eq_URI () 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 (UriManager.eq uri eq_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 = BasicProof ([],p) in let e = (w, proof, stat, newmetas) in Some e, (newmeta+1) | _ -> None, newmeta ) | C.Appl [C.MutInd (uri, _, _); ty; t1; t2] when UriManager.eq uri eq_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 e = (w, BasicProof ([],(C.Rel index)), 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 find_library_equalities dbd context status maxmeta = let module C = Cic in let module S = CicSubstitution in let module T = CicTypeChecker in let blacklist = List.fold_left (fun s u -> UriManager.UriSet.add u s) equations_blacklist [eq_XURI (); sym_eq_URI (); trans_eq_URI (); eq_ind_URI (); eq_ind_r_URI ()] in let candidates = List.fold_left (fun l uri -> if UriManager.UriSet.mem uri blacklist then l else let t = CicUtil.term_of_uri uri in let ty, _ = CicTypeChecker.type_of_aux' [] context t CicUniv.empty_ugraph in (uri, t, ty)::l) [] (let t1 = Unix.gettimeofday () in let eqs = (MetadataQuery.equations_for_goal ~dbd status) in let t2 = Unix.gettimeofday () in (debug_print (lazy (Printf.sprintf "Tempo di MetadataQuery.equations_for_goal: %.9f\n" (t2 -. t1)))); eqs) in let eq_uri1 = eq_XURI () and eq_uri2 = LibraryObjects.eq_URI () in let iseq uri = (UriManager.eq uri eq_uri1) || (UriManager.eq uri eq_uri2) 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 (iseq 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 = BasicProof ([],p) in let e = (w, proof, stat, newmetas) in Some e, (newmeta+1) | _ -> None, newmeta ) | C.Appl [C.MutInd (uri, _, _); ty; t1; t2] when iseq 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 e = (w, BasicProof ([],term), 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 = (List.fold_left (fun (s, l) (u, e) -> if List.exists (meta_convertibility_eq e) (List.map snd l) then ( debug_print (lazy (Printf.sprintf "NO!! %s already there!" (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 blacklist = let refl_equal = UriManager.uri_of_string "cic:/Coq/Init/Logic/eq.ind#xpointer(1/1/1)" in let s = UriManager.UriSet.remove refl_equal (UriManager.UriSet.union equalities_uris equations_blacklist) in List.fold_left (fun s u -> UriManager.UriSet.add u s) s [eq_XURI () ;sym_eq_URI (); trans_eq_URI (); eq_ind_URI (); eq_ind_r_URI ()] in let metasenv, context, ugraph = env in let candidates = List.fold_left (fun l uri -> if UriManager.UriSet.mem uri blacklist then l else let t = CicUtil.term_of_uri uri in let ty, _ = CicTypeChecker.type_of_aux' metasenv context t ugraph in (t, ty, [])::l) [] (MetadataQuery.signature_of_goal ~dbd status) in let refl_equal = let u = eq_XURI () in let t = CicUtil.term_of_uri u in let ty, _ = CicTypeChecker.type_of_aux' [] [] t CicUniv.empty_ugraph in (t, ty, []) in refl_equal::candidates ;; 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 fix_metas_old newmeta (w, p, (ty, left, right, o), menv, args) = let table = Hashtbl.create (List.length args) in let newargs, newmeta = List.fold_right (fun t (newargs, index) -> match t with | Cic.Meta (i, l) -> if Hashtbl.mem table i then let idx = Hashtbl.find table i in ((Cic.Meta (idx, l))::newargs, index+1) else let _ = Hashtbl.add table i index in ((Cic.Meta (index, l))::newargs, index+1) | _ -> assert false) args ([], newmeta+1) in let repl where = ProofEngineReduction.replace ~equality:(=) ~what:args ~with_what:newargs ~where in let menv' = List.fold_right (fun (i, context, term) menv -> try let index = Hashtbl.find table i in (index, context, term)::menv with Not_found -> (i, context, term)::menv) menv [] in let ty = repl ty and left = repl left and right = repl right in let metas = (metas_of_term left) @ (metas_of_term right) @ (metas_of_term ty) @ (metas_of_proof p) in let menv' = List.filter (fun (i, _, _) -> List.mem i metas) menv' in let newargs = List.filter (function Cic.Meta (i, _) -> List.mem i metas | _ -> assert false) newargs in let _ = if List.length metas > 0 then let first = List.hd metas in (* this new equality might have less variables than its parents: here we fill the gap with a dummy arg. Example: with (f X Y) = X we can simplify (g X) = (f X Y) in (g X) = X. So the new equation has only one variable, but it still has type like \lambda X,Y:..., so we need to pass a dummy arg for Y (I hope this makes some sense...) *) Hashtbl.iter (fun k v -> if not (List.exists (function Cic.Meta (i, _) -> i = v | _ -> assert false) newargs) then Hashtbl.replace table k first) (Hashtbl.copy table) in let rec fix_proof = function | NoProof -> NoProof | BasicProof term -> BasicProof (repl term) | ProofBlock (subst, eq_URI, namety, bo, (pos, eq), p) -> let subst' = List.fold_left (fun s arg -> match arg with | Cic.Meta (i, l) -> ( try let j = Hashtbl.find table i in if List.mem_assoc i subst then s else let _, context, ty = CicUtil.lookup_meta i menv in (i, (context, Cic.Meta (j, l), ty))::s with Not_found | CicUtil.Meta_not_found _ -> s ) | _ -> assert false) [] args in ProofBlock (subst' @ subst, eq_URI, namety, bo(* t' *), (pos, eq), p) | p -> assert false in let neweq = (w, fix_proof p, (ty, left, right, o), menv', newargs) in (newmeta +1, neweq) ;; *) let relocate newmeta menv = let subst, metasenv, newmeta = List.fold_right (fun (i, context, ty) (subst, menv, maxmeta) -> let irl = [] (* CicMkImplicit.identity_relocation_list_for_metavariable context *) in let newsubst = buildsubst i context (Cic.Meta(maxmeta,irl)) ty in let newmeta = maxmeta, context, ty in newsubst::subst, newmeta::menv, maxmeta+1) menv ([], [], newmeta+1) in let metasenv = apply_subst_metasenv subst metasenv in let subst = flatten_subst subst in subst, metasenv, newmeta let fix_metas newmeta (w, p, (ty, left, right, o), menv) = (* let metas = (metas_of_term left)@(metas_of_term right) @(metas_of_term ty)@(metas_of_proof p) in let menv = List.filter (fun (i, _, _) -> List.mem i metas) menv in *) (* debug let _ , eq = fix_metas_old newmeta (w, p, (ty, left, right, o), menv, args) in prerr_endline (string_of_equality eq); *) let subst, metasenv, newmeta = relocate newmeta menv in (* if newmeta > 2839 then begin prerr_endline (CicPp.ppterm left ^ " = " ^ CicPp.ppterm right); prerr_endline (CicMetaSubst.ppsubst subst); prerr_endline (CicMetaSubst.ppmetasenv [] metasenv); assert false; end; *) let ty = apply_subst subst ty in let left = apply_subst subst left in let right = apply_subst subst right in let fix_proof = function | NoProof -> NoProof | BasicProof (subst',term) -> BasicProof (subst@subst',term) | ProofBlock (subst', eq_URI, namety, bo, (pos, eq), p) -> (* let newsubst = 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 *) ProofBlock (subst@subst', eq_URI, namety, bo, (pos, eq), p) | p -> assert false in let p = fix_proof p in (* let metas = (metas_of_term left)@(metas_of_term right) @(metas_of_term ty)@(metas_of_proof p) in let metasenv = List.filter (fun (i, _, _) -> List.mem i metas) metasenv in *) let eq = (w, p, (ty, left, right, o), metasenv) in (* debug prerr_endline (string_of_equality eq); *) newmeta+1, eq let term_is_equality term = let iseq uri = UriManager.eq uri (LibraryObjects.eq_URI ()) in match term with | Cic.Appl [Cic.MutInd (uri, _, _); _; _; _] when iseq uri -> true | _ -> false ;; exception TermIsNotAnEquality;; let equality_of_term proof term = let eq_uri = LibraryObjects.eq_URI () in let iseq uri = UriManager.eq uri eq_uri in match term with | Cic.Appl [Cic.MutInd (uri, _, _); ty; t1; t2] when iseq uri -> let o = !Utils.compare_terms t1 t2 in let stat = (ty,t1,t2,o) in let w = compute_equality_weight stat in let e = (w, BasicProof ([],proof), stat, []) in e | _ -> raise TermIsNotAnEquality ;; type environment = Cic.metasenv * Cic.context * CicUniv.universe_graph;; let is_weak_identity (metasenv, context, ugraph) = function | (_, _, (ty, left, right, _), menv) -> (left = right || (meta_convertibility left right)) (* the test below is not a good idea since it stops demodulation too early *) (* (fst (CicReduction.are_convertible ~metasenv:(metasenv @ menv) context left right ugraph)))*) ;; let is_identity (metasenv, context, ugraph) = function | (_, _, (ty, left, right, _), menv) -> (left = right || (* (meta_convertibility left right)) *) (fst (CicReduction.are_convertible ~metasenv:(metasenv @ menv) context left right ugraph))) ;; let term_of_equality equality = let _, _, (ty, left, right, _), menv = equality in let eq i = function Cic.Meta (j, _) -> i = j | _ -> false in let argsno = List.length menv in let t = CicSubstitution.lift argsno (Cic.Appl [Cic.MutInd (LibraryObjects.eq_URI (), 0, []); ty; left; right]) in snd ( List.fold_right (fun (i,_,ty) (n, t) -> let name = Cic.Name ("X" ^ (string_of_int n)) in let ty = CicSubstitution.lift (n-1) ty in let t = ProofEngineReduction.replace ~equality:eq ~what:[i] ~with_what:[Cic.Rel (argsno - (n - 1))] ~where:t in (n-1, Cic.Prod (name, ty, t))) menv (argsno, t)) ;;