(* 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/. *) open Utils;; type equality = int * (* weight *) proof * (Cic.term * (* type *) Cic.term * (* left side *) Cic.term * (* right side *) Utils.comparison) * (* ordering *) Cic.metasenv * (* environment for metas *) Cic.term list (* arguments *) and proof = | NoProof | BasicProof of Cic.term | ProofBlock of Cic.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 t -> "BasicProof " ^ (CicPp.ppterm 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 _ -> "ProofBlock" | ProofGoalBlock (p1, p2) -> Printf.sprintf "ProofGoalBlock(%s, %s)" (string_of_proof p1) (string_of_proof p2) ;; (* 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 proof = let rec do_build_proof proof = match proof with | NoProof -> Printf.fprintf stderr "WARNING: no proof!\n"; Cic.Implicit None | BasicProof term -> 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', args' = eq in let what, other = if pos = Utils.Left then what, other else other, what in CicMetaSubst.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) | _ -> [] ;; exception NotMetaConvertible;; let meta_convertibility_aux table t1 t2 = let module C = Cic in let print_table t = String.concat ", " (List.map (fun (k, v) -> Printf.sprintf "(%d, %d)" k v) t) 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 = let f t = String.concat ", " (List.map (fun (k, v) -> Printf.sprintf "(%d, %d)" k v) t) in if t1 = t2 then true else try let l, r = meta_convertibility_aux ([], []) t1 t2 in 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 lookup_subst meta subst = match meta with | Cic.Meta (i, _) -> ( try let _, (_, t, _) = List.find (fun (m, _) -> m = i) subst in t with Not_found -> meta ) | _ -> assert false ;; let unification_simple metasenv context t1 t2 ugraph = 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 i > j -> unif subst menv t s | C.Meta _, t when occurs_check subst s t -> raise (U.UnificationFailure (U.failure_msg_of_string "Inference.unification.unif")) | C.Meta (i, l), t -> ( try let _, _, ty = CicUtil.lookup_meta i menv in let subst = if not (List.mem_assoc i subst) then (i, (context, t, ty))::subst else 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 (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 (U.failure_msg_of_string "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 (U.failure_msg_of_string "Inference.unification.unif")) ) | _, _ -> raise (U.UnificationFailure (U.failure_msg_of_string "Inference.unification.unif")) in let subst, menv = unif [] metasenv t1 t2 in let menv = List.filter (fun (m, _, _) -> try let _ = List.find (fun (i, _) -> m = i) subst in false with Not_found -> true) menv in List.rev subst, menv, ugraph ;; let unification metasenv context t1 t2 ugraph = 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))); CicUnification.fo_unif metasenv context t1 t2 ugraph ) else unification_simple metasenv context t1 t2 ugraph in let rec fix_term = function | (Cic.Meta (i, l) as t) -> let t' = lookup_subst t subst in if t <> t' then fix_term t' else t | Cic.Appl l -> Cic.Appl (List.map fix_term l) | t -> t in let rec fix_subst = function | [] -> [] | (i, (c, t, ty))::tl -> (i, (c, fix_term t, fix_term ty))::(fix_subst tl) in fix_subst subst, menv, ug ;; (* let unification = CicUnification.fo_unif;; *) exception MatchingFailure;; (* let matching_simple metasenv context t1 t2 ugraph = let module C = Cic in let module M = CicMetaSubst in let module U = CicUnification in let lookup meta subst = match meta with | C.Meta (i, _) -> ( try let _, (_, t, _) = List.find (fun (m, _) -> m = i) subst in t with Not_found -> meta ) | _ -> assert false in let rec do_match subst menv s t = match s, t with | s, t when s = t -> subst, menv | s, C.Meta (i, l) -> let filter_menv i menv = List.filter (fun (m, _, _) -> i <> m) menv in let subst, menv = let value = lookup t subst in match value with | value when value = t -> let _, _, ty = CicUtil.lookup_meta i menv in (i, (context, s, ty))::subst, filter_menv i menv | value when value <> s -> raise MatchingFailure | value -> do_match subst menv s value in subst, menv | C.Appl ls, C.Appl lt -> ( try List.fold_left2 (fun (subst, menv) s t -> do_match subst menv s t) (subst, menv) ls lt with Invalid_argument _ -> raise MatchingFailure ) | _, _ -> raise MatchingFailure in let subst, menv = do_match [] metasenv t1 t2 in subst, menv, ugraph ;; *) let matching metasenv context t1 t2 ugraph = try let subst, metasenv, ugraph = unification metasenv context t1 t2 ugraph in let t' = CicMetaSubst.apply_subst subst t1 in if not (meta_convertibility t1 t') then raise MatchingFailure else let metas = metas_of_term t1 in let fix_subst = function | (i, (c, Cic.Meta (j, lc), ty)) when List.mem i metas -> (j, (c, Cic.Meta (i, lc), ty)) | s -> s in let subst = List.map fix_subst subst in subst, metasenv, ugraph with | CicUnification.UnificationFailure _ | CicUnification.Uncertain _ -> raise MatchingFailure ;; 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 w = compute_equality_weight ty t1 t2 in let proof = BasicProof p in let e = (w, proof, (ty, t1, t2, o), newmetas, args) in Some e, (newmeta+1) | _ -> None, newmeta ) | C.Appl [C.MutInd (uri, _, _); ty; t1; t2] when UriManager.eq uri eq_uri -> let t1 = S.lift index t1 and t2 = S.lift index t2 in let o = !Utils.compare_terms t1 t2 in let w = compute_equality_weight ty t1 t2 in let e = (w, BasicProof (C.Rel index), (ty, t1, t2, o), [], []) 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 (index, p)::tl, max newmeta newmeta' | 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 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 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 -> let suri = UriManager.string_of_uri uri in 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 w = compute_equality_weight ty t1 t2 in let proof = BasicProof p in let e = (w, proof, (ty, t1, t2, o), newmetas, args) 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 w = compute_equality_weight ty t1 t2 in let e = (w, BasicProof term, (ty, t1, t2, o), [], []) in Some e, (newmeta+1) | _ -> None, newmeta in match res with | Some e -> let tl, newmeta' = aux newmeta tl in (uri, e)::tl, max newmeta newmeta' | 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) 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, 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 newmeta ((w, p, (ty, left, right, o), menv, args) as equality) = 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) 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 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 w = compute_equality_weight ty t1 t2 in let e = (w, BasicProof proof, (ty, t1, t2, o), [], []) in e | _ -> raise TermIsNotAnEquality ;; type environment = Cic.metasenv * Cic.context * CicUniv.universe_graph;; let is_identity ((_, context, ugraph) as env) = function | ((_, _, (ty, left, right, _), _, _) as equality) -> (left = right || (meta_convertibility left right) || (fst (CicReduction.are_convertible context left right ugraph))) ;;