1(*=====================================================================  *)
2(* FILE          : permLib.sml                                           *)
3(* DESCRIPTION   : some code to handle permutations                      *)
4(*                                                                       *)
5(* AUTHORS       : Thomas Tuerk                                          *)
6(* DATE          : March 2009                                            *)
7(* ===================================================================== *)
8
9
10structure permLib :> permLib =
11struct
12
13(*
14quietdec := true;
15loadPath :=
16            (concat [Globals.HOLDIR, "/src/sort"])::
17            !loadPath;
18
19map load ["sortingTheory"];
20quietdec := true;
21*)
22
23
24open HolKernel Parse boolLib Drule sortingTheory listTheory
25
26(*
27quietdec := false;
28*)
29
30
31
32val LIST_NIL_CONV =
33    QCONV (REWRITE_CONV [CONJUNCT1 APPEND, APPEND_NIL])
34
35
36val PERM_tm = ``PERM : 'a list -> 'a list -> bool``;
37val dest_PERM = dest_binop PERM_tm (mk_HOL_ERR "permLib" "dest_PERM" "")
38val is_PERM = can dest_PERM;
39
40
41(*
42val t = ``PERM (x1::l1 ++ (l2 ++ (x2::x3::l3) ++ x4::l4)) (x1::l1 ++ ((x2::x3::l3) ++ x4::l4 ++ l2))``
43val t1 =  ``x1::x2::x3::(l1 ++ (x2::x3::l3 ++ x4::l4 ++ l2 ++ l4))``
44val t2 =  ``x1::x2::x8::(x4::l4 ++ l2++l4)``
45*)
46
47
48local
49   fun strip_perm_list_acc xs ls t =
50      if (listSyntax.is_cons t) then
51         let val (x,l) = listSyntax.dest_cons t; in
52             strip_perm_list_acc (x::xs) ls l
53         end
54      else if (listSyntax.is_append t) then
55         let
56             val (t1,t2) = listSyntax.dest_append t;
57             val (xs', ls') = strip_perm_list_acc xs ls t1;
58         in
59             strip_perm_list_acc xs' ls' t2
60         end
61      else
62         if (listSyntax.is_nil t) then (xs,ls) else (xs, t::ls)
63in
64   fun strip_perm_list t =
65      let
66         val (xs,ls) = strip_perm_list_acc [] [] t
67      in
68         (Listsort.sort Term.compare xs, Listsort.sort Term.compare ls)
69      end;
70end;
71
72
73fun bag_inter cmp [] _ = []
74  | bag_inter cmp _ [] = []
75  | bag_inter cmp (x::xs) (y::ys) =
76    case cmp (x, y) of
77        LESS    => bag_inter cmp xs (y::ys)
78      | GREATER => bag_inter cmp (x::xs) ys
79      | EQUAL   => x::(bag_inter cmp xs ys);
80
81
82fun perm_list_inter t1 t2 =
83  let
84     val (xs1,ls1) = strip_perm_list t1
85     val (xs2,ls2) = strip_perm_list t2
86  in
87     (bag_inter Term.compare xs1 xs2,
88      bag_inter Term.compare ls1 ls2)
89  end;
90
91fun perm_sub_list t1 t2 =
92  let
93     val (xs1,ls1) = strip_perm_list t1
94     val (xs2,ls2) = strip_perm_list t2
95
96     val xs = bag_inter Term.compare xs1 xs2;
97     val ls = bag_inter Term.compare ls1 ls2;
98
99     val t1_sub = (length xs = length xs1) andalso (length ls = length ls1);
100     val t2_sub = (length xs = length xs2) andalso (length ls = length ls2);
101  in
102     (t1_sub, t2_sub, (xs, ls))
103  end;
104
105
106
107(*dummy for testing
108
109fun PERM_MOVE_CONS_TO_FRONT e t = SOME (
110let val t' = rand t in
111mk_thm ([], ``PERM ^t' = PERM (^e::^t')``) end);
112*)
113
114
115fun PERM_MOVE_CONS_TO_FRONT e t =
116if (listSyntax.is_cons (rand t)) then
117   let
118      val (x, l) = listSyntax.dest_cons (rand t);
119   in
120      if (aconv x e) then SOME (REFL t) else
121      let
122         val l_term = mk_icomb (PERM_tm, l)
123         val l_thm_opt = PERM_MOVE_CONS_TO_FRONT e l_term;
124      in
125         if not (isSome l_thm_opt) then NONE else
126         let
127            val l2 = (rand o rand o rhs o  concl o valOf) l_thm_opt
128         in
129            SOME (MP (ISPECL [x,l,e,l2] PERM_FUN_CONS_11_SWAP_AT_FRONT)
130               (valOf l_thm_opt))
131         end
132      end
133   end
134else if (listSyntax.is_append (rand t)) then
135   let
136      val (l1,l2) = listSyntax.dest_append (rand t)
137      val l1_thm_opt = PERM_MOVE_CONS_TO_FRONT e (mk_icomb (PERM_tm, l1))
138      val l2_thm_opt = if isSome l1_thm_opt then NONE else
139                       PERM_MOVE_CONS_TO_FRONT e (mk_icomb (PERM_tm, l2))
140   in
141      if (isSome l1_thm_opt) then
142         let
143            val l1' = (rand o rand o rhs o  concl o valOf) l1_thm_opt
144         in
145            SOME (MP (ISPECL [l2,l1,e,l1'] PERM_FUN_CONS_APPEND_1)
146                     (valOf l1_thm_opt))
147         end
148      else if (isSome l2_thm_opt) then
149         let
150            val l2' = (rand o rand o rhs o  concl o valOf) l2_thm_opt
151         in
152            SOME (MP (ISPECL [l1,l2,e,l2'] PERM_FUN_CONS_APPEND_2)
153                     (valOf l2_thm_opt))
154         end
155      else NONE
156   end
157else NONE;
158
159
160(*
161   val t = ``PERM (x1::x2::x3::[])``;
162   val xs = free_vars t;
163   PERM_MOVE_CONS_TO_FRONT_CONV xs t
164*)
165fun PERM_MOVE_CONS_TO_FRONT_CONV [] t = REFL t
166  | PERM_MOVE_CONS_TO_FRONT_CONV (x::xs) t =
167    let
168       val thm0_opt = PERM_MOVE_CONS_TO_FRONT x t;
169       val _ = if isSome thm0_opt then () else raise UNCHANGED;
170       val thm0 = valOf thm0_opt;
171
172       val l1 = (rand o rand o rhs o concl) thm0;
173       val thm1 = PERM_MOVE_CONS_TO_FRONT_CONV xs (mk_icomb (PERM_tm, l1));
174       val l2 = (rand o rhs o concl) thm1;
175
176       val thm2 = ISPECL [x, l1, l2] PERM_FUN_CONS_IFF
177       val thm3 = MP thm2 thm1
178    in
179       TRANS thm0 thm3
180    end;
181
182
183
184
185(*dummy for testing
186
187fun PERM_MOVE_APPEND_TO_FRONT l t = SOME (
188let val t' = rand t in
189mk_thm ([], ``PERM ^t' = PERM (^l ++ ^t')``) end);
190*)
191
192
193fun PERM_MOVE_APPEND_TO_FRONT l t =
194if (listSyntax.is_nil l) then
195   let
196      val ty = listSyntax.dest_list_type (type_of l)
197      val tm = inst [alpha |-> ty] PERM_tm;
198   in
199      SOME (AP_TERM tm (GSYM (ISPEC (rand t) (CONJUNCT1 APPEND))))
200   end
201else if (listSyntax.is_cons (rand t)) then
202   let
203      val (x, l') = listSyntax.dest_cons (rand t);
204   in
205      let
206         val l'_term = mk_icomb (PERM_tm, l')
207         val l'_thm_opt = PERM_MOVE_APPEND_TO_FRONT l l'_term;
208      in
209         if not (isSome l'_thm_opt) then NONE else
210         let
211            val l2 = (rand o rand o rhs o  concl o valOf) l'_thm_opt
212         in
213            SOME (MP (ISPECL [x,l',l,l2] PERM_FUN_CONS_11_APPEND)
214               (valOf l'_thm_opt))
215         end
216      end
217   end
218else if (listSyntax.is_append (rand t)) then
219   let
220      val (l1,l2) = listSyntax.dest_append (rand t);
221   in
222      if (aconv l1 l) then SOME (REFL t) else
223      if (aconv l2 l) then
224         SOME (REWR_CONV PERM_FUN_APPEND t)
225      else
226      let
227         val l1_thm_opt = PERM_MOVE_APPEND_TO_FRONT l (mk_icomb (PERM_tm, l1))
228         val l2_thm_opt = if isSome l1_thm_opt then NONE else
229                       PERM_MOVE_APPEND_TO_FRONT l (mk_icomb (PERM_tm, l2))
230      in
231         if (isSome l1_thm_opt) then
232            let
233               val l1' = (rand o rand o rhs o  concl o valOf) l1_thm_opt
234            in
235               SOME (MP (ISPECL [l1,l,l1',l2] PERM_FUN_APPEND_APPEND_1)
236                        (valOf l1_thm_opt))
237            end
238         else if (isSome l2_thm_opt) then
239            let
240               val l2' = (rand o rand o rhs o  concl o valOf) l2_thm_opt
241            in
242               SOME (MP (ISPECL [l2,l,l2',l1] PERM_FUN_APPEND_APPEND_2)
243                        (valOf l2_thm_opt))
244            end
245         else NONE
246      end
247   end
248else if (aconv l (rand t)) then
249   let
250      val ty = listSyntax.dest_list_type (type_of l)
251      val tm = inst [alpha |-> ty] PERM_tm;
252   in
253      SOME (AP_TERM tm (GSYM (ISPEC l APPEND_NIL)))
254   end
255else NONE;
256
257
258
259(*
260   val t = ``PERM (x1++x2++x3)``;
261   val ls = free_vars t;
262   PERM_MOVE_APPEND_TO_FRONT_CONV ls t
263
264   val (l::ls) = ls
265   val t = (mk_icomb (PERM_tm, l1))
266*)
267
268fun PERM_MOVE_APPEND_TO_FRONT_CONV [] t = REFL t
269  | PERM_MOVE_APPEND_TO_FRONT_CONV (l::ls) t =
270    let
271       val thm0_opt = PERM_MOVE_APPEND_TO_FRONT l t;
272       val _ = if isSome thm0_opt then () else raise UNCHANGED;
273       val thm0 = valOf thm0_opt;
274
275       val l1 = (rand o rand o rhs o concl) thm0;
276       val thm1 = PERM_MOVE_APPEND_TO_FRONT_CONV ls (mk_icomb (PERM_tm, l1));
277       val l2 = (rand o rhs o concl) thm1;
278
279       val thm2 = ISPECL [l, l1, l2] PERM_FUN_APPEND_IFF
280       val thm3 = MP thm2 thm1
281    in
282       TRANS thm0 thm3
283    end;
284
285
286
287(*
288val l = hd ls
289val l = ``x::(l3 ++ z3::l2 ++ x::z::x1::y::l1 ++ x3::x5::l0)``;
290val xs = [``x:'a``, ``x1:'a``, ``y:'a``, ``x:'a``];
291val ls = [``l2:'a list``, ``l0:'a list``, ``l3:'a list``];
292
293val (xs,ls) = strip_perm_list l
294*)
295
296fun PERM_SPLIT_el_lists l (xs,ls) =
297let
298   val t = mk_icomb (PERM_tm, l);
299
300   val thm0 = (QCHANGED_CONV (PERM_MOVE_APPEND_TO_FRONT_CONV ls) THENC
301               RAND_CONV (REWR_CONV (GSYM (CONJUNCT1 APPEND))) THENC
302               QCHANGED_CONV (PERM_MOVE_CONS_TO_FRONT_CONV xs)) t;
303   val thm1 = CONV_RULE (RHS_CONV (REWRITE_CONV [GSYM (CONJUNCT2 APPEND)])) thm0
304
305   val thm2 = CONV_RULE (RHS_CONV (RAND_CONV (
306                 quantHeuristicsLibBase.BOUNDED_REPEATC (length ls) (REWR_CONV APPEND_ASSOC)))) thm1;
307
308   val thm3 = CONV_RULE (RAND_CONV (RAND_CONV (RAND_CONV LIST_NIL_CONV))) thm2
309in
310   CONV_RULE (REWR_CONV (GSYM PERM_EQUIVALENCE_ALT_DEF)) thm3
311end
312
313
314fun PERM_ELIM_DUPLICATES_CONV_DIRECT (l1,l2) common_terms =
315let
316   val thm_l1 = PERM_SPLIT_el_lists l1 common_terms;
317   val thm_l2 = PERM_SPLIT_el_lists l2 common_terms;
318
319   val l3 = (rand o concl) thm_l1
320   val l4 = (rand o concl) thm_l2
321
322   val (lc,l3') = listSyntax.dest_append l3
323   val (_,l4') = listSyntax.dest_append l4
324
325   val thm0 = ISPECL [lc,l1,l3',l2,l4'] PERM_CONG_APPEND_IFF;
326   val thm1 = MP thm0 thm_l1
327   val thm2 = MP thm1 thm_l2
328   val thm3 = CONV_RULE (RHS_CONV (REWRITE_CONV [PERM_REFL, PERM_NIL, NOT_CONS_NIL,
329                            APPEND_eq_NIL])) thm2
330in
331   thm3
332end;
333
334fun ASSUM_BY_CONV conv thm = let
335    val thm = CONV_RULE (RATOR_CONV (RAND_CONV conv)) thm
336  in MP thm TRUTH handle HOL_ERR e => (print ("ASSUM_BY_CONV: conv-ed thm: "
337    ^ Parse.thm_to_string thm ^ "\n"); raise (HOL_ERR e)) end
338
339fun add_count d k n = Redblackmap.update (d, k, fn NONE => n | SOME m => m + n)
340fun look_count d k = case Redblackmap.peek (d, k) of NONE => 0 | SOME n => n
341
342local
343   fun strip_build_opers t ops =
344      if (listSyntax.is_cons t) then
345         strip_build_opers (rand t) (rator t :: ops)
346      else if (listSyntax.is_append t) then
347         let
348             val (t1,t2) = listSyntax.dest_append t;
349         in
350             strip_build_opers t2 (strip_build_opers t1 ops)
351         end
352      else if (listSyntax.is_nil t) then ops
353      else rator (listSyntax.mk_append (t, t)) :: ops
354
355   fun mk_div_list count [] (sel, rej) = (sel, rej)
356     | mk_div_list count (oper :: ops) (sel, rej) =
357      if look_count count (rand oper) > 0
358      then mk_div_list (add_count count (rand oper) (~1)) ops
359         (mk_comb (oper, sel), rej)
360      else mk_div_list count ops (sel, mk_comb (oper, rej))
361in
362   fun strip_perm_list_div count t = let
363         val opers = strip_build_opers t []
364         val empty = listSyntax.mk_list ([], listSyntax.eltype t)
365      in mk_div_list count opers (empty, empty) end
366end
367
368(* Proves PERM l1comm l2comm ==> PERM l1 l2 = PERM l1rem l2rem
369   where l1comm and l2comm are the elements of 'common' in the
370   order they appear in l1/l2, and l1rem and l2rem are the
371   remainders. Fast: O(n) proof steps, O(nlogn) calculation. *)
372fun PERM_ELIM_COMMON_IMP common l1 l2 = let
373    val comm_tab = foldl (fn (x, d) => add_count d x 1)
374        (Redblackmap.mkDict Term.compare) common
375    val (l1_comm, l1_rem) = strip_perm_list_div comm_tab l1
376    val (l2_comm, l2_rem) = strip_perm_list_div comm_tab l2
377    val thm = ISPECL [l1, l1_comm, l1_rem, l2, l2_comm, l2_rem]
378        PERM_CONG_APPEND_IFF2
379    val conv = simpLib.SIMP_CONV boolSimps.bool_ss [PERM_TO_APPEND_SIMPS]
380  in ASSUM_BY_CONV conv (ASSUM_BY_CONV conv thm) end
381
382fun PERM_ELIM_DUPLICATES_CONV t =
383let
384   val (l1,l2) = dest_PERM t handle HOL_ERR _ => raise UNCHANGED
385   val common_terms = perm_list_inter l1 l2
386
387   val _ = length ((op @) common_terms) > 0 orelse raise UNCHANGED
388   val l1_length = length ((op @) (strip_perm_list l1))
389   fun half xs = List.take (xs, Int.min (l1_length div 2, length xs))
390
391in if l1_length > 10
392  then PERM_ELIM_COMMON_IMP (half ((op @) common_terms)) l1 l2
393    |> ASSUM_BY_CONV PERM_ELIM_DUPLICATES_CONV
394    |> CONV_RULE (RHS_CONV PERM_ELIM_DUPLICATES_CONV)
395  else PERM_ELIM_DUPLICATES_CONV_DIRECT (l1,l2) common_terms
396end
397
398(* testing
399
400val t = ``PERM (x1::l1 ++ (l2 ++ (x2::x3::(1 : num)::l3) ++ x4::l4))
401  (x1::(1 : num)::l1 ++ ((x2::x3::l3) ++ x4::l4 ++ l2))``
402val (t1, t2) = dest_PERM t
403val comm = [``l2 : num list``, ``x3 : num``]
404
405val test_IMP = PERM_ELIM_COMMON_IMP comm t1 t2
406
407fun mk_num_list is = listSyntax.mk_list (map numSyntax.term_of_int is, ``: num``);
408fun mk_PERM a b = list_mk_icomb PERM_tm [a, b];
409
410fun test1 n = mk_PERM (mk_num_list (upto 1 n)) (mk_num_list (rev (upto 1 n)))
411    |> PERM_ELIM_DUPLICATES_CONV;
412val t1_200 = test1 200;
413
414fun test2 n = let
415    val app = listSyntax.mk_append
416    val lhs = app (app (mk_num_list (upto 1 n), t1), mk_num_list (upto 12 (n + 11)))
417    val rhs = app (app (mk_num_list (rev (upto 12 (n + 11))), mk_num_list (upto 4 n)),
418        app (``rmn : num list``, t2))
419  in PERM_ELIM_DUPLICATES_CONV (mk_PERM lhs rhs) end
420
421val t2_200 = test2 200;
422*)
423
424
425(*
426PERM_SPLIT ls l
427
428val ls = ``(l1 ++l2):'a list``
429val l = ``l2 ++ x::l1``
430*)
431
432fun PERM_SPLIT ls l =
433let
434   val (b,_,common_terms) = perm_sub_list ls l;
435   val _ = if b then () else raise UNCHANGED;
436
437   val thm_l = PERM_SPLIT_el_lists l common_terms;
438   val thm_ls = PERM_SPLIT_el_lists ls common_terms;
439   val thm_ls = CONV_RULE (RAND_CONV (REWR_CONV APPEND_NIL)) thm_ls;
440
441   val l' = (rand o concl) thm_l
442   val ls' = (rand o concl) thm_ls
443   val (lc,l'') = listSyntax.dest_append l'
444
445   val thm0 = ISPECL [l,lc,ls,l''] PERM_FUN_SPLIT;
446   val thm1 = MP thm0 thm_l
447   val thm2 = MP thm1 thm_ls
448in
449   thm2
450end;
451
452
453(*
454   val t = ``(l2++x::l3)``
455   val t = ``((TAKE n l)++l2++x::l3++(DROP n l))``
456   val t = ``((TAKE n l)++(DROP m l2)++l2++x::l3++(TAKE m l2)++(DROP n l))``
457*)
458fun PERM_TAKE_DROP t =
459   let
460      val (_, ls) = strip_perm_list t;
461      val drop_ls = mapfilter listSyntax.dest_drop ls
462      val take_ls = mapfilter listSyntax.dest_take ls
463      val common = first (fn e => mem e drop_ls) take_ls;
464
465      val common_t = listSyntax.mk_append (listSyntax.mk_take common, listSyntax.mk_drop common);
466      val thm0 = PERM_SPLIT common_t t;
467      val thm1 = CONV_RULE ((RAND_CONV o RATOR_CONV o RAND_CONV) (REWR_CONV listTheory.TAKE_DROP)) thm0
468
469      val thm2_opt = (total PERM_TAKE_DROP) (rand (concl thm1))
470      val thm3 = if not (isSome thm2_opt) then thm1 else
471                   MATCH_MP PERM_TRANS (CONJ thm1 (valOf thm2_opt))
472   in
473      thm3
474   end;
475
476
477(*
478   val l1 = ``(TAKE n l)++l2++x::l3++(DROP n l)``
479   val l2 = ``(DROP m l)++x::l3++(TAKE m l)++(DROP n l)``
480   val t = ``PERM ^l1 ^l2``
481*)
482fun PERM_TAKE_DROP_CONV t =
483let
484   val (l1,l2) = dest_PERM t handle HOL_ERR _ => raise UNCHANGED;
485
486   val thm_l1_opt = (total PERM_TAKE_DROP) l1;
487   val thm_l2_opt = (total PERM_TAKE_DROP) l2;
488   val _ = if isSome thm_l1_opt orelse isSome thm_l2_opt then () else raise UNCHANGED;
489
490   val thm_l1 = if isSome thm_l1_opt then valOf thm_l1_opt else ISPEC l1 PERM_REFL;
491   val thm_l2 = if isSome thm_l2_opt then valOf thm_l2_opt else ISPEC l2 PERM_REFL;
492
493   val l1' = (rand o concl) thm_l1
494   val l2' = (rand o concl) thm_l2
495   val thm0 = ISPECL [l1,l1',l2,l2'] PERM_CONG_2;
496   val thm1 = MP thm0 thm_l1
497   val thm2 = MP thm1 thm_l2
498in
499   thm2
500end;
501
502
503fun PERM_NO_ELIM_NORMALISE_CONV t =
504let
505   val (l1,l2) = dest_PERM t handle HOL_ERR _ => raise UNCHANGED;
506
507   fun ELIM_NIL_RULE thm = CONV_RULE (RAND_CONV (REWR_CONV APPEND_NIL)) thm
508                             handle HOL_ERR _ => thm;
509
510   val thm_l1 = ELIM_NIL_RULE (PERM_SPLIT_el_lists l1 (strip_perm_list l1));
511   val thm_l2 = ELIM_NIL_RULE (PERM_SPLIT_el_lists l2 (strip_perm_list l2));
512
513   val l1' = (rand o concl) thm_l1
514   val l2' = (rand o concl) thm_l2
515
516   val thm0 = ISPECL [l1,l1',l2,l2'] PERM_CONG_2;
517   val thm1 = MP thm0 thm_l1
518   val thm2 = MP thm1 thm_l2
519   val thm3 = CONV_RULE (RHS_CONV (REWRITE_CONV [APPEND, APPEND_NIL])) thm2
520in
521   thm3
522end;
523
524fun PERM_TURN_CONV t =
525let
526   val (l1,l2) = dest_PERM t handle HOL_ERR _ => raise UNCHANGED;
527
528   val (xs1,ls1) = strip_perm_list l1;
529   val (xs2,ls2) = strip_perm_list l2;
530   val comp = pair_compare (list_compare Term.compare, list_compare Term.compare);
531
532   val turn = (length xs1 + length ls1 < length xs2 + length ls2) orelse
533              ((length xs1 + length ls1 = length xs2 + length ls2) andalso
534               (length ls1 < length ls2)) orelse
535              ((length ls1 = length ls2) andalso
536               (length xs1 = length xs2) andalso
537               (comp ((xs1,ls1), (xs2,ls2)) = LESS))
538in
539   if turn then REWR_CONV PERM_SYM t else raise UNCHANGED
540end;
541
542
543val PERM_NORMALISE_CONV = PERM_ELIM_DUPLICATES_CONV THENC
544                          PERM_TAKE_DROP_CONV THENC
545                          PERM_NO_ELIM_NORMALISE_CONV THENC
546                          PERM_TURN_CONV;
547
548(*
549val thm = (ASSUME ``PERM l1 [x;y;z]``)
550val t = ``PERM (z::y::x'::l2) (l3++(x'::l1))``
551
552val thm = (el 2 new_thmL)
553val t =  (concl (el 2 new_thmL))
554PERM_REWR_CONV (el 2 new_thmL) (concl (el 2 new_thmL))
555
556show_assums := true
557PERM_REWR_CONV thm t
558*)
559
560fun PERM_REWR_CONV thm t =
561let
562   val (l,r) = dest_PERM (concl thm)
563
564   val (l1,l2) = dest_PERM t handle HOL_ERR _ => raise UNCHANGED;
565   val (turn,split_thm) =
566     (false, PERM_SPLIT l l1) handle UNCHANGED =>
567     (true,  PERM_SPLIT l l2);
568
569   val (thm0,l1,l2) = if turn then (ISPECL [l1,l2] PERM_SYM,l2,l1) else (REFL t,l1,l2);
570
571   val l1' = (rand o concl) split_thm
572   val thm1a = ISPECL [l1,l1',l2,l2] PERM_CONG_2
573   val thm1b = MP thm1a split_thm
574   val thm1c = MP thm1b (ISPEC l2 PERM_REFL);
575   val thm1 = TRANS thm0 thm1c
576
577
578   val thm2a = ISPECL [l,r,rand l1',l2] PERM_REWR
579   val thm2b = MP thm2a thm
580   val thm2 = TRANS thm1 thm2b
581
582   val thm3 = CONV_RULE (RHS_CONV PERM_NORMALISE_CONV) thm2
583in
584   thm3
585end;
586
587
588
589fun PERM_SIMP_CONV thmL t =
590   let
591      val _ = if is_PERM t then () else raise UNCHANGED;
592      val thm =  FIRST_CONV ((CHANGED_CONV PERM_NORMALISE_CONV)::(map (QCHANGED_CONV o PERM_REWR_CONV) thmL)) t;
593   in
594      thm
595   end;
596
597
598local
599
600exception perm_reducer_context of thm list
601
602fun perm_reducer_get_context e =
603    (raise e)
604    handle perm_reducer_context thmL => thmL;
605
606
607fun clean_perm_thm thm = filter (is_PERM o concl) (BODY_CONJUNCTS thm);
608fun clean_perm_thmL thmL = flatten (map clean_perm_thm thmL);
609fun normalise_RULE l thm = CONV_RULE (REPEATC (PERM_SIMP_CONV l)) thm handle HOL_ERR _ => thm
610fun normalise_RULE_bool l thm =
611   let val thm' = normalise_RULE l thm; in
612      (not (aconv (concl thm) (concl thm')), thm')
613   end;
614
615fun perm_reducer_add_context old_thmL [] = old_thmL
616  | perm_reducer_add_context old_thmL (new_thm::new_thmL) =
617    case clean_perm_thm (normalise_RULE old_thmL new_thm) of
618        [] => perm_reducer_add_context old_thmL new_thmL
619      | (new_thm'::new_thmL') =>
620        let
621           val old_thmLb' = map (normalise_RULE_bool [new_thm']) old_thmL
622           val (new_thmLb'', old_thmLb'') = partition fst old_thmLb';
623           val new_thmL'' = map snd new_thmLb'';
624           val old_thmL'' = map snd old_thmLb'';
625        in
626           perm_reducer_add_context (new_thm'::old_thmL'')
627              (append new_thmL'' (append new_thmL' new_thmL))
628        end;
629
630val perm_simplify_thmL = perm_reducer_add_context [];
631
632fun perm_reducer_add_context2 (ctx, thmL) =
633   perm_reducer_context (perm_reducer_add_context
634                        (perm_reducer_get_context ctx) thmL);
635
636fun perm_reducer_add_context_simple (ctx, thmL) =
637   perm_reducer_context (append (clean_perm_thmL thmL)
638                                (perm_reducer_get_context ctx));
639
640val PERM_REDUCER =
641  Traverse.REDUCER {name = SOME "PERM_REDUCER",
642           initial = perm_reducer_context [],
643           addcontext = perm_reducer_add_context2,
644           apply = fn args => QCHANGED_CONV (PERM_SIMP_CONV (perm_reducer_get_context (#context args)))
645              };
646
647val PERM_REDUCER_SIMPLE =
648  Traverse.REDUCER {name = SOME "PERM_REDUCER_SIMPLE",
649           initial = perm_reducer_context [],
650           addcontext = perm_reducer_add_context_simple,
651           apply = fn args => QCHANGED_CONV (PERM_SIMP_CONV (perm_reducer_get_context (#context args)))
652              };
653
654in
655
656val PERM_ss = simpLib.SSFRAG
657    {name=SOME"PERM_ss",
658     convs = [], rewrs = [], filter = NONE, dprocs = [PERM_REDUCER], congs = [],
659     ac = []
660     }
661
662val PERM_SIMPLE_ss = simpLib.SSFRAG
663    {name=SOME"PERM_SIMPLE_ss",
664     convs = [], rewrs = [], filter = NONE, dprocs = [PERM_REDUCER_SIMPLE], congs = [],
665     ac = []
666     }
667
668fun NORMALISE_ASM_PERM_TAC (asm, t) =
669let
670   val (asm_perm, asm_rest) = partition is_PERM asm;
671   val asm_perm_thmL = perm_simplify_thmL (map ASSUME asm_perm)
672
673   val asm' = append asm_rest (map concl asm_perm_thmL);
674   fun reconstruct thm' = foldl (fn (h, thm) => PROVE_HYP h thm) thm' asm_perm_thmL
675in
676   ([(asm', t)], fn thmL => reconstruct (hd thmL))
677end;
678
679end;
680
681
682(*
683
684val conv = SIMP_CONV (std_ss++PERM_ss) []
685
686
687conv ``X /\ (PERM (x::l1++l2) (l2++[x])) /\ Z``
688conv ``(PERM (x::z::l1++l2) (l3++x::l1)) /\ Z``
689
690conv ``(X /\ (PERM (l2++[]++[z]) (y::l4)) /\ Y) ==> ((PERM (x::z::l1++l2) (l3++x::l1)))``
691
692conv ``(PERM l1 m1 /\
693        PERM l2 m2 /\
694        PERM (l1 ++ l2) n1 /\
695        PERM (m1 ++ m2) n2) ==>
696        PERM n1 n2``
697
698*)
699
700fun SORTED_CONV conv = let
701    fun safe_conv t = if is_conj t orelse t = ``T``
702        then NO_CONV t else CHANGED_CONV conv t
703  in
704    REWRITE_CONV [SORTED_DEF]
705        THENC TOP_DEPTH_CONV safe_conv
706        THENC simpLib.SIMP_CONV boolSimps.bool_ss []
707  end
708
709(* Prove `ALL_DISTINCT xs = T` by permuting to a sorted list
710   (i.e. using theorems ALL_DISTINCT_PERM and SORTED_ALL_DISTINCT).
711   Requires a relation R, a theorem `irreflexive R /\ transitive R`,
712   a function f used to sort the terms of xs in ML, and a conversion that
713   can show `R x y` for any x/y for which f `x` `y`. *)
714fun ALL_DISTINCT_CONV rel_thm ord_f conv tm = let
715    val xs_t = listSyntax.dest_all_distinct tm
716        handle HOL_ERR _ => raise UNCHANGED
717    val (xs, elT) = listSyntax.dest_list xs_t
718        handle HOL_ERR _ => raise UNCHANGED
719    val xs_ord = sort ord_f xs
720    val xs_ord_t = listSyntax.mk_list (xs_ord, elT)
721    val part1 = if xs_ord = xs then (fn t => raise UNCHANGED)
722      else (fn t => sortingTheory.ALL_DISTINCT_PERM
723          |> ISPEC xs_t |> SPEC xs_ord_t
724          |> ASSUM_BY_CONV PERM_ELIM_DUPLICATES_CONV)
725    val part2_thm = MATCH_MP sortingTheory.SORTED_ALL_DISTINCT rel_thm
726          |> ISPEC xs_ord_t |> ASSUM_BY_CONV (SORTED_CONV conv)
727  in (part1 THENC simpLib.SIMP_CONV boolSimps.bool_ss [part2_thm]) tm end
728
729(* testing -- requires good_cmp_Less_irrefl_trans from comparisonTheory
730
731val num_ALL_DISTINCT_CONV = ALL_DISTINCT_CONV
732  (MATCH_MP good_cmp_Less_irrefl_trans comparisonTheory.num_cmp_good)
733  (fn x => fn y => numSyntax.int_of_term x < numSyntax.int_of_term y) EVAL;
734
735val test = mk_icomb (listSyntax.all_distinct_tm, mk_num_list
736    (map (fn x => (x * 17) mod 1000) (upto 5 800)))
737  |> num_ALL_DISTINCT_CONV;
738
739*)
740
741
742end
743