ProgTutorial/Tactical.thy
changeset 544 501491d56798
parent 543 cd28458c2add
child 551 be361e980acf
equal deleted inserted replaced
543:cd28458c2add 544:501491d56798
   405   sometimes useful during the development of tactics.
   405   sometimes useful during the development of tactics.
   406 *}
   406 *}
   407 
   407 
   408 lemma 
   408 lemma 
   409   shows "False" and "Goldbach_conjecture"  
   409   shows "False" and "Goldbach_conjecture"  
   410 apply(tactic {* Skip_Proof.cheat_tac @{theory} *})
   410 apply(tactic {* Skip_Proof.cheat_tac 1 *})
   411 txt{*\begin{minipage}{\textwidth}
   411 txt{*\begin{minipage}{\textwidth}
   412      @{subgoals [display]}
   412      @{subgoals [display]}
   413      \end{minipage}*}
   413      \end{minipage}*}
   414 (*<*)oops(*>*)
   414 (*<*)oops(*>*)
   415 
   415 
  1342   corresponds on the ML-level to the tactic
  1342   corresponds on the ML-level to the tactic
  1343 *}
  1343 *}
  1344 
  1344 
  1345 lemma 
  1345 lemma 
  1346   shows "Suc (1 + 2) < 3 + 2"
  1346   shows "Suc (1 + 2) < 3 + 2"
  1347 apply(tactic {* asm_full_simp_tac @{simpset} 1 *})
  1347 apply(tactic {* asm_full_simp_tac @{context} 1 *})
  1348 done
  1348 done
  1349 
  1349 
  1350 text {*
  1350 text {*
  1351   If the simplifier cannot make any progress, then it leaves the goal unchanged,
  1351   If the simplifier cannot make any progress, then it leaves the goal unchanged,
  1352   i.e., does not raise any error message. That means if you use it to unfold a 
  1352   i.e., does not raise any error message. That means if you use it to unfold a 
  1428 \begin{isabelle}*}
  1428 \begin{isabelle}*}
  1429 ML %grayML{*fun print_ss ctxt ss =
  1429 ML %grayML{*fun print_ss ctxt ss =
  1430 let
  1430 let
  1431   val {simps, congs, procs, ...} = Raw_Simplifier.dest_ss ss
  1431   val {simps, congs, procs, ...} = Raw_Simplifier.dest_ss ss
  1432 
  1432 
  1433   fun name_thm (nm, thm) =
  1433   fun name_sthm (nm, thm) =
       
  1434     Pretty.enclose (nm ^ ": ") "" [pretty_thm_no_vars ctxt thm]
       
  1435   fun name_cthm ((_, nm), thm) =
  1434     Pretty.enclose (nm ^ ": ") "" [pretty_thm_no_vars ctxt thm]
  1436     Pretty.enclose (nm ^ ": ") "" [pretty_thm_no_vars ctxt thm]
  1435   fun name_ctrm (nm, ctrm) =
  1437   fun name_ctrm (nm, ctrm) =
  1436     Pretty.enclose (nm ^ ": ") "" [pretty_cterms ctxt ctrm]
  1438     Pretty.enclose (nm ^ ": ") "" [pretty_cterms ctxt ctrm]
  1437 
  1439 
  1438   val pps = [Pretty.big_list "Simplification rules:" (map name_thm simps),
  1440   val pps = [Pretty.big_list "Simplification rules:" (map name_sthm simps),
  1439              Pretty.big_list "Congruences rules:" (map name_thm congs),
  1441              Pretty.big_list "Congruences rules:" (map name_cthm congs),
  1440              Pretty.big_list "Simproc patterns:" (map name_ctrm procs)]
  1442              Pretty.big_list "Simproc patterns:" (map name_ctrm procs)]
  1441 in
  1443 in
  1442   pps |> Pretty.chunks
  1444   pps |> Pretty.chunks
  1443       |> pwriteln
  1445       |> pwriteln
  1444 end*}
  1446 end*}
  1465   you can see it contains nothing. This simpset is usually not useful, except as a 
  1467   you can see it contains nothing. This simpset is usually not useful, except as a 
  1466   building block to build bigger simpsets. For example you can add to @{ML empty_ss} 
  1468   building block to build bigger simpsets. For example you can add to @{ML empty_ss} 
  1467   the simplification rule @{thm [source] Diff_Int} as follows:
  1469   the simplification rule @{thm [source] Diff_Int} as follows:
  1468 *}
  1470 *}
  1469 
  1471 
  1470 ML %grayML{*val ss1 = empty_ss addsimps [@{thm Diff_Int} RS @{thm eq_reflection}] *}
  1472 ML %grayML{*val ss1 = put_simpset empty_ss @{context} addsimps [@{thm Diff_Int} RS @{thm eq_reflection}] *}
  1471 
  1473 
  1472 text {*
  1474 text {*
  1473   Printing then out the components of the simpset gives:
  1475   Printing then out the components of the simpset gives:
  1474 
  1476 
  1475   @{ML_response_fake [display,gray]
  1477   @{ML_response_fake [display,gray]
  1476   "print_ss @{context} ss1"
  1478   "print_ss @{context} (Raw_Simplifier.simpset_of ss1)"
  1477 "Simplification rules:
  1479 "Simplification rules:
  1478   ??.unknown: A - B \<inter> C \<equiv> A - B \<union> (A - C)
  1480   ??.unknown: A - B \<inter> C \<equiv> A - B \<union> (A - C)
  1479 Congruences rules:
  1481 Congruences rules:
  1480 Simproc patterns:"}
  1482 Simproc patterns:"}
  1481 
  1483 
  1482   \footnote{\bf FIXME: Why does it print out ??.unknown}
  1484   \footnote{\bf FIXME: Why does it print out ??.unknown}
  1483 
  1485 
  1484   Adding also the congruence rule @{thm [source] UN_cong} 
  1486   Adding also the congruence rule @{thm [source] UN_cong} 
  1485 *}
  1487 *}
  1486 
  1488 
  1487 ML %grayML{*val ss2 = Simplifier.add_cong (@{thm UN_cong} RS @{thm eq_reflection}) ss1 *}
  1489 ML %grayML{*val ss2 = ss1 |> Simplifier.add_cong (@{thm UN_cong} RS @{thm eq_reflection}) *}
  1488 
  1490 
  1489 text {*
  1491 text {*
  1490   gives
  1492   gives
  1491 
  1493 
  1492   @{ML_response_fake [display,gray]
  1494   @{ML_response_fake [display,gray]
  1493   "print_ss @{context} ss2"
  1495   "print_ss @{context} (Raw_Simplifier.simpset_of ss2)"
  1494 "Simplification rules:
  1496 "Simplification rules:
  1495   ??.unknown: A - B \<inter> C \<equiv> A - B \<union> (A - C)
  1497   ??.unknown: A - B \<inter> C \<equiv> A - B \<union> (A - C)
  1496 Congruences rules:
  1498 Congruences rules:
  1497   UNION: \<lbrakk>A = B; \<And>x. x \<in> B \<Longrightarrow> C x = D x\<rbrakk> \<Longrightarrow> \<Union>x\<in>A. C x \<equiv> \<Union>x\<in>B. D x
  1499   UNION: \<lbrakk>A = B; \<And>x. x \<in> B \<Longrightarrow> C x = D x\<rbrakk> \<Longrightarrow> \<Union>x\<in>A. C x \<equiv> \<Union>x\<in>B. D x
  1498 Simproc patterns:"}
  1500 Simproc patterns:"}
  1526  shows "True" 
  1528  shows "True" 
  1527   and  "t = t" 
  1529   and  "t = t" 
  1528   and  "t \<equiv> t" 
  1530   and  "t \<equiv> t" 
  1529   and  "False \<Longrightarrow> Foo" 
  1531   and  "False \<Longrightarrow> Foo" 
  1530   and  "\<lbrakk>A; B; C\<rbrakk> \<Longrightarrow> A"
  1532   and  "\<lbrakk>A; B; C\<rbrakk> \<Longrightarrow> A"
  1531 apply(tactic {* ALLGOALS (simp_tac HOL_basic_ss) *})
  1533 apply(tactic {* ALLGOALS (simp_tac (put_simpset HOL_basic_ss @{context})) *})
  1532 done
  1534 done
  1533 
  1535 
  1534 text {*
  1536 text {*
  1535   This behaviour is not because of simplification rules, but how the subgoaler, solver 
  1537   This behaviour is not because of simplification rules, but how the subgoaler, solver 
  1536   and looper are set up in @{ML HOL_basic_ss}.
  1538   and looper are set up in @{ML HOL_basic_ss}.
  1709   other permutations by rule @{thm [source] perm_compose_aux} (Line 10); and
  1711   other permutations by rule @{thm [source] perm_compose_aux} (Line 10); and
  1710   finally ``unfreeze'' all instances of permutation compositions by unfolding 
  1712   finally ``unfreeze'' all instances of permutation compositions by unfolding 
  1711   the definition of the auxiliary constant. 
  1713   the definition of the auxiliary constant. 
  1712 *}
  1714 *}
  1713 
  1715 
  1714 ML %linenosgray{*val perm_simp_tac =
  1716 ML %linenosgray{*fun perm_simp_tac ctxt =
  1715 let
  1717 let
  1716   val thms1 = [@{thm perm_aux_expand}]
  1718   val thms1 = [@{thm perm_aux_expand}]
  1717   val thms2 = [@{thm perm_append}, @{thm perm_bij}, @{thm perm_rev}, 
  1719   val thms2 = [@{thm perm_append}, @{thm perm_bij}, @{thm perm_rev}, 
  1718                @{thm perm_compose_aux}] @ @{thms perm_prod.simps} @ 
  1720                @{thm perm_compose_aux}] @ @{thms perm_prod.simps} @ 
  1719                @{thms perm_list.simps} @ @{thms perm_nat.simps}
  1721                @{thms perm_list.simps} @ @{thms perm_nat.simps}
  1720   val thms3 = [@{thm perm_aux_def}]
  1722   val thms3 = [@{thm perm_aux_def}]
       
  1723   val ss = put_simpset HOL_basic_ss ctxt
  1721 in
  1724 in
  1722   simp_tac (HOL_basic_ss addsimps thms1)
  1725   simp_tac (ss addsimps thms1)
  1723   THEN' simp_tac (HOL_basic_ss addsimps thms2)
  1726   THEN' simp_tac (ss addsimps thms2)
  1724   THEN' simp_tac (HOL_basic_ss addsimps thms3)
  1727   THEN' simp_tac (ss addsimps thms3)
  1725 end*}
  1728 end*}
  1726 
  1729 
  1727 text {*
  1730 text {*
  1728   For all three phases we have to build simpsets adding specific lemmas. As is sufficient
  1731   For all three phases we have to build simpsets adding specific lemmas. As is sufficient
  1729   for our purposes here, we can add these lemmas to @{ML HOL_basic_ss} in order to obtain
  1732   for our purposes here, we can add these lemmas to @{ML HOL_basic_ss} in order to obtain
  1731 *}
  1734 *}
  1732 
  1735 
  1733 lemma 
  1736 lemma 
  1734   fixes c d::"nat" and pi\<^isub>1 pi\<^isub>2::"prm"
  1737   fixes c d::"nat" and pi\<^isub>1 pi\<^isub>2::"prm"
  1735   shows "pi\<^isub>1\<bullet>(c, pi\<^isub>2\<bullet>((rev pi\<^isub>1)\<bullet>d)) = (pi\<^isub>1\<bullet>c, (pi\<^isub>1\<bullet>pi\<^isub>2)\<bullet>d)"
  1738   shows "pi\<^isub>1\<bullet>(c, pi\<^isub>2\<bullet>((rev pi\<^isub>1)\<bullet>d)) = (pi\<^isub>1\<bullet>c, (pi\<^isub>1\<bullet>pi\<^isub>2)\<bullet>d)"
  1736 apply(tactic {* perm_simp_tac 1 *})
  1739 apply(tactic {* perm_simp_tac @{context} 1 *})
  1737 done
  1740 done
  1738 
  1741 
  1739 
  1742 
  1740 text {*
  1743 text {*
  1741   in one step. This tactic can deal with most instances of normalising permutations.
  1744   in one step. This tactic can deal with most instances of normalising permutations.
  1747   (FIXME: Is it interesting to say something about @{term "op =simp=>"}?)
  1750   (FIXME: Is it interesting to say something about @{term "op =simp=>"}?)
  1748 
  1751 
  1749   (FIXME: What are the second components of the congruence rules---something to
  1752   (FIXME: What are the second components of the congruence rules---something to
  1750   do with weak congruence constants?)
  1753   do with weak congruence constants?)
  1751 
  1754 
  1752   (FIXME: Anything interesting to say about @{ML Simplifier.clear_ss}?)
       
  1753 
       
  1754   (FIXME: what are @{ML mksimps_pairs}; used in Nominal.thy)
  1755   (FIXME: what are @{ML mksimps_pairs}; used in Nominal.thy)
  1755 
  1756 
  1756   (FIXME: explain @{ML simplify} and @{ML "Simplifier.rewrite_rule"} etc.)
  1757   (FIXME: explain @{ML simplify} and @{ML "Simplifier.rewrite_rule"} etc.)
  1757 
  1758 
  1758 *}
  1759 *}
  1769   To see how simprocs work, let us first write a simproc that just prints out
  1770   To see how simprocs work, let us first write a simproc that just prints out
  1770   the pattern which triggers it and otherwise does nothing. For this
  1771   the pattern which triggers it and otherwise does nothing. For this
  1771   you can use the function:
  1772   you can use the function:
  1772 *}
  1773 *}
  1773 
  1774 
  1774 ML %linenosgray{*fun fail_simproc simpset redex = 
  1775 ML %linenosgray{*fun fail_simproc ctxt redex = 
  1775 let
  1776 let
  1776   val ctxt = Simplifier.the_context simpset
       
  1777   val _ = pwriteln (Pretty.block 
  1777   val _ = pwriteln (Pretty.block 
  1778     [Pretty.str "The redex: ", pretty_cterm ctxt redex])
  1778     [Pretty.str "The redex: ", pretty_cterm ctxt redex])
  1779 in
  1779 in
  1780   NONE
  1780   NONE
  1781 end*}
  1781 end*}
  1828   as follows:
  1828   as follows:
  1829 *}
  1829 *}
  1830 
  1830 
  1831 lemma 
  1831 lemma 
  1832   shows "Suc 0 = 1"
  1832   shows "Suc 0 = 1"
  1833 apply(tactic {* simp_tac (HOL_basic_ss addsimprocs [@{simproc fail}]) 1*})
  1833 apply(tactic {* simp_tac (put_simpset 
       
  1834   HOL_basic_ss @{context} addsimprocs [@{simproc fail}]) 1*})
  1834 (*<*)oops(*>*)
  1835 (*<*)oops(*>*)
  1835 
  1836 
  1836 text {*
  1837 text {*
  1837   Now the message shows up only once since the term @{term "1::nat"} is 
  1838   Now the message shows up only once since the term @{term "1::nat"} is 
  1838   left unchanged. 
  1839   left unchanged. 
  1842   want this, then you have to use a slightly different method for setting 
  1843   want this, then you have to use a slightly different method for setting 
  1843   up the simproc. First the function @{ML fail_simproc} needs to be modified
  1844   up the simproc. First the function @{ML fail_simproc} needs to be modified
  1844   to
  1845   to
  1845 *}
  1846 *}
  1846 
  1847 
  1847 ML %grayML{*fun fail_simproc' simpset redex = 
  1848 ML %grayML{*fun fail_simproc' ctxt redex = 
  1848 let
  1849 let
  1849   val ctxt = Simplifier.the_context simpset
       
  1850   val _ = pwriteln (Pretty.block 
  1850   val _ = pwriteln (Pretty.block 
  1851     [Pretty.str "The redex:", pretty_term ctxt redex])
  1851     [Pretty.str "The redex:", pretty_term ctxt redex])
  1852 in
  1852 in
  1853   NONE
  1853   NONE
  1854 end*}
  1854 end*}
  1859   We can turn this function into a proper simproc using the function 
  1859   We can turn this function into a proper simproc using the function 
  1860   @{ML Simplifier.simproc_global_i}:
  1860   @{ML Simplifier.simproc_global_i}:
  1861 *}
  1861 *}
  1862 
  1862 
  1863 
  1863 
  1864 ML %grayML{*val fail' = 
  1864 ML %grayML{*fun fail' ctxt = 
  1865 let 
  1865 let 
  1866   val thy = @{theory}
  1866   val thy = @{theory}
  1867   val pat = [@{term "Suc n"}]
  1867   val pat = [@{term "Suc n"}]
  1868 in
  1868 in
  1869   Simplifier.simproc_global_i thy "fail_simproc'" pat (K fail_simproc')
  1869   Simplifier.simproc_global_i thy "fail_simproc'" pat (K fail_simproc' ctxt)
  1870 end*}
  1870 end*}
  1871 
  1871 
  1872 text {*
  1872 text {*
  1873   Here the pattern is given as @{ML_type term} (instead of @{ML_type cterm}).
  1873   Here the pattern is given as @{ML_type term} (instead of @{ML_type cterm}).
  1874   The function also takes a list of patterns that can trigger the simproc.
  1874   The function also takes a list of patterns that can trigger the simproc.
  1880   see this in the proof
  1880   see this in the proof
  1881 *}
  1881 *}
  1882 
  1882 
  1883 lemma 
  1883 lemma 
  1884   shows "Suc (Suc 0) = (Suc 1)"
  1884   shows "Suc (Suc 0) = (Suc 1)"
  1885 apply(tactic {* simp_tac (HOL_basic_ss addsimprocs [fail']) 1*})
  1885 apply(tactic {* simp_tac ((put_simpset HOL_basic_ss @{context}) addsimprocs [fail' @{context}]) 1*})
  1886 (*<*)oops(*>*)
  1886 (*<*)oops(*>*)
  1887 
  1887 
  1888 text {*
  1888 text {*
  1889   The simproc @{ML fail'} prints out the sequence 
  1889   The simproc @{ML fail'} prints out the sequence 
  1890 
  1890 
  1907   the rewriting with simprocs, let us further assume we want that the simproc
  1907   the rewriting with simprocs, let us further assume we want that the simproc
  1908   only rewrites terms ``greater'' than @{term "Suc 0"}. For this we can write 
  1908   only rewrites terms ``greater'' than @{term "Suc 0"}. For this we can write 
  1909 *}
  1909 *}
  1910 
  1910 
  1911 
  1911 
  1912 ML %grayML{*fun plus_one_simproc ss redex =
  1912 ML %grayML{*fun plus_one_simproc ctxt redex =
  1913   case redex of
  1913   case redex of
  1914     @{term "Suc 0"} => NONE
  1914     @{term "Suc 0"} => NONE
  1915   | _ => SOME @{thm plus_one}*}
  1915   | _ => SOME @{thm plus_one}*}
  1916 
  1916 
  1917 text {*
  1917 text {*
  1918   and set up the simproc as follows.
  1918   and set up the simproc as follows.
  1919 *}
  1919 *}
  1920 
  1920 
  1921 ML %grayML{*val plus_one =
  1921 ML %grayML{*fun plus_one ctxt =
  1922 let
  1922 let
  1923   val thy = @{theory}
  1923   val thy = @{theory}
  1924   val pat = [@{term "Suc n"}] 
  1924   val pat = [@{term "Suc n"}] 
  1925 in
  1925 in
  1926   Simplifier.simproc_global_i thy "sproc +1" pat (K plus_one_simproc)
  1926   Simplifier.simproc_global_i thy "sproc +1" pat (K plus_one_simproc ctxt)
  1927 end*}
  1927 end*}
  1928 
  1928 
  1929 text {*
  1929 text {*
  1930   Now the simproc is set up so that it is triggered by terms
  1930   Now the simproc is set up so that it is triggered by terms
  1931   of the form @{term "Suc n"}, but inside the simproc we only produce
  1931   of the form @{term "Suc n"}, but inside the simproc we only produce
  1933   in the following proof
  1933   in the following proof
  1934 *}
  1934 *}
  1935 
  1935 
  1936 lemma 
  1936 lemma 
  1937   shows "P (Suc (Suc (Suc 0))) (Suc 0)"
  1937   shows "P (Suc (Suc (Suc 0))) (Suc 0)"
  1938 apply(tactic {* simp_tac (HOL_basic_ss addsimprocs [plus_one]) 1*})
  1938 apply(tactic {* simp_tac (put_simpset HOL_basic_ss @{context} addsimprocs [plus_one @{context}]) 1*})
  1939 txt{*
  1939 txt{*
  1940   where the simproc produces the goal state
  1940   where the simproc produces the goal state
  1941   \begin{isabelle}
  1941   \begin{isabelle}
  1942   @{subgoals[display]}
  1942   @{subgoals[display]}
  1943   \end{isabelle}
  1943   \end{isabelle}
  1988 
  1988 
  1989 ML %grayML{*fun get_thm_alt ctxt (t, n) =
  1989 ML %grayML{*fun get_thm_alt ctxt (t, n) =
  1990 let
  1990 let
  1991   val num = HOLogic.mk_number @{typ "nat"} n
  1991   val num = HOLogic.mk_number @{typ "nat"} n
  1992   val goal = Logic.mk_equals (t, num)
  1992   val goal = Logic.mk_equals (t, num)
  1993   val num_ss = HOL_ss addsimps @{thms semiring_norm}
  1993   val num_ss = put_simpset HOL_ss ctxt addsimps @{thms semiring_norm}
  1994 in
  1994 in
  1995   Goal.prove ctxt [] [] goal (K (simp_tac num_ss 1))
  1995   Goal.prove ctxt [] [] goal (K (simp_tac num_ss 1))
  1996 end*}
  1996 end*}
  1997 
  1997 
  1998 text {*
  1998 text {*
  2008 
  2008 
  2009   Anyway, either version can be used in the function that produces the actual 
  2009   Anyway, either version can be used in the function that produces the actual 
  2010   theorem for the simproc.
  2010   theorem for the simproc.
  2011 *}
  2011 *}
  2012 
  2012 
  2013 ML %grayML{*fun nat_number_simproc ss t =
  2013 ML %grayML{*fun nat_number_simproc ctxt t =
  2014 let 
       
  2015   val ctxt = Simplifier.the_context ss
       
  2016 in
       
  2017   SOME (get_thm_alt ctxt (t, dest_suc_trm t))
  2014   SOME (get_thm_alt ctxt (t, dest_suc_trm t))
  2018   handle TERM _ => NONE
  2015   handle TERM _ => NONE *}
  2019 end*}
       
  2020 
  2016 
  2021 text {*
  2017 text {*
  2022   This function uses the fact that @{ML dest_suc_trm} might raise an exception 
  2018   This function uses the fact that @{ML dest_suc_trm} might raise an exception 
  2023   @{ML TERM}. In this case there is nothing that can be rewritten and therefore no
  2019   @{ML TERM}. In this case there is nothing that can be rewritten and therefore no
  2024   theorem is produced (i.e.~the function returns @{ML NONE}). To try out the simproc 
  2020   theorem is produced (i.e.~the function returns @{ML NONE}). To try out the simproc 
  2025   on an example, you can set it up as follows:
  2021   on an example, you can set it up as follows:
  2026 *}
  2022 *}
  2027 
  2023 
  2028 ML %grayML{*val nat_number =
  2024 ML %grayML{*fun nat_number ctxt =
  2029 let
  2025 let
  2030   val thy = @{theory}
  2026   val thy = @{theory}
  2031   val pat = [@{term "Suc n"}]
  2027   val pat = [@{term "Suc n"}]
  2032 in 
  2028 in 
  2033   Simplifier.simproc_global_i thy "nat_number" pat (K nat_number_simproc) 
  2029   Simplifier.simproc_global_i thy "nat_number" pat (K nat_number_simproc ctxt) 
  2034 end*}
  2030 end*}
  2035 
  2031 
  2036 text {* 
  2032 text {* 
  2037   Now in the lemma
  2033   Now in the lemma
  2038   *}
  2034   *}
  2039 
  2035 
  2040 lemma 
  2036 lemma 
  2041   shows "P (Suc (Suc 2)) (Suc 99) (0::nat) (Suc 4 + Suc 0) (Suc (0 + 0))"
  2037   shows "P (Suc (Suc 2)) (Suc 99) (0::nat) (Suc 4 + Suc 0) (Suc (0 + 0))"
  2042 apply(tactic {* simp_tac (HOL_ss addsimprocs [nat_number]) 1*})
  2038 apply(tactic {* simp_tac (put_simpset HOL_ss @{context} addsimprocs [nat_number @{context}]) 1*})
  2043 txt {* 
  2039 txt {* 
  2044   you obtain the more legible goal state
  2040   you obtain the more legible goal state
  2045   \begin{isabelle}
  2041   \begin{isabelle}
  2046   @{subgoals [display]}
  2042   @{subgoals [display]}
  2047   \end{isabelle}*}
  2043   \end{isabelle}*}