thys/LexerExt.thy
changeset 223 17c079699ea0
parent 222 4c02878e2fe0
child 224 624b4154325b
equal deleted inserted replaced
222:4c02878e2fe0 223:17c079699ea0
   157 | SEQ rexp rexp
   157 | SEQ rexp rexp
   158 | ALT rexp rexp
   158 | ALT rexp rexp
   159 | STAR rexp
   159 | STAR rexp
   160 | UPNTIMES rexp nat
   160 | UPNTIMES rexp nat
   161 | NTIMES rexp nat
   161 | NTIMES rexp nat
       
   162 | FROMNTIMES rexp nat
   162 
   163 
   163 section {* Semantics of Regular Expressions *}
   164 section {* Semantics of Regular Expressions *}
   164  
   165  
   165 fun
   166 fun
   166   L :: "rexp \<Rightarrow> string set"
   167   L :: "rexp \<Rightarrow> string set"
   171 | "L (SEQ r1 r2) = (L r1) ;; (L r2)"
   172 | "L (SEQ r1 r2) = (L r1) ;; (L r2)"
   172 | "L (ALT r1 r2) = (L r1) \<union> (L r2)"
   173 | "L (ALT r1 r2) = (L r1) \<union> (L r2)"
   173 | "L (STAR r) = (L r)\<star>"
   174 | "L (STAR r) = (L r)\<star>"
   174 | "L (UPNTIMES r n) = (\<Union>i\<in> {..n} . (L r) \<up> i)"
   175 | "L (UPNTIMES r n) = (\<Union>i\<in> {..n} . (L r) \<up> i)"
   175 | "L (NTIMES r n) = ((L r) \<up> n)"
   176 | "L (NTIMES r n) = ((L r) \<up> n)"
   176 
   177 | "L (FROMNTIMES r n) = (\<Union>i\<in> {n..} . (L r) \<up> i)"
   177 
   178 
   178 section {* Nullable, Derivatives *}
   179 section {* Nullable, Derivatives *}
   179 
   180 
   180 fun
   181 fun
   181  nullable :: "rexp \<Rightarrow> bool"
   182  nullable :: "rexp \<Rightarrow> bool"
   186 | "nullable (ALT r1 r2) = (nullable r1 \<or> nullable r2)"
   187 | "nullable (ALT r1 r2) = (nullable r1 \<or> nullable r2)"
   187 | "nullable (SEQ r1 r2) = (nullable r1 \<and> nullable r2)"
   188 | "nullable (SEQ r1 r2) = (nullable r1 \<and> nullable r2)"
   188 | "nullable (STAR r) = True"
   189 | "nullable (STAR r) = True"
   189 | "nullable (UPNTIMES r n) = True"
   190 | "nullable (UPNTIMES r n) = True"
   190 | "nullable (NTIMES r n) = (if n = 0 then True else nullable r)"
   191 | "nullable (NTIMES r n) = (if n = 0 then True else nullable r)"
       
   192 | "nullable (FROMNTIMES r n) = (if n = 0 then True else nullable r)"
   191 
   193 
   192 fun
   194 fun
   193  der :: "char \<Rightarrow> rexp \<Rightarrow> rexp"
   195  der :: "char \<Rightarrow> rexp \<Rightarrow> rexp"
   194 where
   196 where
   195   "der c (ZERO) = ZERO"
   197   "der c (ZERO) = ZERO"
   203 | "der c (STAR r) = SEQ (der c r) (STAR r)"
   205 | "der c (STAR r) = SEQ (der c r) (STAR r)"
   204 | "der c (UPNTIMES r 0) = ZERO"
   206 | "der c (UPNTIMES r 0) = ZERO"
   205 | "der c (UPNTIMES r (Suc n)) = SEQ (der c r) (UPNTIMES r n)"
   207 | "der c (UPNTIMES r (Suc n)) = SEQ (der c r) (UPNTIMES r n)"
   206 | "der c (NTIMES r 0) = ZERO"
   208 | "der c (NTIMES r 0) = ZERO"
   207 | "der c (NTIMES r (Suc n)) = SEQ (der c r) (NTIMES r n)"
   209 | "der c (NTIMES r (Suc n)) = SEQ (der c r) (NTIMES r n)"
   208 
   210 | "der c (FROMNTIMES r 0) = SEQ (der c r) (STAR r)"
       
   211 | "der c (FROMNTIMES r (Suc n)) = SEQ (der c r) (FROMNTIMES r n)"
   209 
   212 
   210 fun 
   213 fun 
   211  ders :: "string \<Rightarrow> rexp \<Rightarrow> rexp"
   214  ders :: "string \<Rightarrow> rexp \<Rightarrow> rexp"
   212 where
   215 where
   213   "ders [] r = r"
   216   "ders [] r = r"
   304 apply(simp)
   307 apply(simp)
   305 (* NTIMES *)
   308 (* NTIMES *)
   306 apply(simp only: L.simps der.simps)
   309 apply(simp only: L.simps der.simps)
   307 apply(simp)
   310 apply(simp)
   308 apply(rule impI)
   311 apply(rule impI)
   309 by (simp add: Der_Pow_subseteq sup_absorb1)
   312 apply (simp add: Der_Pow_subseteq sup_absorb1)
   310 
   313 (* FROMNTIMES *)
       
   314 apply(simp only: der.simps)
       
   315 apply(simp only: L.simps)
       
   316 apply(subst Der_star[symmetric])
       
   317 apply(subst Star_def2)
       
   318 apply(auto)[1]
       
   319 apply(simp only: der.simps)
       
   320 apply(simp only: L.simps)
       
   321 apply(simp add: Der_UNION)
       
   322 by (smt Der_Pow Der_Pow_notin Der_Pow_subseteq SUP_cong Seq_UNION Suc_reduce_Union2 sup.absorb_iff1)
   311 
   323 
   312 lemma ders_correctness:
   324 lemma ders_correctness:
   313   shows "L (ders s r) = Ders s (L r)"
   325   shows "L (ders s r) = Ders s (L r)"
   314 apply(induct s arbitrary: r)
   326 apply(induct s arbitrary: r)
   315 apply(simp_all add: Ders_def der_correctness Der_def)
   327 apply(simp_all add: Ders_def der_correctness Der_def)
   377  "\<lbrakk>\<turnstile> v1 : r1; \<turnstile> v2 : r2\<rbrakk> \<Longrightarrow> \<turnstile> Seq v1 v2 : SEQ r1 r2"
   389  "\<lbrakk>\<turnstile> v1 : r1; \<turnstile> v2 : r2\<rbrakk> \<Longrightarrow> \<turnstile> Seq v1 v2 : SEQ r1 r2"
   378 | "\<turnstile> v1 : r1 \<Longrightarrow> \<turnstile> Left v1 : ALT r1 r2"
   390 | "\<turnstile> v1 : r1 \<Longrightarrow> \<turnstile> Left v1 : ALT r1 r2"
   379 | "\<turnstile> v2 : r2 \<Longrightarrow> \<turnstile> Right v2 : ALT r1 r2"
   391 | "\<turnstile> v2 : r2 \<Longrightarrow> \<turnstile> Right v2 : ALT r1 r2"
   380 | "\<turnstile> Void : ONE"
   392 | "\<turnstile> Void : ONE"
   381 | "\<turnstile> Char c : CHAR c"
   393 | "\<turnstile> Char c : CHAR c"
   382 | "\<turnstile> Stars [] : STAR r"
   394 | "\<lbrakk>\<forall>v \<in> set vs. \<turnstile> v : r\<rbrakk> \<Longrightarrow> \<turnstile> Stars vs : STAR r"
   383 | "\<lbrakk>\<turnstile> v : r; \<turnstile> Stars vs : STAR r\<rbrakk> \<Longrightarrow> \<turnstile> Stars (v # vs) : STAR r"
   395 | "\<lbrakk>\<forall>v \<in> set vs. \<turnstile> v : r; length vs \<le> n\<rbrakk> \<Longrightarrow> \<turnstile> Stars vs : UPNTIMES r n"
   384 | "\<turnstile> Stars [] : UPNTIMES r 0"
   396 | "\<lbrakk>\<forall>v \<in> set vs. \<turnstile> v : r; length vs = n\<rbrakk> \<Longrightarrow> \<turnstile> Stars vs : NTIMES r n"
   385 | "\<lbrakk>\<turnstile> v : r; \<turnstile> Stars vs : UPNTIMES r n\<rbrakk> \<Longrightarrow> \<turnstile> Stars (v # vs) : UPNTIMES r (Suc n)"
   397 | "\<lbrakk>\<forall>v \<in> set vs. \<turnstile> v : r; length vs \<ge> n\<rbrakk> \<Longrightarrow> \<turnstile> Stars vs : FROMNTIMES r n"
   386 | "\<lbrakk>\<turnstile> Stars vs : UPNTIMES r n\<rbrakk> \<Longrightarrow> \<turnstile> Stars vs : UPNTIMES r (Suc n)"
       
   387 | "\<turnstile> Stars [] : NTIMES r 0"
       
   388 | "\<lbrakk>\<turnstile> v : r; \<turnstile> Stars vs : NTIMES r n\<rbrakk> \<Longrightarrow> \<turnstile> Stars (v # vs) : NTIMES r (Suc n)"
       
   389 
       
   390 
   398 
   391 inductive_cases Prf_elims:
   399 inductive_cases Prf_elims:
   392   "\<turnstile> v : ZERO"
   400   "\<turnstile> v : ZERO"
   393   "\<turnstile> v : SEQ r1 r2"
   401   "\<turnstile> v : SEQ r1 r2"
   394   "\<turnstile> v : ALT r1 r2"
   402   "\<turnstile> v : ALT r1 r2"
   395   "\<turnstile> v : ONE"
   403   "\<turnstile> v : ONE"
   396   "\<turnstile> v : CHAR c"
   404   "\<turnstile> v : CHAR c"
   397 (*  "\<turnstile> vs : STAR r"*)
   405 (*  "\<turnstile> vs : STAR r"*)
   398 
   406 
       
   407 lemma Prf_STAR:
       
   408    assumes "\<forall>v\<in>set vs. \<turnstile> v : r \<and> flat v \<in> L r"  
       
   409    shows "concat (map flat vs) \<in> L r\<star>"
       
   410 using assms 
       
   411 apply(induct vs)
       
   412 apply(auto)
       
   413 done
       
   414 
       
   415 lemma Prf_Pow:
       
   416   assumes "\<forall>v\<in>set vs. \<turnstile> v : r \<and> flat v \<in> L r" 
       
   417   shows "concat (map flat vs) \<in> L r \<up> length vs"
       
   418 using assms
       
   419 apply(induct vs)
       
   420 apply(auto simp add: Sequ_def)
       
   421 done
       
   422 
   399 lemma Prf_flat_L:
   423 lemma Prf_flat_L:
   400   assumes "\<turnstile> v : r" shows "flat v \<in> L r"
   424   assumes "\<turnstile> v : r" shows "flat v \<in> L r"
   401 using assms
   425 using assms
   402 apply(induct v r rule: Prf.induct)
   426 apply(induct v r rule: Prf.induct)
   403 apply(auto simp add: Sequ_def)
   427 apply(auto simp add: Sequ_def)
   404 apply(rotate_tac 2)
   428 apply(rule Prf_STAR)
   405 apply(rule_tac x="Suc x" in bexI)
   429 apply(simp)
   406 apply(auto simp add: Sequ_def)[2]
   430 apply(rule_tac x="length vs" in bexI)
   407 done
   431 apply(rule Prf_Pow)
   408 
   432 apply(simp)
   409 lemma Prf_Stars:
   433 apply(simp)
   410   assumes "\<forall>v \<in> set vs. \<turnstile> v : r"
   434 apply(rule Prf_Pow)
   411   shows "\<turnstile> Stars vs : STAR r"
   435 apply(simp)
   412 using assms
   436 apply(rule_tac x="length vs" in bexI)
   413 by(induct vs) (auto intro: Prf.intros)
   437 apply(rule Prf_Pow)
   414 
   438 apply(simp)
   415 lemma Prf_Stars_NTIMES:
   439 apply(simp)
   416   assumes "\<forall>v \<in> set vs. \<turnstile> v : r" "(length vs) = n"
       
   417   shows "\<turnstile> Stars vs : NTIMES r n"
       
   418 using assms
       
   419 apply(induct vs arbitrary: n) 
       
   420 apply(auto intro: Prf.intros)
       
   421 done
       
   422 
       
   423 lemma Prf_Stars_UPNTIMES:
       
   424   assumes "\<forall>v \<in> set vs. \<turnstile> v : r" "(length vs) = n"
       
   425   shows "\<turnstile> Stars vs : UPNTIMES r n"
       
   426 using assms
       
   427 apply(induct vs arbitrary: n) 
       
   428 apply(auto intro: Prf.intros)
       
   429 done
       
   430 
       
   431 lemma Prf_UPNTIMES_bigger:
       
   432   assumes "\<turnstile> Stars vs : UPNTIMES r n" "n \<le> m" 
       
   433   shows "\<turnstile> Stars vs : UPNTIMES r m"
       
   434 using assms
       
   435 apply(induct m arbitrary:)
       
   436 apply(auto)
       
   437 using Prf.intros(10) le_Suc_eq by blast
       
   438 
       
   439 lemma UPNTIMES_Stars:
       
   440  assumes "\<turnstile> v : UPNTIMES r n"
       
   441  shows "\<exists>vs. v = Stars vs \<and> (\<forall>v \<in> set vs. \<turnstile> v : r) \<and> length vs \<le> n"
       
   442 using assms
       
   443 apply(induct n arbitrary: v)
       
   444 apply(erule Prf.cases)
       
   445 apply(simp_all)
       
   446 apply(erule Prf.cases)
       
   447 apply(simp_all)
       
   448 apply(auto)
       
   449 using le_SucI by blast
       
   450 
       
   451 lemma NTIMES_Stars:
       
   452  assumes "\<turnstile> v : NTIMES r n"
       
   453  shows "\<exists>vs. v = Stars vs \<and> (\<forall>v \<in> set vs. \<turnstile> v : r) \<and> length vs = n"
       
   454 using assms
       
   455 apply(induct n arbitrary: v)
       
   456 apply(erule Prf.cases)
       
   457 apply(simp_all)
       
   458 apply(erule Prf.cases)
       
   459 apply(simp_all)
       
   460 apply(auto)
       
   461 done
   440 done
   462 
   441 
   463 lemma Star_string:
   442 lemma Star_string:
   464   assumes "s \<in> A\<star>"
   443   assumes "s \<in> A\<star>"
   465   shows "\<exists>ss. concat ss = s \<and> (\<forall>s \<in> set ss. s \<in> A)"
   444   shows "\<exists>ss. concat ss = s \<and> (\<forall>s \<in> set ss. s \<in> A)"
   500 apply(auto)
   479 apply(auto)
   501 apply(rule_tac x="s1#ss" in exI)
   480 apply(rule_tac x="s1#ss" in exI)
   502 apply(simp)
   481 apply(simp)
   503 done
   482 done
   504 
   483 
   505 lemma L_flat_Prf1:
       
   506   assumes "\<turnstile> v : r" shows "flat v \<in> L r"
       
   507 using assms
       
   508 apply(induct)
       
   509 apply(auto simp add: Sequ_def)
       
   510 apply(rule_tac x="Suc x" in bexI)
       
   511 apply(auto simp add: Sequ_def)[2]
       
   512 done
       
   513 
   484 
   514 lemma L_flat_Prf2:
   485 lemma L_flat_Prf2:
   515   assumes "s \<in> L r" shows "\<exists>v. \<turnstile> v : r \<and> flat v = s"
   486   assumes "s \<in> L r" shows "\<exists>v. \<turnstile> v : r \<and> flat v = s"
   516 using assms
   487 using assms
   517 apply(induct r arbitrary: s)
   488 apply(induct r arbitrary: s)
   521 using Prf.intros(3) flat.simps(4) apply blast
   492 using Prf.intros(3) flat.simps(4) apply blast
   522 apply(subgoal_tac "\<exists>vs::val list. concat (map flat vs) = s \<and> (\<forall>v \<in> set vs. \<turnstile> v : r)")
   493 apply(subgoal_tac "\<exists>vs::val list. concat (map flat vs) = s \<and> (\<forall>v \<in> set vs. \<turnstile> v : r)")
   523 apply(auto)[1]
   494 apply(auto)[1]
   524 apply(rule_tac x="Stars vs" in exI)
   495 apply(rule_tac x="Stars vs" in exI)
   525 apply(simp)
   496 apply(simp)
   526 apply (simp add: Prf_Stars)
   497 apply(rule Prf.intros)
   527 apply(drule Star_string)
   498 apply(simp)
   528 apply(auto)
   499 using Star_string Star_val apply force
   529 apply(rule Star_val)
       
   530 apply(auto)
       
   531 apply(subgoal_tac "\<exists>vs::val list. concat (map flat vs) = s \<and> (\<forall>v \<in> set vs. \<turnstile> v : r) \<and> (length vs = x)")
   500 apply(subgoal_tac "\<exists>vs::val list. concat (map flat vs) = s \<and> (\<forall>v \<in> set vs. \<turnstile> v : r) \<and> (length vs = x)")
   532 apply(auto)[1]
   501 apply(auto)[1]
   533 apply(rule_tac x="Stars vs" in exI)
   502 apply(rule_tac x="Stars vs" in exI)
   534 apply(simp)
   503 apply(simp)
   535 apply(drule_tac n="length vs" in Prf_Stars_UPNTIMES)
   504 apply(rule Prf.intros)
   536 apply(simp)
   505 apply(simp)
   537 using Prf_UPNTIMES_bigger apply blast
   506 apply(simp)
   538 apply(drule Star_Pow)
   507 using Star_Pow Star_val_length apply blast
   539 apply(auto)
       
   540 using Star_val_length apply blast
       
   541 apply(subgoal_tac "\<exists>vs::val list. concat (map flat vs) = s \<and> (\<forall>v \<in> set vs. \<turnstile> v : r) \<and> (length vs = x2)")
   508 apply(subgoal_tac "\<exists>vs::val list. concat (map flat vs) = s \<and> (\<forall>v \<in> set vs. \<turnstile> v : r) \<and> (length vs = x2)")
   542 apply(auto)[1]
   509 apply(auto)[1]
   543 apply(rule_tac x="Stars vs" in exI)
   510 apply(rule_tac x="Stars vs" in exI)
   544 apply(simp)
   511 apply(simp)
   545 apply(rule Prf_Stars_NTIMES)
   512 apply(rule Prf.intros)
   546 apply(simp)
   513 apply(simp)
   547 apply(simp)
   514 apply(simp)
   548 using Star_Pow Star_val_length by blast
   515 using Star_Pow Star_val_length apply blast
   549 
   516 apply(subgoal_tac "\<exists>vs::val list. concat (map flat vs) = s \<and> (\<forall>v \<in> set vs. \<turnstile> v : r) \<and> (length vs = x)")
       
   517 apply(auto)[1]
       
   518 apply(rule_tac x="Stars vs" in exI)
       
   519 apply(simp)
       
   520 apply(rule Prf.intros)
       
   521 apply(simp)
       
   522 apply(simp)
       
   523 using Star_Pow Star_val_length apply blast
       
   524 done
   550 
   525 
   551 lemma L_flat_Prf:
   526 lemma L_flat_Prf:
   552   "L(r) = {flat v | v. \<turnstile> v : r}"
   527   "L(r) = {flat v | v. \<turnstile> v : r}"
   553 using L_flat_Prf1 L_flat_Prf2 by blast
   528 using Prf_flat_L L_flat_Prf2 by blast
   554 
   529 
   555 
   530 
   556 section {* Sulzmann and Lu functions *}
   531 section {* Sulzmann and Lu functions *}
   557 
   532 
   558 fun 
   533 fun 
   562 | "mkeps(SEQ r1 r2) = Seq (mkeps r1) (mkeps r2)"
   537 | "mkeps(SEQ r1 r2) = Seq (mkeps r1) (mkeps r2)"
   563 | "mkeps(ALT r1 r2) = (if nullable(r1) then Left (mkeps r1) else Right (mkeps r2))"
   538 | "mkeps(ALT r1 r2) = (if nullable(r1) then Left (mkeps r1) else Right (mkeps r2))"
   564 | "mkeps(STAR r) = Stars []"
   539 | "mkeps(STAR r) = Stars []"
   565 | "mkeps(UPNTIMES r n) = Stars []"
   540 | "mkeps(UPNTIMES r n) = Stars []"
   566 | "mkeps(NTIMES r n) = Stars (replicate n (mkeps r))"
   541 | "mkeps(NTIMES r n) = Stars (replicate n (mkeps r))"
   567 
   542 | "mkeps(FROMNTIMES r n) = Stars (replicate n (mkeps r))"
   568 
   543 
   569 fun injval :: "rexp \<Rightarrow> char \<Rightarrow> val \<Rightarrow> val"
   544 fun injval :: "rexp \<Rightarrow> char \<Rightarrow> val \<Rightarrow> val"
   570 where
   545 where
   571   "injval (CHAR d) c Void = Char d"
   546   "injval (CHAR d) c Void = Char d"
   572 | "injval (ALT r1 r2) c (Left v1) = Left(injval r1 c v1)"
   547 | "injval (ALT r1 r2) c (Left v1) = Left(injval r1 c v1)"
   575 | "injval (SEQ r1 r2) c (Left (Seq v1 v2)) = Seq (injval r1 c v1) v2"
   550 | "injval (SEQ r1 r2) c (Left (Seq v1 v2)) = Seq (injval r1 c v1) v2"
   576 | "injval (SEQ r1 r2) c (Right v2) = Seq (mkeps r1) (injval r2 c v2)"
   551 | "injval (SEQ r1 r2) c (Right v2) = Seq (mkeps r1) (injval r2 c v2)"
   577 | "injval (STAR r) c (Seq v (Stars vs)) = Stars ((injval r c v) # vs)" 
   552 | "injval (STAR r) c (Seq v (Stars vs)) = Stars ((injval r c v) # vs)" 
   578 | "injval (UPNTIMES r n) c (Seq v (Stars vs)) = Stars ((injval r c v) # vs)"
   553 | "injval (UPNTIMES r n) c (Seq v (Stars vs)) = Stars ((injval r c v) # vs)"
   579 | "injval (NTIMES r n) c (Seq v (Stars vs)) = Stars ((injval r c v) # vs)"
   554 | "injval (NTIMES r n) c (Seq v (Stars vs)) = Stars ((injval r c v) # vs)"
   580 
   555 | "injval (FROMNTIMES r n) c (Seq v (Stars vs)) = Stars ((injval r c v) # vs)"
   581 
   556 
   582 section {* Mkeps, injval *}
   557 section {* Mkeps, injval *}
   583 
   558 
   584 lemma mkeps_nullable:
   559 lemma mkeps_nullable:
   585   assumes "nullable(r)" 
   560   assumes "nullable(r)" 
   586   shows "\<turnstile> mkeps r : r"
   561   shows "\<turnstile> mkeps r : r"
   587 using assms
   562 using assms
   588 apply(induct r rule: mkeps.induct) 
   563 apply(induct r rule: mkeps.induct) 
   589 apply(auto intro: Prf.intros)
   564 apply(auto intro: Prf.intros)
   590 using Prf.intros(8) Prf_UPNTIMES_bigger apply blast
       
   591 apply(case_tac n)
       
   592 apply(auto)
       
   593 apply(rule Prf.intros)
       
   594 apply(rule Prf_Stars_NTIMES)
       
   595 apply(simp)
       
   596 apply(simp)
       
   597 done
   565 done
   598 
   566 
   599 lemma mkeps_flat:
   567 lemma mkeps_flat:
   600   assumes "nullable(r)" 
   568   assumes "nullable(r)" 
   601   shows "flat (mkeps r) = []"
   569   shows "flat (mkeps r) = []"
   610 apply(induct r arbitrary: c v rule: rexp.induct)
   578 apply(induct r arbitrary: c v rule: rexp.induct)
   611 apply(auto intro!: Prf.intros mkeps_nullable elim!: Prf_elims split: if_splits)
   579 apply(auto intro!: Prf.intros mkeps_nullable elim!: Prf_elims split: if_splits)
   612 (* STAR *)
   580 (* STAR *)
   613 apply(rotate_tac 2)
   581 apply(rotate_tac 2)
   614 apply(erule Prf.cases)
   582 apply(erule Prf.cases)
   615 apply(simp_all)[7]
   583 apply(simp_all)
   616 apply(auto)
   584 apply(auto)
   617 apply (metis Prf.intros(6) Prf.intros(7))
   585 using Prf.intros(6) apply auto[1]
   618 apply (metis Prf.intros(7))
       
   619 (* UPNTIMES *)
   586 (* UPNTIMES *)
   620 apply(case_tac x2)
   587 apply(case_tac x2)
   621 apply(simp)
   588 apply(simp)
   622 using Prf_elims(1) apply auto[1]
   589 using Prf_elims(1) apply auto[1]
   623 apply(simp)
   590 apply(simp)
   624 apply(erule Prf.cases)
   591 apply(erule Prf.cases)
   625 apply(simp_all)
   592 apply(simp_all)
   626 apply(clarify)
   593 apply(clarify)
   627 apply(drule UPNTIMES_Stars)
   594 apply(rotate_tac 2)
       
   595 apply(erule Prf.cases)
       
   596 apply(simp_all)
   628 apply(clarify)
   597 apply(clarify)
   629 apply(simp)
   598 using Prf.intros(7) apply auto[1]
   630 apply(rule Prf.intros(9))
       
   631 apply(simp)
       
   632 using Prf_Stars_UPNTIMES Prf_UPNTIMES_bigger apply blast
       
   633 (* NTIMES *)
   599 (* NTIMES *)
   634 apply(case_tac x2)
   600 apply(case_tac x2)
   635 apply(simp)
   601 apply(simp)
   636 using Prf_elims(1) apply auto[1]
   602 using Prf_elims(1) apply auto[1]
   637 apply(simp)
   603 apply(simp)
   638 apply(erule Prf.cases)
   604 apply(erule Prf.cases)
   639 apply(simp_all)
   605 apply(simp_all)
   640 apply(clarify)
   606 apply(clarify)
   641 apply(drule NTIMES_Stars)
   607 apply(rotate_tac 2)
       
   608 apply(erule Prf.cases)
       
   609 apply(simp_all)
   642 apply(clarify)
   610 apply(clarify)
   643 apply(simp)
   611 using Prf.intros(8) apply auto[1]
   644 apply(rule Prf.intros)
   612 (* FROMNTIMES *)
   645 apply(simp)
   613 apply(case_tac x2)
   646 using Prf_Stars_NTIMES by blast
   614 apply(simp)
       
   615 apply(erule Prf.cases)
       
   616 apply(simp_all)
       
   617 apply(clarify)
       
   618 apply(rotate_tac 2)
       
   619 apply(erule Prf.cases)
       
   620 apply(simp_all)
       
   621 apply(clarify)
       
   622 using Prf.intros(9) apply auto[1]
       
   623 apply(rotate_tac 1)
       
   624 apply(erule Prf.cases)
       
   625 apply(simp_all)
       
   626 apply(clarify)
       
   627 apply(rotate_tac 2)
       
   628 apply(erule Prf.cases)
       
   629 apply(simp_all)
       
   630 apply(clarify)
       
   631 using Prf.intros(9) by auto
       
   632 
   647 
   633 
   648 lemma Prf_injval_flat:
   634 lemma Prf_injval_flat:
   649   assumes "\<turnstile> v : der c r" 
   635   assumes "\<turnstile> v : der c r" 
   650   shows "flat (injval r c v) = c # (flat v)"
   636   shows "flat (injval r c v) = c # (flat v)"
   651 using assms
   637 using assms
   653 apply(auto elim!: Prf_elims split: if_splits)
   639 apply(auto elim!: Prf_elims split: if_splits)
   654 apply(metis mkeps_flat)
   640 apply(metis mkeps_flat)
   655 apply(rotate_tac 2)
   641 apply(rotate_tac 2)
   656 apply(erule Prf.cases)
   642 apply(erule Prf.cases)
   657 apply(simp_all)
   643 apply(simp_all)
   658 apply(drule UPNTIMES_Stars)
   644 apply(rotate_tac 2)
   659 apply(clarify)
   645 apply(erule Prf.cases)
   660 apply(simp)
   646 apply(simp_all)
   661 apply(drule NTIMES_Stars)
   647 apply(rotate_tac 2)
   662 apply(clarify)
   648 apply(erule Prf.cases)
   663 apply(simp)
   649 apply(simp_all)
   664 done
   650 apply(rotate_tac 2)
   665 
   651 apply(erule Prf.cases)
       
   652 apply(simp_all)
       
   653 apply(rotate_tac 2)
       
   654 apply(erule Prf.cases)
       
   655 apply(simp_all)
       
   656 done
   666 
   657 
   667 
   658 
   668 section {* Our Alternative Posix definition *}
   659 section {* Our Alternative Posix definition *}
   669 
   660 
   670 inductive 
   661 inductive 
   687 | Posix_UPNTIMES2: "[] \<in> UPNTIMES r n \<rightarrow> Stars []"
   678 | Posix_UPNTIMES2: "[] \<in> UPNTIMES r n \<rightarrow> Stars []"
   688 | Posix_NTIMES1: "\<lbrakk>s1 \<in> r \<rightarrow> v; s2 \<in> NTIMES r n \<rightarrow> Stars vs; 
   679 | Posix_NTIMES1: "\<lbrakk>s1 \<in> r \<rightarrow> v; s2 \<in> NTIMES r n \<rightarrow> Stars vs; 
   689     \<not>(\<exists>s\<^sub>3 s\<^sub>4. s\<^sub>3 \<noteq> [] \<and> s\<^sub>3 @ s\<^sub>4 = s2 \<and> (s1 @ s\<^sub>3) \<in> L r \<and> s\<^sub>4 \<in> L (NTIMES r n))\<rbrakk>
   680     \<not>(\<exists>s\<^sub>3 s\<^sub>4. s\<^sub>3 \<noteq> [] \<and> s\<^sub>3 @ s\<^sub>4 = s2 \<and> (s1 @ s\<^sub>3) \<in> L r \<and> s\<^sub>4 \<in> L (NTIMES r n))\<rbrakk>
   690     \<Longrightarrow> (s1 @ s2) \<in> NTIMES r (Suc n) \<rightarrow> Stars (v # vs)"
   681     \<Longrightarrow> (s1 @ s2) \<in> NTIMES r (Suc n) \<rightarrow> Stars (v # vs)"
   691 | Posix_NTIMES2: "[] \<in> NTIMES r 0 \<rightarrow> Stars []"
   682 | Posix_NTIMES2: "[] \<in> NTIMES r 0 \<rightarrow> Stars []"
   692 
   683 | Posix_FROMNTIMES1: "\<lbrakk>s1 \<in> r \<rightarrow> v; s2 \<in> FROMNTIMES r n \<rightarrow> Stars vs;
       
   684     \<not>(\<exists>s\<^sub>3 s\<^sub>4. s\<^sub>3 \<noteq> [] \<and> s\<^sub>3 @ s\<^sub>4 = s2 \<and> (s1 @ s\<^sub>3) \<in> L r \<and> s\<^sub>4 \<in> L (FROMNTIMES r n))\<rbrakk>
       
   685     \<Longrightarrow> (s1 @ s2) \<in> FROMNTIMES r (Suc n) \<rightarrow> Stars (v # vs)"
       
   686 | Posix_FROMNTIMES2: "[] \<in> FROMNTIMES r 0 \<rightarrow> Stars []"
   693 
   687 
   694 inductive_cases Posix_elims:
   688 inductive_cases Posix_elims:
   695   "s \<in> ZERO \<rightarrow> v"
   689   "s \<in> ZERO \<rightarrow> v"
   696   "s \<in> ONE \<rightarrow> v"
   690   "s \<in> ONE \<rightarrow> v"
   697   "s \<in> CHAR c \<rightarrow> v"
   691   "s \<in> CHAR c \<rightarrow> v"
   705 using assms
   699 using assms
   706 apply (induct s r v rule: Posix.induct)
   700 apply (induct s r v rule: Posix.induct)
   707 apply(auto simp add: Sequ_def)
   701 apply(auto simp add: Sequ_def)
   708 apply(rule_tac x="Suc x" in bexI)
   702 apply(rule_tac x="Suc x" in bexI)
   709 apply(auto simp add: Sequ_def)
   703 apply(auto simp add: Sequ_def)
       
   704 apply(rule_tac x="Suc x" in bexI)
       
   705 apply(auto simp add: Sequ_def)
   710 done
   706 done
   711 
   707 
   712 
   708 
   713 lemma Posix1a:
   709 lemma Posix1a:
   714   assumes "s \<in> r \<rightarrow> v"
   710   assumes "s \<in> r \<rightarrow> v"
   715   shows "\<turnstile> v : r"
   711   shows "\<turnstile> v : r"
   716 using assms
   712 using assms
   717 apply(induct s r v rule: Posix.induct)
   713 apply(induct s r v rule: Posix.induct)
   718 apply(auto intro: Prf.intros)
   714 apply(auto intro: Prf.intros)
   719 using Prf.intros(8) Prf_UPNTIMES_bigger by blast
   715 apply(rule Prf.intros)
   720 
   716 apply(auto)[1]
   721 lemma Posix_NTIMES_length:
   717 apply(rotate_tac 3)
   722   assumes "s \<in> NTIMES r n \<rightarrow> Stars vs"
   718 apply(erule Prf.cases)
   723   shows "length vs = n"
   719 apply(simp_all)
   724 using assms
   720 apply(rule Prf.intros)
   725 using NTIMES_Stars Posix1a val.inject(5) by blast
   721 apply(auto)[1]
   726 
   722 apply(rotate_tac 3)
   727 lemma Posix_UPNTIMES_length:
   723 apply(erule Prf.cases)
   728   assumes "s \<in> UPNTIMES r n \<rightarrow> Stars vs"
   724 apply(simp_all)
   729   shows "length vs \<le> n"
   725 apply (smt Posix_UPNTIMES2 Posix_elims(2) Prf.simps le_0_eq le_Suc_eq length_0_conv nat_induct nullable.simps(3) nullable.simps(7) rexp.distinct(61) rexp.distinct(67) rexp.distinct(69) rexp.inject(5) val.inject(5) val.simps(29) val.simps(33) val.simps(35))
   730 using assms
   726 apply(rule Prf.intros)
   731 using Posix1a UPNTIMES_Stars val.inject(5) by blast
   727 apply(auto)[1]
   732 
   728 apply(rotate_tac 3)
       
   729 apply(erule Prf.cases)
       
   730 apply(simp_all)
       
   731 apply (smt Prf.simps rexp.distinct(63) rexp.distinct(67) rexp.distinct(71) rexp.inject(6) val.distinct(17) val.distinct(9) val.inject(5) val.simps(29) val.simps(33) val.simps(35))
       
   732 apply(rule Prf.intros)
       
   733 apply(auto)[1]
       
   734 apply(rotate_tac 3)
       
   735 apply(erule Prf.cases)
       
   736 apply(simp_all)
       
   737 using Prf.simps by blast
   733 
   738 
   734 lemma  Posix_NTIMES_mkeps:
   739 lemma  Posix_NTIMES_mkeps:
   735   assumes "[] \<in> r \<rightarrow> mkeps r"
   740   assumes "[] \<in> r \<rightarrow> mkeps r"
   736   shows "[] \<in> NTIMES r n \<rightarrow> Stars (replicate n (mkeps r))"
   741   shows "[] \<in> NTIMES r n \<rightarrow> Stars (replicate n (mkeps r))"
   737 apply(induct n)
   742 apply(induct n)
   741 apply(subst append_Nil[symmetric])
   746 apply(subst append_Nil[symmetric])
   742 apply (rule Posix_NTIMES1)
   747 apply (rule Posix_NTIMES1)
   743 apply(auto)
   748 apply(auto)
   744 apply(rule assms)
   749 apply(rule assms)
   745 done
   750 done
       
   751 
       
   752 lemma  Posix_FROMNTIMES_mkeps:
       
   753   assumes "[] \<in> r \<rightarrow> mkeps r"
       
   754   shows "[] \<in> FROMNTIMES r n \<rightarrow> Stars (replicate n (mkeps r))"
       
   755 apply(induct n)
       
   756 apply(simp)
       
   757 apply (rule Posix_FROMNTIMES2)
       
   758 apply(simp)
       
   759 apply(subst append_Nil[symmetric])
       
   760 apply (rule Posix_FROMNTIMES1)
       
   761 apply(auto)
       
   762 apply(rule assms)
       
   763 done
       
   764 
   746 
   765 
   747 lemma Posix_mkeps:
   766 lemma Posix_mkeps:
   748   assumes "nullable r"
   767   assumes "nullable r"
   749   shows "[] \<in> r \<rightarrow> mkeps r"
   768   shows "[] \<in> r \<rightarrow> mkeps r"
   750 using assms
   769 using assms
   754 apply(rule Posix.intros)
   773 apply(rule Posix.intros)
   755 apply(auto)
   774 apply(auto)
   756 apply(case_tac n)
   775 apply(case_tac n)
   757 apply(simp)
   776 apply(simp)
   758 apply (simp add: Posix_NTIMES2)
   777 apply (simp add: Posix_NTIMES2)
       
   778 apply(simp)
       
   779 apply(subst append.simps(1)[symmetric])
       
   780 apply(rule Posix.intros)
       
   781 apply(auto)
   759 apply(rule Posix_NTIMES_mkeps)
   782 apply(rule Posix_NTIMES_mkeps)
       
   783 apply(simp)
       
   784 apply(case_tac n)
       
   785 apply(simp)
       
   786 apply (simp add: Posix_FROMNTIMES2)
       
   787 apply(simp)
       
   788 apply(subst append.simps(1)[symmetric])
       
   789 apply(rule Posix.intros)
       
   790 apply(auto)
       
   791 apply(rule Posix_FROMNTIMES_mkeps)
   760 apply(simp)
   792 apply(simp)
   761 done
   793 done
   762 
   794 
   763 
   795 
   764 lemma Posix_determ:
   796 lemma Posix_determ:
   859   done  
   891   done  
   860   moreover
   892   moreover
   861   have IHs: "\<And>v2. s1 \<in> r \<rightarrow> v2 \<Longrightarrow> v = v2"
   893   have IHs: "\<And>v2. s1 \<in> r \<rightarrow> v2 \<Longrightarrow> v = v2"
   862             "\<And>v2. s2 \<in> NTIMES r n \<rightarrow> v2 \<Longrightarrow> Stars vs = v2" by fact+
   894             "\<And>v2. s2 \<in> NTIMES r n \<rightarrow> v2 \<Longrightarrow> Stars vs = v2" by fact+
   863   ultimately show "Stars (v # vs) = v2" by auto
   895   ultimately show "Stars (v # vs) = v2" by auto
       
   896 next
       
   897   case (Posix_FROMNTIMES2 r v2)
       
   898   have "[] \<in> FROMNTIMES r 0 \<rightarrow> v2" by fact
       
   899   then show "Stars [] = v2" by cases (auto simp add: Posix1)
       
   900 next
       
   901   case (Posix_FROMNTIMES1 s1 r v s2 n vs v2)
       
   902   have "(s1 @ s2) \<in> FROMNTIMES r (Suc n) \<rightarrow> v2" 
       
   903        "s1 \<in> r \<rightarrow> v" "s2 \<in> (FROMNTIMES r n) \<rightarrow> Stars vs"
       
   904        "\<not> (\<exists>s\<^sub>3 s\<^sub>4. s\<^sub>3 \<noteq> [] \<and> s\<^sub>3 @ s\<^sub>4 = s2 \<and> s1 @ s\<^sub>3 \<in> L r \<and> s\<^sub>4 \<in> L (FROMNTIMES r n))" by fact+
       
   905   then obtain v' vs' where "v2 = Stars (v' # vs')" "s1 \<in> r \<rightarrow> v'" "s2 \<in> (FROMNTIMES r n) \<rightarrow> (Stars vs')"
       
   906   apply(cases) apply (auto simp add: append_eq_append_conv2)
       
   907   using Posix1(1) apply fastforce
       
   908   by (metis Posix1(1) Posix_FROMNTIMES1.hyps(5) append_Nil2 self_append_conv2)
       
   909   moreover
       
   910   have IHs: "\<And>v2. s1 \<in> r \<rightarrow> v2 \<Longrightarrow> v = v2"
       
   911             "\<And>v2. s2 \<in> FROMNTIMES r n \<rightarrow> v2 \<Longrightarrow> Stars vs = v2" by fact+
       
   912   ultimately show "Stars (v # vs) = v2" by auto
   864 qed
   913 qed
       
   914 
       
   915 lemma NTIMES_Stars:
       
   916  assumes "\<turnstile> v : NTIMES r n"
       
   917  shows "\<exists>vs. v = Stars vs \<and> (\<forall>v \<in> set vs. \<turnstile> v : r) \<and> length vs = n"
       
   918 using assms
       
   919 apply(induct n arbitrary: v)
       
   920 apply(erule Prf.cases)
       
   921 apply(simp_all)
       
   922 apply(erule Prf.cases)
       
   923 apply(simp_all)
       
   924 done
       
   925 
       
   926 lemma UPNTIMES_Stars:
       
   927  assumes "\<turnstile> v : UPNTIMES r n"
       
   928  shows "\<exists>vs. v = Stars vs \<and> (\<forall>v \<in> set vs. \<turnstile> v : r) \<and> length vs \<le> n"
       
   929 using assms
       
   930 apply(induct n arbitrary: v)
       
   931 apply(erule Prf.cases)
       
   932 apply(simp_all)
       
   933 apply(erule Prf.cases)
       
   934 apply(simp_all)
       
   935 done
       
   936 
       
   937 lemma FROMNTIMES_Stars:
       
   938  assumes "\<turnstile> v : FROMNTIMES r n"
       
   939  shows "\<exists>vs. v = Stars vs \<and> (\<forall>v \<in> set vs. \<turnstile> v : r) \<and> n \<le> length vs"
       
   940 using assms
       
   941 apply(induct n arbitrary: v)
       
   942 apply(erule Prf.cases)
       
   943 apply(simp_all)
       
   944 apply(erule Prf.cases)
       
   945 apply(simp_all)
       
   946 done
   865 
   947 
   866 
   948 
   867 lemma Posix_injval:
   949 lemma Posix_injval:
   868   assumes "s \<in> (der c r) \<rightarrow> v"
   950   assumes "s \<in> (der c r) \<rightarrow> v"
   869   shows "(c # s) \<in> r \<rightarrow> (injval r c v)"
   951   shows "(c # s) \<in> r \<rightarrow> (injval r c v)"
  1023         "\<not> (\<exists>s\<^sub>3 s\<^sub>4. s\<^sub>3 \<noteq> [] \<and> s\<^sub>3 @ s\<^sub>4 = s2 \<and> s1 @ s\<^sub>3 \<in> L (der c r) \<and> s\<^sub>4 \<in> L (UPNTIMES r m))" 
  1105         "\<not> (\<exists>s\<^sub>3 s\<^sub>4. s\<^sub>3 \<noteq> [] \<and> s\<^sub>3 @ s\<^sub>4 = s2 \<and> s1 @ s\<^sub>3 \<in> L (der c r) \<and> s\<^sub>4 \<in> L (UPNTIMES r m))" 
  1024         apply(case_tac n)
  1106         apply(case_tac n)
  1025         apply(simp)
  1107         apply(simp)
  1026         using Posix_elims(1) apply blast
  1108         using Posix_elims(1) apply blast
  1027         apply(simp)
  1109         apply(simp)
  1028         apply(auto elim!: Posix_elims(1-5) simp add: der_correctness Der_def intro: Posix.intros)
  1110         apply(auto elim!: Posix_elims(1-5) simp add: der_correctness Der_def intro: Posix.intros)        
  1029         by (metis Posix1a UPNTIMES_Stars)
  1111         by (metis Posix1a UPNTIMES_Stars)
  1030     then show "(c # s) \<in> UPNTIMES r n \<rightarrow> injval (UPNTIMES r n) c v" 
  1112     then show "(c # s) \<in> UPNTIMES r n \<rightarrow> injval (UPNTIMES r n) c v" 
  1031     proof (cases)
  1113     proof (cases)
  1032       case cons
  1114       case cons
  1033         have "n = Suc m" by fact
  1115         have "n = Suc m" by fact
  1085           apply(rule_tac Posix.intros(10))
  1167           apply(rule_tac Posix.intros(10))
  1086           apply(simp_all)
  1168           apply(simp_all)
  1087           done
  1169           done
  1088         then show "(c # s) \<in> NTIMES r n \<rightarrow> injval (NTIMES r n) c v" using cons by(simp)
  1170         then show "(c # s) \<in> NTIMES r n \<rightarrow> injval (NTIMES r n) c v" using cons by(simp)
  1089     qed
  1171     qed
       
  1172 next 
       
  1173   case (FROMNTIMES r n)
       
  1174   have IH: "\<And>s v. s \<in> der c r \<rightarrow> v \<Longrightarrow> (c # s) \<in> r \<rightarrow> injval r c v" by fact
       
  1175   have "s \<in> der c (FROMNTIMES r n) \<rightarrow> v" by fact
       
  1176   then consider
       
  1177         (null) v1 vs s1 s2 where 
       
  1178         "v = Seq v1 (Stars vs)" "s = s1 @ s2" 
       
  1179         "s1 \<in> der c r \<rightarrow> v1" "s2 \<in> (FROMNTIMES r 0) \<rightarrow> (Stars vs)"
       
  1180         "\<not> (\<exists>s\<^sub>3 s\<^sub>4. s\<^sub>3 \<noteq> [] \<and> s\<^sub>3 @ s\<^sub>4 = s2 \<and> s1 @ s\<^sub>3 \<in> L (der c r) \<and> s\<^sub>4 \<in> L (FROMNTIMES r 0))" 
       
  1181       | (cons) m v1 vs s1 s2 where 
       
  1182         "n = Suc m"
       
  1183         "v = Seq v1 (Stars vs)" "s = s1 @ s2" 
       
  1184         "s1 \<in> der c r \<rightarrow> v1" "s2 \<in> (FROMNTIMES r m) \<rightarrow> (Stars vs)"
       
  1185         "\<not> (\<exists>s\<^sub>3 s\<^sub>4. s\<^sub>3 \<noteq> [] \<and> s\<^sub>3 @ s\<^sub>4 = s2 \<and> s1 @ s\<^sub>3 \<in> L (der c r) \<and> s\<^sub>4 \<in> L (FROMNTIMES r m))" 
       
  1186         apply(case_tac n)
       
  1187         apply(simp)
       
  1188         apply(auto elim!: Posix_elims(1-5) simp add: der_correctness Der_def intro: Posix.intros)
       
  1189         defer
       
  1190         apply (metis FROMNTIMES_Stars Posix1a)
       
  1191         apply(rotate_tac 5)
       
  1192         apply(erule_tac Posix_elims(6))
       
  1193         apply(auto)
       
  1194         apply(drule_tac x="v1" in meta_spec)
       
  1195         apply(simp)
       
  1196         apply(drule_tac x="v # vs" in meta_spec)
       
  1197         apply(simp)
       
  1198         apply(drule_tac x="s1" in meta_spec)
       
  1199         apply(simp)
       
  1200         apply(drule_tac x="s1a @ s2a" in meta_spec)
       
  1201         apply(simp)
       
  1202         apply(drule meta_mp)
       
  1203         defer
       
  1204         using Pow_in_Star apply blast
       
  1205         apply (meson Posix_FROMNTIMES2 append_is_Nil_conv self_append_conv)
       
  1206         sorry
       
  1207     then show "(c # s) \<in> FROMNTIMES r n \<rightarrow> injval (FROMNTIMES r n) c v" 
       
  1208     proof (cases)
       
  1209       case cons
       
  1210         have "n = Suc m" by fact
       
  1211         moreover
       
  1212           have "s1 \<in> der c r \<rightarrow> v1" by fact
       
  1213           then have "(c # s1) \<in> r \<rightarrow> injval r c v1" using IH by simp
       
  1214         moreover
       
  1215           have "s2 \<in> FROMNTIMES r m \<rightarrow> Stars vs" by fact
       
  1216         moreover 
       
  1217           have "\<not> (\<exists>s\<^sub>3 s\<^sub>4. s\<^sub>3 \<noteq> [] \<and> s\<^sub>3 @ s\<^sub>4 = s2 \<and> s1 @ s\<^sub>3 \<in> L (der c r) \<and> s\<^sub>4 \<in> L (FROMNTIMES r m))" by fact
       
  1218           then have "\<not> (\<exists>s\<^sub>3 s\<^sub>4. s\<^sub>3 \<noteq> [] \<and> s\<^sub>3 @ s\<^sub>4 = s2 \<and> (c # s1) @ s\<^sub>3 \<in> L r \<and> s\<^sub>4 \<in> L (FROMNTIMES r m))" 
       
  1219             by (simp add: der_correctness Der_def)
       
  1220         ultimately 
       
  1221         have "((c # s1) @ s2) \<in> FROMNTIMES r (Suc m) \<rightarrow> Stars (injval r c v1 # vs)" 
       
  1222           apply(rule_tac Posix.intros(12))
       
  1223           apply(simp_all)
       
  1224           done
       
  1225         then show "(c # s) \<in> FROMNTIMES r n \<rightarrow> injval (FROMNTIMES r n) c v" using cons by(simp)
       
  1226     qed
  1090 qed
  1227 qed
  1091 
  1228 
  1092 
  1229 
  1093 section {* The Lexer by Sulzmann and Lu  *}
  1230 section {* The Lexer by Sulzmann and Lu  *}
  1094 
  1231