| author | haftmann |
| Mon, 16 Nov 2009 10:16:40 +0100 | |
| changeset 33708 | b45d3b8cc74e |
| parent 33662 | 7be6ee4ee67f |
| child 33710 | ffc5176a9105 |
| permissions | -rw-r--r-- |
| 33419 | 1 |
(* Title: HOL/Boogie/Tools/boogie_split.ML |
2 |
Author: Sascha Boehme, TU Muenchen |
|
3 |
||
4 |
Method to split Boogie-generate verification conditions and pass the splinters |
|
5 |
to user-supplied automated sub-tactics. |
|
6 |
*) |
|
7 |
||
8 |
signature BOOGIE_SPLIT = |
|
9 |
sig |
|
10 |
val add_sub_tactic: string * (Proof.context -> int -> tactic) -> theory -> |
|
11 |
theory |
|
12 |
val sub_tactic_names: theory -> string list |
|
13 |
val setup: theory -> theory |
|
14 |
end |
|
15 |
||
16 |
structure Boogie_Split: BOOGIE_SPLIT = |
|
17 |
struct |
|
18 |
||
19 |
(* sub-tactics store *) |
|
20 |
||
| 33522 | 21 |
structure Sub_Tactics = Theory_Data |
| 33419 | 22 |
( |
23 |
type T = (Proof.context -> int -> tactic) Symtab.table |
|
24 |
val empty = Symtab.empty |
|
25 |
val extend = I |
|
| 33522 | 26 |
fun merge data = Symtab.merge (K true) data |
| 33419 | 27 |
) |
28 |
||
29 |
fun add_sub_tactic tac = Sub_Tactics.map (Symtab.update_new tac) |
|
30 |
||
31 |
val sub_tactic_names = Symtab.keys o Sub_Tactics.get |
|
32 |
||
33 |
fun lookup_sub_tactic ctxt name = |
|
34 |
(case Symtab.lookup (Sub_Tactics.get (ProofContext.theory_of ctxt)) name of |
|
35 |
SOME tac => SOME (name, tac) |
|
36 |
| NONE => (warning ("Unknown sub-tactic: " ^ quote name); NONE))
|
|
37 |
||
38 |
fun as_meta_eq eq = eq RS @{thm eq_reflection}
|
|
39 |
||
40 |
fun full_implies_conv cv ct = |
|
41 |
(case try Thm.dest_implies ct of |
|
42 |
NONE => cv ct |
|
43 |
| SOME (cp, cc) => Drule.imp_cong_rule (cv cp) (full_implies_conv cv cc)) |
|
44 |
||
45 |
fun sub_tactics_tac ctxt (verbose, sub_tac_names) case_name = |
|
46 |
let |
|
47 |
fun trace msg = if verbose then tracing msg else () |
|
48 |
fun trying name = trace ("Trying tactic " ^ quote name ^ " on case " ^
|
|
49 |
quote case_name ^ " ...") |
|
50 |
fun solved () = trace ("Case solved: " ^ quote case_name)
|
|
51 |
fun failed () = trace ("Case remains unsolved: " ^ quote case_name)
|
|
52 |
||
53 |
infix IF_UNSOLVED |
|
54 |
fun (tac1 IF_UNSOLVED tac2) i st = st |> (tac1 i THEN (fn st' => |
|
|
33424
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
55 |
let val j = i + Thm.nprems_of st' - Thm.nprems_of st |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
56 |
in |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
57 |
if i > j then (solved (); Tactical.all_tac st') |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
58 |
else Seq.INTERVAL tac2 i j st' |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
59 |
end)) |
| 33419 | 60 |
|
61 |
fun TRY_ALL [] _ st = (failed (); Tactical.no_tac st) |
|
62 |
| TRY_ALL ((name, tac) :: tacs) i st = (trying name; |
|
63 |
(TRY o tac ctxt IF_UNSOLVED TRY_ALL tacs) i st) |
|
64 |
||
65 |
val unfold_labels = Conv.try_conv (Conv.arg_conv |
|
66 |
(More_Conv.rewrs_conv (map as_meta_eq @{thms labels})))
|
|
67 |
in |
|
68 |
CONVERSION (full_implies_conv unfold_labels) |
|
69 |
THEN' TRY_ALL (map_filter (lookup_sub_tactic ctxt) sub_tac_names) |
|
70 |
end |
|
71 |
||
72 |
||
|
33424
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
73 |
(* case names *) |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
74 |
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
75 |
fun case_name_of t = |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
76 |
(case HOLogic.dest_Trueprop (Logic.strip_imp_concl t) of |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
77 |
@{term assert_at} $ Free (n, _) $ _ => n
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
78 |
| _ => raise TERM ("case_name_of", [t]))
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
79 |
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
80 |
local |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
81 |
fun make_case_name (i, t) = |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
82 |
the_default ("B_" ^ string_of_int (i + 1)) (try case_name_of t)
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
83 |
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
84 |
val assert_intro = Thm.symmetric (as_meta_eq @{thm assert_at_def})
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
85 |
val l = Thm.dest_arg1 (Thm.rhs_of assert_intro) |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
86 |
fun intro new = |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
87 |
Conv.rewr_conv (Thm.instantiate ([], [(l, new)]) assert_intro) |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
88 |
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
89 |
val assert_eq = @{lemma "assert_at x t == assert_at y t"
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
90 |
by (simp add: assert_at_def)} |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
91 |
val (x, y) = pairself Thm.dest_arg1 (Thm.dest_binop (Thm.cprop_of assert_eq)) |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
92 |
fun rename old new = |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
93 |
Conv.rewr_conv (Thm.instantiate ([], [(x, old), (y, new)]) assert_eq) |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
94 |
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
95 |
fun at_concl cv = Conv.concl_conv ~1 (Conv.arg_conv cv) |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
96 |
fun make_label thy name = Thm.cterm_of thy (Free (name, @{typ bool}))
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
97 |
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
98 |
fun rename_case thy new ct = |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
99 |
(case try case_name_of (Thm.term_of ct) of |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
100 |
NONE => at_concl (intro (make_label thy new)) |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
101 |
| SOME old => if new = old then Conv.all_conv |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
102 |
else at_concl (rename (make_label thy old) (make_label thy new))) ct |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
103 |
in |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
104 |
fun unique_case_names thy st = |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
105 |
let |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
106 |
val names = map_index make_case_name (Thm.prems_of st) |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
107 |
|> ` (duplicates (op =)) |-> Name.variant_list |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
108 |
in ALLGOALS (fn i => CONVERSION (rename_case thy (nth names (i-1))) i) st end |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
109 |
end |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
110 |
|
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
111 |
|
| 33419 | 112 |
(* splitting method *) |
113 |
||
114 |
local |
|
115 |
val split_rules = [@{thm impI}, @{thm conjI}, @{thm TrueI}]
|
|
116 |
||
| 33662 | 117 |
fun ALL_GOALS false tac = ALLGOALS tac |
118 |
| ALL_GOALS true tac = PARALLEL_GOALS (HEADGOAL tac) |
|
119 |
||
120 |
fun prep_tac ctxt ((parallel, verbose), subs) facts = |
|
|
33424
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
121 |
HEADGOAL (Method.insert_tac facts) |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
122 |
THEN HEADGOAL (REPEAT_ALL_NEW (Tactic.resolve_tac split_rules)) |
|
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
123 |
THEN unique_case_names (ProofContext.theory_of ctxt) |
| 33662 | 124 |
THEN ALL_GOALS parallel (SUBGOAL (fn (t, i) => |
125 |
TRY (sub_tactics_tac ctxt (verbose, subs) (case_name_of t) i))) |
|
| 33419 | 126 |
|
127 |
val drop_assert_at = Conv.concl_conv ~1 (Conv.try_conv (Conv.arg_conv |
|
128 |
(Conv.rewr_conv (as_meta_eq @{thm assert_at_def}))))
|
|
129 |
||
130 |
fun split_vc args ctxt = METHOD_CASES (fn facts => |
|
|
33424
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
131 |
prep_tac ctxt args facts #> |
| 33419 | 132 |
Seq.maps (fn st => |
133 |
st |
|
134 |
|> ALLGOALS (CONVERSION drop_assert_at) |
|
|
33424
a3b002e2cd55
proper and unique case names for the split_vc method,
boehmes
parents:
33419
diff
changeset
|
135 |
|> Seq.map (pair (map (rpair [] o case_name_of) (Thm.prems_of st)))) #> |
| 33419 | 136 |
Seq.maps (fn (names, st) => |
137 |
CASES |
|
138 |
(Rule_Cases.make_common false |
|
139 |
(ProofContext.theory_of ctxt, Thm.prop_of st) names) |
|
140 |
Tactical.all_tac st)) |
|
141 |
||
| 33662 | 142 |
val options = |
143 |
Args.parens (Args.$$$ "verbose") >> K (false, true) || |
|
144 |
Args.parens (Args.$$$ "fast_verbose") >> K (true, true) |
|
| 33419 | 145 |
val sub_tactics = Args.$$$ "try" -- Args.colon |-- Scan.repeat1 Args.name |
146 |
in |
|
147 |
val setup_split_vc = Method.setup @{binding split_vc}
|
|
| 33662 | 148 |
(Scan.lift (Scan.optional options (true, false) -- |
149 |
Scan.optional sub_tactics []) >> split_vc) |
|
| 33419 | 150 |
("Splits a Boogie-generated verification conditions into smaller problems" ^
|
151 |
" and tries to solve the splinters with the supplied sub-tactics.") |
|
152 |
end |
|
153 |
||
154 |
||
155 |
(* predefined sub-tactics *) |
|
156 |
||
157 |
fun fast_sub_tac ctxt = Classical.fast_tac (Classical.claset_of ctxt) |
|
158 |
fun simp_sub_tac ctxt = |
|
159 |
Simplifier.asm_full_simp_tac (Simplifier.simpset_of ctxt) |
|
160 |
fun smt_sub_tac ctxt = SMT_Solver.smt_tac ctxt (Split_VC_SMT_Rules.get ctxt) |
|
161 |
||
162 |
||
163 |
(* setup *) |
|
164 |
||
165 |
val setup = |
|
166 |
setup_split_vc #> |
|
167 |
add_sub_tactic ("fast", fast_sub_tac) #>
|
|
168 |
add_sub_tactic ("simp", simp_sub_tac) #>
|
|
169 |
add_sub_tactic ("smt", smt_sub_tac)
|
|
170 |
||
171 |
end |