author | krauss |
Fri, 20 Apr 2007 10:06:11 +0200 | |
changeset 22733 | 0b14bb35be90 |
parent 22325 | be61bd159a99 |
child 22997 | d4f3b015b50b |
permissions | -rw-r--r-- |
21131 | 1 |
(* Title: HOL/Tools/function_package/lexicographic_order.ML |
21201 | 2 |
ID: $Id$ |
21131 | 3 |
Author: Lukas Bulwahn, TU Muenchen |
4 |
||
5 |
Method for termination proofs with lexicographic orderings. |
|
6 |
*) |
|
7 |
||
8 |
signature LEXICOGRAPHIC_ORDER = |
|
9 |
sig |
|
21319
cf814e36f788
replaced "auto_term" by the simpler method "relation", which does not try
krauss
parents:
21237
diff
changeset
|
10 |
val lexicographic_order : Proof.context -> Method.method |
21510
7e72185e4b24
exported mk_base_funs for use by size-change tools
krauss
parents:
21319
diff
changeset
|
11 |
|
7e72185e4b24
exported mk_base_funs for use by size-change tools
krauss
parents:
21319
diff
changeset
|
12 |
(* exported for use by size-change termination prototype. |
7e72185e4b24
exported mk_base_funs for use by size-change tools
krauss
parents:
21319
diff
changeset
|
13 |
FIXME: provide a common interface later *) |
7e72185e4b24
exported mk_base_funs for use by size-change tools
krauss
parents:
21319
diff
changeset
|
14 |
val mk_base_funs : typ -> term list |
22309 | 15 |
(* exported for debugging *) |
21237 | 16 |
val setup: theory -> theory |
21131 | 17 |
end |
18 |
||
19 |
structure LexicographicOrder : LEXICOGRAPHIC_ORDER = |
|
20 |
struct |
|
21 |
||
22 |
(* Theory dependencies *) |
|
23 |
val measures = "List.measures" |
|
24 |
val wf_measures = thm "wf_measures" |
|
25 |
val measures_less = thm "measures_less" |
|
26 |
val measures_lesseq = thm "measures_lesseq" |
|
21237 | 27 |
|
21131 | 28 |
fun del_index (n, []) = [] |
29 |
| del_index (n, x :: xs) = |
|
21237 | 30 |
if n>0 then x :: del_index (n - 1, xs) else xs |
21131 | 31 |
|
32 |
fun transpose ([]::_) = [] |
|
33 |
| transpose xss = map hd xss :: transpose (map tl xss) |
|
34 |
||
35 |
fun mk_sum_case (f1, f2) = |
|
36 |
case (fastype_of f1, fastype_of f2) of |
|
21237 | 37 |
(Type("fun", [A, B]), Type("fun", [C, D])) => |
38 |
if (B = D) then |
|
39 |
Const("Datatype.sum.sum_case", (A --> B) --> (C --> D) --> Type("+", [A,C]) --> B) $ f1 $ f2 |
|
40 |
else raise TERM ("mk_sum_case: range type mismatch", [f1, f2]) |
|
41 |
| _ => raise TERM ("mk_sum_case", [f1, f2]) |
|
42 |
||
21131 | 43 |
fun dest_wf (Const ("Wellfounded_Recursion.wf", _) $ t) = t |
44 |
| dest_wf t = raise TERM ("dest_wf", [t]) |
|
21237 | 45 |
|
21131 | 46 |
datatype cell = Less of thm | LessEq of thm | None of thm | False of thm; |
21237 | 47 |
|
21131 | 48 |
fun is_Less cell = case cell of (Less _) => true | _ => false |
21237 | 49 |
|
21131 | 50 |
fun is_LessEq cell = case cell of (LessEq _) => true | _ => false |
21237 | 51 |
|
21131 | 52 |
fun thm_of_cell cell = |
53 |
case cell of |
|
21237 | 54 |
Less thm => thm |
55 |
| LessEq thm => thm |
|
56 |
| False thm => thm |
|
57 |
| None thm => thm |
|
58 |
||
21131 | 59 |
fun mk_base_fun_bodys (t : term) (tt : typ) = |
60 |
case tt of |
|
21237 | 61 |
Type("*", [ft, st]) => (mk_base_fun_bodys (Const("fst", tt --> ft) $ t) ft) @ (mk_base_fun_bodys (Const("snd", tt --> st) $ t) st) |
62 |
| _ => [(t, tt)] |
|
63 |
||
21131 | 64 |
fun mk_base_fun_header fulltyp (t, typ) = |
21816
453fd9857b4c
nat type now has a size functin => no longer needed as special case
krauss
parents:
21757
diff
changeset
|
65 |
Abs ("x", fulltyp, Const("Nat.size", typ --> HOLogic.natT) $ t) |
21237 | 66 |
|
21131 | 67 |
fun mk_base_funs (tt: typ) = |
68 |
mk_base_fun_bodys (Bound 0) tt |> |
|
21237 | 69 |
map (mk_base_fun_header tt) |
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
70 |
|
22309 | 71 |
fun mk_funorder_funs (tt : typ) (one : bool) : Term.term list = |
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
72 |
case tt of |
22309 | 73 |
Type("+", [ft, st]) => let |
74 |
val ft_funs = mk_funorder_funs ft |
|
75 |
val st_funs = mk_funorder_funs st |
|
76 |
in |
|
77 |
(if one then |
|
78 |
(product (ft_funs true) (st_funs false)) @ (product (ft_funs false) (st_funs true)) |
|
79 |
else |
|
80 |
product (ft_funs false) (st_funs false)) |
|
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
81 |
|> map mk_sum_case |
22309 | 82 |
end |
83 |
| _ => if one then [Abs ("x", tt, HOLogic.Suc_zero)] else [Abs ("x", tt, HOLogic.zero)] |
|
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
84 |
|
21131 | 85 |
fun mk_ext_base_funs (tt : typ) = |
86 |
case tt of |
|
21237 | 87 |
Type("+", [ft, st]) => |
88 |
product (mk_ext_base_funs ft) (mk_ext_base_funs st) |
|
89 |
|> map mk_sum_case |
|
90 |
| _ => mk_base_funs tt |
|
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
91 |
|
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
92 |
fun mk_all_measure_funs (tt : typ) = |
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
93 |
case tt of |
22309 | 94 |
Type("+", _) => (mk_ext_base_funs tt) @ (mk_funorder_funs tt true) |
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
95 |
| _ => mk_base_funs tt |
21237 | 96 |
|
21131 | 97 |
fun dest_term (t : term) = |
98 |
let |
|
21237 | 99 |
val (vars, prop) = (FundefLib.dest_all_all t) |
100 |
val prems = Logic.strip_imp_prems prop |
|
101 |
val (tuple, rel) = Logic.strip_imp_concl prop |
|
102 |
|> HOLogic.dest_Trueprop |
|
103 |
|> HOLogic.dest_mem |
|
104 |
val (lhs, rhs) = HOLogic.dest_prod tuple |
|
21131 | 105 |
in |
21237 | 106 |
(vars, prems, lhs, rhs, rel) |
21131 | 107 |
end |
21237 | 108 |
|
21131 | 109 |
fun mk_goal (vars, prems, lhs, rhs) rel = |
110 |
let |
|
21237 | 111 |
val concl = HOLogic.mk_binrel rel (lhs, rhs) |> HOLogic.mk_Trueprop |
112 |
in |
|
113 |
Logic.list_implies (prems, concl) |> |
|
114 |
fold_rev FundefLib.mk_forall vars |
|
21131 | 115 |
end |
21237 | 116 |
|
21131 | 117 |
fun prove (thy: theory) (t: term) = |
118 |
cterm_of thy t |> Goal.init |
|
119 |
|> SINGLE (CLASIMPSET auto_tac) |> the |
|
21237 | 120 |
|
21131 | 121 |
fun mk_cell (thy : theory) (vars, prems) (lhs, rhs) = |
21237 | 122 |
let |
123 |
val goals = mk_goal (vars, prems, lhs, rhs) |
|
124 |
val less_thm = goals "Orderings.less" |> prove thy |
|
21131 | 125 |
in |
21237 | 126 |
if Thm.no_prems less_thm then |
127 |
Less (Goal.finish less_thm) |
|
128 |
else |
|
129 |
let |
|
130 |
val lesseq_thm = goals "Orderings.less_eq" |> prove thy |
|
131 |
in |
|
132 |
if Thm.no_prems lesseq_thm then |
|
133 |
LessEq (Goal.finish lesseq_thm) |
|
134 |
else |
|
135 |
if prems_of lesseq_thm = [HOLogic.Trueprop $ HOLogic.false_const] then False lesseq_thm |
|
136 |
else None lesseq_thm |
|
137 |
end |
|
21131 | 138 |
end |
21237 | 139 |
|
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
140 |
fun mk_row (thy: theory) measure_funs (t : term) = |
21131 | 141 |
let |
21237 | 142 |
val (vars, prems, lhs, rhs, _) = dest_term t |
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
143 |
val lhs_list = map (fn x => x $ lhs) measure_funs |
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
144 |
val rhs_list = map (fn x => x $ rhs) measure_funs |
21131 | 145 |
in |
21237 | 146 |
map (mk_cell thy (vars, prems)) (lhs_list ~~ rhs_list) |
21131 | 147 |
end |
22309 | 148 |
|
149 |
fun pr_cell cell = case cell of Less _ => " < " |
|
150 |
| LessEq _ => " <= " |
|
151 |
| None _ => " N " |
|
152 |
| False _ => " F " |
|
153 |
||
154 |
fun pr_table table = writeln (cat_lines (map (fn r => concat (map pr_cell r)) table)) |
|
155 |
||
156 |
fun check_col ls = (forall (fn c => is_Less c orelse is_LessEq c) ls) andalso not (forall (fn c => is_LessEq c) ls) |
|
157 |
||
158 |
fun transform_table table col = table |> filter_out (fn x => is_Less (nth x col)) |> map (curry del_index col) |
|
159 |
||
160 |
fun transform_order col order = map (fn x => if x>=col then x+1 else x) order |
|
21237 | 161 |
|
21131 | 162 |
(* simple depth-first search algorithm for the table *) |
163 |
fun search_table table = |
|
164 |
case table of |
|
21237 | 165 |
[] => SOME [] |
166 |
| _ => |
|
167 |
let |
|
168 |
val col = find_index (check_col) (transpose table) |
|
169 |
in case col of |
|
170 |
~1 => NONE |
|
171 |
| _ => |
|
172 |
let |
|
22309 | 173 |
val order_opt = (table, col) |-> transform_table |> search_table |
21237 | 174 |
in case order_opt of |
175 |
NONE => NONE |
|
176 |
| SOME order =>SOME (col::(transform_order col order)) |
|
177 |
end |
|
178 |
end |
|
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
179 |
|
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
180 |
(* find all positions of elements in a list *) |
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
181 |
fun find_index_list pred = |
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
182 |
let fun find _ [] = [] |
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
183 |
| find n (x :: xs) = if pred x then n::(find (n + 1) xs) else find (n + 1) xs; |
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
184 |
in find 0 end; |
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
185 |
|
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
186 |
(* simple breadth-first search algorithm for the table *) |
22309 | 187 |
fun bfs_search_table nodes = |
188 |
case nodes of |
|
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
189 |
[] => sys_error "INTERNAL ERROR IN lexicographic order termination tactic - fun search_table (breadth search finished)" |
22309 | 190 |
| (node::rnodes) => let |
191 |
val (order, table) = node |
|
192 |
in |
|
193 |
case table of |
|
194 |
[] => SOME (foldr (fn (c, order) => c::transform_order c order) [] (rev order)) |
|
195 |
| _ => let |
|
196 |
val cols = find_index_list (check_col) (transpose table) |
|
197 |
in |
|
198 |
case cols of |
|
199 |
[] => NONE |
|
200 |
| _ => let |
|
201 |
val newtables = map (transform_table table) cols |
|
202 |
val neworders = map (fn c => c::order) cols |
|
203 |
val newnodes = neworders ~~ newtables |
|
204 |
in |
|
205 |
bfs_search_table (rnodes @ newnodes) |
|
206 |
end |
|
207 |
end |
|
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
208 |
end |
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
209 |
|
22309 | 210 |
fun nsearch_table table = bfs_search_table [([], table)] |
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
211 |
|
21131 | 212 |
fun prove_row row (st : thm) = |
213 |
case row of |
|
21237 | 214 |
[] => sys_error "INTERNAL ERROR IN lexicographic order termination tactic - fun prove_row (row is empty)" |
215 |
| cell::tail => |
|
216 |
case cell of |
|
217 |
Less less_thm => |
|
218 |
let |
|
219 |
val next_thm = st |> SINGLE (rtac measures_less 1) |> the |
|
220 |
in |
|
221 |
implies_elim next_thm less_thm |
|
222 |
end |
|
223 |
| LessEq lesseq_thm => |
|
224 |
let |
|
225 |
val next_thm = st |> SINGLE (rtac measures_lesseq 1) |> the |
|
226 |
in |
|
227 |
implies_elim next_thm lesseq_thm |
|
228 |
|> prove_row tail |
|
229 |
end |
|
230 |
| _ => sys_error "INTERNAL ERROR IN lexicographic order termination tactic - fun prove_row (Only expecting Less or LessEq)" |
|
231 |
||
21131 | 232 |
fun pr_unprovable_subgoals table = |
233 |
filter (fn x => not (is_Less x) andalso not (is_LessEq x)) (flat table) |
|
21237 | 234 |
|> map ((fn th => Pretty.string_of (Pretty.chunks (Display.pretty_goals (Thm.nprems_of th) th))) o thm_of_cell) |
235 |
||
21131 | 236 |
fun pr_goal thy t i = |
237 |
let |
|
21237 | 238 |
val (_, prems, lhs, rhs, _) = dest_term t |
239 |
val prterm = string_of_cterm o (cterm_of thy) |
|
21131 | 240 |
in |
21237 | 241 |
(* also show prems? *) |
21131 | 242 |
i ^ ") " ^ (prterm lhs) ^ " '<' " ^ (prterm rhs) |
243 |
end |
|
21237 | 244 |
|
21131 | 245 |
fun pr_fun thy t i = |
246 |
(string_of_int i) ^ ") " ^ (string_of_cterm (cterm_of thy t)) |
|
21237 | 247 |
|
21131 | 248 |
(* fun pr_err: prints the table if tactic failed *) |
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
249 |
fun pr_err table thy tl measure_funs = |
21131 | 250 |
let |
21237 | 251 |
val gc = map (fn i => chr (i + 96)) (1 upto (length table)) |
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
252 |
val mc = 1 upto (length measure_funs) |
21237 | 253 |
val tstr = (" " ^ (concat (map (fn i => " " ^ (string_of_int i) ^ " ") mc))) :: |
254 |
(map2 (fn r => fn i => i ^ ": " ^ (concat (map pr_cell r))) table gc) |
|
255 |
val gstr = ("Goals:"::(map2 (pr_goal thy) tl gc)) |
|
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
256 |
val mstr = ("Measures:"::(map2 (pr_fun thy) measure_funs mc)) |
21237 | 257 |
val ustr = ("Unfinished subgoals:"::(pr_unprovable_subgoals table)) |
21131 | 258 |
in |
21237 | 259 |
tstr @ gstr @ mstr @ ustr |
21131 | 260 |
end |
21237 | 261 |
|
21131 | 262 |
(* the main function: create table, search table, create relation, |
22733
0b14bb35be90
definition lookup via terms, not names. Methods "relation" and "lexicographic_order"
krauss
parents:
22325
diff
changeset
|
263 |
and prove the subgoals *) |
21319
cf814e36f788
replaced "auto_term" by the simpler method "relation", which does not try
krauss
parents:
21237
diff
changeset
|
264 |
fun lexicographic_order_tac ctxt (st: thm) = |
21131 | 265 |
let |
21237 | 266 |
val thy = theory_of_thm st |
22733
0b14bb35be90
definition lookup via terms, not names. Methods "relation" and "lexicographic_order"
krauss
parents:
22325
diff
changeset
|
267 |
val premlist = prems_of st |
21131 | 268 |
in |
21237 | 269 |
case premlist of |
21131 | 270 |
[] => error "invalid number of subgoals for this tactic - expecting at least 1 subgoal" |
22325 | 271 |
| (wfR::tl) => let |
272 |
val trueprop $ (wf $ rel) = wfR |
|
21237 | 273 |
val crel = cterm_of thy rel |
22325 | 274 |
val (domT, _) = HOLogic.dest_prodT (HOLogic.dest_setT (fastype_of rel)) |
275 |
val measure_funs = mk_all_measure_funs domT |
|
21237 | 276 |
val _ = writeln "Creating table" |
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
277 |
val table = map (mk_row thy measure_funs) tl |
21237 | 278 |
val _ = writeln "Searching for lexicographic order" |
22309 | 279 |
(* val _ = pr_table table *) |
21237 | 280 |
val possible_order = search_table table |
281 |
in |
|
282 |
case possible_order of |
|
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
283 |
NONE => error (cat_lines ("Could not find lexicographic termination order:"::(pr_err table thy tl measure_funs))) |
21237 | 284 |
| SOME order => let |
285 |
val clean_table = map (fn x => map (nth x) order) table |
|
22258
0967b03844b5
changes in lexicographic_order termination tactic
bulwahn
parents:
21817
diff
changeset
|
286 |
val funs = map (nth measure_funs) order |
22325 | 287 |
val list = HOLogic.mk_list (domT --> HOLogic.natT) funs |
288 |
val relterm = Const(measures, (fastype_of list) --> (fastype_of rel)) $ list |
|
21237 | 289 |
val crelterm = cterm_of thy relterm |
290 |
val _ = writeln ("Instantiating R with " ^ (string_of_cterm crelterm)) |
|
291 |
val _ = writeln "Proving subgoals" |
|
292 |
in |
|
22733
0b14bb35be90
definition lookup via terms, not names. Methods "relation" and "lexicographic_order"
krauss
parents:
22325
diff
changeset
|
293 |
st |> cterm_instantiate [(crel, crelterm)] |
21237 | 294 |
|> SINGLE (rtac wf_measures 1) |> the |
295 |
|> fold prove_row clean_table |
|
296 |
|> Seq.single |
|
21131 | 297 |
end |
298 |
end |
|
299 |
end |
|
300 |
||
22733
0b14bb35be90
definition lookup via terms, not names. Methods "relation" and "lexicographic_order"
krauss
parents:
22325
diff
changeset
|
301 |
(* FIXME goal addressing ?? *) |
0b14bb35be90
definition lookup via terms, not names. Methods "relation" and "lexicographic_order"
krauss
parents:
22325
diff
changeset
|
302 |
val lexicographic_order = Method.SIMPLE_METHOD o (fn ctxt => FundefCommon.apply_termination_rule ctxt 1 |
0b14bb35be90
definition lookup via terms, not names. Methods "relation" and "lexicographic_order"
krauss
parents:
22325
diff
changeset
|
303 |
THEN lexicographic_order_tac ctxt) |
21201 | 304 |
|
21319
cf814e36f788
replaced "auto_term" by the simpler method "relation", which does not try
krauss
parents:
21237
diff
changeset
|
305 |
val setup = Method.add_methods [("lexicographic_order", Method.ctxt_args lexicographic_order, "termination prover for lexicographic orderings")] |
21131 | 306 |
|
21590 | 307 |
end |