src/HOL/Tools/SMT/verit_proof.ML
changeset 72513 75f5c63f6cfa
parent 72458 b44e894796d5
child 72908 6a26a955308e
equal deleted inserted replaced
72512:83b5911c0164 72513:75f5c63f6cfa
    44   val simp_arith_rule : string
    44   val simp_arith_rule : string
    45   val veriT_deep_skolemize_rule : string
    45   val veriT_deep_skolemize_rule : string
    46   val veriT_def : string
    46   val veriT_def : string
    47   val subproof_rule : string
    47   val subproof_rule : string
    48   val local_input_rule : string
    48   val local_input_rule : string
    49 
    49   val not_not_rule : string
    50   val is_skolemisation: string -> bool
    50   val contract_rule : string
    51   val is_skolemisation_step: veriT_replay_node -> bool
    51   val ite_intro_rule : string
       
    52   val eq_congruent_rule : string
       
    53   val eq_congruent_pred_rule : string
       
    54   val skolemization_steps : string list
       
    55 
       
    56   val is_skolemization: string -> bool
       
    57   val is_skolemization_step: veriT_replay_node -> bool
    52 
    58 
    53   val number_of_steps: veriT_replay_node list -> int
    59   val number_of_steps: veriT_replay_node list -> int
    54 
    60 
    55   (*Strategy related*)
    61   (*Strategy related*)
    56   val veriT_strategy : string Config.T
    62   val veriT_strategy : string Config.T
   185 datatype veriT_node = VeriT_Node of {
   191 datatype veriT_node = VeriT_Node of {
   186   id: string,
   192   id: string,
   187   rule: string,
   193   rule: string,
   188   prems: string list,
   194   prems: string list,
   189   proof_ctxt: term list,
   195   proof_ctxt: term list,
   190   concl: term,
   196   concl: term}
   191   bounds: string list}
   197 
   192 
   198 fun mk_node id rule prems proof_ctxt concl =
   193 fun mk_node id rule prems proof_ctxt concl bounds =
   199   VeriT_Node {id = id, rule = rule, prems = prems, proof_ctxt = proof_ctxt, concl = concl}
   194   VeriT_Node {id = id, rule = rule, prems = prems, proof_ctxt = proof_ctxt, concl = concl,
       
   195     bounds = bounds}
       
   196 
   200 
   197 datatype veriT_replay_node = VeriT_Replay_Node of {
   201 datatype veriT_replay_node = VeriT_Replay_Node of {
   198   id: string,
   202   id: string,
   199   rule: string,
   203   rule: string,
   200   args: term list,
   204   args: term list,
   224     fixes = fixes}
   228     fixes = fixes}
   225 
   229 
   226 val step_prefix = ".c"
   230 val step_prefix = ".c"
   227 val input_rule = "input"
   231 val input_rule = "input"
   228 val la_generic_rule = "la_generic"
   232 val la_generic_rule = "la_generic"
   229 val normalized_input_rule = "__normalized_input" (* arbitrary *)
   233 val normalized_input_rule = "__normalized_input" (*arbitrary*)
   230 val rewrite_rule = "__rewrite" (* arbitrary *)
   234 val rewrite_rule = "__rewrite" (*arbitrary*)
   231 val subproof_rule = "subproof"
   235 val subproof_rule = "subproof"
   232 val local_input_rule = "__local_input" (* arbitrary *)
   236 val local_input_rule = "__local_input" (*arbitrary*)
   233 val simp_arith_rule = "simp_arith"
   237 val simp_arith_rule = "simp_arith"
   234 val veriT_def = "__skolem_definition" (*arbitrary*)
   238 val veriT_def = "__skolem_definition" (*arbitrary*)
   235 
   239 val not_not_rule = "not_not"
   236 val is_skolemisation = member (op =) ["sko_forall", "sko_ex"]
   240 val contract_rule = "contraction"
   237 val keep_app_symbols = member (op =) ["eq_congruent_pred", "eq_congruent", "ite_intro"]
   241 val eq_congruent_pred_rule = "eq_congruent_pred"
   238 val keep_raw_lifting = member (op =) ["eq_congruent_pred", "eq_congruent", "ite_intro"]
   242 val eq_congruent_rule = "eq_congruent"
   239 
   243 val ite_intro_rule = "ite_intro"
   240 fun is_skolemisation_step (VeriT_Replay_Node {id, ...}) = is_skolemisation id
   244 val default_skolem_rule = "sko_forall" (*arbitrary, but must be one of the skolems*)
       
   245 
       
   246 val skolemization_steps = ["sko_forall", "sko_ex"]
       
   247 val is_skolemization = member (op =) skolemization_steps
       
   248 val keep_app_symbols = member (op =) [eq_congruent_pred_rule, eq_congruent_rule, ite_intro_rule]
       
   249 val keep_raw_lifting = member (op =) [eq_congruent_pred_rule, eq_congruent_rule, ite_intro_rule]
       
   250 val is_SH_trivial = member (op =) [not_not_rule, contract_rule]
       
   251 
       
   252 fun is_skolemization_step (VeriT_Replay_Node {id, ...}) = is_skolemization id
   241 
   253 
   242 (* Even the veriT developers do not know if the following rule can still appear in proofs: *)
   254 (* Even the veriT developers do not know if the following rule can still appear in proofs: *)
   243 val veriT_deep_skolemize_rule = "deep_skolemize"
   255 val veriT_deep_skolemize_rule = "deep_skolemize"
   244 
   256 
   245 fun number_of_steps [] = 0
   257 fun number_of_steps [] = 0
   532 fun filter_split _ [] = ([], [])
   544 fun filter_split _ [] = ([], [])
   533   | filter_split f (a :: xs) =
   545   | filter_split f (a :: xs) =
   534      (if f a then apfst (curry op :: a) else apsnd (curry op :: a)) (filter_split f xs)
   546      (if f a then apfst (curry op :: a) else apsnd (curry op :: a)) (filter_split f xs)
   535 
   547 
   536 fun collect_skolem_defs (Raw_VeriT_Node {rule, subproof = subproof, args, ...}) =
   548 fun collect_skolem_defs (Raw_VeriT_Node {rule, subproof = subproof, args, ...}) =
   537   (if is_skolemisation rule then map (fn id => id ^ veriT_def) (skolems_introduced_by_rule args) else []) @
   549   (if is_skolemization rule then map (fn id => id ^ veriT_def) (skolems_introduced_by_rule args) else []) @
   538   flat (map collect_skolem_defs subproof)
   550   flat (map collect_skolem_defs subproof)
   539 
   551 
   540 (*The postprocessing does:
   552 (*The postprocessing does:
   541   1. translate the terms to Isabelle syntax, taking care of free variables
   553   1. translate the terms to Isabelle syntax, taking care of free variables
   542   2. remove the ambiguity in the proof terms:
   554   2. remove the ambiguity in the proof terms:
   604           |> could_unify
   616           |> could_unify
   605         handle TERM _ => false
   617         handle TERM _ => false
   606       val alpha_conversion = rule = "bind" andalso is_alpha_renaming concl
   618       val alpha_conversion = rule = "bind" andalso is_alpha_renaming concl
   607 
   619 
   608       val can_remove_subproof =
   620       val can_remove_subproof =
   609         compress andalso (is_skolemisation rule orelse alpha_conversion)
   621         compress andalso (is_skolemization rule orelse alpha_conversion)
   610       val (fixed_subproof : veriT_replay_node list, _) =
   622       val (fixed_subproof : veriT_replay_node list, _) =
   611          fold_map postprocess (if can_remove_subproof then [] else subproof)
   623          fold_map postprocess (if can_remove_subproof then [] else subproof)
   612            (subproof_cx, subproof_rew)
   624            (subproof_cx, subproof_rew)
   613 
   625 
   614       val unsk_and_rewrite = SMTLIB_Isar.unskolemize_names ctxt o subproof_rewriter
   626       val unsk_and_rewrite = SMTLIB_Isar.unskolemize_names ctxt o subproof_rewriter
   644 
   656 
   645       (* fix step *)
   657       (* fix step *)
   646       val bound_t = bounds
   658       val bound_t = bounds
   647         |> map (fn s => (s, the (find_type_in_formula concl s)))
   659         |> map (fn s => (s, the (find_type_in_formula concl s)))
   648 
   660 
   649       val skolem_defs = (if is_skolemisation rule
   661       val skolem_defs = (if is_skolemization rule
   650          then map (fn id => id ^ veriT_def) (skolems_introduced_by_rule args) else [])
   662          then map (fn id => id ^ veriT_def) (skolems_introduced_by_rule args) else [])
   651       val skolems_of_subproof = (if is_skolemisation rule
   663       val skolems_of_subproof = (if is_skolemization rule
   652          then flat (map collect_skolem_defs subproof) else [])
   664          then flat (map collect_skolem_defs subproof) else [])
   653       val fixed_prems =
   665       val fixed_prems =
   654         prems @ (if is_assm_repetition id rule then [id] else []) @
   666         prems @ (if is_assm_repetition id rule then [id] else []) @
   655         skolem_defs @ skolems_of_subproof @ (id_of_last_step fixed_subproof)
   667         skolem_defs @ skolems_of_subproof @ (id_of_last_step fixed_subproof)
   656 
   668 
   673    end
   685    end
   674 
   686 
   675 
   687 
   676 val linearize_proof =
   688 val linearize_proof =
   677   let
   689   let
       
   690     fun map_node_concl f (VeriT_Node {id, rule, prems, proof_ctxt, concl}) =
       
   691        mk_node id rule prems proof_ctxt (f concl)
   678     fun linearize (VeriT_Replay_Node {id = id, rule = rule, args = _, prems = prems,
   692     fun linearize (VeriT_Replay_Node {id = id, rule = rule, args = _, prems = prems,
   679         proof_ctxt = proof_ctxt, concl = concl, bounds = bounds, insts = _, declarations = _,
   693         proof_ctxt = proof_ctxt, concl = concl, bounds = bounds, insts = _, declarations = _,
   680         subproof = (_, _, _, subproof)}) =
   694         subproof = (bounds', assms, inputs, subproof)}) =
   681       let
   695       let
       
   696         val bounds = distinct (op =) bounds
       
   697         val bounds' = distinct (op =) bounds'
   682         fun mk_prop_of_term concl =
   698         fun mk_prop_of_term concl =
   683           concl |> fastype_of concl = \<^typ>\<open>bool\<close> ? curry (op $) \<^term>\<open>Trueprop\<close>
   699           concl |> fastype_of concl = \<^typ>\<open>bool\<close> ? curry (op $) \<^term>\<open>Trueprop\<close>
   684         fun remove_assumption_id assumption_id prems =
   700         fun remove_assumption_id assumption_id prems =
   685           filter_out (curry (op =) assumption_id) prems
   701           filter_out (curry (op =) assumption_id) prems
       
   702         fun add_assumption assumption concl =
       
   703           \<^const>\<open>Pure.imp\<close> $ mk_prop_of_term assumption $ mk_prop_of_term concl
   686         fun inline_assumption assumption assumption_id
   704         fun inline_assumption assumption assumption_id
   687             (VeriT_Node {id, rule, prems, proof_ctxt, concl, bounds}) =
   705             (VeriT_Node {id, rule, prems, proof_ctxt, concl}) =
   688           mk_node id rule (remove_assumption_id assumption_id prems) proof_ctxt
   706           mk_node id rule (remove_assumption_id assumption_id prems) proof_ctxt
   689             (\<^const>\<open>Pure.imp\<close> $ mk_prop_of_term assumption $ mk_prop_of_term concl) bounds
   707             (add_assumption assumption concl)
   690         fun find_input_steps_and_inline [] = []
   708         fun find_input_steps_and_inline [] = []
   691           | find_input_steps_and_inline
   709           | find_input_steps_and_inline
   692               (VeriT_Node {id = id', rule, prems, concl, bounds, ...} :: steps) =
   710               (VeriT_Node {id = id', rule, prems, concl, ...} :: steps) =
   693             if rule = input_rule then
   711             if rule = input_rule then
   694               find_input_steps_and_inline (map (inline_assumption concl id') steps)
   712               find_input_steps_and_inline (map (inline_assumption concl id') steps)
   695             else
   713             else
   696               mk_node (id') rule prems [] concl bounds :: find_input_steps_and_inline steps
   714               mk_node (id') rule prems [] concl :: find_input_steps_and_inline steps
   697 
   715 
   698         val subproof = flat (map linearize subproof)
   716         fun free_bounds bounds (concl) =
   699         val subproof' = find_input_steps_and_inline subproof
   717           fold (fn (var, typ) => fn t => Logic.all (Free (var, typ)) t) bounds concl
       
   718         val subproof = subproof
       
   719           |> flat o map linearize
       
   720           |> map (map_node_concl (fold add_assumption (assms @ inputs)))
       
   721           |> map (map_node_concl (free_bounds (bounds @ bounds')))
       
   722           |> find_input_steps_and_inline
       
   723         val concl = free_bounds bounds concl
   700       in
   724       in
   701         subproof' @ [mk_node id rule prems proof_ctxt concl (map fst bounds)]
   725         subproof @ [mk_node id rule prems proof_ctxt concl]
   702       end
   726       end
   703   in linearize end
   727   in linearize end
       
   728 
       
   729 fun rule_of (VeriT_Replay_Node {rule,...}) = rule
       
   730 fun subproof_of (VeriT_Replay_Node {subproof = (_, _, _, subproof),...}) = subproof
       
   731 
       
   732 
       
   733 (* Massage Skolems for Sledgehammer.
       
   734 
       
   735 We have to make sure that there is an "arrow" in the graph for skolemization steps.
       
   736 
       
   737 
       
   738 A. The normal easy case
       
   739 
       
   740 This function detects the steps of the form
       
   741   P \<longleftrightarrow> Q :skolemization
       
   742   Q       :resolution with P
       
   743 and replace them by
       
   744   Q       :skolemization
       
   745 Throwing away the step "P \<longleftrightarrow> Q" completely. This throws away a lot of information, but it does not
       
   746 matter too much for Sledgehammer.
       
   747 
       
   748 
       
   749 B. Skolems in subproofs
       
   750 Supporting this is more or less hopeless as long as the Isar reconstruction of Sledgehammer
       
   751 does not support more features like definitions. veriT is able to generate proofs with skolemization
       
   752 happening in subproofs inside the formula. 
       
   753   (assume "A \<or> P"
       
   754    ...
       
   755    P \<longleftrightarrow> Q :skolemization in the subproof
       
   756    ...)
       
   757   hence A \<or> P \<longrightarrow> A \<or> Q :lemma
       
   758   ...
       
   759   R :something with some rule
       
   760 and replace them by
       
   761   R :skolemization with some rule
       
   762 Without any subproof
       
   763 *)
       
   764 fun remove_skolem_definitions_proof steps =
       
   765   let
       
   766     fun replace_equivalent_by_imp (judgement $ ((Const(\<^const_name>\<open>HOL.eq\<close>, typ) $ arg1) $ arg2)) =
       
   767        judgement $ ((Const(\<^const_name>\<open>HOL.implies\<close>, typ) $ arg1) $ arg2)
       
   768      | replace_equivalent_by_imp a = a (*This case is probably wrong*)
       
   769     fun remove_skolem_definitions (VeriT_Replay_Node {id = id, rule = rule, args = args,
       
   770          prems = prems,
       
   771         proof_ctxt = proof_ctxt, concl = concl, bounds = bounds, insts = insts,
       
   772         declarations = declarations,
       
   773         subproof = (vars, assms', extra_assms', subproof)}) (prems_to_remove, skolems) =
       
   774     let
       
   775       val prems = prems
       
   776         |> filter_out (member (op =) prems_to_remove)
       
   777       val trivial_step = is_SH_trivial rule
       
   778       fun has_skolem_substep st NONE = if is_skolemization (rule_of st) then SOME (rule_of st)
       
   779              else fold has_skolem_substep (subproof_of st) NONE
       
   780         | has_skolem_substep _ a = a
       
   781       val promote_to_skolem = exists (fn t => member (op =) skolems t) prems
       
   782       val promote_from_assms = fold has_skolem_substep subproof NONE <> NONE
       
   783       val promote_step = promote_to_skolem orelse promote_from_assms
       
   784       val skolem_step_to_skip = is_skolemization rule orelse 
       
   785         (promote_from_assms andalso length prems > 1)
       
   786       val is_skolem = is_skolemization rule orelse promote_step
       
   787       val prems = prems
       
   788         |> filter_out (fn t => member (op =) skolems t)
       
   789         |> is_skolem ? filter_out (String.isPrefix id)
       
   790       val rule = (if promote_step then default_skolem_rule else rule)
       
   791       val subproof = subproof
       
   792         |> (is_skolem ? K []) (*subproofs of skolemization steps are useless for SH*)
       
   793         |> map (fst o (fn st => remove_skolem_definitions st (prems_to_remove, skolems)))
       
   794              (*no new definitions in subproofs*)
       
   795         |> flat
       
   796       val concl = concl
       
   797         |> is_skolem ? replace_equivalent_by_imp
       
   798       val step = (if skolem_step_to_skip orelse rule = veriT_def orelse trivial_step then []
       
   799         else mk_replay_node id rule args prems proof_ctxt concl bounds insts declarations
       
   800             (vars, assms', extra_assms', subproof)
       
   801           |> single)
       
   802       val defs = (if rule = veriT_def orelse trivial_step then id :: prems_to_remove
       
   803          else prems_to_remove)
       
   804       val skolems = (if skolem_step_to_skip then id :: skolems else skolems)
       
   805     in
       
   806       (step, (defs, skolems))
       
   807     end
       
   808   in
       
   809     fold_map remove_skolem_definitions steps ([], [])
       
   810     |> fst
       
   811     |> flat
       
   812   end
   704 
   813 
   705 local
   814 local
   706   fun import_proof_and_post_process typs funs lines ctxt =
   815   fun import_proof_and_post_process typs funs lines ctxt =
   707     let
   816     let
   708       val compress = SMT_Config.compress_verit_proofs ctxt
   817       val compress = SMT_Config.compress_verit_proofs ctxt
   717       fun process step (cx, cx') =
   826       fun process step (cx, cx') =
   718         let fun postprocess step (cx, cx') =
   827         let fun postprocess step (cx, cx') =
   719           let val (step, cx) = postprocess_proof compress ctxt step cx
   828           let val (step, cx) = postprocess_proof compress ctxt step cx
   720           in (step, (cx, cx')) end
   829           in (step, (cx, cx')) end
   721         in uncurry (fold_map postprocess) (preprocess compress step (cx, cx')) end
   830         in uncurry (fold_map postprocess) (preprocess compress step (cx, cx')) end
   722        val step =
   831       val step =
   723         (empty_context ctxt typs funs, [])
   832         (empty_context ctxt typs funs, [])
   724         |> fold_map process raw_steps
   833         |> fold_map process raw_steps
   725         |> (fn (steps, (cx, _)) => (flat steps, cx))
   834         |> (fn (steps, (cx, _)) => (flat steps, cx))
   726     in step end
   835     in step end
   727 in
   836 in
   728 
   837 
   729 fun parse typs funs lines ctxt =
   838 fun parse typs funs lines ctxt =
   730   let
   839   let
   731     val (u, env) = import_proof_and_post_process typs funs lines ctxt
   840     val (u, env) = import_proof_and_post_process typs funs lines ctxt
   732     val t = flat (map linearize_proof u)
   841     val t = u
   733     fun node_to_step (VeriT_Node {id, rule, prems, concl, bounds, ...}) =
   842        |> remove_skolem_definitions_proof
   734       mk_step id rule prems [] concl bounds
   843        |> flat o (map linearize_proof)
       
   844     fun node_to_step (VeriT_Node {id, rule, prems, concl, ...}) =
       
   845       mk_step id rule prems [] concl []
   735   in
   846   in
   736     (map node_to_step t, ctxt_of env)
   847     (map node_to_step t, ctxt_of env)
   737   end
   848   end
   738 
   849 
   739 fun parse_replay typs funs lines ctxt =
   850 fun parse_replay typs funs lines ctxt =