diff options
Diffstat (limited to 'hol-light/TacticRecording/xtactics.ml')
-rw-r--r-- | hol-light/TacticRecording/xtactics.ml | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/hol-light/TacticRecording/xtactics.ml b/hol-light/TacticRecording/xtactics.ml new file mode 100644 index 00000000..79b81648 --- /dev/null +++ b/hol-light/TacticRecording/xtactics.ml @@ -0,0 +1,449 @@ +(* ========================================================================= *) +(* HOL Light subgoal package amended for id-carrying goals. *) +(* *) +(* Mark Adams, School of Informatics, University of Edinburgh *) +(* *) +(* (c) Copyright, University of Edinburgh, 2012 *) +(* ========================================================================= *) + +(* The 'xgoal' variant of the 'goal' datatype is defined here, to label *) +(* goals with a unique goal id. This gives a basis for recording tactic *) +(* proofs. Variants of all the datatypes depending on 'goal', such as *) +(* 'xgoalstate' and 'xtactic', are also defined, along with a variant *) +(* subgoal package. ML names are given an "x" prefix to keep them distinct *) +(* from the originals for now (but originals are overwritten later, in *) +(* 'install.ml'). *) + +(* The goal id counter is only adjusted in this file by being incremented in *) +(* 'mk_xgoalstate', used when starting a new subgoal package proof. *) +(* Xtactics are assumed to give their resulting xgoals id labels based on an *) +(* appropriately updated goal id counter. *) + +(* After the implementation of xgoals themselves at the start of this file, *) +(* the rest of the file is more-or-less copied verbatim from HOL Light's *) +(* original 'tactics.ml', with just a few changes required. This enables an *) +(* easy diff operation with the original if required to check that the *) +(* changes are valid. *) + +(* ------------------------------------------------------------------------- *) +(* Goal counter for providing goal ids. *) +(* ------------------------------------------------------------------------- *) + +type goalid = int;; + +let string_of_goal_id (id:goalid) = string_of_int id;; + +let the_goal_id_counter = ref (0 : goalid);; + +let inc_goal_id_counter () = + (the_goal_id_counter := !the_goal_id_counter + 1);; + +(* ------------------------------------------------------------------------- *) +(* An xgoal extends a goal with an identity. *) +(* ------------------------------------------------------------------------- *) + +type xgoal = goal * goalid;; + +let equals_xgoal (((a,w),_):xgoal) (((a',w'),_):xgoal) = + forall2 (fun (s,th) (s',th') -> s = s' & equals_thm th th') a a' & w = w';; + +let mk_xgoal (gn:goal*goalid) : xgoal = gn;; + +let dest_xgoal (gn:xgoal) : goal*goalid = gn;; + +let xgoal_goal ((g,id):xgoal) : goal = g;; + +let xgoal_id ((g,id):xgoal) : goalid = id;; + +(* ------------------------------------------------------------------------- *) +(* The xgoalstate is like goalstate but for xgoals instead of goals. *) +(* ------------------------------------------------------------------------- *) + +type xgoalstate = (term list * instantiation) * xgoal list * justification;; + +(* ------------------------------------------------------------------------- *) +(* A goalstack but for xgoals. *) +(* ------------------------------------------------------------------------- *) + +type xgoalstack = xgoalstate list;; + +(* ------------------------------------------------------------------------- *) +(* Refinements for xgoals. *) +(* ------------------------------------------------------------------------- *) + +type xrefinement = xgoalstate -> xgoalstate;; + +(* ------------------------------------------------------------------------- *) +(* Tactics for xgoals. *) +(* ------------------------------------------------------------------------- *) + +type xtactic = xgoal -> xgoalstate;; + +type xthm_tactic = xthm -> xtactic;; + +type xthm_tactical = xthm_tactic -> xthm_tactic;; + +(* ------------------------------------------------------------------------- *) +(* Instantiation of xgoals. *) +(* ------------------------------------------------------------------------- *) + +let (inst_xgoal:instantiation->xgoal->xgoal) = + fun p ((thms,w),id) -> + (map (I F_F INSTANTIATE_ALL p) thms,instantiate p w),id;; + +(* ------------------------------------------------------------------------- *) +(* Validity check for xtactics. *) +(* ------------------------------------------------------------------------- *) + +let (xVALID:xtactic->xtactic) = + let fake_thm ((asl,w),id) = + let asms = itlist (union o hyp o snd) asl [] in + mk_fthm(asms,w) + and false_tm = `_FALSITY_` in + fun tac ((asl,w),id) -> + let ((mvs,i),gls,just as res) = tac ((asl,w),id) in + let ths = map fake_thm gls in + let asl',w' = dest_thm(just null_inst ths) in + let asl'',w'' = inst_goal i (asl,w) in + let maxasms = + itlist (fun (_,th) -> union (insert (concl th) (hyp th))) asl'' [] in + if aconv w' w'' & forall (C mem maxasms) (subtract asl' [false_tm]) + then res else failwith "VALID: Invalid tactic";; + +(* ------------------------------------------------------------------------- *) +(* Various simple combinators for tactics, identity tactic etc. *) +(* ------------------------------------------------------------------------- *) + +let (xTHEN),(xTHENL) = + let propagate_empty i [] = [] + and propagate_thm th i [] = INSTANTIATE_ALL i th in + let compose_justs n just1 just2 i ths = + let ths1,ths2 = chop_list n ths in + (just1 i ths1)::(just2 i ths2) in + let rec seqapply l1 l2 = match (l1,l2) with + ([],[]) -> null_meta,[],propagate_empty + | ((tac:xtactic)::tacs),((goal:xgoal)::goals) -> + let ((mvs1,insts1),gls1,just1 as gstate1) = tac goal in + let goals' = map (inst_xgoal insts1) goals in + let ((mvs2,insts2),gls2,just2 as gstate2) = seqapply tacs goals' in + ((union mvs1 mvs2,compose_insts insts1 insts2), + gls1@gls2,compose_justs (length gls1) just1 just2) + | _,_ -> failwith "seqapply: Length mismatch" in + let justsequence just1 just2 insts2 i ths = + just1 (compose_insts insts2 i) (just2 i ths) in + let tacsequence ((mvs1,insts1),gls1,just1 as gstate1) tacl = + let ((mvs2,insts2),gls2,just2 as gstate2) = seqapply tacl gls1 in + let jst = justsequence just1 just2 insts2 in + let just = if gls2 = [] then propagate_thm (jst null_inst []) else jst in + ((union mvs1 mvs2,compose_insts insts1 insts2),gls2,just) in + let (then_: xtactic -> xtactic -> xtactic) = + fun tac1 tac2 g -> + let _,gls,_ as gstate = tac1 g in + tacsequence gstate (replicate tac2 (length gls)) + and (thenl_: xtactic -> xtactic list -> xtactic) = + fun tac1 tac2l g -> + let _,gls,_ as gstate = tac1 g in + if gls = [] then tacsequence gstate [] + else tacsequence gstate tac2l in + then_,thenl_;; + +let ((xORELSE): xtactic -> xtactic -> xtactic) = + fun tac1 tac2 g -> + try tac1 g with Failure _ -> tac2 g;; + +let (xFAIL_TAC: string -> xtactic) = + fun tok g -> failwith tok;; + +let (xALL_TAC:xtactic) = + fun g -> null_meta,[g],fun _ [th] -> th;; + +let xTRY tac = + xORELSE tac xALL_TAC;; + +let rec xREPEAT tac g = + (xORELSE (xTHEN tac (xREPEAT tac)) xALL_TAC) g;; + +let xEVERY tacl = + itlist (fun t1 t2 -> xTHEN t1 t2) tacl xALL_TAC;; + +let (xFIRST: xtactic list -> xtactic) = + fun tacl g -> end_itlist (fun t1 t2 -> xORELSE t1 t2) tacl g;; + +let xMAP_EVERY tacf lst = + xEVERY (map tacf lst);; + +let xMAP_FIRST tacf lst = + xFIRST (map tacf lst);; + +let (xCHANGED_TAC: xtactic -> xtactic) = + fun tac g -> + let (meta,gl,_ as gstate) = tac g in + if meta = null_meta & length gl = 1 & equals_xgoal (hd gl) g + then failwith "CHANGED_TAC" else gstate;; + +let rec xREPLICATE_TAC n tac = + if n <= 0 then xALL_TAC else xTHEN tac (xREPLICATE_TAC (n - 1) tac);; + +(* ------------------------------------------------------------------------- *) +(* Combinators for theorem continuations adjusted for xthms and xtactics. *) +(* ------------------------------------------------------------------------- *) + +let ((xTHEN_TCL): xthm_tactical -> xthm_tactical -> xthm_tactical) = + fun ttcl1 ttcl2 ttac -> ttcl1 (ttcl2 ttac);; + +let ((xORELSE_TCL): xthm_tactical -> xthm_tactical -> xthm_tactical) = + fun ttcl1 ttcl2 ttac th -> + try ttcl1 ttac th with Failure _ -> ttcl2 ttac th;; + +let rec xREPEAT_TCL ttcl ttac th = + (xORELSE_TCL (xTHEN_TCL ttcl (xREPEAT_TCL ttcl)) I) ttac th;; + +let (xREPEAT_GTCL: xthm_tactical -> xthm_tactical) = + let rec xREPEAT_GTCL ttcl ttac th g = + try ttcl (xREPEAT_GTCL ttcl ttac) th g with Failure _ -> ttac th g in + xREPEAT_GTCL;; + +let (xALL_THEN: xthm_tactical) = + I;; + +let (xNO_THEN: xthm_tactical) = + fun ttac th -> failwith "NO_THEN";; + +let xEVERY_TCL ttcll = + itlist (fun t1 t2 -> xTHEN_TCL t1 t2) ttcll xALL_THEN;; + +let xFIRST_TCL ttcll = + end_itlist (fun t1 t2 -> xORELSE_TCL t1 t2) ttcll;; + +(* ------------------------------------------------------------------------- *) +(* Tactics to augment assumption list. Note that to allow "ASSUME p" for *) +(* any assumption "p", these add a PROVE_HYP in the justification function, *) +(* just in case. *) +(* ------------------------------------------------------------------------- *) + +let (xLABEL_TAC: string -> xthm_tactic) = + fun s thm ((asl,w),id) -> + let thm' = xthm_thm thm in + null_meta,[(((s,thm')::asl,w),id)], + fun i [th] -> PROVE_HYP (INSTANTIATE_ALL i thm') th;; + +(* ------------------------------------------------------------------------- *) +(* Manipulation of assumption list. *) +(* ------------------------------------------------------------------------- *) + +let mk_asm_xthm th = mk_xthm0 "<asm>" th;; + +let (xFIND_ASSUM: xthm_tactic -> term -> xtactic) = + fun ttac t (((asl,w),id) as g) -> + ttac (mk_asm_xthm (snd(find (fun (_,th) -> concl th = t) asl))) g;; + +let (xPOP_ASSUM: xthm_tactic -> xtactic) = + fun ttac -> + function ((((_,th)::asl),w),id) -> ttac (mk_asm_xthm th) ((asl,w),id) + | _ -> failwith "POP_ASSUM: No assumption to pop";; + +let (xASSUM_LIST: (xthm list -> xtactic) -> xtactic) = + fun aslfun ((asl,w),id) -> aslfun (map (mk_asm_xthm o snd) asl) + ((asl,w),id);; + +let (xPOP_ASSUM_LIST: (xthm list -> xtactic) -> xtactic) = + fun asltac ((asl,w),id) -> asltac (map (mk_asm_xthm o snd) asl) (([],w),id);; + +let (xEVERY_ASSUM: xthm_tactic -> xtactic) = + fun ttac -> xASSUM_LIST (xMAP_EVERY ttac);; + +let (xFIRST_ASSUM: xthm_tactic -> xtactic) = + fun ttac (((asl,w),id) as g) -> + tryfind (fun (_,th) -> ttac (mk_asm_xthm th) g) asl;; + +let (xRULE_ASSUM_TAC :(xthm->xthm)->xtactic) = + fun rule ((asl,w),id) -> + (xTHEN (xPOP_ASSUM_LIST(K xALL_TAC)) + (xMAP_EVERY + (fun (s,th) -> xLABEL_TAC s (rule (mk_asm_xthm th))) + (rev asl))) + ((asl,w),id);; + +(* ------------------------------------------------------------------------- *) +(* Operate on assumption identified by a label. *) +(* ------------------------------------------------------------------------- *) + +let (xUSE_THEN:string->xthm_tactic->xtactic) = + fun s ttac (((asl,w),id) as gl) -> + let th = try assoc s asl with Failure _ -> + failwith("USE_TAC: didn't find assumption "^s) in + ttac (mk_asm_xthm th) gl;; + +let (xREMOVE_THEN:string->xthm_tactic->xtactic) = + fun s ttac ((asl,w),id) -> + let th = try assoc s asl with Failure _ -> + failwith("USE_TAC: didn't find assumption "^s) in + let asl1,asl2 = chop_list(index s (map fst asl)) asl in + let asl' = asl1 @ tl asl2 in + ttac (mk_asm_xthm th) ((asl',w),id);; + +(* ------------------------------------------------------------------------- *) +(* General tool to augment a required set of theorems with assumptions. *) +(* ------------------------------------------------------------------------- *) + +let (xASM :(xthm list -> xtactic)->(xthm list -> xtactic)) = + fun tltac ths + (((asl,w),id) as g) -> tltac (map (mk_asm_xthm o snd) asl @ ths) g;; + +(* ------------------------------------------------------------------------- *) +(* A printer for xgoals etc. *) +(* ------------------------------------------------------------------------- *) + +let print_xgoal ((g,x):xgoal) : unit = + print_goal g;; + +let (print_xgoalstack:xgoalstack->unit) = + let print_xgoalstate k gs = + let (_,gl,_) = gs in + let n = length gl in + let s = if n = 0 then "No subgoals" else + (string_of_int k)^" subgoal"^(if k > 1 then "s" else "") + ^" ("^(string_of_int n)^" total)" in + print_string s; print_newline(); + if gl = [] then () else + do_list (print_xgoal o C el gl) (rev(0--(k-1))) in + fun l -> + if l = [] then print_string "Empty goalstack" + else if tl l = [] then + let (_,gl,_ as gs) = hd l in + print_xgoalstate 1 gs + else + let (_,gl,_ as gs) = hd l + and (_,gl0,_) = hd(tl l) in + let p = length gl - length gl0 in + let p' = if p < 1 then 1 else p + 1 in + print_xgoalstate p' gs;; + +(* ------------------------------------------------------------------------- *) +(* Convert an xtactic into an xrefinement. *) +(* ------------------------------------------------------------------------- *) + +let (xby:xtactic->xrefinement) = + fun tac ((mvs,inst),gls,just) -> + let g = hd gls + and ogls = tl gls in + let ((newmvs,newinst),subgls,subjust) = tac g in + let n = length subgls in + let mvs' = union newmvs mvs + and inst' = compose_insts inst newinst + and gls' = subgls @ map (inst_xgoal newinst) ogls in + let just' i ths = + let i' = compose_insts inst' i in + let cths,oths = chop_list n ths in + let sths = (subjust i cths) :: oths in + just i' sths in + (mvs',inst'),gls',just';; + +(* ------------------------------------------------------------------------- *) +(* Rotate for xgoalstate. *) +(* ------------------------------------------------------------------------- *) + +let (xrotate:int->xrefinement) = + let rotate_p (meta,sgs,just) = + let sgs' = (tl sgs)@[hd sgs] in + let just' i ths = + let ths' = (last ths)::(butlast ths) in + just i ths' in + (meta,sgs',just') + and rotate_n (meta,sgs,just) = + let sgs' = (last sgs)::(butlast sgs) in + let just' i ths = + let ths' = (tl ths)@[hd ths] in + just i ths' in + (meta,sgs',just') in + fun n -> if n > 0 then funpow n rotate_p + else funpow (-n) rotate_n;; + +(* ------------------------------------------------------------------------- *) +(* Refinement proof, tactic proof etc for xgoals/xtactics. *) +(* ------------------------------------------------------------------------- *) + +let (mk_xgoalstate:goal->xgoalstate) = + fun (asl,w) -> + if type_of w = bool_ty then + let id = (inc_goal_id_counter (); !the_goal_id_counter) in + null_meta,[((asl,w),id)], + (fun inst [th] -> INSTANTIATE_ALL inst th) + else failwith "mk_goalstate: Non-boolean goal";; + +let (xTAC_PROOF : goal * xtactic -> thm) = + fun (g,tac) -> + let gstate = mk_xgoalstate g in + let _,sgs,just = xby tac gstate in + if sgs = [] then just null_inst [] + else failwith "TAC_PROOF: Unsolved goals";; + +let xprove(t,tac) = + let th = xTAC_PROOF(([],t),tac) in + let t' = concl th in + if t' = t then th else + try EQ_MP (ALPHA t' t) th + with Failure _ -> failwith "prove: justification generated wrong theorem";; + +(* ------------------------------------------------------------------------- *) +(* Subgoal package for xgoals. *) +(* ------------------------------------------------------------------------- *) + +let current_xgoalstack = ref ([] :xgoalstack);; + +let (xrefine:xrefinement->xgoalstack) = + fun r -> + let l = !current_xgoalstack in + let h = hd l in + let res = r h :: l in + current_xgoalstack := res; + !current_xgoalstack;; + +let flush_xgoalstack() = + let l = !current_xgoalstack in + current_xgoalstack := [hd l];; + +let xe tac = xrefine(xby(xVALID tac));; + +let xr n = xrefine(xrotate n);; + +let xset_goal(asl,w) = + current_xgoalstack := + [mk_xgoalstate(map (fun t -> "",ASSUME t) asl,w)]; + !current_xgoalstack;; + +let xg t = + let fvs = sort (<) (map (fst o dest_var) (frees t)) in + (if fvs <> [] then + let errmsg = end_itlist (fun s t -> s^", "^t) fvs in + warn true ("Free variables in goal: "^errmsg) + else ()); + xset_goal([],t);; + +let xb() = + let l = !current_xgoalstack in + if length l = 1 then failwith "Can't back up any more" else + current_xgoalstack := tl l; + !current_xgoalstack;; + +let xp() = + !current_xgoalstack;; + +let xtop_realgoal() = + let (_,(((asl,w),_)::_),_)::_ = !current_xgoalstack in + asl,w;; + +let xtop_goal() = + let asl,w = xtop_realgoal() in + map (concl o snd) asl,w;; + +let xtop_thm() = + let (_,[],f)::_ = !current_xgoalstack in + f null_inst [];; + +(* ------------------------------------------------------------------------- *) +(* Install the goal-related printers. *) +(* ------------------------------------------------------------------------- *) + +#install_printer print_xgoal;; +#install_printer print_xgoalstack;; |