src/HOL/Tools/ATP/atp_waldmeister.ML
changeset 57267 8b87114357bd
parent 57262 b2c629647a14
child 57270 0260171a51ef
equal deleted inserted replaced
57266:6a3b5085fb8f 57267:8b87114357bd
     5 General-purpose functions used by the Sledgehammer modules.
     5 General-purpose functions used by the Sledgehammer modules.
     6 *)
     6 *)
     7 
     7 
     8 signature ATP_WALDMEISTER =
     8 signature ATP_WALDMEISTER =
     9 sig
     9 sig
    10   type ('a, 'b) atp_term = ('a, 'b) ATP_Problem.atp_term
       
    11   type atp_connective = ATP_Problem.atp_connective
       
    12   type ('a, 'b, 'c, 'd) atp_formula = ('a, 'b, 'c, 'd) ATP_Problem.atp_formula
       
    13   type atp_format = ATP_Problem.atp_format
       
    14   type atp_formula_role = ATP_Problem.atp_formula_role
       
    15   type 'a atp_problem = 'a ATP_Problem.atp_problem
    10   type 'a atp_problem = 'a ATP_Problem.atp_problem
    16   type ('a, 'b) atp_step = ('a,'b) ATP_Proof.atp_step
    11   type ('a, 'b) atp_step = ('a, 'b) ATP_Proof.atp_step
       
    12   type 'a atp_proof = 'a ATP_Proof.atp_proof
       
    13   type stature = ATP_Problem_Generate.stature
    17 
    14 
    18   val const_prefix : char
    15   val generate_waldmeister_problem: Proof.context -> term list -> term ->
    19   val var_prefix : char
    16     ((string * stature) * term) list ->
    20   val free_prefix : char
    17     string atp_problem * string Symtab.table * (string * term) list * int Symtab.table
    21   val thm_prefix : string
    18   val termify_waldmeister_proof : Proof.context -> string Symtab.table -> string atp_proof ->
    22   val hypothesis_prefix : string
    19     (term, string) atp_step list
    23   val thms_header : string
       
    24   val conjecture_condition_name : string
       
    25   val hypothesis_header : string
       
    26   val waldmeister_output_file_path : string
       
    27 
       
    28   val waldmeister_simp_header : string
       
    29   val waldmeister_simp_thms : thm list
       
    30 
       
    31   val thm_to_atps : bool -> thm -> (string * string, 'a) atp_term list
       
    32   val trm_to_atp : term -> (string * string, 'a) atp_term
       
    33   val atp_to_trm : (string, 'a) atp_term -> term
       
    34   val trm_to_atp_to_trm : term -> term
       
    35   val create_tptp_input : thm list -> term ->
       
    36     (string * ((string * string ATP_Problem.atp_problem_line list) list
       
    37       * (string Symtab.table * string Symtab.table) option)) option
       
    38   val run_waldmeister :
       
    39     string * (string ATP_Proof.atp_problem * (string Symtab.table * string Symtab.table) option)
       
    40     -> string ATP_Proof.atp_proof
       
    41   val atp_proof_step_to_term :
       
    42     ((string, string, (string, string) atp_term, string) atp_formula,string) atp_step
       
    43     -> (term,string) atp_step
       
    44   val fix_waldmeister_proof :
       
    45     ((string, string, (string, string) atp_term, string) atp_formula,string) atp_step list ->
       
    46     ((string, string, (string, string) atp_term, string) atp_formula,string) atp_step list
       
    47 end;
    20 end;
    48 
    21 
    49 structure ATP_Waldmeister : ATP_WALDMEISTER =
    22 structure ATP_Waldmeister : ATP_WALDMEISTER =
    50 struct
    23 struct
    51 
    24 
       
    25 open ATP_Util
    52 open ATP_Problem
    26 open ATP_Problem
    53 open ATP_Problem_Generate
    27 open ATP_Problem_Generate
    54 open ATP_Proof
    28 open ATP_Proof
    55 open ATP_Proof_Reconstruct
    29 open ATP_Proof_Reconstruct
    56 
    30 
    62 type 'a atp_problem = 'a ATP_Problem.atp_problem
    36 type 'a atp_problem = 'a ATP_Problem.atp_problem
    63 
    37 
    64 val const_prefix = #"c"
    38 val const_prefix = #"c"
    65 val var_prefix = #"V"
    39 val var_prefix = #"V"
    66 val free_prefix = #"f"
    40 val free_prefix = #"f"
    67 val thm_prefix = "fact"
       
    68 val hypothesis_prefix = "hypothesis"
       
    69 val thms_header = "facts"
       
    70 val conjecture_condition_name = "condition"
    41 val conjecture_condition_name = "condition"
    71 val hypothesis_header = "hypothesis"
       
    72 val broken_waldmeister_formula_prefix = #"1"
       
    73 
    42 
    74 val waldmeister_simp_header = "Waldmeister first order logic facts"
    43 val factsN = "Relevant facts"
    75 val waldmeister_simp_thms = @{thms waldmeister_fol}
    44 val helpersN = "Helper facts"
    76 
    45 val conjN = "Conjecture"
    77 val temp_files_dir = "/home/albert/waldmeister"
       
    78 val input_file_name = "input.tptp"
       
    79 val output_file_name = "output.tptp"
       
    80 val waldmeister_input_file_path = temp_files_dir ^ "/" ^ input_file_name
       
    81 val waldmeister_output_file_path = temp_files_dir ^ "/" ^ output_file_name
       
    82 val script_path = "/opt/Isabelle/src/HOL/Tools/ATP/scripts/remote_atp -s Waldmeister---710 -t 30"
       
    83 
    46 
    84 exception Failure
    47 exception Failure
    85 exception FailureMessage of string
    48 exception FailureMessage of string
    86 
    49 
    87 (*
    50 (*
    88 Some utilitary functions for translation.
    51 Some utilitary functions for translation.
    89 *)
    52 *)
    90 
    53 
    91 fun is_eq (Const (@{const_name "HOL.eq"}, _) $ _ $ _) = true
    54 fun is_eq (Const (@{const_name "HOL.eq"}, _) $ _ $ _) = true
    92   | is_eq _ = false
    55   | is_eq _ = false
    93 
       
    94 fun is_eq_thm thm = thm |> Thm.prop_of |> Object_Logic.atomize_term @{theory } |> is_eq
       
    95 
    56 
    96 fun gen_ascii_tuple str = (str, ascii_of str)
    57 fun gen_ascii_tuple str = (str, ascii_of str)
    97 
    58 
    98 (*
    59 (*
    99 Translation from Isabelle theorms and terms to ATP terms.
    60 Translation from Isabelle theorms and terms to ATP terms.
   106   | trm_to_atp'' _ args = args
    67   | trm_to_atp'' _ args = args
   107 
    68 
   108 fun trm_to_atp' trm = trm_to_atp'' trm [] |> hd
    69 fun trm_to_atp' trm = trm_to_atp'' trm [] |> hd
   109 
    70 
   110 fun eq_trm_to_atp (Const (@{const_name HOL.eq}, _) $ lhs $ rhs) =
    71 fun eq_trm_to_atp (Const (@{const_name HOL.eq}, _) $ lhs $ rhs) =
   111   ATerm (((tptp_equal, tptp_equal), []), [trm_to_atp' lhs, trm_to_atp' rhs])
    72     ATerm ((("equal", "equal"), []), [trm_to_atp' lhs, trm_to_atp' rhs])
   112   | eq_trm_to_atp _ = raise Failure
    73   | eq_trm_to_atp _ = raise Failure
   113 
    74 
   114 fun trm_to_atp trm =
    75 fun trm_to_atp trm =
   115   if is_eq trm then
    76   if is_eq trm then eq_trm_to_atp trm
   116     eq_trm_to_atp trm
    77   else HOLogic.mk_eq (trm, @{term True}) |> eq_trm_to_atp
   117   else
       
   118     HOLogic.mk_eq (trm, @{term True}) |> eq_trm_to_atp
       
   119 
    78 
   120 fun thm_to_atps split_conj thm =
    79 fun thm_to_atps split_conj prop_term =
   121   let
    80   if split_conj then map trm_to_atp (prop_term |> HOLogic.dest_conj)
   122     val prop_term = Thm.prop_of thm |> Object_Logic.atomize_term @{theory}
    81   else [prop_term |> trm_to_atp]
   123   in
       
   124     if split_conj then
       
   125       map trm_to_atp (prop_term |> HOLogic.dest_conj)
       
   126     else
       
   127       [prop_term |> trm_to_atp]
       
   128   end
       
   129 
    82 
   130 fun prepare_conjecture conj_term =
    83 fun prepare_conjecture conj_term =
   131   let
    84   let
   132     fun split_conj_trm (Const (@{const_name Pure.imp}, _)$ condition $ consequence) =
    85     fun split_conj_trm (Const (@{const_name Pure.imp}, _) $ condition $ consequence) =
   133         (SOME condition, consequence)
    86         (SOME condition, consequence)
   134       | split_conj_trm conj = (NONE, conj)
    87       | split_conj_trm conj = (NONE, conj)
   135     val (condition, consequence) = split_conj_trm conj_term
    88     val (condition, consequence) = split_conj_trm conj_term
   136   in
    89   in
   137     (case condition of SOME x => HOLogic.dest_conj x |> map trm_to_atp | NONE => []
    90     (case condition of SOME x => HOLogic.dest_conj x |> map trm_to_atp | NONE => []
   159     (case args of
   112     (case args of
   160       [] => construct_term (ATerm (descr, args))
   113       [] => construct_term (ATerm (descr, args))
   161      | _ => Term.list_comb (construct_term (ATerm (descr, args)), map atp_to_trm' args))
   114      | _ => Term.list_comb (construct_term (ATerm (descr, args)), map atp_to_trm' args))
   162      | atp_to_trm' _ = raise Failure
   115      | atp_to_trm' _ = raise Failure
   163 
   116 
   164 fun atp_to_trm  (ATerm (("equal", _), [lhs, rhs])) =
   117 fun atp_to_trm (ATerm (("equal", _), [lhs, rhs])) =
   165     Const (@{const_name HOL.eq}, Type ("", [])) $ atp_to_trm' lhs $ atp_to_trm' rhs
   118     Const (@{const_name HOL.eq}, Type ("", [])) $ atp_to_trm' lhs $ atp_to_trm' rhs
   166   | atp_to_trm (ATerm (("$true", _), _)) = Const ("HOL.True", Type ("", []))
   119   | atp_to_trm (ATerm (("$true", _), _)) = Const ("HOL.True", Type ("", []))
   167   | atp_to_trm _ = raise Failure
   120   | atp_to_trm _ = raise Failure
   168 
   121 
   169 fun formula_to_trm (AAtom aterm) = atp_to_trm aterm
   122 fun formula_to_trm (AAtom aterm) = atp_to_trm aterm
   170   | formula_to_trm (AConn (ANot, [aterm])) =
   123   | formula_to_trm (AConn (ANot, [aterm])) =
   171     Const (@{const_name HOL.Not}, @{typ "bool \<Rightarrow> bool"}) $ formula_to_trm aterm
   124     Const (@{const_name HOL.Not}, @{typ "bool \<Rightarrow> bool"}) $ formula_to_trm aterm
   172   | formula_to_trm _ = raise Failure
   125   | formula_to_trm _ = raise Failure
   173 
   126 
   174 (* Simple testing function for translation *)
   127 (* Abstract translation *)
   175 
       
   176 fun atp_only_readable_names (ATerm ((("=", _), ty), args)) =
       
   177     ATerm (("equal", ty), map atp_only_readable_names args)
       
   178   | atp_only_readable_names (ATerm (((descr, _), ty), args)) =
       
   179     ATerm ((descr, ty), map atp_only_readable_names args)
       
   180   | atp_only_readable_names _ = raise Failure
       
   181 
       
   182 val trm_to_atp_to_trm = eq_trm_to_atp #> atp_only_readable_names #> atp_to_trm
       
   183 
       
   184 (* Abstract translation from here on. *)
       
   185 
       
   186 fun name_of_thm thm =
       
   187   Thm.get_tags thm
       
   188   |> List.find (fn (x, _) => x = "name")
       
   189   |> the |> snd
       
   190 
   128 
   191 fun mk_formula prefix_name name atype aterm =
   129 fun mk_formula prefix_name name atype aterm =
   192   Formula ((prefix_name ^ "_" ^ ascii_of name, name), atype, AAtom aterm, NONE, [])
   130   Formula ((prefix_name ^ ascii_of name, name), atype, AAtom aterm, NONE, [])
   193 
   131 
   194 fun thms_to_problem_lines [] = []
   132 fun problem_lines_of_fact prefix ((s, _), t) =
   195   | thms_to_problem_lines (t::thms) =
   133   map (mk_formula prefix s Axiom) (thm_to_atps false t)
   196     (thm_to_atps false t |>
       
   197       map (mk_formula thm_prefix (name_of_thm t) Axiom)) @ thms_to_problem_lines thms
       
   198 
   134 
   199 fun make_nice problem = nice_atp_problem true CNF problem
   135 fun make_nice problem = nice_atp_problem true CNF problem
   200 
       
   201 fun problem_to_string [] = ""
       
   202   | problem_to_string ((kind, lines)::problems) =
       
   203     "% " ^ kind ^ "\n"
       
   204     ^ String.concat (map (tptp_string_of_line CNF) lines)
       
   205     ^ "\n"
       
   206     ^ problem_to_string problems
       
   207 
   136 
   208 fun mk_conjecture aterm =
   137 fun mk_conjecture aterm =
   209   let
   138   let
   210     val formula = mk_anot (AAtom aterm)
   139     val formula = mk_anot (AAtom aterm)
   211   in
   140   in
   212     Formula (gen_ascii_tuple hypothesis_prefix, Hypothesis, formula, NONE, [])
   141     Formula ((conjecture_prefix ^ "0", ""), Hypothesis, formula, NONE, [])
   213   end
   142   end
   214 
       
   215 fun mk_condition_lines [] = []
       
   216   | mk_condition_lines (term::terms) =
       
   217     mk_formula thm_prefix conjecture_condition_name Axiom term::mk_condition_lines terms
       
   218 
       
   219 fun create_tptp_input thms conj_t =
       
   220     let
       
   221       val (conditions, consequence) = prepare_conjecture conj_t
       
   222       val thms_lines = thms_to_problem_lines thms
       
   223       val condition_lines = mk_condition_lines conditions
       
   224       val axiom_lines = thms_lines @ condition_lines
       
   225       val conj_line = consequence |> mk_conjecture
       
   226       val waldmeister_simp_lines =
       
   227         if List.exists (fn x => not (is_eq_thm x)) thms orelse not (is_eq conj_t) then
       
   228           [(waldmeister_simp_header, thms_to_problem_lines waldmeister_simp_thms)]
       
   229         else
       
   230           []
       
   231       val problem =
       
   232         waldmeister_simp_lines @ [(thms_header, axiom_lines), (hypothesis_header, [conj_line])]
       
   233       val (problem_nice, symtabs) = make_nice problem
       
   234     in
       
   235       SOME (problem_to_string problem_nice, (problem_nice, symtabs))
       
   236     end
       
   237 
       
   238 val waldmeister_proof_delims =
       
   239   [("% SZS output start CNFRefutation", "% SZS output end CNFRefutation")]
       
   240 val known_waldmeister_failures = [(OutOfResources, "Too many function symbols"),
       
   241      (Inappropriate, "****  Unexpected end of file."),
       
   242      (Crashed, "Unrecoverable Segmentation Fault")]
       
   243 
       
   244 fun extract_proof_part output =
       
   245   case
       
   246     extract_tstplike_proof_and_outcome true
       
   247       waldmeister_proof_delims known_waldmeister_failures output of
       
   248     (x, NONE) => x | (_, SOME y) => raise FailureMessage (string_of_atp_failure y)
       
   249 
       
   250 fun cleanup () =
       
   251   (OS.Process.system ("rm " ^ waldmeister_input_file_path);
       
   252    OS.Process.system ("rm " ^ waldmeister_output_file_path))
       
   253 
       
   254 fun run_script input =
       
   255   let
       
   256     val outputFile = TextIO.openOut waldmeister_input_file_path
       
   257   in
       
   258     (TextIO.output (outputFile, input);
       
   259     TextIO.flushOut outputFile;
       
   260     TextIO.closeOut outputFile;
       
   261     OS.Process.system (script_path ^ " " ^ waldmeister_input_file_path ^ " > " ^
       
   262       waldmeister_output_file_path))
       
   263   end
       
   264 
       
   265 fun read_result () =
       
   266   let
       
   267     val inputFile = TextIO.openIn waldmeister_output_file_path
       
   268     fun readAllLines is =
       
   269       if TextIO.endOfStream is then (TextIO.closeIn is; [])
       
   270       else (TextIO.inputLine is |> the) :: readAllLines is
       
   271   in
       
   272     readAllLines inputFile |> String.concat
       
   273   end
       
   274 
       
   275 fun run_waldmeister (input, (problem, SOME (_, nice_to_nasty_table))) =
       
   276     (cleanup ();
       
   277      run_script input;
       
   278      read_result ()
       
   279      |> extract_proof_part
       
   280      |> atp_proof_of_tstplike_proof waldmeister_newN problem
       
   281      |> nasty_atp_proof nice_to_nasty_table)
       
   282   | run_waldmeister _ = raise Failure
       
   283 
   143 
   284 fun atp_proof_step_to_term (name, role, formula, formula_name, step_names) =
   144 fun atp_proof_step_to_term (name, role, formula, formula_name, step_names) =
   285   (name, role, formula_to_trm formula, formula_name, step_names)
   145   (name, role, formula_to_trm formula, formula_name, step_names)
   286 
   146 
   287 fun fix_waldmeister_proof [] = []
   147 fun generate_waldmeister_problem ctxt hyp_ts0 concl_t0 facts0 =
   288   | fix_waldmeister_proof (((name, extra_names), role, formula, formula_name, step_names)::steps) =
   148   let
   289     if String.sub (name, 0) = broken_waldmeister_formula_prefix then
   149     val hyp_ts = map HOLogic.dest_Trueprop hyp_ts0
   290       ((name, extra_names), role, mk_anot formula, formula_name, step_names)::fix_waldmeister_proof steps
   150     val concl_t = HOLogic.dest_Trueprop concl_t0
   291     else
   151     val facts = map (apsnd HOLogic.dest_Trueprop) facts0
   292       ((name, extra_names), role, formula, formula_name, step_names)::fix_waldmeister_proof steps
   152 
       
   153     val (conditions, consequence) = prepare_conjecture concl_t
       
   154     val fact_lines = maps (problem_lines_of_fact (fact_prefix ^ "0_" (* FIXME *))) facts
       
   155     val condition_lines =
       
   156       map (mk_formula fact_prefix conjecture_condition_name Hypothesis) conditions
       
   157     val axiom_lines = fact_lines @ condition_lines
       
   158     val conj_line = mk_conjecture consequence
       
   159 
       
   160     val helper_lines =
       
   161       if List.exists (is_eq o snd) facts orelse not (is_eq concl_t) then
       
   162         [(helpersN,
       
   163           @{thms waldmeister_fol}
       
   164           |> map (fn th => (("", (Global, General)), HOLogic.dest_Trueprop (prop_of th)))
       
   165           |> maps (problem_lines_of_fact helper_prefix))]
       
   166       else
       
   167         []
       
   168     val problem = (factsN, axiom_lines) :: helper_lines @ [(conjN, [conj_line])]
       
   169 
       
   170     val (nice_problem, symtabs) = make_nice problem
       
   171   in
       
   172     (nice_problem, Symtab.empty, [], Symtab.empty)
       
   173   end
       
   174 
       
   175 fun termify_line ctxt (name, role, AAtom u, rule, deps) =
       
   176   let
       
   177     val thy = Proof_Context.theory_of ctxt
       
   178     val t = u
       
   179       |> atp_to_trm
       
   180       |> infer_formula_types ctxt
       
   181       |> HOLogic.mk_Trueprop
       
   182   in
       
   183     (name, role, t, rule, deps)
       
   184   end
       
   185 
       
   186 fun termify_waldmeister_proof ctxt pool =
       
   187   nasty_atp_proof pool
       
   188   #> map (termify_line ctxt)
       
   189   #> repair_waldmeister_endgame
   293 
   190 
   294 end;
   191 end;