summaryrefslogtreecommitdiff
path: root/tactics/decl_proof_instr.ml
diff options
context:
space:
mode:
Diffstat (limited to 'tactics/decl_proof_instr.ml')
-rw-r--r--tactics/decl_proof_instr.ml291
1 files changed, 188 insertions, 103 deletions
diff --git a/tactics/decl_proof_instr.ml b/tactics/decl_proof_instr.ml
index e7acd6d6..b19d8c04 100644
--- a/tactics/decl_proof_instr.ml
+++ b/tactics/decl_proof_instr.ml
@@ -6,7 +6,7 @@
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(* $Id:$ *)
+(* $Id$ *)
open Util
open Pp
@@ -54,7 +54,7 @@ let tcl_change_info_gen info_gen =
[pftree] ->
{pftree with
goal=gl;
- ref=Some (Change_evars,[pftree])}
+ ref=Some (Prim Change_evars,[pftree])}
| _ -> anomaly "change_info : Wrong number of subtrees")
let tcl_change_info info gls = tcl_change_info_gen (Some (pm_in info)) gls
@@ -92,18 +92,29 @@ let mk_evd metalist gls =
let add_one (meta,typ) evd =
meta_declare meta typ evd in
List.fold_right add_one metalist evd0
+
+let set_last cpl gls =
+ let info = get_its_info gls in
+ tclTHEN
+ begin
+ match info.pm_last with
+ Some (lid,false) when
+ not (occur_id [] lid info.pm_partial_goal) ->
+ tclTRY (clear [lid])
+ | _ -> tclIDTAC
+ end
+ begin
+ tcl_change_info
+ {info with
+ pm_last=Some cpl }
+ end gls
(* start a proof *)
let start_proof_tac gls=
let gl=sig_it gls in
- let info={pm_last=Anonymous;
+ let info={pm_last=None;
pm_partial_goal=mkMeta 1;
- pm_hyps=
- begin
- let hyps = pf_ids_of_hyps gls in
- List.fold_right Idset.add hyps Idset.empty
- end;
pm_subgoals= [1,gl.evar_concl];
pm_stack=[]} in
{it=[{gl with evar_extra=Some (pm_in info)}];sigma=sig_sig gls},
@@ -259,13 +270,12 @@ let add_justification_hyps keep items gls =
letin_tac false (Names.Name id) c Tacexpr.nowhere gls in
tclMAP add_aux items gls
-let apply_to_prepared_goal items kont gls =
+let prepare_goal items gls =
let tokeep = ref Idset.empty in
let auxres = add_justification_hyps tokeep items gls in
tclTHENLIST
[ (fun _ -> auxres);
- filter_hyps (let keep = !tokeep in fun id -> Idset.mem id keep);
- kont ] gls
+ filter_hyps (let keep = !tokeep in fun id -> Idset.mem id keep)] gls
let my_automation_tac = ref
(fun gls -> anomaly "No automation registered")
@@ -276,7 +286,7 @@ let automation_tac gls = !my_automation_tac gls
let justification tac gls=
tclORELSE
- (tclSOLVE [tac])
+ (tclSOLVE [tclTHEN tac assumption])
(fun gls ->
if get_strictness () then
error "insufficient justification"
@@ -286,8 +296,8 @@ let justification tac gls=
daimon_tac gls
end) gls
-let default_justification items gls=
- justification (apply_to_prepared_goal items automation_tac) gls
+let default_justification elems gls=
+ justification (tclTHEN (prepare_goal elems) automation_tac) gls
(* code for have/then/thus/hence *)
@@ -342,10 +352,11 @@ let enstack_subsubgoals env se stack gls=
Array.iteri process gentypes
| _ -> ()
-let find_subsubgoal env c ctyp skip evd metas gls =
+let find_subsubgoal env c ctyp skip evd metas submetas gls =
let stack = Stack.create () in
let max_meta =
- List.fold_left (fun a (m,_) -> max a m) 0 metas in
+ let tmp = List.fold_left (fun a (m,_) -> max a m) 0 metas in
+ List.fold_left (fun a (m,_) -> max a m) tmp submetas in
let _ =
List.iter (fun (m,typ) ->
Stack.push
@@ -361,7 +372,10 @@ let find_subsubgoal env c ctyp skip evd metas gls =
Unification.w_unify true env Reduction.CUMUL
ctyp se.se_type se.se_evd in
if n <= 0 then
- {se with se_evd=meta_assign se.se_meta c unifier}
+ {se with
+ se_evd=meta_assign se.se_meta c unifier;
+ se_meta_list=replace_in_list
+ se.se_meta submetas se.se_meta_list}
else
dfs (pred n)
with _ ->
@@ -381,7 +395,6 @@ let rec nf_list evd =
else
(m,nf_meta evd typ)::nf_list evd others
-
let rec max_linear_context meta_one c =
if !meta_one = None then
if isMeta c then
@@ -403,12 +416,12 @@ let rec max_linear_context meta_one c =
else
map_constr (max_linear_context meta_one) c
-let thus_tac c ctyp gls =
+let thus_tac c ctyp submetas gls =
let info = get_its_info gls in
- let evd0 = mk_evd info.pm_subgoals gls in
+ let evd0 = mk_evd (info.pm_subgoals@submetas) gls in
let list,evd =
try
- find_subsubgoal (pf_env gls) c ctyp 0 evd0 info.pm_subgoals gls
+ find_subsubgoal (pf_env gls) c ctyp 0 evd0 info.pm_subgoals submetas gls
with Not_found ->
error "I could not relate this statement to the thesis" in
let nflist = nf_list evd list in
@@ -450,34 +463,44 @@ let mk_stat_or_thesis info = function
[_,c] -> c
| _ -> error
"\"thesis\" is split, please specify which part you refer to."
-
-let instr_cut mkstat _thus _then cut gls0 =
- let info = get_its_info gls0 in
- let just_tac gls =
+
+let just_tac _then cut info gls0 =
+ let items_tac gls =
match cut.cut_by with
- Automated l ->
- let elems =
+ None -> tclIDTAC gls
+ | Some items ->
+ let items_ =
if _then then
match info.pm_last with
- Anonymous -> l
- | Name id -> (mkVar id) ::l
- else l in
- default_justification elems gls
- | By_tactic t ->
- justification (Tacinterp.eval_tactic t) gls in
- let c_id = match cut.cut_stat.st_label with
+ None -> error "no previous statement to use"
+ | Some (id,_) -> (mkVar id)::items
+ else items
+ in prepare_goal items_ gls in
+ let method_tac gls =
+ match cut.cut_using with
+ None ->
+ automation_tac gls
+ | Some tac ->
+ (Tacinterp.eval_tactic tac) gls in
+ justification (tclTHEN items_tac method_tac) gls0
+
+let instr_cut mkstat _thus _then cut gls0 =
+ let info = get_its_info gls0 in
+ let stat = cut.cut_stat in
+ let (c_id,_) as cpl = match stat.st_label with
Anonymous ->
- pf_get_new_id (id_of_string "_fact") gls0
- | Name id -> id in
- let c_stat = mkstat info cut.cut_stat.st_it in
+ pf_get_new_id (id_of_string "_fact") gls0,false
+ | Name id -> id,true in
+ let c_stat = mkstat info stat.st_it in
let thus_tac gls=
if _thus then
- thus_tac (mkVar c_id) c_stat gls
+ thus_tac (mkVar c_id) c_stat [] gls
else tclIDTAC gls in
- let ninfo = {info with pm_last=Name c_id} in
tclTHENS (internal_cut c_id c_stat)
- [tclTHEN tcl_erase_info just_tac;
- tclTHEN (tcl_change_info ninfo) thus_tac] gls0
+ [tclTHEN tcl_erase_info (just_tac _then cut info);
+ tclTHEN (set_last cpl) thus_tac] gls0
+
+
(* iterated equality *)
let _eq = Libnames.constr_of_reference (Coqlib.glob_eq)
@@ -498,24 +521,28 @@ let instr_rew _thus rew_side cut gls0 =
let info = get_its_info gls0 in
let last_id =
match info.pm_last with
- Anonymous -> error "no previous equality"
- | Name id -> id in
+ None -> error "no previous equality"
+ | Some (id,_) -> id in
let typ,lhs,rhs = decompose_eq last_id gls0 in
- let just_tac gls =
+ let items_tac gls =
match cut.cut_by with
- Automated l ->
- let elems = (mkVar last_id) :: l in
- default_justification elems gls
- | By_tactic t ->
- justification (Tacinterp.eval_tactic t) gls in
- let c_id = match cut.cut_stat.st_label with
+ None -> tclIDTAC gls
+ | Some items -> prepare_goal items gls in
+ let method_tac gls =
+ match cut.cut_using with
+ None ->
+ automation_tac gls
+ | Some tac ->
+ (Tacinterp.eval_tactic tac) gls in
+ let just_tac gls =
+ justification (tclTHEN items_tac method_tac) gls in
+ let (c_id,_) as cpl = match cut.cut_stat.st_label with
Anonymous ->
- pf_get_new_id (id_of_string "_eq") gls0
- | Name id -> id in
- let ninfo = {info with pm_last=Name c_id} in
+ pf_get_new_id (id_of_string "_eq") gls0,false
+ | Name id -> id,true in
let thus_tac new_eq gls=
if _thus then
- thus_tac (mkVar c_id) new_eq gls
+ thus_tac (mkVar c_id) new_eq [] gls
else tclIDTAC gls in
match rew_side with
Lhs ->
@@ -524,14 +551,14 @@ let instr_rew _thus rew_side cut gls0 =
[tclTHEN tcl_erase_info
(tclTHENS (transitivity lhs)
[just_tac;exact_check (mkVar last_id)]);
- tclTHEN (tcl_change_info ninfo) (thus_tac new_eq)] gls0
+ tclTHEN (set_last cpl) (thus_tac new_eq)] gls0
| Rhs ->
let new_eq = mkApp(_eq,[|typ;lhs;cut.cut_stat.st_it|]) in
tclTHENS (internal_cut c_id new_eq)
[tclTHEN tcl_erase_info
(tclTHENS (transitivity rhs)
[exact_check (mkVar last_id);just_tac]);
- tclTHEN (tcl_change_info ninfo) (thus_tac new_eq)] gls0
+ tclTHEN (set_last cpl) (thus_tac new_eq)] gls0
@@ -539,22 +566,21 @@ let instr_rew _thus rew_side cut gls0 =
let instr_claim _thus st gls0 =
let info = get_its_info gls0 in
- let id = match st.st_label with
- Anonymous -> pf_get_new_id (id_of_string "_claim") gls0
- | Name id -> id in
+ let (id,_) as cpl = match st.st_label with
+ Anonymous -> pf_get_new_id (id_of_string "_claim") gls0,false
+ | Name id -> id,true in
let thus_tac gls=
if _thus then
- thus_tac (mkVar id) st.st_it gls
+ thus_tac (mkVar id) st.st_it [] gls
else tclIDTAC gls in
let ninfo1 = {info with
pm_stack=
(if _thus then Focus_claim else Claim)::info.pm_stack;
pm_partial_goal=mkMeta 1;
pm_subgoals = [1,st.st_it]} in
- let ninfo2 = {info with pm_last=Name id} in
tclTHENS (internal_cut id st.st_it)
[tcl_change_info ninfo1;
- tclTHEN (tcl_change_info ninfo2) thus_tac] gls0
+ tclTHEN (set_last cpl) thus_tac] gls0
(* tactics for assume *)
@@ -565,11 +591,6 @@ let reset_concl gls =
pm_partial_goal=mkMeta 1;
pm_subgoals= [1,gls.it.evar_concl]} gls
-let set_last id gls =
- let info = get_its_info gls in
- tcl_change_info
- {info with
- pm_last=Name id} gls
let intro_pm id gls=
let info = get_its_info gls in
@@ -579,20 +600,14 @@ let intro_pm id gls=
| _ -> error "Goal is split"
let push_intro_tac coerce nam gls =
- let hid =
+ let (hid,_) as cpl =
match nam with
- Anonymous -> pf_get_new_id (id_of_string "_hyp") gls
- | Name id -> id in
- let mark_id gls0 =
- let info = get_its_info gls0 in
- let ninfo = {info with
- pm_last = Name hid;
- pm_hyps = Idset.add hid info.pm_hyps } in
- tcl_change_info ninfo gls0 in
+ Anonymous -> pf_get_new_id (id_of_string "_hyp") gls,false
+ | Name id -> id,true in
tclTHENLIST
[intro_pm hid;
coerce hid;
- mark_id]
+ set_last cpl]
gls
let assume_tac hyps gls =
@@ -635,6 +650,56 @@ let assume_st_letin hyps gls =
convert_hyp (id,Some (fst st.st_it),snd st.st_it)) st.st_label))
hyps tclIDTAC gls
+(* suffices *)
+
+let free_meta info =
+ let max_next (i,_) j = if j <= i then succ i else j in
+ List.fold_right max_next info.pm_subgoals 1
+
+let rec metas_from n hyps =
+ match hyps with
+ _ :: q -> n :: metas_from (succ n) q
+ | [] -> []
+
+let rec build_product args body =
+ match args with
+ (Hprop st| Hvar st )::rest ->
+ let pprod= lift 1 (build_product rest body) in
+ let lbody =
+ match st.st_label with
+ Anonymous -> pprod
+ | Name id -> subst_term (mkVar id) pprod in
+ mkProd (st.st_label, st.st_it, lbody)
+ | [] -> body
+
+let rec build_applist prod = function
+ [] -> [],prod
+ | n::q ->
+ let (_,typ,_) = destProd prod in
+ let ctx,head = build_applist (Term.prod_applist prod [mkMeta n]) q in
+ (n,typ)::ctx,head
+
+let instr_suffices _then cut gls0 =
+ let info = get_its_info gls0 in
+ let c_id = pf_get_new_id (id_of_string "_cofact") gls0 in
+ let ctx,hd = cut.cut_stat in
+ let c_stat = build_product ctx (mk_stat_or_thesis info hd) in
+ let metas = metas_from (free_meta info) ctx in
+ let c_ctx,c_head = build_applist c_stat metas in
+ let c_term = applist (mkVar c_id,List.map mkMeta metas) in
+ let thus_tac gls=
+ thus_tac c_term c_head c_ctx gls in
+ tclTHENS (internal_cut c_id c_stat)
+ [tclTHENLIST
+ [ tcl_change_info
+ {info with
+ pm_partial_goal=mkMeta 1;
+ pm_subgoals=[1,c_stat]};
+ assume_tac ctx;
+ tcl_erase_info;
+ just_tac _then cut info];
+ tclTHEN (set_last (c_id,false)) thus_tac] gls0
+
(* tactics for consider/given *)
let update_goal_info gls =
@@ -684,14 +749,7 @@ let pm_rename_hyp id hid gls =
let rec consider_match may_intro introduced available expected gls =
match available,expected with
[],[] ->
- if not may_intro then
set_last (List.hd introduced) gls
- else
- let info = get_its_info gls in
- let nameset=List.fold_right Idset.add introduced info.pm_hyps in
- tcl_change_info {info with
- pm_last = Name (List.hd introduced);
- pm_hyps = nameset} gls
| _,[] -> error "last statements do not match a complete hypothesis"
(* should tell which ones *)
| [],hyps ->
@@ -704,7 +762,7 @@ let rec consider_match may_intro introduced available expected gls =
(fun _ ->
error "not enough sub-hypotheses to match statements")
gls
- end
+ end
else
error "not enough sub-hypotheses to match statements"
(* should tell which ones *)
@@ -713,11 +771,11 @@ let rec consider_match may_intro introduced available expected gls =
begin
match st.st_label with
Anonymous ->
- consider_match may_intro (id::introduced) rest_ids rest
+ consider_match may_intro ((id,false)::introduced) rest_ids rest
| Name hid ->
tclTHENLIST
[pm_rename_hyp id hid;
- consider_match may_intro (hid::introduced) rest_ids rest]
+ consider_match may_intro ((hid,true)::introduced) rest_ids rest]
end
begin
(fun gls ->
@@ -753,7 +811,7 @@ let rec take_tac wits gls =
[] -> tclIDTAC gls
| wit::rest ->
let typ = pf_type_of gls wit in
- tclTHEN (thus_tac wit typ) (take_tac rest) gls
+ tclTHEN (thus_tac wit typ []) (take_tac rest) gls
(* tactics for define *)
@@ -874,17 +932,6 @@ let per_tac etype casee gls=
(* suppose *)
-let rec build_product args body =
- match args with
- (Hprop st| Hvar st )::rest ->
- let pprod= lift 1 (build_product rest body) in
- let lbody =
- match st.st_label with
- Anonymous -> body
- | Name id -> subst_term (mkVar id) pprod in
- mkProd (st.st_label, st.st_it, lbody)
- | [] -> body
-
let register_nodep_subcase id= function
Per(et,pi,ek,clauses)::s ->
begin
@@ -1201,6 +1248,30 @@ let hrec_for obj_id fix_id per_info gls=
else None
| _ -> None
+
+(* custom elim performs the case analysis of hypothesis id from the local
+context,
+
+- generalizing hypotheses below id
+- computing the elimination predicate (abstract inductive predicate)
+- build case analysis term
+- generalize rec_calls (use wf_paths)
+- vector of introduced identifiers per branch
+
+match id in t return p with
+ C1 ... => ?1
+|C2 ... => ?2
+...
+end*)
+
+
+
+
+
+
+
+
+
let rec execute_cases at_top fix_name per_info kont0 stacks tree gls =
match tree with
Pop t ->
@@ -1388,6 +1459,8 @@ let rec do_proof_instr_gen _thus _then instr =
do_proof_instr_gen true true i
| Pcut c ->
instr_cut mk_stat_or_thesis _thus _then c
+ | Psuffices c ->
+ instr_suffices _then c
| Prew (s,c) ->
assert (not _then);
instr_rew _thus s c
@@ -1412,7 +1485,7 @@ let eval_instr {instr=instr} =
let rec preprocess pts instr =
match instr with
Phence i |Pthus i | Pthen i -> preprocess pts i
- | Pcut _ | Passume _ | Plet _ | Pclaim _ | Pfocus _
+ | Psuffices _ | Pcut _ | Passume _ | Plet _ | Pclaim _ | Pfocus _
| Pconsider (_,_) | Pcast (_,_) | Pgiven _ | Ptake _
| Pdefine (_,_,_) | Pper _ | Prew _ ->
check_not_per pts;
@@ -1428,11 +1501,23 @@ let rec preprocess pts instr =
let rec postprocess pts instr =
match instr with
Phence i | Pthus i | Pthen i -> postprocess pts i
- | Pcut _ | Passume _ | Plet _ | Pconsider (_,_) | Pcast (_,_)
+ | Pcut _ | Psuffices _ | Passume _ | Plet _ | Pconsider (_,_) | Pcast (_,_)
| Pgiven _ | Ptake _ | Pdefine (_,_,_) | Prew (_,_) -> pts
| Pclaim _ | Pfocus _ | Psuppose _ | Pcase _ | Pper _ -> nth_unproven 1 pts
- | Pescape ->
- escape_command pts
+ | Pescape -> escape_command pts
+ | Pend (B_elim ET_Induction) ->
+ begin
+ let pf = proof_of_pftreestate pts in
+ let (pfterm,_) = extract_open_pftreestate pts in
+ let env = Evd.evar_env (goal_of_proof pf) in
+ try
+ Inductiveops.control_only_guard env pfterm;
+ goto_current_focus_or_top (mark_as_done pts)
+ with
+ Type_errors.TypeError(env,
+ Type_errors.IllFormedRecBody(_,_,_)) ->
+ anomaly "\"end induction\" generated an ill-formed fixpoint"
+ end
| Pend _ ->
goto_current_focus_or_top (mark_as_done pts)