blanchet@35866: (* Title: HOL/Sledgehammer/sledgehammer_isar.ML blanchet@35866: Author: Jasmin Blanchette, TU Muenchen blanchet@35866: blanchet@35866: Adds "sledgehammer" and related commands to Isabelle/Isar's outer syntax. blanchet@35866: *) blanchet@35866: blanchet@35961: signature SLEDGEHAMMER_ISAR = blanchet@35961: sig blanchet@35961: type params = ATP_Manager.params blanchet@35961: blanchet@36371: val atps: string Unsynchronized.ref blanchet@36371: val timeout: int Unsynchronized.ref blanchet@36371: val full_types: bool Unsynchronized.ref blanchet@35961: val default_params : theory -> (string * string) list -> params blanchet@35961: end; blanchet@35961: blanchet@35969: structure Sledgehammer_Isar : SLEDGEHAMMER_ISAR = blanchet@35866: struct blanchet@35866: blanchet@35969: open Sledgehammer_Util blanchet@35866: open ATP_Manager blanchet@35866: open ATP_Minimal blanchet@35963: open ATP_Wrapper blanchet@35866: blanchet@35866: structure K = OuterKeyword and P = OuterParse blanchet@35866: blanchet@35964: fun add_to_relevance_override ns : relevance_override = blanchet@35964: {add = ns, del = [], only = false} blanchet@35964: fun del_from_relevance_override ns : relevance_override = blanchet@35964: {add = [], del = ns, only = false} blanchet@35964: fun only_relevance_override ns : relevance_override = blanchet@35964: {add = ns, del = [], only = true} blanchet@36188: val no_relevance_override = add_to_relevance_override [] blanchet@36003: fun merge_relevance_override_pairwise (r1 : relevance_override) blanchet@36003: (r2 : relevance_override) = blanchet@35964: {add = #add r1 @ #add r2, del = #del r1 @ #del r2, blanchet@36183: only = #only r1 andalso #only r2} blanchet@36188: fun merge_relevance_overrides rs = blanchet@36188: fold merge_relevance_override_pairwise rs (only_relevance_override []) blanchet@35963: blanchet@36371: (*** parameters ***) blanchet@36371: blanchet@36371: val atps = Unsynchronized.ref (default_atps_param_value ()) blanchet@36371: val timeout = Unsynchronized.ref 60 blanchet@36371: val full_types = Unsynchronized.ref false blanchet@36371: blanchet@36371: val _ = blanchet@36371: ProofGeneralPgip.add_preference Preferences.category_proof blanchet@36371: (Preferences.string_pref atps blanchet@36371: "Sledgehammer: ATPs" blanchet@36371: "Default automatic provers (separated by whitespace)") blanchet@36371: blanchet@36371: val _ = blanchet@36371: ProofGeneralPgip.add_preference Preferences.category_proof blanchet@36371: (Preferences.int_pref timeout blanchet@36371: "Sledgehammer: Time limit" blanchet@36371: "ATPs will be interrupted after this time (in seconds)") blanchet@36371: blanchet@36371: val _ = blanchet@36371: ProofGeneralPgip.add_preference Preferences.category_proof blanchet@36371: (Preferences.bool_pref full_types blanchet@36371: "Sledgehammer: Full types" "ATPs will use full type information") blanchet@36371: blanchet@35961: type raw_param = string * string list blanchet@35866: blanchet@35961: val default_default_params = blanchet@35961: [("debug", "false"), blanchet@35961: ("verbose", "false"), blanchet@36141: ("overlord", "false"), blanchet@36235: ("explicit_apply", "false"), blanchet@36058: ("respect_no_atp", "true"), blanchet@35964: ("relevance_threshold", "50"), blanchet@36058: ("convergence", "320"), blanchet@36220: ("theory_relevant", "smart"), blanchet@35961: ("higher_order", "smart"), blanchet@35961: ("follow_defs", "false"), blanchet@35961: ("isar_proof", "false"), blanchet@36064: ("modulus", "1"), blanchet@36064: ("sorts", "false"), blanchet@35961: ("minimize_timeout", "5 s")] blanchet@35866: blanchet@36138: val alias_params = blanchet@36138: [("atp", "atps")] blanchet@36138: val negated_alias_params = blanchet@35961: [("no_debug", "debug"), blanchet@35961: ("quiet", "verbose"), blanchet@36141: ("no_overlord", "overlord"), blanchet@36235: ("implicit_apply", "explicit_apply"), blanchet@36058: ("ignore_no_atp", "respect_no_atp"), blanchet@35961: ("partial_types", "full_types"), blanchet@36220: ("theory_irrelevant", "theory_relevant"), blanchet@35961: ("first_order", "higher_order"), blanchet@35961: ("dont_follow_defs", "follow_defs"), blanchet@36064: ("metis_proof", "isar_proof"), blanchet@36064: ("no_sorts", "sorts")] blanchet@35866: blanchet@36281: val params_for_minimize = blanchet@36281: ["full_types", "explicit_apply", "higher_order", "isar_proof", "modulus", blanchet@36281: "sorts", "minimize_timeout"] blanchet@36281: blanchet@35969: val property_dependent_params = ["atps", "full_types", "timeout"] blanchet@35866: blanchet@35961: fun is_known_raw_param s = blanchet@35961: AList.defined (op =) default_default_params s orelse blanchet@36138: AList.defined (op =) alias_params s orelse blanchet@36138: AList.defined (op =) negated_alias_params s orelse blanchet@35969: member (op =) property_dependent_params s blanchet@35866: blanchet@35961: fun check_raw_param (s, _) = blanchet@35961: if is_known_raw_param s then () blanchet@35961: else error ("Unknown parameter: " ^ quote s ^ ".") blanchet@35961: blanchet@36138: fun unalias_raw_param (name, value) = blanchet@36138: case AList.lookup (op =) alias_params name of blanchet@36138: SOME name' => (name', value) blanchet@36138: | NONE => blanchet@36138: case AList.lookup (op =) negated_alias_params name of blanchet@36138: SOME name' => (name', case value of blanchet@36138: ["false"] => ["true"] blanchet@36138: | ["true"] => ["false"] blanchet@36138: | [] => ["false"] blanchet@36138: | _ => value) blanchet@36138: | NONE => (name, value) blanchet@35961: blanchet@35961: structure Data = Theory_Data( blanchet@35961: type T = raw_param list blanchet@35961: val empty = default_default_params |> map (apsnd single) blanchet@35961: val extend = I blanchet@35961: fun merge p : T = AList.merge (op =) (K true) p) blanchet@35961: blanchet@36138: val set_default_raw_param = Data.map o AList.update (op =) o unalias_raw_param blanchet@35961: fun default_raw_params thy = blanchet@35961: Data.get thy blanchet@36138: |> fold (AList.default (op =)) blanchet@36290: [("atps", [!atps]), blanchet@36138: ("full_types", [if !full_types then "true" else "false"]), blanchet@36140: ("timeout", let val timeout = !timeout in blanchet@36140: [if timeout <= 0 then "none" blanchet@36140: else string_of_int timeout ^ " s"] blanchet@36140: end)] blanchet@35961: blanchet@35961: val infinity_time_in_secs = 60 * 60 * 24 * 365 blanchet@35961: val the_timeout = the_default (Time.fromSeconds infinity_time_in_secs) blanchet@35961: blanchet@35961: fun extract_params thy default_params override_params = blanchet@35961: let blanchet@36138: val override_params = map unalias_raw_param override_params blanchet@35961: val raw_params = rev override_params @ rev default_params blanchet@35961: val lookup = Option.map (space_implode " ") o AList.lookup (op =) raw_params blanchet@35961: val lookup_string = the_default "" o lookup blanchet@35961: fun general_lookup_bool option default_value name = blanchet@35961: case lookup name of blanchet@35968: SOME s => parse_bool_option option name s blanchet@35961: | NONE => default_value blanchet@35961: val lookup_bool = the o general_lookup_bool false (SOME false) blanchet@35961: val lookup_bool_option = general_lookup_bool true NONE blanchet@35961: fun lookup_time name = blanchet@35961: the_timeout (case lookup name of blanchet@35961: NONE => NONE blanchet@35961: | SOME s => parse_time_option name s) blanchet@35964: fun lookup_int name = blanchet@35961: case lookup name of blanchet@35964: NONE => 0 blanchet@35964: | SOME s => case Int.fromString s of blanchet@35964: SOME n => n blanchet@35964: | NONE => error ("Parameter " ^ quote name ^ blanchet@35964: " must be assigned an integer value.") blanchet@35961: val debug = lookup_bool "debug" blanchet@35961: val verbose = debug orelse lookup_bool "verbose" blanchet@36141: val overlord = lookup_bool "overlord" blanchet@35961: val atps = lookup_string "atps" |> space_explode " " blanchet@35961: val full_types = lookup_bool "full_types" blanchet@36235: val explicit_apply = lookup_bool "explicit_apply" blanchet@36058: val respect_no_atp = lookup_bool "respect_no_atp" blanchet@35964: val relevance_threshold = blanchet@35964: 0.01 * Real.fromInt (lookup_int "relevance_threshold") blanchet@36058: val convergence = 0.01 * Real.fromInt (lookup_int "convergence") blanchet@36220: val theory_relevant = lookup_bool_option "theory_relevant" blanchet@35961: val higher_order = lookup_bool_option "higher_order" blanchet@35961: val follow_defs = lookup_bool "follow_defs" blanchet@35961: val isar_proof = lookup_bool "isar_proof" blanchet@36064: val modulus = Int.max (1, lookup_int "modulus") blanchet@36064: val sorts = lookup_bool "sorts" blanchet@35961: val timeout = lookup_time "timeout" blanchet@35961: val minimize_timeout = lookup_time "minimize_timeout" blanchet@35961: in blanchet@36141: {debug = debug, verbose = verbose, overlord = overlord, atps = atps, blanchet@36235: full_types = full_types, explicit_apply = explicit_apply, blanchet@36235: respect_no_atp = respect_no_atp, relevance_threshold = relevance_threshold, blanchet@36235: convergence = convergence, theory_relevant = theory_relevant, blanchet@36235: higher_order = higher_order, follow_defs = follow_defs, blanchet@36235: isar_proof = isar_proof, modulus = modulus, sorts = sorts, blanchet@36235: timeout = timeout, minimize_timeout = minimize_timeout} blanchet@35961: end blanchet@35961: blanchet@35963: fun get_params thy = extract_params thy (default_raw_params thy) blanchet@35963: fun default_params thy = get_params thy o map (apsnd single) blanchet@35866: blanchet@36139: fun minimize override_params old_style_args i fact_refs state = blanchet@35866: let blanchet@35961: val thy = Proof.theory_of state blanchet@35961: val ctxt = Proof.context_of state blanchet@35963: fun theorems_from_refs ctxt = blanchet@35963: map (fn fact_ref => blanchet@35866: let blanchet@35963: val ths = ProofContext.get_fact ctxt fact_ref blanchet@35963: val name' = Facts.string_of_ref fact_ref blanchet@35866: in (name', ths) end) blanchet@35961: fun get_time_limit_arg s = blanchet@35961: (case Int.fromString s of blanchet@35961: SOME t => Time.fromSeconds t blanchet@36223: | NONE => error ("Invalid time limit: " ^ quote s ^ ".")) blanchet@35866: fun get_opt (name, a) (p, t) = blanchet@35866: (case name of blanchet@35866: "time" => (p, get_time_limit_arg a) blanchet@35866: | "atp" => (a, t) blanchet@36223: | n => error ("Invalid argument: " ^ n ^ ".")) blanchet@35963: val {atps, minimize_timeout, ...} = get_params thy override_params blanchet@35963: val (atp, timeout) = fold get_opt old_style_args (hd atps, minimize_timeout) blanchet@35961: val params = blanchet@35963: get_params thy blanchet@36223: (override_params @ blanchet@36223: [("atps", [atp]), blanchet@36223: ("minimize_timeout", blanchet@36223: [string_of_int (Time.toMilliseconds timeout) ^ " ms"])]) blanchet@35866: val prover = blanchet@35961: (case get_prover thy atp of blanchet@35866: SOME prover => prover blanchet@36223: | NONE => error ("Unknown ATP: " ^ quote atp ^ ".")) blanchet@35963: val name_thms_pairs = theorems_from_refs ctxt fact_refs blanchet@35866: in blanchet@36223: priority (#2 (minimize_theorems params prover atp i state name_thms_pairs)) blanchet@35866: end blanchet@35866: blanchet@35963: val runN = "run" blanchet@35963: val minimizeN = "minimize" blanchet@35963: val messagesN = "messages" blanchet@35963: val available_atpsN = "available_atps" blanchet@35963: val running_atpsN = "running_atps" blanchet@35963: val kill_atpsN = "kill_atps" blanchet@35963: val refresh_tptpN = "refresh_tptp" blanchet@35963: val helpN = "help" blanchet@35866: blanchet@36139: fun minimizize_raw_param_name "timeout" = "minimize_timeout" blanchet@36139: | minimizize_raw_param_name name = name blanchet@36139: blanchet@36281: val is_raw_param_relevant_for_minimize = blanchet@36281: member (op =) params_for_minimize o fst o unalias_raw_param blanchet@36281: fun string_for_raw_param (key, values) = blanchet@36281: key ^ (case space_implode " " values of blanchet@36281: "" => "" blanchet@36281: | value => " = " ^ value) blanchet@36281: blanchet@36281: fun minimize_command override_params i atp_name facts = blanchet@36281: "sledgehammer minimize [atp = " ^ atp_name ^ blanchet@36281: (override_params |> filter is_raw_param_relevant_for_minimize blanchet@36281: |> implode o map (prefix ", " o string_for_raw_param)) ^ blanchet@36281: "] (" ^ space_implode " " facts ^ ")" ^ blanchet@36281: (if i = 1 then "" else " " ^ string_of_int i) blanchet@36281: blanchet@35964: fun hammer_away override_params subcommand opt_i relevance_override state = blanchet@35961: let blanchet@35961: val thy = Proof.theory_of state blanchet@35961: val _ = List.app check_raw_param override_params blanchet@35963: in blanchet@35963: if subcommand = runN then blanchet@36281: let val i = the_default 1 opt_i in blanchet@36281: sledgehammer (get_params thy override_params) i relevance_override blanchet@36281: (minimize_command override_params i) state blanchet@36281: end blanchet@35963: else if subcommand = minimizeN then blanchet@36139: minimize (map (apfst minimizize_raw_param_name) override_params) [] blanchet@36139: (the_default 1 opt_i) (#add relevance_override) state blanchet@35963: else if subcommand = messagesN then blanchet@35963: messages opt_i blanchet@35963: else if subcommand = available_atpsN then blanchet@35963: available_atps thy blanchet@35963: else if subcommand = running_atpsN then blanchet@35963: running_atps () blanchet@35963: else if subcommand = kill_atpsN then blanchet@35963: kill_atps () blanchet@35963: else if subcommand = refresh_tptpN then blanchet@35963: refresh_systems_on_tptp () blanchet@35963: else blanchet@35963: error ("Unknown subcommand: " ^ quote subcommand ^ ".") blanchet@35963: end blanchet@35961: blanchet@35964: fun sledgehammer_trans (((subcommand, params), relevance_override), opt_i) = blanchet@35964: Toplevel.keep (hammer_away params subcommand opt_i relevance_override blanchet@35964: o Toplevel.proof_of) blanchet@35961: blanchet@35961: fun string_for_raw_param (name, value) = name ^ " = " ^ space_implode " " value blanchet@35961: blanchet@35963: fun sledgehammer_params_trans params = blanchet@35961: Toplevel.theory blanchet@35963: (fold set_default_raw_param params blanchet@35961: #> tap (fn thy => blanchet@35961: writeln ("Default parameters for Sledgehammer:\n" ^ blanchet@35961: (case rev (default_raw_params thy) of blanchet@35961: [] => "none" blanchet@35961: | params => blanchet@35961: (map check_raw_param params; blanchet@35961: params |> map string_for_raw_param blanchet@35961: |> sort_strings |> cat_lines))))) blanchet@35961: blanchet@35961: val parse_key = Scan.repeat1 P.typ_group >> space_implode " " blanchet@35964: val parse_value = Scan.repeat1 P.xname blanchet@35963: val parse_param = parse_key -- Scan.optional (P.$$$ "=" |-- parse_value) [] blanchet@35963: val parse_params = Scan.optional (Args.bracks (P.list parse_param)) [] blanchet@35963: val parse_fact_refs = blanchet@35964: Scan.repeat1 (Scan.unless (P.name -- Args.colon) blanchet@35964: (P.xname -- Scan.option Attrib.thm_sel) blanchet@35964: >> (fn (name, interval) => blanchet@35964: Facts.Named ((name, Position.none), interval))) blanchet@35964: val parse_relevance_chunk = blanchet@35964: (Args.add |-- Args.colon |-- parse_fact_refs >> add_to_relevance_override) blanchet@35964: || (Args.del |-- Args.colon |-- parse_fact_refs blanchet@35964: >> del_from_relevance_override) blanchet@36188: || (parse_fact_refs >> only_relevance_override) blanchet@35964: val parse_relevance_override = blanchet@36188: Scan.optional (Args.parens (Scan.repeat parse_relevance_chunk blanchet@36188: >> merge_relevance_overrides)) blanchet@36188: (add_to_relevance_override []) blanchet@35961: val parse_sledgehammer_command = blanchet@35964: (Scan.optional P.short_ident runN -- parse_params -- parse_relevance_override blanchet@35964: -- Scan.option P.nat) #>> sledgehammer_trans blanchet@35961: val parse_sledgehammer_params_command = blanchet@35961: parse_params #>> sledgehammer_params_trans blanchet@35961: blanchet@35963: val parse_minimize_args = blanchet@35964: Scan.optional (Args.bracks (P.list (P.short_ident --| P.$$$ "=" -- P.xname))) blanchet@35964: [] blanchet@35961: val _ = blanchet@35961: OuterSyntax.improper_command "atp_kill" "kill all managed provers" K.diag blanchet@35963: (Scan.succeed (Toplevel.no_timing o Toplevel.imperative kill_atps)) blanchet@35961: val _ = blanchet@35961: OuterSyntax.improper_command "atp_info" blanchet@35961: "print information about managed provers" K.diag blanchet@35963: (Scan.succeed (Toplevel.no_timing o Toplevel.imperative running_atps)) blanchet@35961: val _ = blanchet@35961: OuterSyntax.improper_command "atp_messages" blanchet@35961: "print recent messages issued by managed provers" K.diag blanchet@35961: (Scan.option (P.$$$ "(" |-- P.nat --| P.$$$ ")") >> blanchet@35961: (fn limit => Toplevel.no_timing blanchet@35961: o Toplevel.imperative (fn () => messages limit))) blanchet@35961: val _ = blanchet@35961: OuterSyntax.improper_command "print_atps" "print external provers" K.diag blanchet@35961: (Scan.succeed (Toplevel.no_timing o Toplevel.unknown_theory o blanchet@35963: Toplevel.keep (available_atps o Toplevel.theory_of))) blanchet@35963: val _ = blanchet@35963: OuterSyntax.improper_command "atp_minimize" blanchet@35963: "minimize theorem list with external prover" K.diag blanchet@35963: (parse_minimize_args -- parse_fact_refs >> (fn (args, fact_refs) => blanchet@35963: Toplevel.no_timing o Toplevel.unknown_proof o blanchet@36139: Toplevel.keep (minimize [] args 1 fact_refs o Toplevel.proof_of))) blanchet@35963: blanchet@35961: val _ = blanchet@35961: OuterSyntax.improper_command "sledgehammer" blanchet@35961: "search for first-order proof using automatic theorem provers" K.diag blanchet@35961: parse_sledgehammer_command blanchet@35961: val _ = blanchet@35961: OuterSyntax.command "sledgehammer_params" blanchet@35961: "set and display the default parameters for Sledgehammer" K.thy_decl blanchet@35961: parse_sledgehammer_params_command blanchet@35866: blanchet@35866: end;