(* ========================================================================== *)
(* FLYSPECK - BOOK FORMALIZATION *)
(* Author: Thomas C. Hales *)
(* Date: 2011-06-18 *)
(* ========================================================================== *)
#load "str.cma";;
flyspeck_needs "usr/thales/hales_tactic.hl";;
module Searching = struct
open Hales_tactic;;
(*
? forces interpretation as a theorem.
?-n follows suggestion n.
%`x` performs type matching
%%[`x`;`y`] performs type matching.
*)
(*
TODO:
-Combine different search mechanisms with the same return type.
-Make a log of all searches, all bookmarked items, with context, for data mining purposes.
-integrate suggest.
*)
(* quicksilver style search for name matching.
ignore case and look for nonconsecutive letters. *)
let unsplit d f = function
| (x::xs) -> List.fold_left (fun s t -> s^d^(f t)) (f x) xs
| [] -> "";;
let match_sparse s u =
let re = Str.regexp_case_fold (".*"^(unsplit ".*" I ( explode s))) in
Str.string_match re u 0;;
let maxl0 xs = try (end_itlist max xs) with _ -> 0;;
(*
let ignore = Pervasives.ignore;;
*)
(* ========================================================================== *)
(* TYPES *)
let types_of = Print_types.print_term_types;;
let type_of_thm = Print_types.print_thm_types;;
let type_of_goal = Print_types.print_goal_types;;
let goal_types = Print_types.print_goal_types;;
(* ========================================================================== *)
(* HELP *)
let hollight_dir =
(try Sys.getenv "HOLLIGHT_DIR" with Not_found -> Sys.getcwd());;
(* let local_help_dir = Filename.concat flyspeck_dir "../help";; *)
let local_help_dir = ".";;
let helpdirs = ref [
local_help_dir;
Filename.concat hollight_dir "Help"
];;
help_path := !helpdirs @ (!help_path);; (* hol-light help *)
let help_grep pat =
let split = Str.split (Str.regexp "\n") in
let cmd s = process_to_string ("(cd " ^s^ "; ls | grep -v '~' | sed 's/.doc$//g' | grep '" ^pat^ "')") in
List.flatten (map ( split o cmd ) (!helpdirs));;
(*
todo: if pat starts with regexp "-[a-z]+ " then it should be taken as a flags command.
Also make help_grep_local a flag, say -l for local.
*)
let help_flag flag pat =
let constant_of_regexp ss =
let re = Str.regexp_case_fold (".*"^ss) in
let c = map fst (constants()) in
filter (fun s -> Str.string_match re s 0) c in
let help_grep_local pat =
let backup = !helpdirs in
let _ = helpdirs := [local_help_dir] in
let out = help_grep pat in
let _ = helpdirs := backup in
out in
let split = Str.split (Str.regexp "\n") in
let grep_s s = Printf.sprintf "(cd %s; ls | sed 's/.doc$//g' | grep -i '%s')" s pat in
let cmd s = process_to_string (grep_s s) in
match flag with
| 'i' -> List.flatten (map ( split o cmd ) (!helpdirs))
| 'd' -> constant_of_regexp pat
| 'l' -> help_grep_local pat
| 'g' -> help_grep pat
| _ -> [" 'd' search constants";"'g' help_grep"; "'i' ignore case"; "'l' help_grep local dir"];;
(*
Example:
help_grep "ASM.*REWRITE";;
help_grep "^ASM_";;
help_grep "help";;
help_grep "RULE";;
help_grep "ARITH";;
help_grep "_TAC$";;
List.length (help_grep ".*");;
help_flag '?' "";;
help_flag 'd' ".*contin";;
help_flag 'd' ".*integr";;
help_flag 'd' ".*auchy";;
help_flag 'd' "at.*[ng]$";;
help_flag 'd' "cos" ;;
*)
(* ========================================================================== *)
(* SEARCH *)
let def s = mk_comb(mk_var("<match constant def>",W mk_fun_ty aty),
mk_var(s,aty));;
let searches = ref[];;
let searcht n pat =
let _ = searches := (n,pat)::!searches in
let def_of_regexp ss =
let c = help_flag 'd' ss in
let strip d = (fst o dest_const o fst o dest_eq o concl) d in
let def_assoc = map (fun t -> (strip t,t)) (definitions()) in
map (fun s -> (s,assoc s def_assoc)) c in
let raw = match pat with
| Comb(Var("<match constant def>",_),Var(ss,_))::_ -> def_of_regexp ss
| _ -> search pat in
let m = min n (List.length raw) in
let s = sortlength_thml raw in
let r = fst (chop_list m s) in
let z = zip (0--(List.length r - 1)) r in
z;;
let searchl ls pat = search_thml (term_match []) pat ls;;
(* added Oct 2012 *)
let save_searc = ref [];;
let searc c n tl =
let u = snd(List.nth (searcht (n+1) tl) n) in
let _ = (save_searc := (c,u)::!save_searc) in
u;;
(* tactics that search assumption list for match.
Deprecated. Replaced with FIRST_X_ASSUM_ST *)
(*
let SEARCH_THEN pat ttac (asl,w) =
let thl = map snd (searchl asl pat) in
ttac thl (asl,w);;
let FIRST_SEARCH_THEN pat ttac (asl,w) =
let thl = map snd (searchl asl pat) in
ttac (hd thl) (asl,w);;
*)
let searchn n f s = snd(List.nth (searcht (n+1) f) n);; (* used for write-up of search results *)
(*
Example: searcht 5 [def "cos"];;
searcht 5 [def "mul"];;
*)
let research m =
let (n,pat) = hd (!searches) in
searcht (m) pat;;
let search_results = ref [];;
(* add stored searches to list *)
let augment_search_results ss =
let get s = try (Lib.assoc s !theorems) with _ -> failwith s in
let cs = map (fun (_,s,_,_) -> s) !search_results in
let ss = Lib.subtract ss cs in
let ns = List.length cs in
let ss = Lib.zip (ns -- (ns+List.length ss - 1)) ss in
let ss = map (fun (i,s) -> (i,s,get s,[])) ss in
!search_results @ ss;;
let mark m =
let (n,pat) = hd (!searches) in
let (s,th) = snd(List.nth (searcht (1 + min n m) pat) m) in
let v = (List.length !search_results,s,th,pat) in
let _ = search_results := v::(!search_results) in
v;;
let result n pat =
let ls = map (fun (_,s,th,_) -> (s,th)) !search_results in
let a = zip ls !search_results in
let sl = if pat = [] then ls else searchl ls pat in
let n' = min n (List.length sl) in
let ts = fst(chop_list n' (sl)) in
map (fun t -> assoc t a) ts;;
let results pat =
let n = List.length (!search_results) in
result n pat;;
let retrieve_search_number n =
let (_,s,_,_) = Lib.find (fun (c,_,_,_) -> (c=n)) !search_results in
s;;
(*
let (srch,more,less,retrieve_search) =
let allsearch = ref [] in
let tags = explode "abcdefghijklmnopqrstuvwxyz" in
let tag_num = ref 0 in
let update () = (tag_num := (!tag_num + 1) mod (List.length tags)) in
let current_search = ref [] in
let nextdisplayed = ref 0 in
let ziptg tg a xs =
let z = zip (a--(List.length xs - 1 + a)) xs in
map (fun (i,x) -> (tg^(string_of_int i),x)) z in
let sub_range tg a b xs =
let b' = min b (List.length xs - 1) in
let _ = (a <= b') or failwith "bad range" in
let _ = (0 <= a) or failwith "bad neg index" in
let bs = fst (chop_list (b'+1) xs) in
ziptg tg a (snd (chop_list a bs)) in
let more () =
let tg = List.nth tags (!tag_num) in
let sr = sub_range tg (!nextdisplayed) (!nextdisplayed + 5) (!current_search) in
let _ = (nextdisplayed := 5 + !nextdisplayed) in
sr in
let less () =
let _ = (nextdisplayed := max 0 (!nextdisplayed - 10)) in
more() in
let srch pat =
let raw = search pat in
let _ = update() in
let _ = (nextdisplayed := 0) in
let _ = current_search := sortlength_thml raw in
let tg = List.nth tags (!tag_num) in
let _ = (allsearch := (tg,!current_search) :: !allsearch) in
more() in
let retrieve_search tag item =
fst ( List.nth (Hol_pervasives.assoc tag !allsearch) item) in
(srch,more,less,retrieve_search);;
*)
(* ========================================================================== *)
(* STATS of WORD COUNTS, indexing all words in HOL LIGHT and FLYSPECK *)
let wc_tmpfile = Filename.temp_file "tmp_" ".txt";;
let int_tmpfile =
let ss1 = process_to_string ("ls "^flyspeck_dir^"/*/*.hl") in
let ss2 = Str.split (Str.regexp "\n") ss1 in
let ss1 = process_to_string ("ls "^hollight_dir^"/*/*.ml") in
let ss2 = Str.split (Str.regexp "\n") ss1 @ ss2 in
let tmpfile = wc_tmpfile in
let _ = Sys.command("touch "^tmpfile) in
let _ = map (fun s -> Sys.command("cat "^ s^ " >> " ^ tmpfile)) ss2 in
();;
let word_counts() =
let sout = Str.split (Str.regexp "\n")
(process_to_string("cat "^wc_tmpfile^" | tr -C 'A-Z:a-z0-9_' '\n' | sort | uniq -c | sed 's/^ *//'")) in
let sout1 = map (Str.split (Str.regexp " ")) sout in
let sout2 = filter (fun t -> List.length t = 2) sout1 in
let sout3 = map (function | [a;b]-> (b,int_of_string a) | _ -> ("?",0)) sout2 in
sout3;;
let word_count_list = word_counts();;
(* stats of the word immediately following another word.
This can be useful in determining, for example, which theorems are used
with MATCH_MP_TAC. Or which tactics are used with REPEAT. *)
let word_successor_counts word_successor =
let sed_pipe = Printf.sprintf "grep '%s ' %s | sed 's/^.*%s *//' | sed 's/^[^a-z.A-Z]*//g' | sed 's/ .*$//g' | tr -C 'A-Z.a-z_0-9' '\n' | sed 's/ //g' | sort | uniq -c | sed 's/^ *//'"
word_successor wc_tmpfile word_successor in
let sout = Str.split (Str.regexp "\n")
(process_to_string(sed_pipe )) in
let sout1 = map (Str.split (Str.regexp " ")) sout in
let sout2 = filter (fun t -> List.length t = 2) sout1 in
let sout3 = map (function | [a;b]-> (b,int_of_string a) | _ -> ("?",0)) sout2 in
sort (fun (_,a) (_,b) -> (a > b)) sout3;;
(* inaccurate because constants and theorems with the same name are overcounted *)
let thm_counts =
let alpha_thm = sort (<) (map fst !theorems) in
let rec build buff ats bts = match (ats,bts) with
| ([],_) -> buff
| (_,[]) -> buff
| (a::atss,(b,n)::btss) -> if (a=b) then build ((b,n)::buff) atss btss
else if (a>b) then build buff ats btss else build buff atss bts in
sort (fun (_,a) (_,b) -> (a > b)) (build [] (alpha_thm) word_count_list);;
let quasi_tactic_list =
let tactic_wordlist =
["REPEAT";"POP_ASSUM";
"FIRST_X_ASSUM";"FIRST_ASSUM";
"fun";"REAL_ARITH";"ARITH_RULE";"TAUT"] in
let tactic_list = (help_grep "TAC$") in
let then_list = (help_grep "THEN") in
tactic_wordlist @ tactic_list @ then_list;;
let tactic_counts = sort (fun (_,a) (_,b) -> (a > b))
(filter (fun (a,_) -> mem a (quasi_tactic_list)) word_count_list);;
(* ========================================================================== *)
(* DEPTH FUNCTIONS *)
(* each constant is defined in terms of other constants.
The depth of a constant is the length of its longest chain down to the primitives *)
(* SLOW BUT POTENTIALLY USEFUL. START HERE.
let nub = Parse_ineq.nub;;
let rec c_of buf = function
| Const _ as t -> nub (t:: buf)
| Comb (r,s) -> c_of (c_of buf r) s
| Abs (x,t) -> c_of buf t
| _ -> nub buf;;
let def_assoc =
let r = (map (dest_eq o concl) (definitions())) in
let s = fst o dest_const in
map (fun (x,y) -> ( s x,nub (map s (c_of [] y)))) r;;
let stm_depth =
let cache = ref [] in
let rec s_depth t =
try (assoc t !cache)
with _ ->
let rs = try (assoc t def_assoc)
with _ -> [] in
let _ = not(mem t rs) or failwith t in
let u = 1 + maxl0 (map s_depth rs) in
let _ = cache:= (t,u)::!cache in
u in
s_depth;;
let sdef_assoc = map (fun (t,ul) -> ((t,stm_depth t),(map (fun u -> (u,stm_depth u)) ul)))
def_assoc;;
let tm_depth t =
let c = map (fst o dest_const )(c_of [] t) in
let u = map (fun x -> (x,stm_depth x)) c in
let s = nub (sort (fun (_,a) (_,b) -> a > b) u) in
s;;
(* ball park distance of goal *)
let rec rec_hash n acc = function
| [] -> acc
| (a,_)::b -> if (n<=0) then acc else rec_hash (n-1) (Hashtbl.hash a ::acc) b;;
let hash_depths = sort (<) o (rec_hash 3 []);;
let rec sorted_meet k al bl = if (k<1) then true else (* look for at least k matches *)
(match bl with
| [] -> false
| b::bl' -> match al with
| [] -> false
| a::al' -> if (a = b) then
(sorted_meet (k-1) al' bl')
else
(if (a<b) then sorted_meet k al' bl else sorted_meet k al bl'));;
let strip_imp = striplist dest_imp;;
let preprocess_theorems thml =
let get_tm_depth = (tm_depth o last o strip_imp o snd o strip_forall o concl ) in
let de = function | [] -> 0 | ((_,d)::_) -> d in
let data r = (de r,hash_depths r) in
let thl = map (fun (s,t) -> ((data o get_tm_depth) t,s,t) ) thml in
thl;;
let depth_encoded_theorems = preprocess_theorems (!theorems);;
let rec ballpark i j thml (d,hd) =
if (List.length thml < 80) then thml else
let k = max i j in
let (thml',i',j') =
if (k=i) then (filter (fun ((d',_),_,_)-> abs(d-d') < 1+k) thml,i-1,j) else
(filter (fun ((_,hd'),_,_) -> (sorted_meet (3-k) hd hd')) thml,i,j-1) in
if (List.length thml' < 20) then thml else ballpark i' j' thml' (d,hd);;
let ballpark_theorems (_,w) =
let thml = depth_encoded_theorems in
let get_tm_depth = (tm_depth o last o strip_imp o snd o strip_forall ) in
let de = function | [] -> 0 | ((_,d)::_) -> d in
let data r = (de r,hash_depths r) in
map (fun (_,s,t)->(s,t)) (ballpark 3 3 thml (data (get_tm_depth w)));;
(* fails on depth 0 *)
let drop_depth_once ul =
List.flatten (map (fun u -> assoc u sdef_assoc) ul);;
let rec drop_depth_to d ul =
let (hi,lo) = partition (fun (_,h) -> (h>d)) ul in
if hi = [] then ul else
let hi' = drop_depth_once hi in
(nub ((drop_depth_to d hi') @ lo));;
(* metric symbol distance, an estimate of the distance between two lists of symbols.
dsofar = distance so far.
common = list of symbols and their shallowings that the two lists have already in common.
depth_weight is a heuristic weighting: matches should increase distance less than mismatches.
*)
let rec msd dsofar common al bl =
if (al=[]) && (bl=[]) then dsofar else
let depth_weight = 10 in
let d = maxl0 (map snd (al @ bl)) in
let c = ( drop_depth_to d common) @ (intersect al bl) in
let al' = subtract al c in
let bl' = subtract bl c in
let dsofar' = dsofar +. float_of_int( List.length ((intersect al c) @ (intersect bl c)) +
depth_weight * List.length (al' @ bl')) in
if (d <=1) then dsofar' else
let al'' = drop_depth_to (d-1) al' in
let bl'' = drop_depth_to (d-1) bl' in
msd dsofar' c al'' bl'';;
let metric_symbol_distance bl cl =
let tt tl = List.flatten (map tm_depth tl) in
if (List.length bl = 1)&&(List.length cl=1)&& (aconv (hd bl) (hd cl)) then 0.0
else msd 10.0 [] (tt bl) (tt cl);;
let nearest_thm_to_goal (asl,w) =
let tt tl = List.flatten (map (tm_depth o concl) tl) in
let common = tt (map snd asl) in
let thl = map (fun (s,t) -> ((tm_depth o snd o strip_forall o concl )t,s,t) ) (!theorems) in
let r = map (fun (tl,s,t) -> (tl,s,t,msd 0.0 common (tm_depth w) tl)) thl in
(sort (<) r);;
let thm_depth = tm_depth o concl;;
let search_depth =
let dthm = map (fun (s,t) -> (maxl0 (map snd(thm_depth t)),(s,t))) !theorems in
let m tml = maxl0 (map snd (List.flatten (map (tm_depth) tml))) in
let fthm tml = map snd (filter (fun (x,(_,_)) -> (x <=m tml)) dthm) in
fun tml -> searchl (fthm tml) tml;;
END SLOW BUT POTENTIALLY USEFUL
*)
(* ========================================================================== *)
(* EVAL AND PROOF STACK *)
(*
eval_command comes from
http://solaria.dimino.org/cgi-bin/darcsweb.cgi?r=peps;a=headblob;f=/src/core/peps_top.ml
License: BSD3
If the expression is syntactically correct
and the evaluation raises an exception, then the return value is true.
*)
let eval_command ?(silent=false) command =
let buffer = Buffer.create 512 in
let pp = Format.formatter_of_buffer buffer in
Format.pp_set_margin pp max_int;
try
let _ =
Toploop.execute_phrase (not silent) pp
(!Toploop.parse_toplevel_phrase (Lexing.from_string (command ^ ";;")))
in
(true, Buffer.contents buffer)
with exn ->
let save = !Toploop.parse_use_file in
Toploop.parse_use_file := (fun _ -> raise exn);
Pervasives.ignore (Toploop.use_silently pp "/dev/null");
Toploop.parse_use_file := save;
(false, Buffer.contents buffer);;
(* eval_command ~silent:false "g `x=y`";; *)
type proof_record = Tax of string*int*tactic | Bax | Gax of term*string;;
let proof_record =ref [];;
let tactic_cache = ref (fun () -> ALL_TAC);;
(* we evaluate the tactic outside eval_command, so that we can catch exceptions *)
let eval_tactic =
fun s ->
let (b,r) = eval_command ~silent:false
("tactic_cache := (fun () -> ("^s^"));;") in
let _ = b or (print_string (r^"\n"^s^"\n"); failwith "bad input string") in
let t= (!tactic_cache)() in
let (_,gs,_) ::_ = !current_goalstack in
let i = List.length gs in
let v = Hol_pervasives.e(t) in
let _ = proof_record := Tax (s,i,t)::!proof_record in
v;;
(*
let string_of_frees t =
let u = (map (fst o dest_var) o frees) t in
(unsplit " " I) u;;
*)
let eval_goal t =
let _ = print_goalstack (Hol_pervasives.g(t));
proof_record := Gax (t,process_to_string "date")::!proof_record;
warn (has_stv t) "?type in goal" in
();;
let eval_back () =
let _ = proof_record := Bax::!proof_record in Hol_pervasives.b();;
(*
eval_goal `1 + 1 = 2`;;
eval_tactic "REPEAT STRIP_TAC";;
eval_back();;
eval_tactic "ARITH_TAC";;
eval_tactic "REWRITE_TAC[TRUTH]";;
*)
let string_starts_with u s =
(String.length u <= String.length s) && (u = String.sub s 0 (String.length u));;
let rec strs_of_proof_records ind skip buf =
let by t s = if t && (not (string_starts_with "BY" s)) then "BY("^s^")" else s in
function
[] -> buf
| Gax _ :: xs -> buf
| Tax (s,i,_) :: xs ->
let indent = String.make (2*i) ' ' in
if (skip=0) then strs_of_proof_records i skip ((indent^(by (i>ind) s))::buf) xs
else strs_of_proof_records ind (skip-1) buf xs
| Bax :: xs -> strs_of_proof_records ind (skip+1) buf xs;;
let string_of_proof () =
let ss = strs_of_proof_records 0 0 [] !proof_record in
"\n[\n"^unsplit ";\n" I (ss) ^"\n]\n";;
let print_proof () =
print_string (string_of_proof());;
let string_of_proof_k k () =
let ss = strs_of_proof_records 0 0 [] !proof_record in
let k' = min k (List.length ss) in
let ss' = (fst(chop_list k' (List.rev ss))) in
if (List.length ss' = 0) then ""
else if (List.length ss' = 1) then hd(ss')
else "\n[ ... most recent steps ...\n"^unsplit ";\n" I (List.rev ss') ^"\n]\n";;
let rec split_proof_record acc cur = function
| [] -> if (List.length cur > 0) then acc @[cur] else acc
| Gax (_,_) as a :: xs ->
let acc' = acc @ [cur @ [a]] in
split_proof_record acc' [] xs
| a :: xs -> split_proof_record acc (cur @ [a]) xs;;
let gax() =
let u = split_proof_record [] [] (!proof_record) in
let j = zip u (0-- (List.length u - 1)) in
let k = map (fun (u,z) -> (z,List.length u,last u)) j in
k;;
split_proof_record [] [] (!proof_record);;
(*
print_string (string_of_proof());;
*)
(* ========================================================================== *)
(* SUGGEST TACTIC *)
(* term matching without higher order matches *)
let term_match_no_ho pat u =
let (_,b,c) = (term_match[] pat u) in
let v = instantiate ([],b,c) pat in
aconv v u or failwith "no match";;
let match_g_no_ho pat (_,w) = not(search_thml term_match_no_ho pat [("", ASSUME w)] = []);;
let match_g pat (_,w) = not(search_thml (term_match[]) pat [("", ASSUME w)] = []);;
let match_asm pat (asl,_) = not(search_thml term_match_no_ho pat asl = []);;
(* new version, july 2012 *)
let noses = ref [];;
let add_your_nose x = (noses := x::!noses);;
let follow_your_nose_string() =
let aslw = top_realgoal() in
let n =
try
let (_,_,a) = find (fun (p,_,_) -> p aslw) !noses
in a
with Failure _ -> "" in
n;;
let fyn () =
let aslw = top_realgoal() in
let (_,t,_) = find (fun (p,_,_) -> p aslw) !noses in
t;;
let follow_your_nose_string_list() =
let aslw = top_realgoal() in
let m = filter (fun (p,_,_) -> p aslw) !noses in
let m2 = map (fun ((_,_,a),b) -> ("{"^string_of_int b ^":"^a^"}")) (zip m (0--((List.length m) -1))) in
Flyspeck_lib.join_comma m2;;
let fynlist k =
let aslw = top_realgoal() in
let m = filter (fun (p,_,_) -> p aslw) !noses in
let l = List.length m in
let _ = k < l or failwith ("fyn length = "^string_of_int k ^ " "^string_of_int l) in
let (_,t,_) = List.nth m k in
t;;
(* new version, march 2012 *)
let nub = Parse_ineq.nub;;
let rec c_of buf = function
| Const _ as t -> nub (t:: buf)
| Comb (r,s) -> c_of (c_of buf r) s
| Abs (x,t) -> c_of buf t
| _ -> nub buf;;
let rewrite_tags = ref [];;
let remove_rewrite_tag s =
rewrite_tags:= filter (fun (_,_,s',_) -> not (s =s')) !rewrite_tags;;
let st_of tm = map (fst o dest_const) (c_of [] tm);;
let add_rewrite_tag (s,th) =
let thl = mk_rewrites true th [] in
let tml = map concl thl in
let wd tm = if (is_imp ( tm)) then (snd(dest_imp( tm))) else tm in
let tml = map (fst o dest_eq o wd) tml in
let stl = map st_of tml in
let zl = map (fun (a,b)-> (a,b,s,th)) (zip tml stl) in
let _ = rewrite_tags := zl @ !rewrite_tags in
();;
let add_rewrite_stag s =
let _ = (can (assoc s) !theorems) or failwith (s ^ " not found ") in
add_rewrite_tag (s,assoc s !theorems);;
let refresh_rewrite_stag s =
let _ = remove_rewrite_tag s in
add_rewrite_stag s;;
let refresh() =
let _ = map (fun (_,s,_,_) -> refresh_rewrite_stag s) !search_results in
();;
let write m =
let u = mark m in
let (_,s,_,_) = u in
let _ = refresh_rewrite_stag s in
u;;
let lookup_rewrite_tags (asl,w) =
let sw = st_of w in
let f1 = filter (fun (_,sl,_,_) -> (subset sl sw)) !rewrite_tags in
let ml = filter (fun (pat,_,_,_) -> match_g [pat] (asl,w)) f1 in
ml;;
let rewrite_suggest() =
let rawl = lookup_rewrite_tags (top_realgoal()) in
zip (0--(List.length rawl - 1)) (map (fun (_,_,s,th) -> (s,th)) rawl);;
let suggest = rewrite_suggest;;
(* let assum t = mk_comb(mk_var("<assum>",W mk_fun_ty (type_of t)),t);; *)
(*
trigger pattern;
English text;
prompt;
tactic;
*)
let tactic_patterns = ref [];;
let add_tactic_pattern t = (tactic_patterns := t::!tactic_patterns);;
let tactic_suggest _ =
let s = filter (fun (a,_,_,_) -> a (top_realgoal())) !tactic_patterns in
zip (0-- (List.length s -1) ) s;;
let print_suggest sg =
let print_one (i,(_,_,s,_)) = (print_int i; print_string (": "^s)) in
map (print_one) sg;;
(*
let s () = let sg = suggest() in Pervasives.ignore(print_suggest sg);;
*)
let expand_suggest s =
let sg = tactic_suggest() in
let n = (int_of_string s) in
let r = Lib.assoc n sg in
(fun (_,s,_,_) -> s) r;;
(*
let eh n = let (_,(_,_,_,tac)) = List.nth (suggest()) n in e(tac());;
*)
(* let follow n = let (_,(_,_,_,tac)) = List.nth (suggest()) n in tac();; *)
(*
let rewrite_suggest = [
([`x IN {y}`],"IN_SING",IN_SING);
];;
let rewrites _ =
let s = filter (fun (a,_,_) -> match_g a (top_realgoal())) rewrite_suggest in
zip (0-- (List.length s -1) ) s;;
*)
(* ========================================================================== *)
(* ABBREVIATIONS *)
let matching_tactics s =
filter (match_sparse s) (map fst tactic_counts);;
let tactic_abbreviations = ref [];;
let abbrev u = (tactic_abbreviations:= (u::!tactic_abbreviations));;
let unabbrev s = (tactic_abbreviations:= (filter (fun (s',_) -> (s <> s')) !tactic_abbreviations));;
let thm_abbreviations = ref[("elim","IN_ELIM_THM");("morgan","DE_MORGAN_THM")];;
let thm_abbrev s = (let _ = thm_abbreviations:= s::!thm_abbreviations in s);;
thm_abbrev ("empty","EMPTY");;
let expansive_thms =
let full = (map fst thm_counts) in
fun op s ->
let searches = map (fun (_,s,_,_) -> s) !search_results in
op (match_sparse s) (searches @ full);;
(*
?n to get marked theorem n.
?abbrev to abbreviate.
*)
let expand_thm =
let charset = (explode "abcdefghijklmnopqrstuvwxyz0123456789'_.") in
let number s =
let n = int_of_string s in
retrieve_search_number n in
let search_thm s =
let c = s.[0] in
fst(Hol_pervasives.assoc c (!save_searc)) in
let abbreviable s = (subset (explode s) charset) in
let unabbrev s =
let _ = not(abbreviable s) or failwith "abbrev" in s in
let exact_thm s = (Pervasives.ignore (Hol_pervasives.assoc s !theorems); s) in
let assoct s = Hol_pervasives.assoc s !thm_abbreviations in
let match_t = expansive_thms Lib.find in
fun s-> tryfind (fun f -> f s) [unabbrev;search_thm;number;exact_thm;assoct;match_t;I];;
(*
%`x` to expand types of term
%%[`x`;`y`] to expand types of term list.
*)
(* deprecated HASH: *)
(*
let el_to_hash s i =
let el_assoc = [
("u","HASH_UNDISCH_TAC");
("r","HASH_RULE_TAC");
("k","HASH_KILL_TAC");
("p","HASH_COPY_TAC");
("c","HASH_CHOOSE_TAC");
("x","HASH_X_CHOOSE_TAC");
("a","HASH_ASM_REWRITE_TAC")] in
let tac = assoc s el_assoc in
let h = el_hash i (top_realgoal()) in
tac ^ " " ^ (string_of_int h);;
*)
let el_to_hash s i = failwith "el_to_hash has been deprecated";;
let break_init init s =
let l_init = String.length init in
let _ = (l_init <= String.length s) or failwith "length mismatch break_init" in
let _ = (String.sub s 0 l_init = init) or failwith "mismatch break_init" in
String.sub s (l_init) (String.length s - l_init);;
let unabbrev_string =
let charset = (explode "abcdefghijklmnopqrstuvwxyz0123456789'_/\\!?@") in
let abbreviable s = (subset (explode s) charset) in
let unabbrev s =
let _ = not(abbreviable s) or failwith "abbrev" in s in
let assoc_thm s = (Pervasives.ignore (Hol_pervasives.assoc s !theorems); s) in
let assoct s = Hol_pervasives.assoc s !tactic_abbreviations in
let assoc_sans_t s =
let len = String.length s in
let _ = (len > 1) or failwith "too short" in
let _ = (s.[len-1]= 't') or failwith "final char t" in
assoct (String.sub s 0 (len -1)) in
let hash s =
let rest = break_init "el" s in
let c = String.sub rest 0 1 in
let n = int_of_string (String.sub rest 1 (String.length rest - 1)) in
el_to_hash c n in
let tac s =
let v = matching_tactics s in
if (List.length v > 0) then hd v else s in
let fynose s =
if (s = "fyn") then fyn ()
else
let _ = String.length s = 4 or failwith "fynose" in
let _ = "fyn" = String.sub s 0 3 or failwith "fynose2" in
let k = int_of_string (String.sub s 3 1) in
fynlist k in
let deprecated_fynose s =
let _ = (s = "fyn") or failwith "fynose" in fyn () in
fun s-> tryfind (fun f -> f s) [unabbrev;assoc_thm;fynose;assoct;assoc_sans_t;hash;hash;tac;];;
(* ========================================================================== *)
(* PARSING INPUT *)
type mtoken =
| M_comment
| M_string of string
| M_hol_term of string
| M_semicolon
| M_white of string
| M_text of string
| M_query of string
| M_lparen
| M_rparen
| M_lbracket
| M_rbracket
| M_env of int
(* not implemented : *)
| M_local of string
| M_asm of int ;;
let some_look p =
function
[] -> raise Noparse
| [_] -> raise Noparse
| (h1::h2::t) -> if p (h1,h2) then (h1,h2::t) else raise Noparse;;
let rec m_lex =
let stringchar =
some (fun i -> i <> "\"") in
let string = a "\"" ++ many stringchar ++ a "\"" >>
(fun ((_,s),_) -> M_string (implode s)) in
let hol_term_char =
some (fun i -> i <> "`") in
let hol_term = a "`" ++ many hol_term_char ++ a "`" >>
(fun ((_,s),_) -> M_hol_term (implode s)) in
let nonendcomment = (some_look (fun (h1,h2) -> h1 <> "*" or h2 <> ")")) in (* comment nesting unrecognized *)
let comment = a "(" ++ (a "*") ++ many nonendcomment ++ a "*" ++ a ")"
>> (fun _ -> M_comment) in
let semi = a ";" >> (fun _ -> M_semicolon) in
let textchar = some (fun i -> not (mem i (explode " %\t\n;()[]`\""))) in
let text = atleast 1 (textchar) >> (fun s -> M_text (implode s)) in
let numerical = (some (fun i -> (mem i (explode "0123456789")))) in
let asm = a "_" ++ atleast 1 numerical >> (fun (_,s) -> M_asm (int_of_string (implode s))) in
let local = a "_" ++ atleast 1 (textchar) >> (fun (_,s) -> M_local (implode s)) in
let query = a "?" ++ atleast 1 (textchar) >> (fun (_,s) -> M_query (implode s)) in
let lparen = a "(" >> (fun _ -> M_lparen) in
let rparen = a ")" >> (fun _ -> M_rparen) in
let lbracket = a "[" >> (fun _ -> M_lbracket) in
let rbracket = a "]" >> (fun _ -> M_rbracket) in
let menv = atleast 1 (a "%") >> (fun s -> M_env (List.length s)) in
let white = atleast 1 (some isspace) >> (fun s -> M_white (implode s)) in
many (some isspace) ++
many(comment || string || hol_term || semi || menv || lparen || rparen ||
lbracket || rbracket || asm || query || local || text || white) ;;
let rec strip_space = function
| M_comment :: xs -> strip_space xs
| M_white _ :: xs -> strip_space xs
| M_semicolon :: xs -> strip_space xs
| xs -> xs;;
let end_strip_space = List.rev o strip_space o List.rev o strip_space;;
(*
let test1 = " (* note *) _t _44 __33 `1 /\\ [3] (* 42` (* hi *) ; [lade] da(%% (\"quote\";)) then (* c *) \t\n ";;
let test2 = " (* hi *) (* (* hi again *) *) \"quote\" `&1 + &1`;; (* there *) ;; ";;
(end_strip_space o snd o fst o m_lex o explode) test1;;
implode;;
many (some isspace);;
test1;;
unabbrev test1;;
*)
(*
let unabbrev_thm s =
let tg = String.sub s 0 1 in
let item = int_of_string (String.sub s 1 (String.length s - 1)) in
retrieve_search tg item;;
*)
let unabbrev_token = function
| M_comment -> ""
| M_string s -> "\""^s^"\""
| M_hol_term s -> "`"^s^"`"
| M_semicolon -> ";"
| M_white s -> " "
| M_text s -> unabbrev_string s
| M_lparen -> "("
| M_rparen -> ")"
| M_lbracket -> "["
| M_rbracket -> "]"
| M_query s -> if (s.[0]='-') then expand_suggest (String.sub s 1 (String.length s - 1))
else expand_thm s
| M_env level -> if (level <=1) then " env w" else " envl w"
| M_local s -> ("loc_"^s)
| M_asm i -> ("asm_"^(string_of_int i));;
let which_asms = mapfilter (function | M_asm i -> i | _ -> failwith "");;
let has_env = can (Lib.find (function M_env _ -> true | _ -> false));;
let really_expand s =
let ((_,r),rest) = m_lex (explode s) in
let _ = (rest=[]) or (failwith ("unparsed data : " ^ (implode rest))) in
let r = end_strip_space r in
let rs = map unabbrev_token r in
let u = unsplit "" I rs in
let which = setify( which_asms r) in
let gets = map (fun i ->Printf.sprintf " let asm_%d = snd(List.nth (List.rev asl) %d ) in " i i) which in
let v = unsplit "" I gets in
let envA,envB = if (has_env r) or (List.length which > 0) then
"GOAL_TERM (fun w -> (","))" else "","" in
(envA^v^u^envB);;
(*
let escape s =
let ss = Str.split (Str.regexp "\"") s in
let s = unsplit "\\\"" I ss in
let ss = Str.split (Str.regexp "\\ ") s in
let s = unsplit "\\\\ " I ss in
s;;
*)
let p() =
let history = 5 in
let _ = print_string (string_of_proof_k history ()) in
if ((!current_goalstack=[])) then print_string "There is no current goal."
else
let (_,gl,_) = hd !current_goalstack in
let ns = follow_your_nose_string_list() in
if (gl = []) then print_string "\nNo subgoal"
else
(Print_types.print_goal_var_overload() ;
print_goalstack (!current_goalstack);
print_string ("\n >>>last step: "^ (string_of_proof_k 1 ()) ^ "\n");
print_string (" >>>total: "^(string_of_int (length gl)) ^ "\n");
if not(ns="") then print_string ("Follow your nose: "^ns)
);;
(*
let eval_tactic_abbrev s =
try(
let i = String.index s ',' in
let pre = String.sub s 0 i in
let post = String.sub s (i+1) (String.length s - (i+1)) in
((unabbrev_tactic pre)^" "^post)
)
with _ -> s in
(* let _ = print_string (String.escaped expand_s) in *)
let _ = eval_tactic (expand_s) in
p();;
*)
let eval_tactic_abbrev2 s =
let sexp = really_expand s in
let _ = report sexp in
let _ = eval_tactic (sexp) in
p();;
let blank_line = Str.regexp ("^ *$");;
let eval_tactic_lines s =
let ss = Str.split (Str.regexp "\n") s in
let one_line s1 =
let sepx = try (really_expand s1) with _ -> (failwith "expansion error : "^s1) in
if (Str.string_match blank_line sepx 0) then ()
else
try (Pervasives.ignore(eval_tactic sepx))
with _ -> failwith ("tactic failure : "^s1^" >>> "^sepx) in
let _ = do_list one_line ss in
p();;
(* emacs: hol-light-tactic-replay "\C-c\C-r" *)
let e_abbrev = eval_tactic_abbrev2;;
let g = eval_goal;;
let b() =
let _ = eval_back() in p();;
let bb k =
let _ = map eval_back (replicate () k) in p();;
let back_to s =
let r = List.rev (strs_of_proof_records 0 0 [] !proof_record) in
let re = Str.regexp_case_fold (".*"^s) in
let searcher a = Str.string_match re a 0 in
let z = find searcher r in
let _ = report z in
let i = index z r in
bb i;;
(*
let directive_abbreviations= ref[
("-b",eval_back);
("-?",fun () ->
let s = map snd tactic_counts in
let s1 = unsplit ": "
];;
*)
(* EMACS BINDINGS:
see hol-light-mode.el
eval_tactic_lines -> hol-light-tactic-replay "\C-c\C-r"
(local-set-key "\C-ct" 'hol-light-goal-types)
(local-set-key "\C-c\C-y" 'hol-light-type-region)
(local-set-key "\C-cr" 'hol-light-eval-region)
*)
end;;