Improved tactic for rewriting set comprehensions into pointfree form.
authorRafal Kolanski <rafal.kolanski@nicta.com.au>
Tue, 19 Jun 2012 11:16:41 +0200
changeset 48108 f93433b451b8
parent 48107 6cebeee3863e
child 48109 0a58f7eefba2
Improved tactic for rewriting set comprehensions into pointfree form. Currently the simproc targets a term with an arbitrary number of conjuncts of form "x : S". The tactic should now handle all cases of this form.
src/HOL/ex/Set_Comprehension_Pointfree_Tests.thy
src/HOL/ex/set_comprehension_pointfree.ML
--- a/src/HOL/ex/Set_Comprehension_Pointfree_Tests.thy	Tue Jun 19 11:18:09 2012 +0200
+++ b/src/HOL/ex/Set_Comprehension_Pointfree_Tests.thy	Tue Jun 19 11:16:41 2012 +0200
@@ -1,5 +1,5 @@
 (*  Title:      HOL/ex/Set_Comprehension_Pointfree_Tests.thy
-    Author:     Lukas Bulwahn
+    Author:     Lukas Bulwahn, Rafal Kolanski
     Copyright   2012 TU Muenchen
 *)
 
@@ -10,36 +10,62 @@
 uses "set_comprehension_pointfree.ML"
 begin
 
-simproc_setup finite_Collect ("finite (Collect P)") = {* Set_Comprehension_Pointfree.simproc *}
+simproc_setup finite_Collect ("finite (Collect P)") =
+  {* Set_Comprehension_Pointfree.simproc *}
+
+lemma
+  "finite {p. EX x. p = (x, x)}"
+  apply simp
+  oops
 
 lemma
   "finite {f a b| a b. a : A \<and> b : B}"
-apply simp (* works :) *)
-oops
+  apply simp
+  oops
 
 lemma
   "finite {f a b| a b. a : A \<and> a : A' \<and> b : B}"
-(* apply simp -- does not terminate *)
-oops
+  apply simp
+  oops
 
 lemma
   "finite {f a b| a b. a : A \<and> b : B \<and> b : B'}"
-(* apply simp -- does not terminate *)
-oops
+  apply simp
+  oops
 
 lemma
   "finite {f a b c| a b c. a : A \<and> b : B \<and> c : C}"
-(* apply simp -- failed *) 
-oops
+  apply simp
+  oops
 
 lemma
   "finite {f a b c d| a b c d. a : A \<and> b : B \<and> c : C \<and> d : D}"
-(* apply simp -- failed *)
-oops
+  apply simp
+  oops
 
 lemma
   "finite {f a b c d e | a b c d e. a : A \<and> b : B \<and> c : C \<and> d : D \<and> e : E}"
