src/HOL/ex/Reflection_Examples.thy
changeset 61343 5b5656a63bd6
parent 58889 5b7a9633cfa8
child 61933 cf58b5b794b2
equal deleted inserted replaced
61342:b98cd131e2b5 61343:5b5656a63bd6
     1 (*  Title:      HOL/ex/Reflection_Examples.thy
     1 (*  Title:      HOL/ex/Reflection_Examples.thy
     2     Author:     Amine Chaieb, TU Muenchen
     2     Author:     Amine Chaieb, TU Muenchen
     3 *)
     3 *)
     4 
     4 
     5 section {* Examples for generic reflection and reification *}
     5 section \<open>Examples for generic reflection and reification\<close>
     6 
     6 
     7 theory Reflection_Examples
     7 theory Reflection_Examples
     8 imports Complex_Main "~~/src/HOL/Library/Reflection"
     8 imports Complex_Main "~~/src/HOL/Library/Reflection"
     9 begin
     9 begin
    10 
    10 
    11 text {* This theory presents two methods: reify and reflection *}
    11 text \<open>This theory presents two methods: reify and reflection\<close>
    12 
    12 
    13 text {* 
    13 text \<open>
    14 Consider an HOL type @{text \<sigma>}, the structure of which is not recongnisable
    14 Consider an HOL type @{text \<sigma>}, the structure of which is not recongnisable
    15 on the theory level.  This is the case of @{typ bool}, arithmetical terms such as @{typ int},
    15 on the theory level.  This is the case of @{typ bool}, arithmetical terms such as @{typ int},
    16 @{typ real} etc \dots  In order to implement a simplification on terms of type @{text \<sigma>} we
    16 @{typ real} etc \dots  In order to implement a simplification on terms of type @{text \<sigma>} we
    17 often need its structure.  Traditionnaly such simplifications are written in ML,
    17 often need its structure.  Traditionnaly such simplifications are written in ML,
    18 proofs are synthesized.
    18 proofs are synthesized.
    39 and @{text f} is some useful and executable simplification of type @{text "\<tau> \<Rightarrow> \<tau>"}.
    39 and @{text f} is some useful and executable simplification of type @{text "\<tau> \<Rightarrow> \<tau>"}.
    40 The method @{text reflection} applies reification and hence the theorem @{prop "t = I xs s"}
    40 The method @{text reflection} applies reification and hence the theorem @{prop "t = I xs s"}
    41 and hence using @{text corr_thm} derives @{prop "t = I xs (f s)"}.  It then uses
    41 and hence using @{text corr_thm} derives @{prop "t = I xs (f s)"}.  It then uses
    42 normalization by equational rewriting to prove @{prop "f s = s'"} which almost finishes
    42 normalization by equational rewriting to prove @{prop "f s = s'"} which almost finishes
    43 the proof of @{prop "t = t'"} where @{prop "I xs s' = t'"}.
    43 the proof of @{prop "t = t'"} where @{prop "I xs s' = t'"}.
    44 *}
    44 \<close>
    45 
    45 
    46 text {* Example 1 : Propositional formulae and NNF. *}
    46 text \<open>Example 1 : Propositional formulae and NNF.\<close>
    47 text {* The type @{text fm} represents simple propositional formulae: *}
    47 text \<open>The type @{text fm} represents simple propositional formulae:\<close>
    48 
    48 
    49 datatype form = TrueF | FalseF | Less nat nat
    49 datatype form = TrueF | FalseF | Less nat nat
    50   | And form form | Or form form | Neg form | ExQ form
    50   | And form form | Or form form | Neg form | ExQ form
    51 
    51 
    52 primrec interp :: "form \<Rightarrow> ('a::ord) list \<Rightarrow> bool"
    52 primrec interp :: "form \<Rightarrow> ('a::ord) list \<Rightarrow> bool"
    79 
    79 
    80 lemma "Q \<longrightarrow> (D \<and> F \<and> ((\<not> D) \<and> (\<not> F)))"
    80 lemma "Q \<longrightarrow> (D \<and> F \<and> ((\<not> D) \<and> (\<not> F)))"
    81   apply (reify Ifm.simps)
    81   apply (reify Ifm.simps)
    82 oops
    82 oops
    83 
    83 
    84 text {* Method @{text reify} maps a @{typ bool} to an @{typ fm}.  For this it needs the 
    84 text \<open>Method @{text reify} maps a @{typ bool} to an @{typ fm}.  For this it needs the 
    85 semantics of @{text fm}, i.e.\ the rewrite rules in @{text Ifm.simps}. *}
    85 semantics of @{text fm}, i.e.\ the rewrite rules in @{text Ifm.simps}.\<close>
    86 
    86 
    87 text {* You can also just pick up a subterm to reify. *}
    87 text \<open>You can also just pick up a subterm to reify.\<close>
    88 lemma "Q \<longrightarrow> (D \<and> F \<and> ((\<not> D) \<and> (\<not> F)))"
    88 lemma "Q \<longrightarrow> (D \<and> F \<and> ((\<not> D) \<and> (\<not> F)))"
    89   apply (reify Ifm.simps ("((\<not> D) \<and> (\<not> F))"))
    89   apply (reify Ifm.simps ("((\<not> D) \<and> (\<not> F))"))
    90 oops
    90 oops
    91 
    91 
    92 text {* Let's perform NNF. This is a version that tends to generate disjunctions *}
    92 text \<open>Let's perform NNF. This is a version that tends to generate disjunctions\<close>
    93 primrec fmsize :: "fm \<Rightarrow> nat"
    93 primrec fmsize :: "fm \<Rightarrow> nat"
    94 where
    94 where
    95   "fmsize (At n) = 1"
    95   "fmsize (At n) = 1"
    96 | "fmsize (NOT p) = 1 + fmsize p"
    96 | "fmsize (NOT p) = 1 + fmsize p"
    97 | "fmsize (And p q) = 1 + fmsize p + fmsize q"
    97 | "fmsize (And p q) = 1 + fmsize p + fmsize q"
   113 | "nnf (NOT (Imp p q)) = And (nnf p) (nnf (NOT q))"
   113 | "nnf (NOT (Imp p q)) = And (nnf p) (nnf (NOT q))"
   114 | "nnf (NOT (Iff p q)) = Or (And (nnf p) (nnf (NOT q))) (And (nnf (NOT p)) (nnf q))"
   114 | "nnf (NOT (Iff p q)) = Or (And (nnf p) (nnf (NOT q))) (And (nnf (NOT p)) (nnf q))"
   115 | "nnf (NOT (NOT p)) = nnf p"
   115 | "nnf (NOT (NOT p)) = nnf p"
   116 | "nnf (NOT p) = NOT p"
   116 | "nnf (NOT p) = NOT p"
   117 
   117 
   118 text {* The correctness theorem of @{const nnf}: it preserves the semantics of @{typ fm} *}
   118 text \<open>The correctness theorem of @{const nnf}: it preserves the semantics of @{typ fm}\<close>
   119 lemma nnf [reflection]:
   119 lemma nnf [reflection]:
   120   "Ifm (nnf p) vs = Ifm p vs"
   120   "Ifm (nnf p) vs = Ifm p vs"
   121   by (induct p rule: nnf.induct) auto
   121   by (induct p rule: nnf.induct) auto
   122 
   122 
   123 text {* Now let's perform NNF using our @{const nnf} function defined above.  First to the
   123 text \<open>Now let's perform NNF using our @{const nnf} function defined above.  First to the
   124   whole subgoal. *}
   124   whole subgoal.\<close>
   125 lemma "A \<noteq> B \<and> (B \<longrightarrow> A \<noteq> (B \<or> C \<and> (B \<longrightarrow> A \<or> D))) \<longrightarrow> A \<or> B \<and> D"
   125 lemma "A \<noteq> B \<and> (B \<longrightarrow> A \<noteq> (B \<or> C \<and> (B \<longrightarrow> A \<or> D))) \<longrightarrow> A \<or> B \<and> D"
   126   apply (reflection Ifm.simps)
   126   apply (reflection Ifm.simps)
   127 oops
   127 oops
   128 
   128 
   129 text {* Now we specify on which subterm it should be applied *}
   129 text \<open>Now we specify on which subterm it should be applied\<close>
   130 lemma "A \<noteq> B \<and> (B \<longrightarrow> A \<noteq> (B \<or> C \<and> (B \<longrightarrow> A \<or> D))) \<longrightarrow> A \<or> B \<and> D"
   130 lemma "A \<noteq> B \<and> (B \<longrightarrow> A \<noteq> (B \<or> C \<and> (B \<longrightarrow> A \<or> D))) \<longrightarrow> A \<or> B \<and> D"
   131   apply (reflection Ifm.simps only: "B \<or> C \<and> (B \<longrightarrow> A \<or> D)")
   131   apply (reflection Ifm.simps only: "B \<or> C \<and> (B \<longrightarrow> A \<or> D)")
   132 oops
   132 oops
   133 
   133 
   134 
   134 
   135 text {* Example 2: Simple arithmetic formulae *}
   135 text \<open>Example 2: Simple arithmetic formulae\<close>
   136 
   136 
   137 text {* The type @{text num} reflects linear expressions over natural number *}
   137 text \<open>The type @{text num} reflects linear expressions over natural number\<close>
   138 datatype num = C nat | Add num num | Mul nat num | Var nat | CN nat nat num
   138 datatype num = C nat | Add num num | Mul nat num | Var nat | CN nat nat num
   139 
   139 
   140 text {* This is just technical to make recursive definitions easier. *}
   140 text \<open>This is just technical to make recursive definitions easier.\<close>
   141 primrec num_size :: "num \<Rightarrow> nat" 
   141 primrec num_size :: "num \<Rightarrow> nat" 
   142 where
   142 where
   143   "num_size (C c) = 1"
   143   "num_size (C c) = 1"
   144 | "num_size (Var n) = 1"
   144 | "num_size (Var n) = 1"
   145 | "num_size (Add a b) = 1 + num_size a + num_size b"
   145 | "num_size (Add a b) = 1 + num_size a + num_size b"
   146 | "num_size (Mul c a) = 1 + num_size a"
   146 | "num_size (Mul c a) = 1 + num_size a"
   147 | "num_size (CN n c a) = 4 + num_size a "
   147 | "num_size (CN n c a) = 4 + num_size a "
   148 
   148 
   149 lemma [measure_function]: "is_measure num_size" ..
   149 lemma [measure_function]: "is_measure num_size" ..
   150 
   150 
   151 text {* The semantics of num *}
   151 text \<open>The semantics of num\<close>
   152 primrec Inum:: "num \<Rightarrow> nat list \<Rightarrow> nat"
   152 primrec Inum:: "num \<Rightarrow> nat list \<Rightarrow> nat"
   153 where
   153 where
   154   Inum_C  : "Inum (C i) vs = i"
   154   Inum_C  : "Inum (C i) vs = i"
   155 | Inum_Var: "Inum (Var n) vs = vs!n"
   155 | Inum_Var: "Inum (Var n) vs = vs!n"
   156 | Inum_Add: "Inum (Add s t) vs = Inum s vs + Inum t vs "
   156 | Inum_Add: "Inum (Add s t) vs = Inum s vs + Inum t vs "
   157 | Inum_Mul: "Inum (Mul c t) vs = c * Inum t vs "
   157 | Inum_Mul: "Inum (Mul c t) vs = c * Inum t vs "
   158 | Inum_CN : "Inum (CN n c t) vs = c*(vs!n) + Inum t vs "
   158 | Inum_CN : "Inum (CN n c t) vs = c*(vs!n) + Inum t vs "
   159 
   159 
   160 text {* Let's reify some nat expressions \dots *}
   160 text \<open>Let's reify some nat expressions \dots\<close>
   161 lemma "4 * (2 * x + (y::nat)) + f a \<noteq> 0"
   161 lemma "4 * (2 * x + (y::nat)) + f a \<noteq> 0"
   162   apply (reify Inum.simps ("4 * (2 * x + (y::nat)) + f a"))
   162   apply (reify Inum.simps ("4 * (2 * x + (y::nat)) + f a"))
   163 oops
   163 oops
   164 text {* We're in a bad situation! @{text x}, @{text y} and @{text f} have been recongnized
   164 text \<open>We're in a bad situation! @{text x}, @{text y} and @{text f} have been recongnized
   165 as constants, which is correct but does not correspond to our intuition of the constructor C.
   165 as constants, which is correct but does not correspond to our intuition of the constructor C.
   166 It should encapsulate constants, i.e. numbers, i.e. numerals. *}
   166 It should encapsulate constants, i.e. numbers, i.e. numerals.\<close>
   167 
   167 
   168 text {* So let's leave the @{text "Inum_C"} equation at the end and see what happens \dots*}
   168 text \<open>So let's leave the @{text "Inum_C"} equation at the end and see what happens \dots\<close>
   169 lemma "4 * (2 * x + (y::nat)) \<noteq> 0"
   169 lemma "4 * (2 * x + (y::nat)) \<noteq> 0"
   170   apply (reify Inum_Var Inum_Add Inum_Mul Inum_CN Inum_C ("4 * (2 * x + (y::nat))"))
   170   apply (reify Inum_Var Inum_Add Inum_Mul Inum_CN Inum_C ("4 * (2 * x + (y::nat))"))
   171 oops
   171 oops
   172 text {* Hm, let's specialize @{text Inum_C} with numerals.*}
   172 text \<open>Hm, let's specialize @{text Inum_C} with numerals.\<close>
   173 
   173 
   174 lemma Inum_number: "Inum (C (numeral t)) vs = numeral t" by simp
   174 lemma Inum_number: "Inum (C (numeral t)) vs = numeral t" by simp
   175 lemmas Inum_eqs = Inum_Var Inum_Add Inum_Mul Inum_CN Inum_number
   175 lemmas Inum_eqs = Inum_Var Inum_Add Inum_Mul Inum_CN Inum_number
   176 
   176 
   177 text {* Second attempt *}
   177 text \<open>Second attempt\<close>
   178 lemma "1 * (2 * x + (y::nat)) \<noteq> 0"
   178 lemma "1 * (2 * x + (y::nat)) \<noteq> 0"
   179   apply (reify Inum_eqs ("1 * (2 * x + (y::nat))"))
   179   apply (reify Inum_eqs ("1 * (2 * x + (y::nat))"))
   180 oops
   180 oops
   181 
   181 
   182 text{* That was fine, so let's try another one \dots *}
   182 text\<open>That was fine, so let's try another one \dots\<close>
   183 
   183 
   184 lemma "1 * (2 * x + (y::nat) + 0 + 1) \<noteq> 0"
   184 lemma "1 * (2 * x + (y::nat) + 0 + 1) \<noteq> 0"
   185   apply (reify Inum_eqs ("1 * (2 * x + (y::nat) + 0 + 1)"))
   185   apply (reify Inum_eqs ("1 * (2 * x + (y::nat) + 0 + 1)"))
   186 oops
   186 oops
   187 
   187 
   188 text {* Oh!! 0 is not a variable \dots\ Oh! 0 is not a @{text "numeral"} \dots\ thing.
   188 text \<open>Oh!! 0 is not a variable \dots\ Oh! 0 is not a @{text "numeral"} \dots\ thing.
   189 The same for 1. So let's add those equations, too. *}
   189 The same for 1. So let's add those equations, too.\<close>
   190 
   190 
   191 lemma Inum_01: "Inum (C 0) vs = 0" "Inum (C 1) vs = 1" "Inum (C(Suc n)) vs = Suc n"
   191 lemma Inum_01: "Inum (C 0) vs = 0" "Inum (C 1) vs = 1" "Inum (C(Suc n)) vs = Suc n"
   192   by simp_all
   192   by simp_all
   193 
   193 
   194 lemmas Inum_eqs'= Inum_eqs Inum_01
   194 lemmas Inum_eqs'= Inum_eqs Inum_01
   195 
   195 
   196 text{* Third attempt: *}
   196 text\<open>Third attempt:\<close>
   197 
   197 
   198 lemma "1 * (2 * x + (y::nat) + 0 + 1) \<noteq> 0"
   198 lemma "1 * (2 * x + (y::nat) + 0 + 1) \<noteq> 0"
   199   apply (reify Inum_eqs' ("1 * (2 * x + (y::nat) + 0 + 1)"))
   199   apply (reify Inum_eqs' ("1 * (2 * x + (y::nat) + 0 + 1)"))
   200 oops
   200 oops
   201 
   201 
   202 text {* Okay, let's try reflection. Some simplifications on @{typ num} follow. You can
   202 text \<open>Okay, let's try reflection. Some simplifications on @{typ num} follow. You can
   203   skim until the main theorem @{text linum}. *}
   203   skim until the main theorem @{text linum}.\<close>
   204   
   204   
   205 fun lin_add :: "num \<Rightarrow> num \<Rightarrow> num"
   205 fun lin_add :: "num \<Rightarrow> num \<Rightarrow> num"
   206 where
   206 where
   207   "lin_add (CN n1 c1 r1) (CN n2 c2 r2) =
   207   "lin_add (CN n1 c1 r1) (CN n2 c2 r2) =
   208     (if n1 = n2 then 
   208     (if n1 = n2 then 
   242 
   242 
   243 lemma linum [reflection]:
   243 lemma linum [reflection]:
   244   "Inum (linum t) bs = Inum t bs"
   244   "Inum (linum t) bs = Inum t bs"
   245   by (induct t rule: linum.induct) (simp_all add: lin_mul lin_add)
   245   by (induct t rule: linum.induct) (simp_all add: lin_mul lin_add)
   246 
   246 
   247 text {* Now we can use linum to simplify nat terms using reflection *}
   247 text \<open>Now we can use linum to simplify nat terms using reflection\<close>
   248 
   248 
   249 lemma "Suc (Suc 1) * (x + Suc 1 * y) = 3 * x + 6 * y"
   249 lemma "Suc (Suc 1) * (x + Suc 1 * y) = 3 * x + 6 * y"
   250   apply (reflection Inum_eqs' only: "Suc (Suc 1) * (x + Suc 1 * y)")
   250   apply (reflection Inum_eqs' only: "Suc (Suc 1) * (x + Suc 1 * y)")
   251 oops
   251 oops
   252 
   252 
   253 text {* Let's lift this to formulae and see what happens *}
   253 text \<open>Let's lift this to formulae and see what happens\<close>
   254 
   254 
   255 datatype aform = Lt num num  | Eq num num | Ge num num | NEq num num | 
   255 datatype aform = Lt num num  | Eq num num | Ge num num | NEq num num | 
   256   Conj aform aform | Disj aform aform | NEG aform | T | F
   256   Conj aform aform | Disj aform aform | NEG aform | T | F
   257 
   257 
   258 primrec linaformsize:: "aform \<Rightarrow> nat"
   258 primrec linaformsize:: "aform \<Rightarrow> nat"
   279 | "is_aform (NEq a b) vs = (Inum a vs \<noteq> Inum b vs)"
   279 | "is_aform (NEq a b) vs = (Inum a vs \<noteq> Inum b vs)"
   280 | "is_aform (NEG p) vs = (\<not> (is_aform p vs))"
   280 | "is_aform (NEG p) vs = (\<not> (is_aform p vs))"
   281 | "is_aform (Conj p q) vs = (is_aform p vs \<and> is_aform q vs)"
   281 | "is_aform (Conj p q) vs = (is_aform p vs \<and> is_aform q vs)"
   282 | "is_aform (Disj p q) vs = (is_aform p vs \<or> is_aform q vs)"
   282 | "is_aform (Disj p q) vs = (is_aform p vs \<or> is_aform q vs)"
   283 
   283 
   284 text{* Let's reify and do reflection *}
   284 text\<open>Let's reify and do reflection\<close>
   285 lemma "(3::nat) * x + t < 0 \<and> (2 * x + y \<noteq> 17)"
   285 lemma "(3::nat) * x + t < 0 \<and> (2 * x + y \<noteq> 17)"
   286   apply (reify Inum_eqs' is_aform.simps) 
   286   apply (reify Inum_eqs' is_aform.simps) 
   287 oops
   287 oops
   288 
   288 
   289 text {* Note that reification handles several interpretations at the same time*}
   289 text \<open>Note that reification handles several interpretations at the same time\<close>
   290 lemma "(3::nat) * x + t < 0 \<and> x * x + t * x + 3 + 1 = z * t * 4 * z \<or> x + x + 1 < 0"
   290 lemma "(3::nat) * x + t < 0 \<and> x * x + t * x + 3 + 1 = z * t * 4 * z \<or> x + x + 1 < 0"
   291   apply (reflection Inum_eqs' is_aform.simps only: "x + x + 1") 
   291   apply (reflection Inum_eqs' is_aform.simps only: "x + x + 1") 
   292 oops
   292 oops
   293 
   293 
   294 text {* For reflection we now define a simple transformation on aform: NNF + linum on atoms *}
   294 text \<open>For reflection we now define a simple transformation on aform: NNF + linum on atoms\<close>
   295 
   295 
   296 fun linaform:: "aform \<Rightarrow> aform"
   296 fun linaform:: "aform \<Rightarrow> aform"
   297 where
   297 where
   298   "linaform (Lt s t) = Lt (linum s) (linum t)"
   298   "linaform (Lt s t) = Lt (linum s) (linum t)"
   299 | "linaform (Eq s t) = Eq (linum s) (linum t)"
   299 | "linaform (Eq s t) = Eq (linum s) (linum t)"
   325 lemma "(Suc (Suc (Suc 0)) * ((x::nat) + Suc (Suc 0)) + Suc (Suc (Suc 0)) *
   325 lemma "(Suc (Suc (Suc 0)) * ((x::nat) + Suc (Suc 0)) + Suc (Suc (Suc 0)) *
   326   (Suc (Suc (Suc 0))) * ((x::nat) + Suc (Suc 0))) < 0 \<and> Suc 0 + Suc 0 < 0"
   326   (Suc (Suc (Suc 0))) * ((x::nat) + Suc (Suc 0))) < 0 \<and> Suc 0 + Suc 0 < 0"
   327   apply (reflection Inum_eqs' is_aform.simps)
   327   apply (reflection Inum_eqs' is_aform.simps)
   328 oops
   328 oops
   329 
   329 
   330 text {* We now give an example where interpretaions have zero or more than only
   330 text \<open>We now give an example where interpretaions have zero or more than only
   331   one envornement of different types and show that automatic reification also deals with
   331   one envornement of different types and show that automatic reification also deals with
   332   bindings *}
   332   bindings\<close>
   333   
   333   
   334 datatype rb = BC bool | BAnd rb rb | BOr rb rb
   334 datatype rb = BC bool | BAnd rb rb | BOr rb rb
   335 
   335 
   336 primrec Irb :: "rb \<Rightarrow> bool"
   336 primrec Irb :: "rb \<Rightarrow> bool"
   337 where
   337 where
   447 
   447 
   448 lemma " \<forall>x. \<exists>n. ((Suc n) * length (([(3::int) * x + f t * y - 9 + (- z)] @ []) @ xs) = length xs) \<and> m < 5*n - length (xs @ [2,3,4,x*z + 8 - y]) \<longrightarrow> (\<exists>p. \<forall>q. p \<and> q \<longrightarrow> r)"
   448 lemma " \<forall>x. \<exists>n. ((Suc n) * length (([(3::int) * x + f t * y - 9 + (- z)] @ []) @ xs) = length xs) \<and> m < 5*n - length (xs @ [2,3,4,x*z + 8 - y]) \<longrightarrow> (\<exists>p. \<forall>q. p \<and> q \<longrightarrow> r)"
   449   apply (reify Irifm.simps Irnat_simps Irlist.simps Irint_simps)
   449   apply (reify Irifm.simps Irnat_simps Irlist.simps Irint_simps)
   450 oops
   450 oops
   451 
   451 
   452 text {* An example for equations containing type variables *}
   452 text \<open>An example for equations containing type variables\<close>
   453 
   453 
   454 datatype prod = Zero | One | Var nat | Mul prod prod 
   454 datatype prod = Zero | One | Var nat | Mul prod prod 
   455   | Pw prod nat | PNM nat nat prod
   455   | Pw prod nat | PNM nat nat prod
   456 
   456 
   457 primrec Iprod :: " prod \<Rightarrow> ('a::linordered_idom) list \<Rightarrow>'a" 
   457 primrec Iprod :: " prod \<Rightarrow> ('a::linordered_idom) list \<Rightarrow>'a"