+
+module TC = CicTypeChecker
+module UM = UriManager
+module R = CicReduction
+module C = Cic
+module PEH = ProofEngineHelpers
+module PER = ProofEngineReduction
+module MS = CicMetaSubst
+module S = CicSubstitution
+module T = Tacticals
+module RT = ReductionTactics
+
+let rec args_init n f =
+ if n <= 0 then [] else f n :: args_init (pred n) f
+
+let mk_predicate_for_elim
+ ~context ~metasenv ~ugraph ~goal ~arg ~using ~cpattern ~args_no =
+ let instantiated_eliminator =
+ let f n = if n = 1 then arg else C.Implicit None in
+ C.Appl (using :: args_init args_no f)
+ in
+ let _actual_arg, iety, _metasenv', _ugraph =
+ CicRefine.type_of_aux' metasenv context instantiated_eliminator ugraph
+ in
+ let _actual_meta, actual_args = match iety with
+ | C.Meta (i, _) -> i, []
+ | C.Appl (C.Meta (i, _) :: args) -> i, args
+ | _ -> assert false
+ in
+(* let _, upto = PEH.split_with_whd (List.nth splits pred_pos) in *)
+ let rec mk_pred metasenv context' pred arg' cpattern' = function
+ | [] -> metasenv, pred, arg'
+ | arg :: tail ->
+(* FG: we find the predicate for the eliminator as in the rewrite tactic ****)
+ let argty, _ugraph = TC.type_of_aux' metasenv context arg ugraph in
+ let argty = CicReduction.whd context argty in
+ let fresh_name =
+ FreshNamesGenerator.mk_fresh_name
+ ~subst:[] metasenv context' C.Anonymous ~typ:argty in
+ let hyp = Some (fresh_name, C.Decl argty) in
+ let lazy_term c m u =
+ let distance = List.length c - List.length context in
+ S.lift distance arg, m, u in
+ let pattern = Some lazy_term, [], Some cpattern' in
+ let subst, metasenv, _ugraph, _conjecture, selected_terms =
+ ProofEngineHelpers.select ~metasenv ~ugraph
+ ~conjecture:(0, context, pred) ~pattern in
+ let metasenv = MS.apply_subst_metasenv subst metasenv in
+ let map (_context_of_t, t) l = t :: l in
+ let what = List.fold_right map selected_terms [] in
+ let arg' = MS.apply_subst subst arg' in
+ let argty = MS.apply_subst subst argty in
+ let pred = PER.replace_with_rel_1_from ~equality:(==) ~what 1 pred in
+ let pred = MS.apply_subst subst pred in
+ let pred = C.Lambda (fresh_name, argty, pred) in
+ let cpattern' = C.Lambda (C.Anonymous, C.Implicit None, cpattern') in
+ mk_pred metasenv (hyp :: context') pred arg' cpattern' tail
+ in
+ let metasenv, pred, arg =
+ mk_pred metasenv context goal arg cpattern (List.rev actual_args)
+ in
+ HLog.debug ("PREDICATE: " ^ CicPp.ppterm ~metasenv pred ^ " ARGS: " ^ String.concat " " (List.map (CicPp.ppterm ~metasenv) actual_args));
+ metasenv, pred, arg, actual_args
+
+let beta_after_elim_tac upto predicate =
+ let beta_after_elim_tac status =
+ let proof, goal = status in
+ let _, metasenv, _subst, _, _, _ = proof in
+ let _, _, ty = CicUtil.lookup_meta goal metasenv in
+ let mk_pattern ~equality ~upto ~predicate ty =
+ (* code adapted from ProceduralConversion.generalize *)
+ let meta = C.Implicit None in
+ let hole = C.Implicit (Some `Hole) in
+ let anon = C.Anonymous in
+ let is_meta =
+ let map b = function
+ | C.Implicit None when b -> b
+ | _ -> false
+ in
+ List.fold_left map true
+ in
+ let rec gen_fix len k (name, i, ty, bo) =
+ name, i, gen_term k ty, gen_term (k + len) bo
+ and gen_cofix len k (name, ty, bo) =
+ name, gen_term k ty, gen_term (k + len) bo
+ and gen_term k = function
+ | C.Sort _
+ | C.Implicit _
+ | C.Const (_, _)
+ | C.Var (_, _)
+ | C.MutInd (_, _, _)
+ | C.MutConstruct (_, _, _, _)
+ | C.Meta (_, _)
+ | C.Rel _ -> meta
+ | C.Appl (hd :: tl) when equality hd (S.lift k predicate) ->
+ assert (List.length tl = upto);
+ hole
+ | C.Appl ts ->
+ let ts = List.map (gen_term k) ts in
+ if is_meta ts then meta else C.Appl ts
+ | C.Cast (te, ty) ->
+ let te, ty = gen_term k te, gen_term k ty in
+ if is_meta [te; ty] then meta else C.Cast (te, ty)
+ | C.MutCase (sp, i, outty, t, pl) ->
+ let outty, t, pl = gen_term k outty, gen_term k t, List.map (gen_term k) pl in
+ if is_meta (outty :: t :: pl) then meta else hole (* C.MutCase (sp, i, outty, t, pl) *)
+ | C.Prod (_, s, t) ->
+ let s, t = gen_term k s, gen_term (succ k) t in
+ if is_meta [s; t] then meta else C.Prod (anon, s, t)
+ | C.Lambda (_, s, t) ->
+ let s, t = gen_term k s, gen_term (succ k) t in
+ if is_meta [s; t] then meta else C.Lambda (anon, s, t)
+ | C.LetIn (_, s, ty, t) ->
+ let s,ty,t = gen_term k s, gen_term k ty, gen_term (succ k) t in
+ if is_meta [s; t] then meta else C.LetIn (anon, s, ty, t)
+ | C.Fix (i, fl) -> C.Fix (i, List.map (gen_fix (List.length fl) k) fl)
+ | C.CoFix (i, fl) -> C.CoFix (i, List.map (gen_cofix (List.length fl) k) fl)
+ in
+ None, [], Some (gen_term 0 ty)
+ in
+ let equality = CicUtil.alpha_equivalence in
+ let pattern = mk_pattern ~equality ~upto ~predicate ty in
+ let tactic = RT.head_beta_reduce_tac ~delta:false ~upto ~pattern in
+ PET.apply_tactic tactic status
+ in
+ PET.mk_tactic beta_after_elim_tac
+
+(* ANCORA DA DEBUGGARE *)
+
+exception UnableToDetectTheTermThatMustBeGeneralizedYouMustGiveItExplicitly;;
+exception TheSelectedTermsMustLiveInTheGoalContext
+exception AllSelectedTermsMustBeConvertible;;
+exception GeneralizationInHypothesesNotImplementedYet;;
+
+let generalize_tac
+ ?(mk_fresh_name_callback = FreshNamesGenerator.mk_fresh_name ~subst:[])
+ pattern
+ =
+ let module PET = ProofEngineTypes in
+ let generalize_tac mk_fresh_name_callback
+ ~pattern:(term,hyps_pat,_) status
+ =
+ if hyps_pat <> [] then raise GeneralizationInHypothesesNotImplementedYet;
+ let (proof, goal) = status in
+ let module C = Cic in
+ let module T = Tacticals in
+ let uri,metasenv,_subst,pbo,pty, attrs = proof in
+ let (_,context,ty) as conjecture = CicUtil.lookup_meta goal metasenv in
+ let subst,metasenv,u,selected_hyps,terms_with_context =
+ ProofEngineHelpers.select ~metasenv ~ugraph:CicUniv.oblivion_ugraph
+ ~conjecture ~pattern in
+ let context = CicMetaSubst.apply_subst_context subst context in
+ let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
+ let pbo = lazy (CicMetaSubst.apply_subst subst (Lazy.force pbo)) in
+ let pty = CicMetaSubst.apply_subst subst pty in
+ let term =
+ match term with
+ None -> None
+ | Some term ->
+ Some (fun context metasenv ugraph ->
+ let term, metasenv, ugraph = term context metasenv ugraph in
+ CicMetaSubst.apply_subst subst term,
+ CicMetaSubst.apply_subst_metasenv subst metasenv,
+ ugraph)
+ in
+ let u,typ,term, metasenv' =
+ let context_of_t, (t, metasenv, u) =
+ match terms_with_context, term with
+ [], None ->
+ raise
+ UnableToDetectTheTermThatMustBeGeneralizedYouMustGiveItExplicitly
+ | [], Some t -> context, t context metasenv u
+ | (context_of_t, _)::_, Some t ->
+ context_of_t, t context_of_t metasenv u
+ | (context_of_t, t)::_, None -> context_of_t, (t, metasenv, u)
+ in
+ let t,subst,metasenv' =
+ try
+ CicMetaSubst.delift_rels [] metasenv
+ (List.length context_of_t - List.length context) t
+ with
+ CicMetaSubst.DeliftingARelWouldCaptureAFreeVariable ->
+ raise TheSelectedTermsMustLiveInTheGoalContext
+ in
+ (*CSC: I am not sure about the following two assertions;
+ maybe I need to propagate the new subst and metasenv *)
+ assert (subst = []);
+ assert (metasenv' = metasenv);
+ let typ,u = CicTypeChecker.type_of_aux' ~subst metasenv context t u in
+ u,typ,t,metasenv
+ in
+ (* We need to check:
+ 1. whether they live in the context of the goal;
+ if they do they are also well-typed since they are closed subterms
+ of a well-typed term in the well-typed context of the well-typed
+ term
+ 2. whether they are convertible
+ *)
+ ignore (
+ List.fold_left
+ (fun u (context_of_t,t) ->
+ (* 1 *)
+ let t,subst,metasenv'' =
+ try
+ CicMetaSubst.delift_rels [] metasenv'
+ (List.length context_of_t - List.length context) t
+ with
+ CicMetaSubst.DeliftingARelWouldCaptureAFreeVariable ->
+ raise TheSelectedTermsMustLiveInTheGoalContext in
+ (*CSC: I am not sure about the following two assertions;
+ maybe I need to propagate the new subst and metasenv *)
+ assert (subst = []);
+ assert (metasenv'' = metasenv');
+ (* 2 *)
+ let b,u1 = CicReduction.are_convertible ~subst context term t u in
+ if not b then
+ raise AllSelectedTermsMustBeConvertible
+ else
+ u1
+ ) u terms_with_context) ;
+ let status = (uri,metasenv',_subst,pbo,pty, attrs),goal in
+ let proof,goals =
+ PET.apply_tactic
+ (T.thens
+ ~start:
+ (cut_tac
+ (C.Prod(
+ (mk_fresh_name_callback metasenv context C.Anonymous ~typ:typ),
+ typ,
+ (ProofEngineReduction.replace_lifting_csc 1
+ ~equality:(==)
+ ~what:(List.map snd terms_with_context)
+ ~with_what:(List.map (function _ -> C.Rel 1) terms_with_context)
+ ~where:ty)
+ )))
+ ~continuations:
+ [(apply_tac ~term:(C.Appl [C.Rel 1; CicSubstitution.lift 1 term])) ;
+ T.id_tac])
+ status
+ in
+ let _,metasenv'',_subst,_,_, _ = proof in
+ (* CSC: the following is just a bad approximation since a meta
+ can be closed and then re-opened! *)
+ (proof,
+ goals @
+ (List.filter
+ (fun j -> List.exists (fun (i,_,_) -> i = j) metasenv'')
+ (ProofEngineHelpers.compare_metasenvs ~oldmetasenv:metasenv
+ ~newmetasenv:metasenv')))
+ in
+ PET.mk_tactic (generalize_tac mk_fresh_name_callback ~pattern)
+;;
+
+let generalize_pattern_tac pattern =
+ let generalize_pattern_tac (proof,goal) =
+ let _,metasenv,_,_,_,_ = proof in
+ let conjecture = CicUtil.lookup_meta goal metasenv in
+ let _,context,_ = conjecture in
+ let generalize_hyps =
+ let _,hpatterns,_ = ProofEngineHelpers.sort_pattern_hyps context pattern in
+ List.map fst hpatterns in
+ let ids_and_patterns =
+ List.map
+ (fun id ->
+ let rel,_ = ProofEngineHelpers.find_hyp id context in
+ id,(Some (fun ctx m u -> CicSubstitution.lift (List.length ctx - List.length context) rel,m,u), [], Some (ProofEngineTypes.hole))
+ ) generalize_hyps in
+ let tactics =
+ List.map
+ (function (id,pattern) ->
+ Tacticals.then_ ~start:(generalize_tac pattern)
+ ~continuation:(Tacticals.try_tactic
+ (ProofEngineStructuralRules.clear [id]))
+ ) ids_and_patterns
+ in
+ PET.apply_tactic (Tacticals.seq tactics) (proof,goal)
+ in
+ PET.mk_tactic (generalize_pattern_tac)
+;;
+
+let pattern_after_generalize_pattern_tac (tp, hpatterns, cpattern) =
+ let cpattern =
+ match cpattern with
+ None -> ProofEngineTypes.hole
+ | Some t -> t
+ in
+ let cpattern =
+ List.fold_left
+ (fun t (_,ty) -> Cic.Prod (Cic.Anonymous, ty, t)) cpattern hpatterns
+ in
+ tp, [], Some cpattern
+;;
+
+let elim_tac ?using ?(pattern = PET.conclusion_pattern None) term =
+ let elim_tac pattern (proof, goal) =
+ let ugraph = CicUniv.oblivion_ugraph in
+ let curi, metasenv, _subst, proofbo, proofty, attrs = proof in
+ let conjecture = CicUtil.lookup_meta goal metasenv in
+ let metano, context, ty = conjecture in
+ let pattern = pattern_after_generalize_pattern_tac pattern in
+ let cpattern =
+ match pattern with
+ | None, [], Some cpattern -> cpattern
+ | _ -> raise (PET.Fail (lazy "not implemented")) in
+ let termty,_ugraph = TC.type_of_aux' metasenv context term ugraph in