-(* apply simp -- failed *)
-oops
+  apply simp
+  oops
+
+lemma (* check arbitrary ordering *)
+  "finite {f a d c b e | e b c d a. b : B \<and> a : A \<and> e : E' \<and> c : C \<and> d : D \<and> e : E \<and> b : B'}"
+  apply simp
+  oops
+
+lemma
+  "\<lbrakk> finite A ; finite B ; finite C ; finite D \<rbrakk>
+  \<Longrightarrow> finite ({f a b c d| a b c d. a : A \<and> b : B \<and> c : C \<and> d : D})"
+  by simp
+
+lemma
+  "finite ((\<lambda>(a,b,c,d). f a b c d) ` (A \<times> B \<times> C \<times> D))
+  \<Longrightarrow> finite ({f a b c d| a b c d. a : A \<and> b : B \<and> c : C \<and> d : D})"
+  by simp
+
+schematic_lemma (* check interaction with schematics *)
+  "finite {x :: ?'A \<Rightarrow> ?'B \<Rightarrow> bool. \<exists>a b. x = Pair_Rep a b}
+   = finite ((\<lambda>(a:: ?'A, b :: ?'B). Pair_Rep a b) ` (UNIV \<times> UNIV))"
+  by simp
 
 end
--- a/src/HOL/ex/set_comprehension_pointfree.ML	Tue Jun 19 11:18:09 2012 +0200
+++ b/src/HOL/ex/set_comprehension_pointfree.ML	Tue Jun 19 11:16:41 2012 +0200
@@ -1,5 +1,6 @@
 (*  Title:      HOL/ex/set_comprehension_pointfree.ML
     Author:     Felix Kuperjans, Lukas Bulwahn, TU Muenchen
+                Rafal Kolanski, NICTA
 
 Simproc for rewriting set comprehensions to pointfree expressions.
 *)
@@ -7,6 +8,8 @@
 signature SET_COMPREHENSION_POINTFREE =
 sig
   val simproc : morphism -> simpset -> cterm -> thm option
+  val rewrite_term : term -> term option
+  val conv : Proof.context -> term -> thm option
 end
 
 structure Set_Comprehension_Pointfree : SET_COMPREHENSION_POINTFREE =
@@ -25,7 +28,8 @@
   let
     val T as Type (@{type_name fun}, [_ , R]) = fastype_of t1
   in
-    Const (@{const_name image}, T --> fastype_of t2 --> HOLogic.mk_setT R) $ t1 $ t2
+    Const (@{const_name image},
+      T --> fastype_of t2 --> HOLogic.mk_setT R) $ t1 $ t2
   end;
 
 fun mk_sigma (t1, t2) =
@@ -33,9 +37,10 @@
     val T1 = fastype_of t1
     val T2 = fastype_of t2
     val setT = HOLogic.dest_setT T1
-    val resultT = HOLogic.mk_setT (HOLogic.mk_prodT (setT, HOLogic.dest_setT T2))
+    val resT = HOLogic.mk_setT (HOLogic.mk_prodT (setT, HOLogic.dest_setT T2))
   in
-    Const (@{const_name Sigma}, T1 --> (setT --> T2) --> resultT) $ t1 $ absdummy setT t2
+    Const (@{const_name Sigma},
+      T1 --> (setT --> T2) --> resT) $ t1 $ absdummy setT t2
   end;
 
 fun dest_Bound (Bound x) = x
@@ -55,8 +60,9 @@
 
 fun list_tupled_abs [] f = f
   | list_tupled_abs [(n, T)] f = (Abs (n, T, f))
-  | list_tupled_abs ((n, T)::v::vs) f = HOLogic.mk_split (Abs (n, T, list_tupled_abs (v::vs) f))
-  
+  | list_tupled_abs ((n, T)::v::vs) f =
+      HOLogic.mk_split (Abs (n, T, list_tupled_abs (v::vs) f))
+
 fun mk_pointfree_expr t =
   let
     val (vs, t'') = strip_ex (dest_Collect t)
@@ -75,32 +81,63 @@
     mk_image (list_tupled_abs vs f) (foldr1 mk_sigma complete_sets)
   end;
 
+val rewrite_term = try mk_pointfree_expr
+
 (* proof tactic *)
 
-(* This tactic is terribly incomplete *) 
+(* Tactic works for arbitrary number of m : S conjuncts *)
+
+val dest_Collect_tac = dtac @{thm iffD1[OF mem_Collect_eq]}
+  THEN' (REPEAT_DETERM o (eresolve_tac @{thms exE conjE}))
+  THEN' hyp_subst_tac;
 
-val goal1_tac_part2 = REPEAT_ALL_NEW (CHANGED o (atac ORELSE' rtac @{thm SigmaI}))
+val intro_image_Sigma_tac = rtac @{thm image_eqI}
+    THEN' (REPEAT_DETERM1 o
+      (rtac @{thm refl}
+      ORELSE' rtac
+        @{thm arg_cong2[OF refl, where f="op =", OF prod.cases, THEN iffD2]}));
 
-val goal1_tac = etac @{thm CollectE}
-  THEN' REPEAT1 o CHANGED o etac @{thm exE}
-  THEN' REPEAT1 o CHANGED o etac @{thm conjE}
-  THEN' rtac @{thm image_eqI}
-  THEN' RANGE [(REPEAT o CHANGED o stac @{thm split}) THEN' goal1_tac_part2, goal1_tac_part2]
+val dest_image_Sigma_tac = etac @{thm imageE}
+  THEN' (TRY o REPEAT_DETERM1 o Splitter.split_asm_tac @{thms prod.split_asm})
+  THEN' hyp_subst_tac
+  THEN' (TRY o REPEAT_DETERM1 o
+    (etac @{thm conjE} ORELSE' dtac @{thm iffD1[OF mem_Sigma_iff]}));
 
-val goal2_tac = etac @{thm imageE}
-  THEN' rtac @{thm CollectI}
-  THEN' REPEAT o CHANGED o etac @{thm SigmaE}
-  THEN' REPEAT o CHANGED o rtac @{thm exI}
-  THEN' REPEAT_ALL_NEW (rtac @{thm conjI})
-  THEN_ALL_NEW
-    (atac ORELSE'
-    (asm_full_simp_tac HOL_basic_ss THEN' stac @{thm split} THEN' rtac @{thm refl}))
+val intro_Collect_tac = rtac @{thm iffD2[OF mem_Collect_eq]}
+  THEN' REPEAT_DETERM1 o resolve_tac @{thms exI}
+  THEN' (TRY o (rtac @{thm conjI}))
+  THEN' (TRY o hyp_subst_tac)
+  THEN' rtac @{thm refl};
 
 val tac =
-  rtac @{thm set_eqI} 1
-  THEN rtac @{thm iffI} 1
-  THEN goal1_tac 1
-  THEN goal2_tac 1
+  let
+    val subset_tac1 = rtac @{thm subsetI}
+      THEN' dest_Collect_tac
+      THEN' intro_image_Sigma_tac
+      THEN' (REPEAT_DETERM1 o
+        (rtac @{thm SigmaI}
+        ORELSE' rtac @{thm UNIV_I}
+        ORELSE' rtac @{thm IntI}
+        ORELSE' atac));
+
+    val subset_tac2 = rtac @{thm subsetI}
+      THEN' dest_image_Sigma_tac
+      THEN' intro_Collect_tac
+      THEN' REPEAT_DETERM o
+        (rtac @{thm conjI}
+        ORELSE' eresolve_tac @{thms IntD1 IntD2}
+        ORELSE' atac);
+  in
+    rtac @{thm subset_antisym} THEN' subset_tac1 THEN' subset_tac2
+  end;
+
+fun conv ctxt t =
+  let
+    fun mk_thm t' = Goal.prove ctxt [] []
+      (HOLogic.mk_Trueprop (HOLogic.mk_eq (t, t'))) (K (tac 1));
+  in
+    Option.map mk_thm (rewrite_term t)
+  end;
 
 (* simproc *)
 
@@ -109,12 +146,10 @@
     val ctxt = Simplifier.the_context ss
     val _ $ set_compr = term_of redex
   in
-    case try mk_pointfree_expr set_compr of
-      NONE => NONE
-    | SOME pointfree_expr =>
-        SOME (Goal.prove ctxt [] []
-          (HOLogic.mk_Trueprop (HOLogic.mk_eq (set_compr, pointfree_expr))) (K tac)
-        RS @{thm arg_cong[of _ _ finite]} RS @{thm eq_reflection})
-  end
+    conv ctxt set_compr
+    |> Option.map (fn thm =>
+         thm RS @{thm arg_cong[of _ _ finite]} RS @{thm eq_reflection})
+  end;
 
 end;
+