src/HOL/Presburger.thy
changeset 60758 d8d85a8172b5
parent 58925 1b655309617c
child 61476 1884c40f1539
equal deleted inserted replaced
60757:c09598a97436 60758:d8d85a8172b5
     1 (* Title:      HOL/Presburger.thy
     1 (* Title:      HOL/Presburger.thy
     2    Author:     Amine Chaieb, TU Muenchen
     2    Author:     Amine Chaieb, TU Muenchen
     3 *)
     3 *)
     4 
     4 
     5 section {* Decision Procedure for Presburger Arithmetic *}
     5 section \<open>Decision Procedure for Presburger Arithmetic\<close>
     6 
     6 
     7 theory Presburger
     7 theory Presburger
     8 imports Groebner_Basis Set_Interval
     8 imports Groebner_Basis Set_Interval
     9 keywords "try0" :: diag
     9 keywords "try0" :: diag
    10 begin
    10 begin
    11 
    11 
    12 ML_file "Tools/Qelim/qelim.ML"
    12 ML_file "Tools/Qelim/qelim.ML"
    13 ML_file "Tools/Qelim/cooper_procedure.ML"
    13 ML_file "Tools/Qelim/cooper_procedure.ML"
    14 
    14 
    15 subsection{* The @{text "-\<infinity>"} and @{text "+\<infinity>"} Properties *}
    15 subsection\<open>The @{text "-\<infinity>"} and @{text "+\<infinity>"} Properties\<close>
    16 
    16 
    17 lemma minf:
    17 lemma minf:
    18   "\<lbrakk>\<exists>(z ::'a::linorder).\<forall>x<z. P x = P' x; \<exists>z.\<forall>x<z. Q x = Q' x\<rbrakk> 
    18   "\<lbrakk>\<exists>(z ::'a::linorder).\<forall>x<z. P x = P' x; \<exists>z.\<forall>x<z. Q x = Q' x\<rbrakk> 
    19      \<Longrightarrow> \<exists>z.\<forall>x<z. (P x \<and> Q x) = (P' x \<and> Q' x)"
    19      \<Longrightarrow> \<exists>z.\<forall>x<z. (P x \<and> Q x) = (P' x \<and> Q' x)"
    20   "\<lbrakk>\<exists>(z ::'a::linorder).\<forall>x<z. P x = P' x; \<exists>z.\<forall>x<z. Q x = Q' x\<rbrakk> 
    20   "\<lbrakk>\<exists>(z ::'a::linorder).\<forall>x<z. P x = P' x; \<exists>z.\<forall>x<z. Q x = Q' x\<rbrakk> 
    57 apply (auto elim!: dvdE simp add: algebra_simps)
    57 apply (auto elim!: dvdE simp add: algebra_simps)
    58 unfolding mult.assoc [symmetric] distrib_right [symmetric] left_diff_distrib [symmetric]
    58 unfolding mult.assoc [symmetric] distrib_right [symmetric] left_diff_distrib [symmetric]
    59 unfolding dvd_def mult.commute [of d] 
    59 unfolding dvd_def mult.commute [of d] 
    60 by auto
    60 by auto
    61 
    61 
    62 subsection{* The A and B sets *}
    62 subsection\<open>The A and B sets\<close>
    63 lemma bset:
    63 lemma bset:
    64   "\<lbrakk>\<forall>x.(\<forall>j \<in> {1 .. D}. \<forall>b\<in>B. x \<noteq> b + j)\<longrightarrow> P x \<longrightarrow> P(x - D) ;
    64   "\<lbrakk>\<forall>x.(\<forall>j \<in> {1 .. D}. \<forall>b\<in>B. x \<noteq> b + j)\<longrightarrow> P x \<longrightarrow> P(x - D) ;
    65      \<forall>x.(\<forall>j\<in>{1 .. D}. \<forall>b\<in>B. x \<noteq> b + j)\<longrightarrow> Q x \<longrightarrow> Q(x - D)\<rbrakk> \<Longrightarrow> 
    65      \<forall>x.(\<forall>j\<in>{1 .. D}. \<forall>b\<in>B. x \<noteq> b + j)\<longrightarrow> Q x \<longrightarrow> Q(x - D)\<rbrakk> \<Longrightarrow> 
    66   \<forall>x.(\<forall>j\<in>{1 .. D}. \<forall>b\<in>B. x \<noteq> b + j) \<longrightarrow> (P x \<and> Q x) \<longrightarrow> (P(x - D) \<and> Q (x - D))"
    66   \<forall>x.(\<forall>j\<in>{1 .. D}. \<forall>b\<in>B. x \<noteq> b + j) \<longrightarrow> (P x \<and> Q x) \<longrightarrow> (P(x - D) \<and> Q (x - D))"
    67   "\<lbrakk>\<forall>x.(\<forall>j\<in>{1 .. D}. \<forall>b\<in>B. x \<noteq> b + j)\<longrightarrow> P x \<longrightarrow> P(x - D) ;
    67   "\<lbrakk>\<forall>x.(\<forall>j\<in>{1 .. D}. \<forall>b\<in>B. x \<noteq> b + j)\<longrightarrow> P x \<longrightarrow> P(x - D) ;
   174   {fix x assume H: "\<not>(d dvd x + t)" with d have "\<not>d dvd (x + D) + t"
   174   {fix x assume H: "\<not>(d dvd x + t)" with d have "\<not>d dvd (x + D) + t"
   175       by (clarsimp simp add: dvd_def,erule_tac x= "ka - k" in allE,simp add: algebra_simps)}
   175       by (clarsimp simp add: dvd_def,erule_tac x= "ka - k" in allE,simp add: algebra_simps)}
   176   thus "\<forall>(x::int).(\<forall>j\<in>{1 .. D}. \<forall>b\<in>A. x \<noteq> b - j)\<longrightarrow> (\<not>d dvd x+t) \<longrightarrow> (\<not>d dvd (x + D) + t)" by auto
   176   thus "\<forall>(x::int).(\<forall>j\<in>{1 .. D}. \<forall>b\<in>A. x \<noteq> b - j)\<longrightarrow> (\<not>d dvd x+t) \<longrightarrow> (\<not>d dvd (x + D) + t)" by auto
   177 qed blast
   177 qed blast
   178 
   178 
   179 subsection{* Cooper's Theorem @{text "-\<infinity>"} and @{text "+\<infinity>"} Version *}
   179 subsection\<open>Cooper's Theorem @{text "-\<infinity>"} and @{text "+\<infinity>"} Version\<close>
   180 
   180 
   181 subsubsection{* First some trivial facts about periodic sets or predicates *}
   181 subsubsection\<open>First some trivial facts about periodic sets or predicates\<close>
   182 lemma periodic_finite_ex:
   182 lemma periodic_finite_ex:
   183   assumes dpos: "(0::int) < d" and modd: "ALL x k. P x = P(x - k*d)"
   183   assumes dpos: "(0::int) < d" and modd: "ALL x k. P x = P(x - k*d)"
   184   shows "(EX x. P x) = (EX j : {1..d}. P j)"
   184   shows "(EX x. P x) = (EX j : {1..d}. P j)"
   185   (is "?LHS = ?RHS")
   185   (is "?LHS = ?RHS")
   186 proof
   186 proof
   207     qed
   207     qed
   208     ultimately show ?RHS ..
   208     ultimately show ?RHS ..
   209   qed
   209   qed
   210 qed auto
   210 qed auto
   211 
   211 
   212 subsubsection{* The @{text "-\<infinity>"} Version*}
   212 subsubsection\<open>The @{text "-\<infinity>"} Version\<close>
   213 
   213 
   214 lemma decr_lemma: "0 < (d::int) \<Longrightarrow> x - (abs(x-z)+1) * d < z"
   214 lemma decr_lemma: "0 < (d::int) \<Longrightarrow> x - (abs(x-z)+1) * d < z"
   215 by(induct rule: int_gr_induct,simp_all add:int_distrib)
   215 by(induct rule: int_gr_induct,simp_all add:int_distrib)
   216 
   216 
   217 lemma incr_lemma: "0 < (d::int) \<Longrightarrow> z < x + (abs(x-z)+1) * d"
   217 lemma incr_lemma: "0 < (d::int) \<Longrightarrow> z < x + (abs(x-z)+1) * d"
   275    with periodic_finite_ex[OF dp pd]
   275    with periodic_finite_ex[OF dp pd]
   276    have "?R1" by blast}
   276    have "?R1" by blast}
   277  ultimately show ?thesis by blast
   277  ultimately show ?thesis by blast
   278 qed
   278 qed
   279 
   279 
   280 subsubsection {* The @{text "+\<infinity>"} Version*}
   280 subsubsection \<open>The @{text "+\<infinity>"} Version\<close>
   281 
   281 
   282 lemma  plusinfinity:
   282 lemma  plusinfinity:
   283   assumes dpos: "(0::int) < d" and
   283   assumes dpos: "(0::int) < d" and
   284     P1eqP1: "\<forall>x k. P' x = P'(x - k*d)" and ePeqP1: "\<exists> z. \<forall> x>z. P x = P' x"
   284     P1eqP1: "\<forall>x k. P' x = P'(x - k*d)" and ePeqP1: "\<exists> z. \<forall> x>z. P x = P' x"
   285   shows "(\<exists> x. P' x) \<longrightarrow> (\<exists> x. P x)"
   285   shows "(\<exists> x. P' x) \<longrightarrow> (\<exists> x. P x)"
   370 lemma uminus_dvd_conv:
   370 lemma uminus_dvd_conv:
   371   fixes d t :: int
   371   fixes d t :: int
   372   shows "d dvd t \<equiv> - d dvd t" and "d dvd t \<equiv> d dvd - t"
   372   shows "d dvd t \<equiv> - d dvd t" and "d dvd t \<equiv> d dvd - t"
   373   by simp_all
   373   by simp_all
   374 
   374 
   375 text {* \bigskip Theorems for transforming predicates on nat to predicates on @{text int}*}
   375 text \<open>\bigskip Theorems for transforming predicates on nat to predicates on @{text int}\<close>
   376 
   376 
   377 lemma zdiff_int_split: "P (int (x - y)) =
   377 lemma zdiff_int_split: "P (int (x - y)) =
   378   ((y \<le> x \<longrightarrow> P (int x - int y)) \<and> (x < y \<longrightarrow> P 0))"
   378   ((y \<le> x \<longrightarrow> P (int x - int y)) \<and> (x < y \<longrightarrow> P 0))"
   379   by (cases "y \<le> x") (simp_all add: zdiff_int)
   379   by (cases "y \<le> x") (simp_all add: zdiff_int)
   380 
   380 
   381 text {*
   381 text \<open>
   382   \medskip Specific instances of congruence rules, to prevent
   382   \medskip Specific instances of congruence rules, to prevent
   383   simplifier from looping. *}
   383   simplifier from looping.\<close>
   384 
   384 
   385 theorem imp_le_cong:
   385 theorem imp_le_cong:
   386   "\<lbrakk>x = x'; 0 \<le> x' \<Longrightarrow> P = P'\<rbrakk> \<Longrightarrow> (0 \<le> (x::int) \<longrightarrow> P) = (0 \<le> x' \<longrightarrow> P')"
   386   "\<lbrakk>x = x'; 0 \<le> x' \<Longrightarrow> P = P'\<rbrakk> \<Longrightarrow> (0 \<le> (x::int) \<longrightarrow> P) = (0 \<le> x' \<longrightarrow> P')"
   387   by simp
   387   by simp
   388 
   388 
   390   "\<lbrakk>x = x'; 0 \<le> x' \<Longrightarrow> P = P'\<rbrakk> \<Longrightarrow> (0 \<le> (x::int) \<and> P) = (0 \<le> x' \<and> P')"
   390   "\<lbrakk>x = x'; 0 \<le> x' \<Longrightarrow> P = P'\<rbrakk> \<Longrightarrow> (0 \<le> (x::int) \<and> P) = (0 \<le> x' \<and> P')"
   391   by (simp cong: conj_cong)
   391   by (simp cong: conj_cong)
   392 
   392 
   393 ML_file "Tools/Qelim/cooper.ML"
   393 ML_file "Tools/Qelim/cooper.ML"
   394 
   394 
   395 method_setup presburger = {*
   395 method_setup presburger = \<open>
   396   let
   396   let
   397     fun keyword k = Scan.lift (Args.$$$ k -- Args.colon) >> K ()
   397     fun keyword k = Scan.lift (Args.$$$ k -- Args.colon) >> K ()
   398     fun simple_keyword k = Scan.lift (Args.$$$ k) >> K ()
   398     fun simple_keyword k = Scan.lift (Args.$$$ k) >> K ()
   399     val addN = "add"
   399     val addN = "add"
   400     val delN = "del"
   400     val delN = "del"
   406     Scan.optional (keyword addN |-- thms) [] --
   406     Scan.optional (keyword addN |-- thms) [] --
   407     Scan.optional (keyword delN |-- thms) [] >>
   407     Scan.optional (keyword delN |-- thms) [] >>
   408     (fn ((elim, add_ths), del_ths) => fn ctxt =>
   408     (fn ((elim, add_ths), del_ths) => fn ctxt =>
   409       SIMPLE_METHOD' (Cooper.tac elim add_ths del_ths ctxt))
   409       SIMPLE_METHOD' (Cooper.tac elim add_ths del_ths ctxt))
   410   end
   410   end
   411 *} "Cooper's algorithm for Presburger arithmetic"
   411 \<close> "Cooper's algorithm for Presburger arithmetic"
   412 
   412 
   413 declare dvd_eq_mod_eq_0 [symmetric, presburger]
   413 declare dvd_eq_mod_eq_0 [symmetric, presburger]
   414 declare mod_1 [presburger] 
   414 declare mod_1 [presburger] 
   415 declare mod_0 [presburger]
   415 declare mod_0 [presburger]
   416 declare mod_by_1 [presburger]
   416 declare mod_by_1 [presburger]
   488 lemma [presburger]:
   488 lemma [presburger]:
   489   "even n \<longleftrightarrow> even (int n)"
   489   "even n \<longleftrightarrow> even (int n)"
   490   using even_int_iff [of n] by simp
   490   using even_int_iff [of n] by simp
   491   
   491   
   492 
   492 
   493 subsection {* Nice facts about division by @{term 4} *}  
   493 subsection \<open>Nice facts about division by @{term 4}\<close>  
   494 
   494 
   495 lemma even_even_mod_4_iff:
   495 lemma even_even_mod_4_iff:
   496   "even (n::nat) \<longleftrightarrow> even (n mod 4)"
   496   "even (n::nat) \<longleftrightarrow> even (n mod 4)"
   497   by presburger
   497   by presburger
   498 
   498 
   503 lemma even_mod_4_div_2:
   503 lemma even_mod_4_div_2:
   504   "n mod 4 = (1::nat) \<Longrightarrow> even ((n - 1) div 2)"
   504   "n mod 4 = (1::nat) \<Longrightarrow> even ((n - 1) div 2)"
   505   by presburger
   505   by presburger
   506 
   506 
   507 
   507 
   508 subsection {* Try0 *}
   508 subsection \<open>Try0\<close>
   509 
   509 
   510 ML_file "Tools/try0.ML"
   510 ML_file "Tools/try0.ML"
   511 
   511 
   512 end
   512 end