(* ========================================================================== *) (* FLYSPECK - BOOK FORMALIZATION *) (* Author: Thomas C. Hales *) (* Date: 2011-06-18 *) (* ========================================================================== *) (* Tactics. *) module Hales_tactic = struct let unlist tac t = tac [t];; let kill th = ALL_TAC;; (* moved to strictbuild.hl. let dest_goal gl = gl;; let goal_asms = fst;; let goal_concl = snd;; let mk_goal(asl,w) = (asl,w);; *) let LET_THM = CONJ LET_DEF LET_END_DEF;; let UNDISCH2 = repeat UNDISCH;; let COMBINE_TAC ttac1 ttac2 = (fun t -> ttac1 t THEN ttac2 t);; let ASM_TAC=REPEAT(POP_ASSUM MP_TAC);; let RED_TAC=ASM_REWRITE_TAC[] THEN DISCH_TAC;; let RES_TAC=ASM_REWRITE_TAC[] THEN STRIP_TAC;; let REDA_TAC=ASM_REWRITE_TAC[] THEN DISCH_TAC THEN ASM_REWRITE_TAC[];; let RESA_TAC=ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[];; let REDAL_TAC (th: thm list) =ASM_REWRITE_TAC th THEN DISCH_TAC THEN ASM_REWRITE_TAC th;; let RESAL_TAC (th: thm list) = ASM_REWRITE_TAC th THEN STRIP_TAC THEN ASM_REWRITE_TAC th;; (* let REMOVE_ASSUM_TAC=POP_ASSUM(fun th-> REWRITE_TAC[]);; let SYM_ASSUM_TAC=POP_ASSUM(fun th-> REWRITE_TAC[SYM(th)]);; *) let REMOVE_ASSUM_TAC=POP_ASSUM kill THEN REWRITE_TAC[];; let SYM_ASSUM_TAC=POP_ASSUM((unlist REWRITE_TAC) o SYM);; let SYM_ASSUM1_TAC=POP_ASSUM(COMBINE_TAC ((unlist REWRITE_TAC) o SYM ) ASSUME_TAC);; let RESP_TAC=ASM_REWRITE_TAC[] THEN STRIP_TAC THEN POP_ASSUM(unlist REWRITE_TAC);; let RESPL_TAC (th: thm list) =ASM_REWRITE_TAC th THEN STRIP_TAC THEN POP_ASSUM(unlist REWRITE_TAC);; let REDUCE_ARITH_TAC=REWRITE_TAC[REAL_ARITH`&0 * a= &0`; REAL_ARITH`a * &0 = &0`; REAL_ARITH`a + &0 = a`; REAL_ARITH`a- &0 =a`;REAL_ARITH`&0 +a =a`;REAL_ARITH`&1 * a =a`;REAL_ARITH`a * &1 =a`;REAL_ARITH`(A+B)-B=A`];; let REDUCE_VECTOR_TAC=REWRITE_TAC[VECTOR_ARITH`&0 % a= vec 0`; VECTOR_ARITH`a % vec 0= vec 0`;VECTOR_ARITH`a + vec 0 = a`; VECTOR_ARITH`vec 0 +a =a`; VECTOR_ARITH`a- vec 0 =a`;VECTOR_ARITH`&1 % a =a`;VECTOR_ARITH`a- b =vec 0<=> a=b`];; let MRESA_TAC th1 (th: term list) = MP_TAC(ISPECL th th1) THEN RESA_TAC;; let MRESA1_TAC th1 th = MP_TAC(ISPEC th th1) THEN RESA_TAC;; let MRESAL_TAC th1 (th: term list) (th2: thm list) =MP_TAC(ISPECL th th1) THEN ASM_REWRITE_TAC th2 THEN STRIP_TAC THEN ASM_REWRITE_TAC th2;; let MRESAL1_TAC th1 th (th2: thm list) =MP_TAC(ISPEC th th1) THEN ASM_REWRITE_TAC th2 THEN STRIP_TAC THEN ASM_REWRITE_TAC th2;; let ASM_SET_TAC l = (TRY(POP_ASSUM_LIST(MP_TAC o end_itlist CONJ))) THEN SET_TAC l;; (* GSYM theorems explicit *) let GSYM_EXISTS_PAIRED_THM = GSYM EXISTS_PAIRED_THM;; let has_stv t = let typ = (type_vars_in_term t) in can (find (fun ty -> (is_vartype ty) && ((dest_vartype ty).[0] = '?'))) typ;; let frees_of_goal gl = let (asl,w) = dest_goal gl in let tms = w::(map (concl o snd) asl) in let varl = List.flatten (map frees tms) in map (fun t -> (fst (dest_var t), t)) varl;; (* let retype gls tm = let varl = filter has_stv (setify(frees tm)) in let svarl = map (fun t-> (fst(dest_var t),t)) varl in let fn = fun buff (s,t) -> try (let (_,_,m)= term_match [] t (assoc s gls) in m @ buff) with _ -> failwith ("not found: "^s) in let tyassoc = List.fold_left fn [] svarl in (instantiate ([],[],tyassoc)) tm ;; *) (* new version 2013-07-13. Doesn't allow any new free variables, even if type inference works *) let retype gls tm = let allv = setify(frees tm) in let varl = filter has_stv allv in let svarl = map (fun t-> (fst(dest_var t),t)) varl in let fn = fun buff (s,t) -> try (let (_,_,m)= term_match [] t (assoc s gls) in m @ buff) with _ -> failwith ("not found: "^s) in let tyassoc = List.fold_left fn [] svarl in let tm' = (instantiate ([],[],tyassoc)) tm in let glt = map snd gls in let _ = map (fun x -> mem x glt or failwith ("not found: "^ fst (dest_var x))) (setify (frees tm')) in tm';; let env gl tm = let gls = frees_of_goal gl in retype gls tm;; let envl gl tml = let gls = frees_of_goal gl in let varl = filter has_stv (setify (List.flatten(map frees tml))) in let svarl = setify(map (fun t-> (fst(dest_var t),t)) varl) in let fn = fun buff (s,t) -> try (let (_,_,m)= term_match [] t (assoc s gls) in m @ buff) with _ -> failwith ("not found: "^s) in let tyassoc = List.fold_left fn [] svarl in map (instantiate ([],[],tyassoc)) tml ;; let gtyp (ttac:term->tactic) tm gl = ttac (env gl tm) gl;; let gtypl (ttacl:term list -> tactic) tml gl = ttacl (map (env gl) tml) gl;; let GEXISTS_TAC = gtyp EXISTS_TAC;; let GSUBGOAL_THEN t ttac gl = SUBGOAL_THEN (env gl t) ttac gl;; let argthen ttac tac t = (ttac t) THEN tac;; let CONJ2_TAC = let t = (TAUT `a /\ b ==> b /\ a`) in MATCH_MP_TAC t THEN CONJ_TAC;; let GEXISTL_TAC tl = EVERY (map GEXISTS_TAC tl);; (* ========================================================================== *) (* TACTIC *) let FORCE_EQ = REPEAT (CHANGED_TAC (AP_TERM_TAC ORELSE AP_THM_TAC ORELSE BINOP_TAC)) ;; let FORCE_MATCH = (MATCH_MP_TAC (TAUT `(a = b) ==> (a ==> b)`)) THEN FORCE_EQ ;; let FORCE_MATCH_MP_TAC th = MP_TAC th THEN ANTS_TAC THENL[ALL_TAC;FORCE_MATCH ];; let HYP_CONJ_TAC = let th = TAUT `(a ==> b==> c) ==> (a /\ b ==> c)` in FIRST_X_ASSUM (fun t-> MP_TAC t THEN MATCH_MP_TAC th THEN DISCH_TAC THEN DISCH_TAC);; (* ****************************** UNSORTED ****************************** *) let SELECT_EXIST = prove_by_refinement( `!(P:A->bool) Q. (?y. P y) /\ (!t. (P t ==> Q t)) ==> Q ((@) P)`, (* {{{ proof *) [ REPEAT STRIP_TAC; ASSUME_TAC (ISPECL[`P:(A->bool)`;`y:A`] SELECT_AX); ASM_MESON_TAC[]; ]);; (* }}} *) let SELECT_THM = MESON[SELECT_EXIST] `!(P:A->bool) Q. (((?y. P y) ==> (!t. (P t ==> Q t))) /\ ((~(?y. P y)) ==> (!t. Q t))) ==> Q ((@) P)`;; let SELECT_TAC = let unbeta = prove( `!(P:A->bool) (Q:A->bool). (Q ((@) P)) <=> (\t. Q t) ((@) P)`,MESON_TAC[]) in let unbeta_tac = CONV_TAC (HIGHER_REWRITE_CONV[unbeta] true) in unbeta_tac THEN (MATCH_MP_TAC SELECT_THM) THEN BETA_TAC THEN REPEAT STRIP_TAC;; (* let SELECT_TAC = Tactics.SELECT_TAC;; *) let COMMENT s = (report s; ALL_TAC);; let NAME _ = ALL_TAC;; let ROT_TAC = (* permute conjuncts *) let t1 = TAUT `b /\ a ==> a /\ b` in let t2 = TAUT `((b /\ c) /\ a) = (b /\ c /\ a)` in MATCH_MP_TAC t1 THEN PURE_REWRITE_TAC[t2];; let ENOUGH_TO_SHOW_TAC t = let u = INST [(t,`A:bool`)] (TAUT ` ((A ==> B) /\ A) ==> B`) in MATCH_MP_TAC u THEN CONJ_TAC;; (* like FIRST_X_ASSUM, except some subterm has to match t *) let FIRST_X_ASSUM_ST t x = FIRST_X_ASSUM (fun u -> let _ = find_term (can(term_match[] t)) (concl u) in x u);; let FIRST_ASSUM_ST t x = FIRST_ASSUM (fun u -> let _ = find_term (can(term_match[] t)) (concl u) in x u);; let BURY_TAC t gl = let n = List.length (goal_asms gl) in (REPEAT (FIRST_X_ASSUM MP_TAC) THEN ASSUME_TAC t THEN REPLICATE_TAC n DISCH_TAC) gl;; let BURY_MP_TAC gl = (POP_ASSUM_LIST(K ALL_TAC) THEN DISCH_TAC THEN MAP_EVERY (fun (s,th) -> LABEL_TAC s (th)) (rev (goal_asms gl))) gl;; let GOAL_TERM ttac g = (ttac g) g;; let TYPIFY t u = GOAL_TERM (fun w -> u (env w t));; let TYPIFY_GOAL_THEN t u = TYPIFY t (C SUBGOAL_THEN u);; (* puts the hypotheses of a conditional rewrite as a conjunct, rather than trying to prove them thm should have the form a ==> (b = c) or the form a ==> b. Doesn't do matching on bound variables. *) let GMATCH_SIMP_TAC thm gl = let w = goal_concl gl in let lift_eq_thm = MESON[] `! a b c. (a ==> ((b:B) = c)) ==> (!P. a /\ P c ==> P b)` in let lift_eq t = GEN_ALL (MATCH_MP lift_eq_thm (SPEC_ALL t)) in let thm' = hd (mk_rewrites true thm []) in let t1 = fst (dest_eq(snd (dest_imp(concl(thm'))))) in let matcher u t = let m = term_match [] t1 t in let _ = subset (frees t) (frees u) or failwith "" in m in let w' = find_term (can (matcher w)) w in let var1 = mk_var("v",type_of w') in let vv = variant (frees w) var1 in let athm = REWRITE_CONV[ ASSUME (mk_eq (w',vv))] w in let bthm = (ISPECL [mk_abs(vv,rhs (concl athm));w'] BETA_THM) in let betx = SYM(TRANS bthm (BETA_CONV (rhs (concl bthm)))) in (ONCE_REWRITE_TAC[betx] THEN MATCH_MP_TAC (lift_eq thm') THEN BETA_TAC THEN REWRITE_TAC[]) gl;; (* let ASM_REAL_ARITH_TAC t = REPEAT (POP_ASSUM MP_TAC) THEN MP_TAC (itlist CONJ t TRUTH) THEN REAL_ARITH_TAC;; let MP_LIST t = EVERY (map MP_TAC t);; *) (* Gonthier's script organizational tactics. *) let BY (t:tactic) gl = let (a,b,c) = t gl in let _ = (b = []) or failwith "by failed to finish goal" in (a,b,c);; let BRANCH_A (t::tl) = t THENL [EVERY tl;ALL_TAC];; let BRANCH_B (t::tl) = t THENL [ALL_TAC;EVERY tl];; (* a few from Jordan *) let X_IN = REWRITE_RULE[IN];; let SUBCONJ_TAC = MATCH_MP_TAC (TAUT `A /\ (A ==>B) ==> (A /\ B)`) THEN CONJ_TAC;; let SUBCONJ2_TAC = MATCH_MP_TAC (TAUT `B /\ (B ==>A) ==> (A /\ B)`) THEN CONJ_TAC;; let nCONJ_TAC n gl = let w = goal_concl gl in let w' = rhs(concl(PURE_REWRITE_CONV[GSYM CONJ_ASSOC] w)) in let wn = List.nth (conjuncts w') n in (SUBGOAL_THEN wn ASSUME_TAC) gl;; let PROOF_BY_CONTR_TAC = MATCH_MP_TAC (TAUT `(~A ==> F) ==> A`) THEN DISCH_TAC;; let (UNDISCH_FIND_TAC: term -> tactic) = fun tm gl -> let asl = goal_asms gl in let p = can (term_match[] tm) in try let sthm,_ = remove (fun (_,asm) -> can (find_term p) (concl ( asm))) asl in UNDISCH_TAC (concl (snd sthm)) gl with Failure _ -> failwith "UNDISCH_FIND_TAC";; let rec type_set: (string*term) list -> (term list*term) -> (term list*term)= fun typinfo (acclist,utm) -> match acclist with | [] -> (acclist,utm) | (Var(s,_) as a)::rest -> let a' = (assocd s typinfo a) in if (a = a') then type_set typinfo (rest,utm) else let inst = instantiate (term_match [] a a') in type_set typinfo ((map inst rest),inst utm) | _ -> failwith "type_set: variable expected" ;; let has_stv t = let typ = (type_vars_in_term t) in can (find (fun ty -> (is_vartype ty) && ((dest_vartype ty).[0] = '?'))) typ;; let TYPE_THEN: term -> (term -> tactic) -> tactic = fun t (tac:term->tactic) gl -> let (asl,w) = dest_goal gl in let avoids = itlist (union o frees o concl o snd) asl (frees w) in let strip = fun t-> (match t with |Var(s,_) -> (s,t) | _ -> failwith "TYPE_THEN" ) in let typinfo = map strip avoids in let t' = (snd (type_set typinfo ((frees t),t))) in (warn ((has_stv t')) "TYPE_THEN: unresolved type variables"); tac t' gl;; (* this version must take variables *) let TYPEL_THEN: term list -> (term list -> tactic) -> tactic = fun t (tac:term list->tactic) gl -> let (asl,w) = dest_goal gl in let avoids = itlist (union o frees o concl o snd) asl (frees w) in let strip = fun t-> (match t with |Var(s,_) -> (s,t) | _ -> failwith "TYPE_THEN" ) in let typinfo = map strip avoids in let t' = map (fun u -> snd (type_set typinfo ((frees u),u))) t in (warn ((can (find has_stv) t')) "TYPEL_THEN: unresolved type vars"); tac t' gl;; let (EXISTSv_TAC :string -> tactic) = fun s gl -> let (v,_) = dest_binder "?" (goal_concl gl) in let (_,ty) = dest_var v in EXISTS_TAC (mk_var(s,ty)) gl;; let (X_GENv_TAC:string ->tactic) = fun s gl -> let (v,_) = dest_binder "!" (goal_concl gl) in let (_,ty) = dest_var v in X_GEN_TAC (mk_var(s,ty)) gl;; (* weak version doesn't do conj *) let (WEAK_STRIP_TAC: tactic) = fun gl -> try (fun ttac -> FIRST [GEN_TAC; DISCH_THEN ttac]) STRIP_ASSUME_TAC gl with Failure _ -> failwith "STRIP_TAC";; let WEAK_STRIP_THM_THEN = FIRST_TCL [CONJUNCTS_THEN; CHOOSE_THEN];; let WEAK_STRIP_ASSUME_TAC = let DISCARD_TAC th = let tm = concl th in fun gl -> if exists (fun a -> aconv tm (concl(snd a))) (goal_asms gl) then ALL_TAC gl else failwith "DISCARD_TAC: not already present" in (REPEAT_TCL WEAK_STRIP_THM_THEN) (fun gth -> FIRST [CONTR_TAC gth; ACCEPT_TAC gth; DISCARD_TAC gth; ASSUME_TAC gth]);; let (WEAKER_STRIP_TAC: tactic) = fun gl -> try (fun ttac -> FIRST [GEN_TAC; DISCH_THEN ttac]) WEAK_STRIP_ASSUME_TAC gl with Failure _ -> failwith "STRIP_TAC";; let hold_def = new_definition `(hold:A->A) = I`;; let hold = MATCH_MP_TAC (prove_by_refinement( `!a. hold a ==> a`, [REWRITE_TAC [hold_def;I_DEF] ]));; let unhold = MATCH_MP_TAC (prove_by_refinement( `!a. a ==> hold a`, [REWRITE_TAC [hold_def;I_DEF] ]));; let MP_ASM_THEN = fun tac -> hold THEN (REPEAT (POP_ASSUM MP_TAC)) THEN tac THEN REPEAT DISCH_TAC THEN unhold;; let FULL_EXPAND_TAC s = FIRST_ASSUM (fun t -> let _ = (s = fst(dest_var(rhs(concl t)))) or failwith "" in (MP_ASM_THEN (SUBST1_TAC (SYM t) THEN BETA_TAC)));; (* let RENAME_VAR (t,s) = (* rename free variable *) let svar = mk_var (s,snd(dest_var t)) in MP_ASM_THEN (SPEC_TAC (t,s) THEN X_GENv_TAC s);; *) let RENAME_FREE_VAR (t,s) = (* rename free variable *) MP_ASM_THEN (SPEC_TAC (t,t) THEN X_GENv_TAC s);; (* rebind bound variables *) let rec rec_alpha_at (t,s) tm = match tm with | Comb (u,v) -> mk_comb (rec_alpha_at (t,s) u,rec_alpha_at (t,s) v) | Abs (a,b) -> if (a=t) then alpha s tm else mk_abs(a,rec_alpha_at (t,s) b) | _ -> tm;; let alpha_at (t,s) = rec_alpha_at (t,mk_var(s,snd(dest_var t)));; let REBIND_CONV ts g = ALPHA g (alpha_at ts g);; REBIND_CONV (`x:real`,"y") (`pi + (\ x . x + pi) pi`);; let REBIND_RULE ts th1 = EQ_MP (REBIND_CONV ts (concl th1)) th1;; REBIND_RULE (`x:real`,"y") (ASSUME (`pi + (\ x . x + pi) pi = &1`));; let REBIND_TAC ts gl = (SUBST1_TAC (REBIND_CONV ts (goal_concl gl))) gl;; (* MISCELL. *) let arith tm = let v = [ARITH_RULE;REAL_ARITH;(fun t -> prove(t,SIMPLE_COMPLEX_ARITH_TAC));REAL_RING;VECTOR_ARITH] in tryfind (fun h -> h tm) v;; let varith = VECTOR_ARITH;; let COMMENT _ = ALL_TAC;; let INTRO_TAC th1 tml = GOAL_TERM (fun w -> (MP_TAC (ISPECL ( envl w tml) th1)));; let COPY_TAC = DISCH_THEN (fun t -> MP_TAC t THEN ASSUME_TAC t);; let TYPED_ABBREV_TAC t gl = let (a,b) = dest_eq t in let b' = env gl b in let (a',_) = dest_var a in let t' = mk_eq(mk_var(a',type_of b'),b') in ABBREV_TAC t' gl;; end;;