1 (* Title: HOL/Tools/ATP/atp_proof_redirect.ML
2 Author: Jasmin Blanchette, TU Muenchen
4 Transformation of a proof by contradiction into a direct proof.
10 val ord : key * key -> order
11 val string_of : key -> string
14 signature ATP_PROOF_REDIRECT =
18 structure Atom_Graph : GRAPH
20 type ref_sequent = atom list * atom
21 type refute_graph = unit Atom_Graph.T
23 type clause = atom list
24 type direct_sequent = atom list * clause
25 type direct_graph = unit Atom_Graph.T
27 type rich_sequent = clause list * clause
29 datatype direct_inference =
30 Have of rich_sequent |
31 Cases of (clause * direct_inference list) list
33 type direct_proof = direct_inference list
35 val make_refute_graph : (atom list * atom) list -> refute_graph
36 val axioms_of_refute_graph : refute_graph -> atom list -> atom list
37 val tainted_atoms_of_refute_graph : refute_graph -> atom list -> atom list
38 val sequents_of_refute_graph : refute_graph -> ref_sequent list
39 val string_of_refute_graph : refute_graph -> string
40 val redirect_sequent : atom list -> atom -> ref_sequent -> direct_sequent
41 val direct_graph : direct_sequent list -> direct_graph
43 atom list -> atom list -> atom -> refute_graph -> direct_proof
44 val succedent_of_cases : (clause * direct_inference list) list -> clause
45 val string_of_direct_proof : direct_proof -> string
48 functor ATP_Proof_Redirect(Atom : ATP_ATOM): ATP_PROOF_REDIRECT =
53 structure Atom_Graph = Graph(Atom)
55 type ref_sequent = atom list * atom
56 type refute_graph = unit Atom_Graph.T
58 type clause = atom list
59 type direct_sequent = atom list * clause
60 type direct_graph = unit Atom_Graph.T
62 type rich_sequent = clause list * clause
64 datatype direct_inference =
65 Have of rich_sequent |
66 Cases of (clause * direct_inference list) list
68 type direct_proof = direct_inference list
70 fun atom_eq p = (Atom.ord p = EQUAL)
71 fun clause_eq (c, d) = (length c = length d andalso forall atom_eq (c ~~ d))
72 fun direct_sequent_eq ((gamma, c), (delta, d)) =
73 clause_eq (gamma, delta) andalso clause_eq (c, d)
75 fun make_refute_graph infers =
77 fun add_edge to from =
78 Atom_Graph.default_node (from, ())
79 #> Atom_Graph.default_node (to, ())
80 #> Atom_Graph.add_edge_acyclic (from, to)
81 fun add_infer (froms, to) = fold (add_edge to) froms
82 in Atom_Graph.empty |> fold add_infer infers end
84 fun axioms_of_refute_graph refute_graph conjs =
85 subtract atom_eq conjs (Atom_Graph.minimals refute_graph)
87 fun tainted_atoms_of_refute_graph refute_graph =
88 Atom_Graph.all_succs refute_graph
90 fun sequents_of_refute_graph refute_graph =
91 map (`(Atom_Graph.immediate_preds refute_graph))
92 (filter_out (Atom_Graph.is_minimal refute_graph)
93 (Atom_Graph.keys refute_graph))
95 val string_of_context = map Atom.string_of #> space_implode ", "
97 fun string_of_sequent (gamma, c) =
98 string_of_context gamma ^ " \<turnstile> " ^ Atom.string_of c
100 val string_of_refute_graph =
101 sequents_of_refute_graph #> map string_of_sequent #> cat_lines
103 fun redirect_sequent tainted bot (gamma, c) =
104 if member atom_eq tainted c then
105 gamma |> List.partition (not o member atom_eq tainted)
106 |>> not (atom_eq (c, bot)) ? cons c
110 fun direct_graph seqs =
112 fun add_edge from to =
113 Atom_Graph.default_node (from, ())
114 #> Atom_Graph.default_node (to, ())
115 #> Atom_Graph.add_edge_acyclic (from, to)
116 fun add_seq (gamma, c) = fold (fn l => fold (add_edge l) c) gamma
117 in Atom_Graph.empty |> fold add_seq seqs end
119 fun disj cs = fold (union atom_eq) cs [] |> sort Atom.ord
121 fun succedent_of_inference (Have (_, c)) = c
122 | succedent_of_inference (Cases cases) = succedent_of_cases cases
123 and succedent_of_case (c, []) = c
124 | succedent_of_case (_, infs) = succedent_of_inference (List.last infs)
125 and succedent_of_cases cases = disj (map succedent_of_case cases)
127 fun dest_Have (Have z) = z
128 | dest_Have _ = raise Fail "non-Have"
130 fun enrich_Have nontrivs trivs (cs, c) =
131 (cs |> map (fn c => if member clause_eq nontrivs c then disj (c :: trivs)
137 case cases |> List.partition (null o snd) of
138 (trivs, nontrivs as [(nontriv0, proof)]) =>
139 if forall (can dest_Have) proof then
140 let val seqs = proof |> map dest_Have in
141 seqs |> map (enrich_Have (nontriv0 :: map snd seqs) (map fst trivs))
145 | (_, nontrivs) => [Cases nontrivs]
147 fun descendants direct_graph =
148 these o try (Atom_Graph.all_succs direct_graph) o single
150 fun zones_of 0 _ = []
151 | zones_of n (bs :: bss) =
152 (fold (subtract atom_eq) bss) bs :: zones_of (n - 1) (bss @ [bs])
154 fun redirect_graph axioms tainted bot refute_graph =
157 map (redirect_sequent tainted bot) (sequents_of_refute_graph refute_graph)
158 val direct_graph = direct_graph seqs
159 fun redirect c proved seqs =
162 else if length c < 2 then
164 val proved = c @ proved
166 filter (fn (gamma, _) => subset atom_eq (gamma, proved)) seqs
167 val horn_provable = filter (fn (_, [_]) => true | _ => false) provable
168 val seq as (gamma, c) =
169 case horn_provable @ provable of
170 [] => raise Fail "ill-formed refutation graph"
173 Have (map single gamma, c) ::
174 redirect c proved (filter (curry (not o direct_sequent_eq) seq) seqs)
178 fun subsequents seqs zone =
179 filter (fn (gamma, _) => subset atom_eq (gamma, zone @ proved)) seqs
180 val zones = zones_of (length c) (map (descendants direct_graph) c)
181 val subseqss = map (subsequents seqs) zones
182 val seqs = fold (subtract direct_sequent_eq) subseqss seqs
184 map2 (fn l => fn subseqs => ([l], redirect [l] proved subseqs))
186 in s_cases cases @ redirect (succedent_of_cases cases) proved seqs end
187 in redirect [] axioms seqs end
190 | indent n = " " ^ indent (n - 1)
192 fun string_of_clause [] = "\<bottom>"
193 | string_of_clause ls = space_implode " \<or> " (map Atom.string_of ls)
195 fun string_of_rich_sequent ch ([], c) = ch ^ " " ^ string_of_clause c
196 | string_of_rich_sequent ch (cs, c) =
197 commas (map string_of_clause cs) ^ " " ^ ch ^ " " ^ string_of_clause c
199 fun string_of_case depth (c, proof) =
200 indent (depth + 1) ^ "[" ^ string_of_clause c ^ "]"
201 |> not (null proof) ? suffix ("\n" ^ string_of_subproof (depth + 1) proof)
203 and string_of_inference depth (Have seq) =
204 indent depth ^ string_of_rich_sequent "\<triangleright>" seq
205 | string_of_inference depth (Cases cases) =
206 indent depth ^ "[\n" ^
207 space_implode ("\n" ^ indent depth ^ "|\n")
208 (map (string_of_case depth) cases) ^ "\n" ^
211 and string_of_subproof depth = cat_lines o map (string_of_inference depth)
213 val string_of_direct_proof = string_of_subproof 0