diff --git a/src/HOL/Code_Numeral.thy b/src/HOL/Code_Numeral.thy --- a/src/HOL/Code_Numeral.thy +++ b/src/HOL/Code_Numeral.thy @@ -1,1329 +1,1313 @@ (* Title: HOL/Code_Numeral.thy Author: Florian Haftmann, TU Muenchen *) section \Numeric types for code generation onto target language numerals only\ theory Code_Numeral imports Divides Lifting Bit_Operations begin subsection \Type of target language integers\ typedef integer = "UNIV :: int set" morphisms int_of_integer integer_of_int .. setup_lifting type_definition_integer lemma integer_eq_iff: "k = l \ int_of_integer k = int_of_integer l" by transfer rule lemma integer_eqI: "int_of_integer k = int_of_integer l \ k = l" using integer_eq_iff [of k l] by simp lemma int_of_integer_integer_of_int [simp]: "int_of_integer (integer_of_int k) = k" by transfer rule lemma integer_of_int_int_of_integer [simp]: "integer_of_int (int_of_integer k) = k" by transfer rule instantiation integer :: ring_1 begin lift_definition zero_integer :: integer is "0 :: int" . declare zero_integer.rep_eq [simp] lift_definition one_integer :: integer is "1 :: int" . declare one_integer.rep_eq [simp] lift_definition plus_integer :: "integer \ integer \ integer" is "plus :: int \ int \ int" . declare plus_integer.rep_eq [simp] lift_definition uminus_integer :: "integer \ integer" is "uminus :: int \ int" . declare uminus_integer.rep_eq [simp] lift_definition minus_integer :: "integer \ integer \ integer" is "minus :: int \ int \ int" . declare minus_integer.rep_eq [simp] lift_definition times_integer :: "integer \ integer \ integer" is "times :: int \ int \ int" . declare times_integer.rep_eq [simp] instance proof qed (transfer, simp add: algebra_simps)+ end instance integer :: Rings.dvd .. context includes lifting_syntax notes transfer_rule_numeral [transfer_rule] begin lemma [transfer_rule]: "(pcr_integer ===> pcr_integer ===> (\)) (dvd) (dvd)" by (unfold dvd_def) transfer_prover lemma [transfer_rule]: "((\) ===> pcr_integer) of_bool of_bool" by (unfold of_bool_def) transfer_prover lemma [transfer_rule]: "((=) ===> pcr_integer) int of_nat" by (rule transfer_rule_of_nat) transfer_prover+ lemma [transfer_rule]: "((=) ===> pcr_integer) (\k. k) of_int" proof - have "((=) ===> pcr_integer) of_int of_int" by (rule transfer_rule_of_int) transfer_prover+ then show ?thesis by (simp add: id_def) qed lemma [transfer_rule]: "((=) ===> pcr_integer) numeral numeral" by transfer_prover lemma [transfer_rule]: "((=) ===> (=) ===> pcr_integer) Num.sub Num.sub" by (unfold Num.sub_def) transfer_prover lemma [transfer_rule]: "(pcr_integer ===> (=) ===> pcr_integer) (^) (^)" by (unfold power_def) transfer_prover end lemma int_of_integer_of_nat [simp]: "int_of_integer (of_nat n) = of_nat n" by transfer rule lift_definition integer_of_nat :: "nat \ integer" is "of_nat :: nat \ int" . lemma integer_of_nat_eq_of_nat [code]: "integer_of_nat = of_nat" by transfer rule lemma int_of_integer_integer_of_nat [simp]: "int_of_integer (integer_of_nat n) = of_nat n" by transfer rule lift_definition nat_of_integer :: "integer \ nat" is Int.nat . lemma nat_of_integer_of_nat [simp]: "nat_of_integer (of_nat n) = n" by transfer simp lemma int_of_integer_of_int [simp]: "int_of_integer (of_int k) = k" by transfer simp lemma nat_of_integer_integer_of_nat [simp]: "nat_of_integer (integer_of_nat n) = n" by transfer simp lemma integer_of_int_eq_of_int [simp, code_abbrev]: "integer_of_int = of_int" by transfer (simp add: fun_eq_iff) lemma of_int_integer_of [simp]: "of_int (int_of_integer k) = (k :: integer)" by transfer rule lemma int_of_integer_numeral [simp]: "int_of_integer (numeral k) = numeral k" by transfer rule lemma int_of_integer_sub [simp]: "int_of_integer (Num.sub k l) = Num.sub k l" by transfer rule definition integer_of_num :: "num \ integer" where [simp]: "integer_of_num = numeral" lemma integer_of_num [code]: "integer_of_num Num.One = 1" "integer_of_num (Num.Bit0 n) = (let k = integer_of_num n in k + k)" "integer_of_num (Num.Bit1 n) = (let k = integer_of_num n in k + k + 1)" by (simp_all only: integer_of_num_def numeral.simps Let_def) lemma integer_of_num_triv: "integer_of_num Num.One = 1" "integer_of_num (Num.Bit0 Num.One) = 2" by simp_all instantiation integer :: "{linordered_idom, equal}" begin lift_definition abs_integer :: "integer \ integer" is "abs :: int \ int" . declare abs_integer.rep_eq [simp] lift_definition sgn_integer :: "integer \ integer" is "sgn :: int \ int" . declare sgn_integer.rep_eq [simp] lift_definition less_eq_integer :: "integer \ integer \ bool" is "less_eq :: int \ int \ bool" . lemma integer_less_eq_iff: "k \ l \ int_of_integer k \ int_of_integer l" by (fact less_eq_integer.rep_eq) lift_definition less_integer :: "integer \ integer \ bool" is "less :: int \ int \ bool" . lemma integer_less_iff: "k < l \ int_of_integer k < int_of_integer l" by (fact less_integer.rep_eq) lift_definition equal_integer :: "integer \ integer \ bool" is "HOL.equal :: int \ int \ bool" . instance by standard (transfer, simp add: algebra_simps equal less_le_not_le [symmetric] mult_strict_right_mono linear)+ end context includes lifting_syntax begin lemma [transfer_rule]: \(pcr_integer ===> pcr_integer ===> pcr_integer) min min\ by (unfold min_def) transfer_prover lemma [transfer_rule]: \(pcr_integer ===> pcr_integer ===> pcr_integer) max max\ by (unfold max_def) transfer_prover end lemma int_of_integer_min [simp]: "int_of_integer (min k l) = min (int_of_integer k) (int_of_integer l)" by transfer rule lemma int_of_integer_max [simp]: "int_of_integer (max k l) = max (int_of_integer k) (int_of_integer l)" by transfer rule lemma nat_of_integer_non_positive [simp]: "k \ 0 \ nat_of_integer k = 0" by transfer simp lemma of_nat_of_integer [simp]: "of_nat (nat_of_integer k) = max 0 k" by transfer auto instantiation integer :: unique_euclidean_ring begin lift_definition divide_integer :: "integer \ integer \ integer" is "divide :: int \ int \ int" . declare divide_integer.rep_eq [simp] lift_definition modulo_integer :: "integer \ integer \ integer" is "modulo :: int \ int \ int" . declare modulo_integer.rep_eq [simp] lift_definition euclidean_size_integer :: "integer \ nat" is "euclidean_size :: int \ nat" . declare euclidean_size_integer.rep_eq [simp] lift_definition division_segment_integer :: "integer \ integer" is "division_segment :: int \ int" . declare division_segment_integer.rep_eq [simp] instance by (standard; transfer) (use mult_le_mono2 [of 1] in \auto simp add: sgn_mult_abs abs_mult sgn_mult abs_mod_less sgn_mod nat_mult_distrib division_segment_mult division_segment_mod intro: div_eqI\) end lemma [code]: "euclidean_size = nat_of_integer \ abs" by (simp add: fun_eq_iff nat_of_integer.rep_eq) lemma [code]: "division_segment (k :: integer) = (if k \ 0 then 1 else - 1)" by transfer (simp add: division_segment_int_def) instance integer :: unique_euclidean_ring_with_nat by (standard; transfer) (simp_all add: of_nat_div division_segment_int_def) instantiation integer :: ring_bit_operations begin lift_definition bit_integer :: \integer \ nat \ bool\ is bit . lift_definition not_integer :: \integer \ integer\ is not . lift_definition and_integer :: \integer \ integer \ integer\ is \and\ . lift_definition or_integer :: \integer \ integer \ integer\ is or . lift_definition xor_integer :: \integer \ integer \ integer\ is xor . lift_definition mask_integer :: \nat \ integer\ is mask . lift_definition set_bit_integer :: \nat \ integer \ integer\ is set_bit . lift_definition unset_bit_integer :: \nat \ integer \ integer\ is unset_bit . lift_definition flip_bit_integer :: \nat \ integer \ integer\ is flip_bit . lift_definition push_bit_integer :: \nat \ integer \ integer\ is push_bit . lift_definition drop_bit_integer :: \nat \ integer \ integer\ is drop_bit . lift_definition take_bit_integer :: \nat \ integer \ integer\ is take_bit . instance by (standard; transfer) (fact bit_eq_rec bits_induct bit_iff_odd push_bit_eq_mult drop_bit_eq_div take_bit_eq_mod bits_div_0 bits_div_by_1 bits_mod_div_trivial even_succ_div_2 exp_div_exp_eq div_exp_eq mod_exp_eq mult_exp_mod_exp_eq div_exp_mod_exp_eq even_mask_div_iff even_mult_exp_div_exp_iff bit_and_iff bit_or_iff bit_xor_iff mask_eq_exp_minus_1 set_bit_def bit_unset_bit_iff flip_bit_def bit_not_iff_eq minus_eq_not_minus_1)+ end instance integer :: unique_euclidean_semiring_with_bit_operations .. context includes bit_operations_syntax begin lemma [code]: \bit k n \ odd (drop_bit n k)\ \NOT k = - k - 1\ \mask n = 2 ^ n - (1 :: integer)\ \set_bit n k = k OR push_bit n 1\ \unset_bit n k = k AND NOT (push_bit n 1)\ \flip_bit n k = k XOR push_bit n 1\ \push_bit n k = k * 2 ^ n\ \drop_bit n k = k div 2 ^ n\ \take_bit n k = k mod 2 ^ n\ for k :: integer by (fact bit_iff_odd_drop_bit not_eq_complement mask_eq_exp_minus_1 set_bit_eq_or unset_bit_eq_and_not flip_bit_eq_xor push_bit_eq_mult drop_bit_eq_div take_bit_eq_mod)+ lemma [code]: \k AND l = (if k = 0 \ l = 0 then 0 else if k = - 1 then l else if l = - 1 then k else (k mod 2) * (l mod 2) + 2 * ((k div 2) AND (l div 2)))\ for k l :: integer by transfer (fact and_int_unfold) lemma [code]: \k OR l = (if k = - 1 \ l = - 1 then - 1 else if k = 0 then l else if l = 0 then k else max (k mod 2) (l mod 2) + 2 * ((k div 2) OR (l div 2)))\ for k l :: integer by transfer (fact or_int_unfold) lemma [code]: \k XOR l = (if k = - 1 then NOT l else if l = - 1 then NOT k else if k = 0 then l else if l = 0 then k else \k mod 2 - l mod 2\ + 2 * ((k div 2) XOR (l div 2)))\ for k l :: integer by transfer (fact xor_int_unfold) end -instantiation integer :: unique_euclidean_semiring_numeral +instantiation integer :: unique_euclidean_semiring_with_nat_division begin definition divmod_integer :: "num \ num \ integer \ integer" where divmod_integer'_def: "divmod_integer m n = (numeral m div numeral n, numeral m mod numeral n)" definition divmod_step_integer :: "integer \ integer \ integer \ integer \ integer" where "divmod_step_integer l qr = (let (q, r) = qr - in if r \ l then (2 * q + 1, r - l) + in if \l\ \ \r\ then (2 * q + 1, r - l) else (2 * q, r))" -instance proof - show "divmod m n = (numeral m div numeral n :: integer, numeral m mod numeral n)" - for m n by (fact divmod_integer'_def) - show "divmod_step l qr = (let (q, r) = qr - in if r \ l then (2 * q + 1, r - l) - else (2 * q, r))" for l and qr :: "integer \ integer" - by (fact divmod_step_integer_def) -qed (transfer, - fact le_add_diff_inverse2 - unique_euclidean_semiring_numeral_class.div_less - unique_euclidean_semiring_numeral_class.mod_less - unique_euclidean_semiring_numeral_class.div_positive - unique_euclidean_semiring_numeral_class.mod_less_eq_dividend - unique_euclidean_semiring_numeral_class.pos_mod_bound - unique_euclidean_semiring_numeral_class.pos_mod_sign - unique_euclidean_semiring_numeral_class.mod_mult2_eq - unique_euclidean_semiring_numeral_class.div_mult2_eq - unique_euclidean_semiring_numeral_class.discrete)+ +instance by standard + (auto simp add: divmod_integer'_def divmod_step_integer_def integer_less_eq_iff) end declare divmod_algorithm_code [where ?'a = integer, folded integer_of_num_def, unfolded integer_of_num_triv, code] lemma integer_of_nat_0: "integer_of_nat 0 = 0" by transfer simp lemma integer_of_nat_1: "integer_of_nat 1 = 1" by transfer simp lemma integer_of_nat_numeral: "integer_of_nat (numeral n) = numeral n" by transfer simp subsection \Code theorems for target language integers\ text \Constructors\ definition Pos :: "num \ integer" where [simp, code_post]: "Pos = numeral" context includes lifting_syntax begin lemma [transfer_rule]: \((=) ===> pcr_integer) numeral Pos\ by simp transfer_prover end lemma Pos_fold [code_unfold]: "numeral Num.One = Pos Num.One" "numeral (Num.Bit0 k) = Pos (Num.Bit0 k)" "numeral (Num.Bit1 k) = Pos (Num.Bit1 k)" by simp_all definition Neg :: "num \ integer" where [simp, code_abbrev]: "Neg n = - Pos n" context includes lifting_syntax begin lemma [transfer_rule]: \((=) ===> pcr_integer) (\n. - numeral n) Neg\ by (unfold Neg_def) transfer_prover end code_datatype "0::integer" Pos Neg text \A further pair of constructors for generated computations\ context begin qualified definition positive :: "num \ integer" where [simp]: "positive = numeral" qualified definition negative :: "num \ integer" where [simp]: "negative = uminus \ numeral" lemma [code_computation_unfold]: "numeral = positive" "Pos = positive" "Neg = negative" by (simp_all add: fun_eq_iff) end text \Auxiliary operations\ lift_definition dup :: "integer \ integer" is "\k::int. k + k" . lemma dup_code [code]: "dup 0 = 0" "dup (Pos n) = Pos (Num.Bit0 n)" "dup (Neg n) = Neg (Num.Bit0 n)" by (transfer, simp only: numeral_Bit0 minus_add_distrib)+ lift_definition sub :: "num \ num \ integer" is "\m n. numeral m - numeral n :: int" . lemma sub_code [code]: "sub Num.One Num.One = 0" "sub (Num.Bit0 m) Num.One = Pos (Num.BitM m)" "sub (Num.Bit1 m) Num.One = Pos (Num.Bit0 m)" "sub Num.One (Num.Bit0 n) = Neg (Num.BitM n)" "sub Num.One (Num.Bit1 n) = Neg (Num.Bit0 n)" "sub (Num.Bit0 m) (Num.Bit0 n) = dup (sub m n)" "sub (Num.Bit1 m) (Num.Bit1 n) = dup (sub m n)" "sub (Num.Bit1 m) (Num.Bit0 n) = dup (sub m n) + 1" "sub (Num.Bit0 m) (Num.Bit1 n) = dup (sub m n) - 1" by (transfer, simp add: dbl_def dbl_inc_def dbl_dec_def)+ text \Implementations\ lemma one_integer_code [code, code_unfold]: "1 = Pos Num.One" by simp lemma plus_integer_code [code]: "k + 0 = (k::integer)" "0 + l = (l::integer)" "Pos m + Pos n = Pos (m + n)" "Pos m + Neg n = sub m n" "Neg m + Pos n = sub n m" "Neg m + Neg n = Neg (m + n)" by (transfer, simp)+ lemma uminus_integer_code [code]: "uminus 0 = (0::integer)" "uminus (Pos m) = Neg m" "uminus (Neg m) = Pos m" by simp_all lemma minus_integer_code [code]: "k - 0 = (k::integer)" "0 - l = uminus (l::integer)" "Pos m - Pos n = sub m n" "Pos m - Neg n = Pos (m + n)" "Neg m - Pos n = Neg (m + n)" "Neg m - Neg n = sub n m" by (transfer, simp)+ lemma abs_integer_code [code]: "\k\ = (if (k::integer) < 0 then - k else k)" by simp lemma sgn_integer_code [code]: "sgn k = (if k = 0 then 0 else if (k::integer) < 0 then - 1 else 1)" by simp lemma times_integer_code [code]: "k * 0 = (0::integer)" "0 * l = (0::integer)" "Pos m * Pos n = Pos (m * n)" "Pos m * Neg n = Neg (m * n)" "Neg m * Pos n = Neg (m * n)" "Neg m * Neg n = Pos (m * n)" by simp_all definition divmod_integer :: "integer \ integer \ integer \ integer" where "divmod_integer k l = (k div l, k mod l)" lemma fst_divmod_integer [simp]: "fst (divmod_integer k l) = k div l" by (simp add: divmod_integer_def) lemma snd_divmod_integer [simp]: "snd (divmod_integer k l) = k mod l" by (simp add: divmod_integer_def) definition divmod_abs :: "integer \ integer \ integer \ integer" where "divmod_abs k l = (\k\ div \l\, \k\ mod \l\)" lemma fst_divmod_abs [simp]: "fst (divmod_abs k l) = \k\ div \l\" by (simp add: divmod_abs_def) lemma snd_divmod_abs [simp]: "snd (divmod_abs k l) = \k\ mod \l\" by (simp add: divmod_abs_def) lemma divmod_abs_code [code]: "divmod_abs (Pos k) (Pos l) = divmod k l" "divmod_abs (Neg k) (Neg l) = divmod k l" "divmod_abs (Neg k) (Pos l) = divmod k l" "divmod_abs (Pos k) (Neg l) = divmod k l" "divmod_abs j 0 = (0, \j\)" "divmod_abs 0 j = (0, 0)" by (simp_all add: prod_eq_iff) lemma divmod_integer_eq_cases: "divmod_integer k l = (if k = 0 then (0, 0) else if l = 0 then (0, k) else (apsnd \ times \ sgn) l (if sgn k = sgn l then divmod_abs k l else (let (r, s) = divmod_abs k l in if s = 0 then (- r, 0) else (- r - 1, \l\ - s))))" proof - have *: "sgn k = sgn l \ k = 0 \ l = 0 \ 0 < l \ 0 < k \ l < 0 \ k < 0" for k l :: int by (auto simp add: sgn_if) have **: "- k = l * q \ k = - (l * q)" for k l q :: int by auto show ?thesis by (simp add: divmod_integer_def divmod_abs_def) (transfer, auto simp add: * ** not_less zdiv_zminus1_eq_if zmod_zminus1_eq_if div_minus_right mod_minus_right) qed lemma divmod_integer_code [code]: \<^marker>\contributor \René Thiemann\\ \<^marker>\contributor \Akihisa Yamada\\ "divmod_integer k l = (if k = 0 then (0, 0) else if l > 0 then (if k > 0 then Code_Numeral.divmod_abs k l else case Code_Numeral.divmod_abs k l of (r, s) \ if s = 0 then (- r, 0) else (- r - 1, l - s)) else if l = 0 then (0, k) else apsnd uminus (if k < 0 then Code_Numeral.divmod_abs k l else case Code_Numeral.divmod_abs k l of (r, s) \ if s = 0 then (- r, 0) else (- r - 1, - l - s)))" by (cases l "0 :: integer" rule: linorder_cases) (auto split: prod.splits simp add: divmod_integer_eq_cases) lemma div_integer_code [code]: "k div l = fst (divmod_integer k l)" by simp lemma mod_integer_code [code]: "k mod l = snd (divmod_integer k l)" by simp definition bit_cut_integer :: "integer \ integer \ bool" where "bit_cut_integer k = (k div 2, odd k)" lemma bit_cut_integer_code [code]: "bit_cut_integer k = (if k = 0 then (0, False) else let (r, s) = Code_Numeral.divmod_abs k 2 in (if k > 0 then r else - r - s, s = 1))" proof - have "bit_cut_integer k = (let (r, s) = divmod_integer k 2 in (r, s = 1))" by (simp add: divmod_integer_def bit_cut_integer_def odd_iff_mod_2_eq_one) then show ?thesis by (simp add: divmod_integer_code) (auto simp add: split_def) qed lemma equal_integer_code [code]: "HOL.equal 0 (0::integer) \ True" "HOL.equal 0 (Pos l) \ False" "HOL.equal 0 (Neg l) \ False" "HOL.equal (Pos k) 0 \ False" "HOL.equal (Pos k) (Pos l) \ HOL.equal k l" "HOL.equal (Pos k) (Neg l) \ False" "HOL.equal (Neg k) 0 \ False" "HOL.equal (Neg k) (Pos l) \ False" "HOL.equal (Neg k) (Neg l) \ HOL.equal k l" by (simp_all add: equal) lemma equal_integer_refl [code nbe]: "HOL.equal (k::integer) k \ True" by (fact equal_refl) lemma less_eq_integer_code [code]: "0 \ (0::integer) \ True" "0 \ Pos l \ True" "0 \ Neg l \ False" "Pos k \ 0 \ False" "Pos k \ Pos l \ k \ l" "Pos k \ Neg l \ False" "Neg k \ 0 \ True" "Neg k \ Pos l \ True" "Neg k \ Neg l \ l \ k" by simp_all lemma less_integer_code [code]: "0 < (0::integer) \ False" "0 < Pos l \ True" "0 < Neg l \ False" "Pos k < 0 \ False" "Pos k < Pos l \ k < l" "Pos k < Neg l \ False" "Neg k < 0 \ True" "Neg k < Pos l \ True" "Neg k < Neg l \ l < k" by simp_all lift_definition num_of_integer :: "integer \ num" is "num_of_nat \ nat" . lemma num_of_integer_code [code]: "num_of_integer k = (if k \ 1 then Num.One else let (l, j) = divmod_integer k 2; l' = num_of_integer l; l'' = l' + l' in if j = 0 then l'' else l'' + Num.One)" proof - { assume "int_of_integer k mod 2 = 1" then have "nat (int_of_integer k mod 2) = nat 1" by simp moreover assume *: "1 < int_of_integer k" ultimately have **: "nat (int_of_integer k) mod 2 = 1" by (simp add: nat_mod_distrib) have "num_of_nat (nat (int_of_integer k)) = num_of_nat (2 * (nat (int_of_integer k) div 2) + nat (int_of_integer k) mod 2)" by simp then have "num_of_nat (nat (int_of_integer k)) = num_of_nat (nat (int_of_integer k) div 2 + nat (int_of_integer k) div 2 + nat (int_of_integer k) mod 2)" by (simp add: mult_2) with ** have "num_of_nat (nat (int_of_integer k)) = num_of_nat (nat (int_of_integer k) div 2 + nat (int_of_integer k) div 2 + 1)" by simp } note aux = this show ?thesis by (auto simp add: num_of_integer_def nat_of_integer_def Let_def case_prod_beta not_le integer_eq_iff less_eq_integer_def nat_mult_distrib nat_div_distrib num_of_nat_One num_of_nat_plus_distrib mult_2 [where 'a=nat] aux add_One) qed lemma nat_of_integer_code [code]: "nat_of_integer k = (if k \ 0 then 0 else let (l, j) = divmod_integer k 2; l' = nat_of_integer l; l'' = l' + l' in if j = 0 then l'' else l'' + 1)" proof - obtain j where k: "k = integer_of_int j" proof show "k = integer_of_int (int_of_integer k)" by simp qed have *: "nat j mod 2 = nat_of_integer (of_int j mod 2)" if "j \ 0" using that by transfer (simp add: nat_mod_distrib) from k show ?thesis by (auto simp add: split_def Let_def nat_of_integer_def nat_div_distrib mult_2 [symmetric] minus_mod_eq_mult_div [symmetric] *) qed lemma int_of_integer_code [code]: "int_of_integer k = (if k < 0 then - (int_of_integer (- k)) else if k = 0 then 0 else let (l, j) = divmod_integer k 2; l' = 2 * int_of_integer l in if j = 0 then l' else l' + 1)" by (auto simp add: split_def Let_def integer_eq_iff minus_mod_eq_mult_div [symmetric]) lemma integer_of_int_code [code]: "integer_of_int k = (if k < 0 then - (integer_of_int (- k)) else if k = 0 then 0 else let l = 2 * integer_of_int (k div 2); j = k mod 2 in if j = 0 then l else l + 1)" by (auto simp add: split_def Let_def integer_eq_iff minus_mod_eq_mult_div [symmetric]) hide_const (open) Pos Neg sub dup divmod_abs subsection \Serializer setup for target language integers\ code_reserved Eval int Integer abs code_printing type_constructor integer \ (SML) "IntInf.int" and (OCaml) "Z.t" and (Haskell) "Integer" and (Scala) "BigInt" and (Eval) "int" | class_instance integer :: equal \ (Haskell) - code_printing constant "0::integer" \ (SML) "!(0/ :/ IntInf.int)" and (OCaml) "Z.zero" and (Haskell) "!(0/ ::/ Integer)" and (Scala) "BigInt(0)" setup \ fold (fn target => Numeral.add_code \<^const_name>\Code_Numeral.Pos\ I Code_Printer.literal_numeral target #> Numeral.add_code \<^const_name>\Code_Numeral.Neg\ (~) Code_Printer.literal_numeral target) ["SML", "OCaml", "Haskell", "Scala"] \ code_printing constant "plus :: integer \ _ \ _" \ (SML) "IntInf.+ ((_), (_))" and (OCaml) "Z.add" and (Haskell) infixl 6 "+" and (Scala) infixl 7 "+" and (Eval) infixl 8 "+" | constant "uminus :: integer \ _" \ (SML) "IntInf.~" and (OCaml) "Z.neg" and (Haskell) "negate" and (Scala) "!(- _)" and (Eval) "~/ _" | constant "minus :: integer \ _" \ (SML) "IntInf.- ((_), (_))" and (OCaml) "Z.sub" and (Haskell) infixl 6 "-" and (Scala) infixl 7 "-" and (Eval) infixl 8 "-" | constant Code_Numeral.dup \ (SML) "IntInf.*/ (2,/ (_))" and (OCaml) "Z.shift'_left/ _/ 1" and (Haskell) "!(2 * _)" and (Scala) "!(2 * _)" and (Eval) "!(2 * _)" | constant Code_Numeral.sub \ (SML) "!(raise/ Fail/ \"sub\")" and (OCaml) "failwith/ \"sub\"" and (Haskell) "error/ \"sub\"" and (Scala) "!sys.error(\"sub\")" | constant "times :: integer \ _ \ _" \ (SML) "IntInf.* ((_), (_))" and (OCaml) "Z.mul" and (Haskell) infixl 7 "*" and (Scala) infixl 8 "*" and (Eval) infixl 9 "*" | constant Code_Numeral.divmod_abs \ (SML) "IntInf.divMod/ (IntInf.abs _,/ IntInf.abs _)" and (OCaml) "!(fun k l ->/ if Z.equal Z.zero l then/ (Z.zero, l) else/ Z.div'_rem/ (Z.abs k)/ (Z.abs l))" and (Haskell) "divMod/ (abs _)/ (abs _)" and (Scala) "!((k: BigInt) => (l: BigInt) =>/ if (l == 0)/ (BigInt(0), k) else/ (k.abs '/% l.abs))" and (Eval) "Integer.div'_mod/ (abs _)/ (abs _)" | constant "HOL.equal :: integer \ _ \ bool" \ (SML) "!((_ : IntInf.int) = _)" and (OCaml) "Z.equal" and (Haskell) infix 4 "==" and (Scala) infixl 5 "==" and (Eval) infixl 6 "=" | constant "less_eq :: integer \ _ \ bool" \ (SML) "IntInf.<= ((_), (_))" and (OCaml) "Z.leq" and (Haskell) infix 4 "<=" and (Scala) infixl 4 "<=" and (Eval) infixl 6 "<=" | constant "less :: integer \ _ \ bool" \ (SML) "IntInf.< ((_), (_))" and (OCaml) "Z.lt" and (Haskell) infix 4 "<" and (Scala) infixl 4 "<" and (Eval) infixl 6 "<" | constant "abs :: integer \ _" \ (SML) "IntInf.abs" and (OCaml) "Z.abs" and (Haskell) "Prelude.abs" and (Scala) "_.abs" and (Eval) "abs" code_identifier code_module Code_Numeral \ (SML) Arith and (OCaml) Arith and (Haskell) Arith subsection \Type of target language naturals\ typedef natural = "UNIV :: nat set" morphisms nat_of_natural natural_of_nat .. setup_lifting type_definition_natural lemma natural_eq_iff [termination_simp]: "m = n \ nat_of_natural m = nat_of_natural n" by transfer rule lemma natural_eqI: "nat_of_natural m = nat_of_natural n \ m = n" using natural_eq_iff [of m n] by simp lemma nat_of_natural_of_nat_inverse [simp]: "nat_of_natural (natural_of_nat n) = n" by transfer rule lemma natural_of_nat_of_natural_inverse [simp]: "natural_of_nat (nat_of_natural n) = n" by transfer rule instantiation natural :: "{comm_monoid_diff, semiring_1}" begin lift_definition zero_natural :: natural is "0 :: nat" . declare zero_natural.rep_eq [simp] lift_definition one_natural :: natural is "1 :: nat" . declare one_natural.rep_eq [simp] lift_definition plus_natural :: "natural \ natural \ natural" is "plus :: nat \ nat \ nat" . declare plus_natural.rep_eq [simp] lift_definition minus_natural :: "natural \ natural \ natural" is "minus :: nat \ nat \ nat" . declare minus_natural.rep_eq [simp] lift_definition times_natural :: "natural \ natural \ natural" is "times :: nat \ nat \ nat" . declare times_natural.rep_eq [simp] instance proof qed (transfer, simp add: algebra_simps)+ end instance natural :: Rings.dvd .. context includes lifting_syntax begin lemma [transfer_rule]: \(pcr_natural ===> pcr_natural ===> (\)) (dvd) (dvd)\ by (unfold dvd_def) transfer_prover lemma [transfer_rule]: \((\) ===> pcr_natural) of_bool of_bool\ by (unfold of_bool_def) transfer_prover lemma [transfer_rule]: \((=) ===> pcr_natural) (\n. n) of_nat\ proof - have "rel_fun HOL.eq pcr_natural (of_nat :: nat \ nat) (of_nat :: nat \ natural)" by (unfold of_nat_def) transfer_prover then show ?thesis by (simp add: id_def) qed lemma [transfer_rule]: \((=) ===> pcr_natural) numeral numeral\ proof - have \((=) ===> pcr_natural) numeral (\n. of_nat (numeral n))\ by transfer_prover then show ?thesis by simp qed lemma [transfer_rule]: \(pcr_natural ===> (=) ===> pcr_natural) (^) (^)\ by (unfold power_def) transfer_prover end lemma nat_of_natural_of_nat [simp]: "nat_of_natural (of_nat n) = n" by transfer rule lemma natural_of_nat_of_nat [simp, code_abbrev]: "natural_of_nat = of_nat" by transfer rule lemma of_nat_of_natural [simp]: "of_nat (nat_of_natural n) = n" by transfer rule lemma nat_of_natural_numeral [simp]: "nat_of_natural (numeral k) = numeral k" by transfer rule instantiation natural :: "{linordered_semiring, equal}" begin lift_definition less_eq_natural :: "natural \ natural \ bool" is "less_eq :: nat \ nat \ bool" . declare less_eq_natural.rep_eq [termination_simp] lift_definition less_natural :: "natural \ natural \ bool" is "less :: nat \ nat \ bool" . declare less_natural.rep_eq [termination_simp] lift_definition equal_natural :: "natural \ natural \ bool" is "HOL.equal :: nat \ nat \ bool" . instance proof qed (transfer, simp add: algebra_simps equal less_le_not_le [symmetric] linear)+ end context includes lifting_syntax begin lemma [transfer_rule]: \(pcr_natural ===> pcr_natural ===> pcr_natural) min min\ by (unfold min_def) transfer_prover lemma [transfer_rule]: \(pcr_natural ===> pcr_natural ===> pcr_natural) max max\ by (unfold max_def) transfer_prover end lemma nat_of_natural_min [simp]: "nat_of_natural (min k l) = min (nat_of_natural k) (nat_of_natural l)" by transfer rule lemma nat_of_natural_max [simp]: "nat_of_natural (max k l) = max (nat_of_natural k) (nat_of_natural l)" by transfer rule instantiation natural :: unique_euclidean_semiring begin lift_definition divide_natural :: "natural \ natural \ natural" is "divide :: nat \ nat \ nat" . declare divide_natural.rep_eq [simp] lift_definition modulo_natural :: "natural \ natural \ natural" is "modulo :: nat \ nat \ nat" . declare modulo_natural.rep_eq [simp] lift_definition euclidean_size_natural :: "natural \ nat" is "euclidean_size :: nat \ nat" . declare euclidean_size_natural.rep_eq [simp] lift_definition division_segment_natural :: "natural \ natural" is "division_segment :: nat \ nat" . declare division_segment_natural.rep_eq [simp] instance by (standard; transfer) (auto simp add: algebra_simps unit_factor_nat_def gr0_conv_Suc) end lemma [code]: "euclidean_size = nat_of_natural" by (simp add: fun_eq_iff) lemma [code]: "division_segment (n::natural) = 1" by (simp add: natural_eq_iff) instance natural :: linordered_semidom by (standard; transfer) simp_all instance natural :: unique_euclidean_semiring_with_nat by (standard; transfer) simp_all instantiation natural :: semiring_bit_operations begin lift_definition bit_natural :: \natural \ nat \ bool\ is bit . lift_definition and_natural :: \natural \ natural \ natural\ is \and\ . lift_definition or_natural :: \natural \ natural \ natural\ is or . lift_definition xor_natural :: \natural \ natural \ natural\ is xor . lift_definition mask_natural :: \nat \ natural\ is mask . lift_definition set_bit_natural :: \nat \ natural \ natural\ is set_bit . lift_definition unset_bit_natural :: \nat \ natural \ natural\ is unset_bit . lift_definition flip_bit_natural :: \nat \ natural \ natural\ is flip_bit . lift_definition push_bit_natural :: \nat \ natural \ natural\ is push_bit . lift_definition drop_bit_natural :: \nat \ natural \ natural\ is drop_bit . lift_definition take_bit_natural :: \nat \ natural \ natural\ is take_bit . instance by (standard; transfer) (fact bit_eq_rec bits_induct bit_iff_odd push_bit_eq_mult drop_bit_eq_div take_bit_eq_mod bits_div_0 bits_div_by_1 bits_mod_div_trivial even_succ_div_2 exp_div_exp_eq div_exp_eq mod_exp_eq mult_exp_mod_exp_eq div_exp_mod_exp_eq even_mask_div_iff even_mult_exp_div_exp_iff bit_and_iff bit_or_iff bit_xor_iff mask_eq_exp_minus_1 set_bit_def bit_unset_bit_iff flip_bit_def)+ end instance natural :: unique_euclidean_semiring_with_bit_operations .. context includes bit_operations_syntax begin lemma [code]: \bit m n \ odd (drop_bit n m)\ \mask n = 2 ^ n - (1 :: integer)\ \set_bit n m = m OR push_bit n 1\ \flip_bit n m = m XOR push_bit n 1\ \push_bit n m = m * 2 ^ n\ \drop_bit n m = m div 2 ^ n\ \take_bit n m = m mod 2 ^ n\ for m :: natural by (fact bit_iff_odd_drop_bit mask_eq_exp_minus_1 set_bit_eq_or flip_bit_eq_xor push_bit_eq_mult drop_bit_eq_div take_bit_eq_mod)+ lemma [code]: \m AND n = (if m = 0 \ n = 0 then 0 else (m mod 2) * (n mod 2) + 2 * ((m div 2) AND (n div 2)))\ for m n :: natural by transfer (fact and_nat_unfold) lemma [code]: \m OR n = (if m = 0 then n else if n = 0 then m else max (m mod 2) (n mod 2) + 2 * ((m div 2) OR (n div 2)))\ for m n :: natural by transfer (fact or_nat_unfold) lemma [code]: \m XOR n = (if m = 0 then n else if n = 0 then m else (m mod 2 + n mod 2) mod 2 + 2 * ((m div 2) XOR (n div 2)))\ for m n :: natural by transfer (fact xor_nat_unfold) lemma [code]: \unset_bit 0 m = 2 * (m div 2)\ \unset_bit (Suc n) m = m mod 2 + 2 * unset_bit n (m div 2)\ for m :: natural by (transfer; simp add: unset_bit_Suc)+ end lift_definition natural_of_integer :: "integer \ natural" is "nat :: int \ nat" . lift_definition integer_of_natural :: "natural \ integer" is "of_nat :: nat \ int" . lemma natural_of_integer_of_natural [simp]: "natural_of_integer (integer_of_natural n) = n" by transfer simp lemma integer_of_natural_of_integer [simp]: "integer_of_natural (natural_of_integer k) = max 0 k" by transfer auto lemma int_of_integer_of_natural [simp]: "int_of_integer (integer_of_natural n) = of_nat (nat_of_natural n)" by transfer rule lemma integer_of_natural_of_nat [simp]: "integer_of_natural (of_nat n) = of_nat n" by transfer rule lemma [measure_function]: "is_measure nat_of_natural" by (rule is_measure_trivial) subsection \Inductive representation of target language naturals\ lift_definition Suc :: "natural \ natural" is Nat.Suc . declare Suc.rep_eq [simp] old_rep_datatype "0::natural" Suc by (transfer, fact nat.induct nat.inject nat.distinct)+ lemma natural_cases [case_names nat, cases type: natural]: fixes m :: natural assumes "\n. m = of_nat n \ P" shows P using assms by transfer blast instantiation natural :: size begin definition size_nat where [simp, code]: "size_nat = nat_of_natural" instance .. end lemma natural_decr [termination_simp]: "n \ 0 \ nat_of_natural n - Nat.Suc 0 < nat_of_natural n" by transfer simp lemma natural_zero_minus_one: "(0::natural) - 1 = 0" by (rule zero_diff) lemma Suc_natural_minus_one: "Suc n - 1 = n" by transfer simp hide_const (open) Suc subsection \Code refinement for target language naturals\ lift_definition Nat :: "integer \ natural" is nat . lemma [code_post]: "Nat 0 = 0" "Nat 1 = 1" "Nat (numeral k) = numeral k" by (transfer, simp)+ lemma [code abstype]: "Nat (integer_of_natural n) = n" by transfer simp lemma [code]: "natural_of_nat n = natural_of_integer (integer_of_nat n)" by transfer simp lemma [code abstract]: "integer_of_natural (natural_of_integer k) = max 0 k" by simp lemma [code]: \integer_of_natural (mask n) = mask n\ by transfer (simp add: mask_eq_exp_minus_1 of_nat_diff) lemma [code_abbrev]: "natural_of_integer (Code_Numeral.Pos k) = numeral k" by transfer simp lemma [code abstract]: "integer_of_natural 0 = 0" by transfer simp lemma [code abstract]: "integer_of_natural 1 = 1" by transfer simp lemma [code abstract]: "integer_of_natural (Code_Numeral.Suc n) = integer_of_natural n + 1" by transfer simp lemma [code]: "nat_of_natural = nat_of_integer \ integer_of_natural" by transfer (simp add: fun_eq_iff) lemma [code, code_unfold]: "case_natural f g n = (if n = 0 then f else g (n - 1))" by (cases n rule: natural.exhaust) (simp_all, simp add: Suc_def) declare natural.rec [code del] lemma [code abstract]: "integer_of_natural (m + n) = integer_of_natural m + integer_of_natural n" by transfer simp lemma [code abstract]: "integer_of_natural (m - n) = max 0 (integer_of_natural m - integer_of_natural n)" by transfer simp lemma [code abstract]: "integer_of_natural (m * n) = integer_of_natural m * integer_of_natural n" by transfer simp lemma [code abstract]: "integer_of_natural (m div n) = integer_of_natural m div integer_of_natural n" by transfer (simp add: zdiv_int) lemma [code abstract]: "integer_of_natural (m mod n) = integer_of_natural m mod integer_of_natural n" by transfer (simp add: zmod_int) lemma [code]: "HOL.equal m n \ HOL.equal (integer_of_natural m) (integer_of_natural n)" by transfer (simp add: equal) lemma [code nbe]: "HOL.equal n (n::natural) \ True" by (rule equal_class.equal_refl) lemma [code]: "m \ n \ integer_of_natural m \ integer_of_natural n" by transfer simp lemma [code]: "m < n \ integer_of_natural m < integer_of_natural n" by transfer simp hide_const (open) Nat code_reflect Code_Numeral datatypes natural functions "Code_Numeral.Suc" "0 :: natural" "1 :: natural" "plus :: natural \ _" "minus :: natural \ _" "times :: natural \ _" "divide :: natural \ _" "modulo :: natural \ _" integer_of_natural natural_of_integer lifting_update integer.lifting lifting_forget integer.lifting lifting_update natural.lifting lifting_forget natural.lifting end diff --git a/src/HOL/Divides.thy b/src/HOL/Divides.thy --- a/src/HOL/Divides.thy +++ b/src/HOL/Divides.thy @@ -1,1091 +1,1093 @@ (* Title: HOL/Divides.thy Author: Lawrence C Paulson, Cambridge University Computer Laboratory Copyright 1999 University of Cambridge *) section \More on quotient and remainder\ theory Divides imports Parity begin subsection \More on division\ subsubsection \Monotonicity in the First Argument (Dividend)\ lemma unique_quotient_lemma: assumes "b * q' + r' \ b * q + r" "0 \ r'" "r' < b" "r < b" shows "q' \ (q::int)" proof - have "r' + b * (q'-q) \ r" using assms by (simp add: right_diff_distrib) moreover have "0 < b * (1 + q - q') " using assms by (simp add: right_diff_distrib distrib_left) moreover have "b * q' < b * (1 + q)" using assms by (simp add: right_diff_distrib distrib_left) ultimately show ?thesis using assms by (simp add: mult_less_cancel_left) qed lemma unique_quotient_lemma_neg: "b * q' + r' \ b*q + r \ r \ 0 \ b < r \ b < r' \ q \ (q'::int)" using unique_quotient_lemma[where b = "-b" and r = "-r'" and r'="-r"] by auto lemma zdiv_mono1: \a div b \ a' div b\ if \a \ a'\ \0 < b\ for a b b' :: int proof (rule unique_quotient_lemma) show "b * (a div b) + a mod b \ b * (a' div b) + a' mod b" using \a \ a'\ by auto qed (use that in auto) lemma zdiv_mono1_neg: fixes b::int assumes "a \ a'" "b < 0" shows "a' div b \ a div b" proof (rule unique_quotient_lemma_neg) show "b * (a div b) + a mod b \ b * (a' div b) + a' mod b" using assms(1) by auto qed (use assms in auto) subsubsection \Monotonicity in the Second Argument (Divisor)\ lemma q_pos_lemma: fixes q'::int assumes "0 \ b'*q' + r'" "r' < b'" "0 < b'" shows "0 \ q'" proof - have "0 < b'* (q' + 1)" using assms by (simp add: distrib_left) with assms show ?thesis by (simp add: zero_less_mult_iff) qed lemma zdiv_mono2_lemma: fixes q'::int assumes eq: "b*q + r = b'*q' + r'" and le: "0 \ b'*q' + r'" and "r' < b'" "0 \ r" "0 < b'" "b' \ b" shows "q \ q'" proof - have "0 \ q'" using q_pos_lemma le \r' < b'\ \0 < b'\ by blast moreover have "b*q = r' - r + b'*q'" using eq by linarith ultimately have "b*q < b* (q' + 1)" using mult_right_mono assms unfolding distrib_left by fastforce with assms show ?thesis by (simp add: mult_less_cancel_left_pos) qed lemma zdiv_mono2: fixes a::int assumes "0 \ a" "0 < b'" "b' \ b" shows "a div b \ a div b'" proof (rule zdiv_mono2_lemma) have "b \ 0" using assms by linarith show "b * (a div b) + a mod b = b' * (a div b') + a mod b'" by simp qed (use assms in auto) lemma zdiv_mono2_neg_lemma: fixes q'::int assumes "b*q + r = b'*q' + r'" "b'*q' + r' < 0" "r < b" "0 \ r'" "0 < b'" "b' \ b" shows "q' \ q" proof - have "b'*q' < 0" using assms by linarith with assms have "q' \ 0" by (simp add: mult_less_0_iff) have "b*q' \ b'*q'" by (simp add: \q' \ 0\ assms(6) mult_right_mono_neg) then have "b*q' < b* (q + 1)" using assms by (simp add: distrib_left) then show ?thesis using assms by (simp add: mult_less_cancel_left) qed lemma zdiv_mono2_neg: fixes a::int assumes "a < 0" "0 < b'" "b' \ b" shows "a div b' \ a div b" proof (rule zdiv_mono2_neg_lemma) have "b \ 0" using assms by linarith show "b * (a div b) + a mod b = b' * (a div b') + a mod b'" by simp qed (use assms in auto) subsubsection \Computing \div\ and \mod\ with shifting\ inductive eucl_rel_int :: "int \ int \ int \ int \ bool" where eucl_rel_int_by0: "eucl_rel_int k 0 (0, k)" | eucl_rel_int_dividesI: "l \ 0 \ k = q * l \ eucl_rel_int k l (q, 0)" | eucl_rel_int_remainderI: "sgn r = sgn l \ \r\ < \l\ \ k = q * l + r \ eucl_rel_int k l (q, r)" lemma eucl_rel_int_iff: "eucl_rel_int k l (q, r) \ k = l * q + r \ (if 0 < l then 0 \ r \ r < l else if l < 0 then l < r \ r \ 0 else q = 0)" by (cases "r = 0") (auto elim!: eucl_rel_int.cases intro: eucl_rel_int_by0 eucl_rel_int_dividesI eucl_rel_int_remainderI simp add: ac_simps sgn_1_pos sgn_1_neg) lemma unique_quotient: "eucl_rel_int a b (q, r) \ eucl_rel_int a b (q', r') \ q = q'" apply (rule order_antisym) apply (simp_all add: eucl_rel_int_iff linorder_neq_iff split: if_split_asm) apply (blast intro: order_eq_refl [THEN unique_quotient_lemma] order_eq_refl [THEN unique_quotient_lemma_neg] sym)+ done lemma unique_remainder: assumes "eucl_rel_int a b (q, r)" and "eucl_rel_int a b (q', r')" shows "r = r'" proof - have "q = q'" using assms by (blast intro: unique_quotient) then show "r = r'" using assms by (simp add: eucl_rel_int_iff) qed lemma eucl_rel_int: "eucl_rel_int k l (k div l, k mod l)" proof (cases k rule: int_cases3) case zero then show ?thesis by (simp add: eucl_rel_int_iff divide_int_def modulo_int_def) next case (pos n) then show ?thesis using div_mult_mod_eq [of n] by (cases l rule: int_cases3) (auto simp del: of_nat_mult of_nat_add simp add: mod_greater_zero_iff_not_dvd of_nat_mult [symmetric] of_nat_add [symmetric] algebra_simps eucl_rel_int_iff divide_int_def modulo_int_def) next case (neg n) then show ?thesis using div_mult_mod_eq [of n] by (cases l rule: int_cases3) (auto simp del: of_nat_mult of_nat_add simp add: mod_greater_zero_iff_not_dvd of_nat_mult [symmetric] of_nat_add [symmetric] algebra_simps eucl_rel_int_iff divide_int_def modulo_int_def) qed lemma divmod_int_unique: assumes "eucl_rel_int k l (q, r)" shows div_int_unique: "k div l = q" and mod_int_unique: "k mod l = r" using assms eucl_rel_int [of k l] using unique_quotient [of k l] unique_remainder [of k l] by auto lemma div_pos_geq: fixes k l :: int assumes "0 < l" and "l \ k" shows "k div l = (k - l) div l + 1" proof - have "k = (k - l) + l" by simp then obtain j where k: "k = j + l" .. with assms show ?thesis by (simp add: div_add_self2) qed lemma mod_pos_geq: fixes k l :: int assumes "0 < l" and "l \ k" shows "k mod l = (k - l) mod l" proof - have "k = (k - l) + l" by simp then obtain j where k: "k = j + l" .. with assms show ?thesis by simp qed lemma pos_eucl_rel_int_mult_2: assumes "0 \ b" assumes "eucl_rel_int a b (q, r)" shows "eucl_rel_int (1 + 2*a) (2*b) (q, 1 + 2*r)" using assms unfolding eucl_rel_int_iff by auto lemma neg_eucl_rel_int_mult_2: assumes "b \ 0" assumes "eucl_rel_int (a + 1) b (q, r)" shows "eucl_rel_int (1 + 2*a) (2*b) (q, 2*r - 1)" using assms unfolding eucl_rel_int_iff by auto text\computing div by shifting\ lemma pos_zdiv_mult_2: "(0::int) \ a ==> (1 + 2*b) div (2*a) = b div a" using pos_eucl_rel_int_mult_2 [OF _ eucl_rel_int] by (rule div_int_unique) lemma neg_zdiv_mult_2: assumes A: "a \ (0::int)" shows "(1 + 2*b) div (2*a) = (b+1) div a" using neg_eucl_rel_int_mult_2 [OF A eucl_rel_int] by (rule div_int_unique) lemma zdiv_numeral_Bit0 [simp]: "numeral (Num.Bit0 v) div numeral (Num.Bit0 w) = numeral v div (numeral w :: int)" unfolding numeral.simps unfolding mult_2 [symmetric] by (rule div_mult_mult1, simp) lemma zdiv_numeral_Bit1 [simp]: "numeral (Num.Bit1 v) div numeral (Num.Bit0 w) = (numeral v div (numeral w :: int))" unfolding numeral.simps unfolding mult_2 [symmetric] add.commute [of _ 1] by (rule pos_zdiv_mult_2, simp) lemma pos_zmod_mult_2: fixes a b :: int assumes "0 \ a" shows "(1 + 2 * b) mod (2 * a) = 1 + 2 * (b mod a)" using pos_eucl_rel_int_mult_2 [OF assms eucl_rel_int] by (rule mod_int_unique) lemma neg_zmod_mult_2: fixes a b :: int assumes "a \ 0" shows "(1 + 2 * b) mod (2 * a) = 2 * ((b + 1) mod a) - 1" using neg_eucl_rel_int_mult_2 [OF assms eucl_rel_int] by (rule mod_int_unique) lemma zmod_numeral_Bit0 [simp]: "numeral (Num.Bit0 v) mod numeral (Num.Bit0 w) = (2::int) * (numeral v mod numeral w)" unfolding numeral_Bit0 [of v] numeral_Bit0 [of w] unfolding mult_2 [symmetric] by (rule mod_mult_mult1) lemma zmod_numeral_Bit1 [simp]: "numeral (Num.Bit1 v) mod numeral (Num.Bit0 w) = 2 * (numeral v mod numeral w) + (1::int)" unfolding numeral_Bit1 [of v] numeral_Bit0 [of w] unfolding mult_2 [symmetric] add.commute [of _ 1] by (rule pos_zmod_mult_2, simp) subsubsection \Quotients of Signs\ lemma div_eq_minus1: "0 < b \ - 1 div b = - 1" for b :: int by (simp add: divide_int_def) lemma zmod_minus1: "0 < b \ - 1 mod b = b - 1" for b :: int by (auto simp add: modulo_int_def) lemma minus_mod_int_eq: \- k mod l = l - 1 - (k - 1) mod l\ if \l \ 0\ for k l :: int proof (cases \l = 0\) case True then show ?thesis by simp next case False with that have \l > 0\ by simp then show ?thesis proof (cases \l dvd k\) case True then obtain j where \k = l * j\ .. moreover have \(l * j mod l - 1) mod l = l - 1\ using \l > 0\ by (simp add: zmod_minus1) then have \(l * j - 1) mod l = l - 1\ by (simp only: mod_simps) ultimately show ?thesis by simp next case False moreover have 1: \0 < k mod l\ using \0 < l\ False le_less by fastforce moreover have 2: \k mod l < 1 + l\ using \0 < l\ pos_mod_bound[of l k] by linarith from 1 2 \l > 0\ have \(k mod l - 1) mod l = k mod l - 1\ by (simp add: zmod_trivial_iff) ultimately show ?thesis by (simp only: zmod_zminus1_eq_if) (simp add: mod_eq_0_iff_dvd algebra_simps mod_simps) qed qed lemma div_neg_pos_less0: fixes a::int assumes "a < 0" "0 < b" shows "a div b < 0" proof - have "a div b \ - 1 div b" using zdiv_mono1 assms by auto also have "... \ -1" by (simp add: assms(2) div_eq_minus1) finally show ?thesis by force qed lemma div_nonneg_neg_le0: "[| (0::int) \ a; b < 0 |] ==> a div b \ 0" by (drule zdiv_mono1_neg, auto) lemma div_nonpos_pos_le0: "[| (a::int) \ 0; b > 0 |] ==> a div b \ 0" by (drule zdiv_mono1, auto) text\Now for some equivalences of the form \a div b >=< 0 \ \\ conditional upon the sign of \a\ or \b\. There are many more. They should all be simp rules unless that causes too much search.\ lemma pos_imp_zdiv_nonneg_iff: fixes a::int assumes "0 < b" shows "(0 \ a div b) = (0 \ a)" proof show "0 \ a div b \ 0 \ a" using assms by (simp add: linorder_not_less [symmetric]) (blast intro: div_neg_pos_less0) next assume "0 \ a" then have "0 div b \ a div b" using zdiv_mono1 assms by blast then show "0 \ a div b" by auto qed lemma pos_imp_zdiv_pos_iff: "0 0 < (i::int) div k \ k \ i" using pos_imp_zdiv_nonneg_iff[of k i] zdiv_eq_0_iff[of i k] by arith lemma neg_imp_zdiv_nonneg_iff: fixes a::int assumes "b < 0" shows "(0 \ a div b) = (a \ 0)" using assms by (simp add: div_minus_minus [of a, symmetric] pos_imp_zdiv_nonneg_iff del: div_minus_minus) (*But not (a div b \ 0 iff a\0); consider a=1, b=2 when a div b = 0.*) lemma pos_imp_zdiv_neg_iff: "(0::int) < b ==> (a div b < 0) = (a < 0)" by (simp add: linorder_not_le [symmetric] pos_imp_zdiv_nonneg_iff) (*Again the law fails for \: consider a = -1, b = -2 when a div b = 0*) lemma neg_imp_zdiv_neg_iff: "b < (0::int) ==> (a div b < 0) = (0 < a)" by (simp add: linorder_not_le [symmetric] neg_imp_zdiv_nonneg_iff) lemma nonneg1_imp_zdiv_pos_iff: fixes a::int assumes "0 \ a" shows "a div b > 0 \ a \ b \ b>0" proof - have "0 < a div b \ b \ a" using div_pos_pos_trivial[of a b] assms by arith moreover have "0 < a div b \ b > 0" using assms div_nonneg_neg_le0[of a b] by(cases "b=0"; force) moreover have "b \ a \ 0 < b \ 0 < a div b" using int_one_le_iff_zero_less[of "a div b"] zdiv_mono1[of b a b] by simp ultimately show ?thesis by blast qed lemma zmod_le_nonneg_dividend: "(m::int) \ 0 \ m mod k \ m" by (rule split_zmod[THEN iffD2]) (fastforce dest: q_pos_lemma intro: split_mult_pos_le) lemma sgn_div_eq_sgn_mult: \sgn (k div l) = of_bool (k div l \ 0) * sgn (k * l)\ for k l :: int proof (cases \k div l = 0\) case True then show ?thesis by simp next case False have \0 \ \k\ div \l\\ by (cases \l = 0\) (simp_all add: pos_imp_zdiv_nonneg_iff) then have \\k\ div \l\ \ 0 \ 0 < \k\ div \l\\ by (simp add: less_le) also have \\ \ \k\ \ \l\\ using False nonneg1_imp_zdiv_pos_iff by auto finally have *: \\k\ div \l\ \ 0 \ \l\ \ \k\\ . show ?thesis using \0 \ \k\ div \l\\ False by (auto simp add: div_eq_div_abs [of k l] div_eq_sgn_abs [of k l] sgn_mult sgn_1_pos sgn_1_neg sgn_eq_0_iff nonneg1_imp_zdiv_pos_iff * dest: sgn_not_eq_imp) qed subsubsection \Further properties\ lemma div_int_pos_iff: "k div l \ 0 \ k = 0 \ l = 0 \ k \ 0 \ l \ 0 \ k < 0 \ l < 0" for k l :: int proof (cases "k = 0 \ l = 0") case False then have *: "k \ 0" "l \ 0" by auto then have "0 \ k div l \ \ k < 0 \ 0 \ l" by (meson neg_imp_zdiv_neg_iff not_le not_less_iff_gr_or_eq) then show ?thesis using * by (auto simp add: pos_imp_zdiv_nonneg_iff neg_imp_zdiv_nonneg_iff) qed auto lemma mod_int_pos_iff: "k mod l \ 0 \ l dvd k \ l = 0 \ k \ 0 \ l > 0" for k l :: int proof (cases "l > 0") case False then show ?thesis by (simp add: dvd_eq_mod_eq_0) (use neg_mod_sign [of l k] in \auto simp add: le_less not_less\) qed auto text \Simplify expressions in which div and mod combine numerical constants\ lemma int_div_pos_eq: "\(a::int) = b * q + r; 0 \ r; r < b\ \ a div b = q" by (rule div_int_unique [of a b q r]) (simp add: eucl_rel_int_iff) lemma int_div_neg_eq: "\(a::int) = b * q + r; r \ 0; b < r\ \ a div b = q" by (rule div_int_unique [of a b q r], simp add: eucl_rel_int_iff) lemma int_mod_pos_eq: "\(a::int) = b * q + r; 0 \ r; r < b\ \ a mod b = r" by (rule mod_int_unique [of a b q r], simp add: eucl_rel_int_iff) lemma int_mod_neg_eq: "\(a::int) = b * q + r; r \ 0; b < r\ \ a mod b = r" by (rule mod_int_unique [of a b q r], simp add: eucl_rel_int_iff) lemma abs_div: "(y::int) dvd x \ \x div y\ = \x\ div \y\" unfolding dvd_def by (cases "y=0") (auto simp add: abs_mult) text\Suggested by Matthias Daum\ lemma int_power_div_base: fixes k :: int assumes "0 < m" "0 < k" shows "k ^ m div k = (k::int) ^ (m - Suc 0)" proof - have eq: "k ^ m = k ^ ((m - Suc 0) + Suc 0)" by (simp add: assms) show ?thesis using assms by (simp only: power_add eq) auto qed text\Suggested by Matthias Daum\ lemma int_div_less_self: fixes x::int assumes "0 < x" "1 < k" shows "x div k < x" proof - have "nat x div nat k < nat x" by (simp add: assms) with assms show ?thesis by (simp add: nat_div_distrib [symmetric]) qed lemma mod_eq_dvd_iff_nat: "m mod q = n mod q \ q dvd m - n" if "m \ n" for m n q :: nat proof - have "int m mod int q = int n mod int q \ int q dvd int m - int n" by (simp add: mod_eq_dvd_iff) with that have "int (m mod q) = int (n mod q) \ int q dvd int (m - n)" by (simp only: of_nat_mod of_nat_diff) then show ?thesis by simp qed lemma mod_eq_nat1E: fixes m n q :: nat assumes "m mod q = n mod q" and "m \ n" obtains s where "m = n + q * s" proof - from assms have "q dvd m - n" by (simp add: mod_eq_dvd_iff_nat) then obtain s where "m - n = q * s" .. with \m \ n\ have "m = n + q * s" by simp with that show thesis . qed lemma mod_eq_nat2E: fixes m n q :: nat assumes "m mod q = n mod q" and "n \ m" obtains s where "n = m + q * s" using assms mod_eq_nat1E [of n q m] by (auto simp add: ac_simps) lemma nat_mod_eq_lemma: assumes "(x::nat) mod n = y mod n" and "y \ x" shows "\q. x = y + n * q" using assms by (rule mod_eq_nat1E) (rule exI) lemma nat_mod_eq_iff: "(x::nat) mod n = y mod n \ (\q1 q2. x + n * q1 = y + n * q2)" (is "?lhs = ?rhs") proof assume H: "x mod n = y mod n" {assume xy: "x \ y" from H have th: "y mod n = x mod n" by simp from nat_mod_eq_lemma[OF th xy] have ?rhs proof fix q assume "y = x + n * q" then have "x + n * q = y + n * 0" by simp then show "\q1 q2. x + n * q1 = y + n * q2" by blast qed} moreover {assume xy: "y \ x" from nat_mod_eq_lemma[OF H xy] have ?rhs proof fix q assume "x = y + n * q" then have "x + n * 0 = y + n * q" by simp then show "\q1 q2. x + n * q1 = y + n * q2" by blast qed} ultimately show ?rhs using linear[of x y] by blast next assume ?rhs then obtain q1 q2 where q12: "x + n * q1 = y + n * q2" by blast hence "(x + n * q1) mod n = (y + n * q2) mod n" by simp thus ?lhs by simp qed subsection \Numeral division with a pragmatic type class\ text \ The following type class contains everything necessary to formulate a division algorithm in ring structures with numerals, restricted - to its positive segments. This is its primary motivation, and it - could surely be formulated using a more fine-grained, more algebraic - and less technical class hierarchy. + to its positive segments. \ -class unique_euclidean_semiring_numeral = unique_euclidean_semiring_with_nat + linordered_semidom + - assumes div_less: "0 \ a \ a < b \ a div b = 0" - and mod_less: " 0 \ a \ a < b \ a mod b = a" - and div_positive: "0 < b \ b \ a \ a div b > 0" - and mod_less_eq_dividend: "0 \ a \ a mod b \ a" - and pos_mod_bound: "0 < b \ a mod b < b" - and pos_mod_sign: "0 < b \ 0 \ a mod b" - and mod_mult2_eq: "0 \ c \ a mod (b * c) = b * (a div b mod c) + a mod b" - and div_mult2_eq: "0 \ c \ a div (b * c) = a div b div c" - assumes discrete: "a < b \ a + 1 \ b" - fixes divmod :: "num \ num \ 'a \ 'a" - and divmod_step :: "'a \ 'a \ 'a \ 'a \ 'a" - assumes divmod_def: "divmod m n = (numeral m div numeral n, numeral m mod numeral n)" - and divmod_step_def: "divmod_step l qr = (let (q, r) = qr - in if r \ l then (2 * q + 1, r - l) - else (2 * q, r))" - \ \These are conceptually definitions but force generated code - to be monomorphic wrt. particular instances of this class which - yields a significant speedup.\ +class unique_euclidean_semiring_with_nat_division = unique_euclidean_semiring_with_nat + + fixes divmod :: \num \ num \ 'a \ 'a\ + and divmod_step :: \'a \ 'a \ 'a \ 'a \ 'a\ \ \ + These are conceptually definitions but force generated code + to be monomorphic wrt. particular instances of this class which + yields a significant speedup.\ + assumes divmod_def: \divmod m n = (numeral m div numeral n, numeral m mod numeral n)\ + and divmod_step_def [simp]: \divmod_step l (q, r) = + (if euclidean_size l \ euclidean_size r then (2 * q + 1, r - l) + else (2 * q, r))\ \ \ + This is a formulation of one step (referring to one digit position) + in school-method division: compare the dividend at the current + digit position with the remainder from previous division steps + and evaluate accordingly.\ begin -lemma divmod_digit_1: - assumes "0 \ a" "0 < b" and "b \ a mod (2 * b)" - shows "2 * (a div (2 * b)) + 1 = a div b" (is "?P") - and "a mod (2 * b) - b = a mod b" (is "?Q") -proof - - from assms mod_less_eq_dividend [of a "2 * b"] have "b \ a" - by (auto intro: trans) - with \0 < b\ have "0 < a div b" by (auto intro: div_positive) - then have [simp]: "1 \ a div b" by (simp add: discrete) - with \0 < b\ have mod_less: "a mod b < b" by (simp add: pos_mod_bound) - define w where "w = a div b mod 2" - then have w_exhaust: "w = 0 \ w = 1" by auto - have mod_w: "a mod (2 * b) = a mod b + b * w" - by (simp add: w_def mod_mult2_eq ac_simps) - from assms w_exhaust have "w = 1" - using mod_less by (auto simp add: mod_w) - with mod_w have mod: "a mod (2 * b) = a mod b + b" by simp - have "2 * (a div (2 * b)) = a div b - w" - by (simp add: w_def div_mult2_eq minus_mod_eq_mult_div ac_simps) - with \w = 1\ have div: "2 * (a div (2 * b)) = a div b - 1" by simp - then show ?P and ?Q - by (simp_all add: div mod add_implies_diff [symmetric]) -qed - -lemma divmod_digit_0: - assumes "0 < b" and "a mod (2 * b) < b" - shows "2 * (a div (2 * b)) = a div b" (is "?P") - and "a mod (2 * b) = a mod b" (is "?Q") -proof - - define w where "w = a div b mod 2" - then have w_exhaust: "w = 0 \ w = 1" by auto - have mod_w: "a mod (2 * b) = a mod b + b * w" - by (simp add: w_def mod_mult2_eq ac_simps) - moreover have "b \ a mod b + b" - proof - - from \0 < b\ pos_mod_sign have "0 \ a mod b" by blast - then have "0 + b \ a mod b + b" by (rule add_right_mono) - then show ?thesis by simp - qed - moreover note assms w_exhaust - ultimately have "w = 0" by auto - with mod_w have mod: "a mod (2 * b) = a mod b" by simp - have "2 * (a div (2 * b)) = a div b - w" - by (simp add: w_def div_mult2_eq minus_mod_eq_mult_div ac_simps) - with \w = 0\ have div: "2 * (a div (2 * b)) = a div b" by simp - then show ?P and ?Q - by (simp_all add: div mod) -qed - -lemma mod_double_modulus: - assumes "m > 0" "x \ 0" - shows "x mod (2 * m) = x mod m \ x mod (2 * m) = x mod m + m" -proof (cases "x mod (2 * m) < m") - case True - thus ?thesis using assms using divmod_digit_0(2)[of m x] by auto -next - case False - hence *: "x mod (2 * m) - m = x mod m" - using assms by (intro divmod_digit_1) auto - hence "x mod (2 * m) = x mod m + m" - by (subst * [symmetric], subst le_add_diff_inverse2) (use False in auto) - thus ?thesis by simp -qed - lemma fst_divmod: - "fst (divmod m n) = numeral m div numeral n" + \fst (divmod m n) = numeral m div numeral n\ by (simp add: divmod_def) lemma snd_divmod: - "snd (divmod m n) = numeral m mod numeral n" + \snd (divmod m n) = numeral m mod numeral n\ by (simp add: divmod_def) text \ - This is a formulation of one step (referring to one digit position) - in school-method division: compare the dividend at the current - digit position with the remainder from previous division steps - and evaluate accordingly. -\ - -lemma divmod_step_eq [simp]: - "divmod_step l (q, r) = (if l \ r - then (2 * q + 1, r - l) else (2 * q, r))" - by (simp add: divmod_step_def) - -text \ - This is a formulation of school-method division. + Following a formulation of school-method division. If the divisor is smaller than the dividend, terminate. If not, shift the dividend to the right until termination occurs and then reiterate single division steps in the opposite direction. \ lemma divmod_divmod_step: - "divmod m n = (if m < n then (0, numeral m) - else divmod_step (numeral n) (divmod m (Num.Bit0 n)))" -proof (cases "m < n") - case True then have "numeral m < numeral n" by simp + \divmod m n = (if m < n then (0, numeral m) + else divmod_step (numeral n) (divmod m (Num.Bit0 n)))\ +proof (cases \m < n\) + case True then show ?thesis - by (simp add: prod_eq_iff div_less mod_less fst_divmod snd_divmod) + by (simp add: prod_eq_iff fst_divmod snd_divmod flip: of_nat_numeral of_nat_div of_nat_mod) next case False - have "divmod m n = - divmod_step (numeral n) (numeral m div (2 * numeral n), - numeral m mod (2 * numeral n))" - proof (cases "numeral n \ numeral m mod (2 * numeral n)") - case True - with divmod_step_eq - have "divmod_step (numeral n) (numeral m div (2 * numeral n), numeral m mod (2 * numeral n)) = - (2 * (numeral m div (2 * numeral n)) + 1, numeral m mod (2 * numeral n) - numeral n)" - by simp - moreover from True divmod_digit_1 [of "numeral m" "numeral n"] - have "2 * (numeral m div (2 * numeral n)) + 1 = numeral m div numeral n" - and "numeral m mod (2 * numeral n) - numeral n = numeral m mod numeral n" - by simp_all - ultimately show ?thesis by (simp only: divmod_def) - next - case False then have *: "numeral m mod (2 * numeral n) < numeral n" - by (simp add: not_le) - with divmod_step_eq - have "divmod_step (numeral n) (numeral m div (2 * numeral n), numeral m mod (2 * numeral n)) = - (2 * (numeral m div (2 * numeral n)), numeral m mod (2 * numeral n))" - by auto - moreover from * divmod_digit_0 [of "numeral n" "numeral m"] - have "2 * (numeral m div (2 * numeral n)) = numeral m div numeral n" - and "numeral m mod (2 * numeral n) = numeral m mod numeral n" - by (simp_all only: zero_less_numeral) - ultimately show ?thesis by (simp only: divmod_def) - qed - then have "divmod m n = - divmod_step (numeral n) (numeral m div numeral (Num.Bit0 n), - numeral m mod numeral (Num.Bit0 n))" - by (simp only: numeral.simps distrib mult_1) - then have "divmod m n = divmod_step (numeral n) (divmod m (Num.Bit0 n))" - by (simp add: divmod_def) - with False show ?thesis by simp + define r s t where \r = (numeral m :: nat)\ \s = (numeral n :: nat)\ \t = 2 * s\ + then have *: \numeral m = of_nat r\ \numeral n = of_nat s\ \numeral (num.Bit0 n) = of_nat t\ + and \\ s \ r mod s\ + by (simp_all add: not_le) + have t: \2 * (r div t) = r div s - r div s mod 2\ + \r mod t = s * (r div s mod 2) + r mod s\ + by (simp add: Rings.minus_mod_eq_mult_div Groups.mult.commute [of 2] Euclidean_Division.div_mult2_eq \t = 2 * s\) + (use mod_mult2_eq [of r s 2] in \simp add: ac_simps \t = 2 * s\\) + have rs: \r div s mod 2 = 0 \ r div s mod 2 = Suc 0\ + by auto + from \\ s \ r mod s\ have \s \ r mod t \ + r div s = Suc (2 * (r div t)) \ + r mod s = r mod t - s\ + using rs + by (auto simp add: t) + moreover have \r mod t < s \ + r div s = 2 * (r div t) \ + r mod s = r mod t\ + using rs + by (auto simp add: t) + ultimately show ?thesis + by (simp add: divmod_def prod_eq_iff split_def Let_def + not_less mod_eq_0_iff_dvd Rings.mod_eq_0_iff_dvd False not_le *) + (simp add: flip: of_nat_numeral of_nat_mult add.commute [of 1] of_nat_div of_nat_mod of_nat_Suc of_nat_diff) qed text \The division rewrite proper -- first, trivial results involving \1\\ lemma divmod_trivial [simp]: "divmod m Num.One = (numeral m, 0)" "divmod num.One (num.Bit0 n) = (0, Numeral1)" "divmod num.One (num.Bit1 n) = (0, Numeral1)" using divmod_divmod_step [of "Num.One"] by (simp_all add: divmod_def) text \Division by an even number is a right-shift\ lemma divmod_cancel [simp]: - "divmod (Num.Bit0 m) (Num.Bit0 n) = (case divmod m n of (q, r) \ (q, 2 * r))" (is ?P) - "divmod (Num.Bit1 m) (Num.Bit0 n) = (case divmod m n of (q, r) \ (q, 2 * r + 1))" (is ?Q) + \divmod (Num.Bit0 m) (Num.Bit0 n) = (case divmod m n of (q, r) \ (q, 2 * r))\ (is ?P) + \divmod (Num.Bit1 m) (Num.Bit0 n) = (case divmod m n of (q, r) \ (q, 2 * r + 1))\ (is ?Q) proof - - have *: "\q. numeral (Num.Bit0 q) = 2 * numeral q" - "\q. numeral (Num.Bit1 q) = 2 * numeral q + 1" - by (simp_all only: numeral_mult numeral.simps distrib) simp_all - have "1 div 2 = 0" "1 mod 2 = 1" by (auto intro: div_less mod_less) - then show ?P and ?Q - by (simp_all add: fst_divmod snd_divmod prod_eq_iff split_def * [of m] * [of n] mod_mult_mult1 - div_mult2_eq [of _ _ 2] mod_mult2_eq [of _ _ 2] - add.commute del: numeral_times_numeral) + define r s where \r = (numeral m :: nat)\ \s = (numeral n :: nat)\ + then have *: \numeral m = of_nat r\ \numeral n = of_nat s\ + \numeral (num.Bit0 m) = of_nat (2 * r)\ \numeral (num.Bit0 n) = of_nat (2 * s)\ + \numeral (num.Bit1 m) = of_nat (Suc (2 * r))\ + by simp_all + show ?P and ?Q + by (simp_all add: divmod_def *) + (simp_all flip: of_nat_numeral of_nat_div of_nat_mod of_nat_mult add.commute [of 1] of_nat_Suc + add: Euclidean_Division.mod_mult_mult1 div_mult2_eq [of _ 2] mod_mult2_eq [of _ 2]) qed text \The really hard work\ lemma divmod_steps [simp]: "divmod (num.Bit0 m) (num.Bit1 n) = (if m \ n then (0, numeral (num.Bit0 m)) else divmod_step (numeral (num.Bit1 n)) (divmod (num.Bit0 m) (num.Bit0 (num.Bit1 n))))" "divmod (num.Bit1 m) (num.Bit1 n) = (if m < n then (0, numeral (num.Bit1 m)) else divmod_step (numeral (num.Bit1 n)) (divmod (num.Bit1 m) (num.Bit0 (num.Bit1 n))))" by (simp_all add: divmod_divmod_step) -lemmas divmod_algorithm_code = divmod_step_eq divmod_trivial divmod_cancel divmod_steps +lemmas divmod_algorithm_code = divmod_trivial divmod_cancel divmod_steps text \Special case: divisibility\ definition divides_aux :: "'a \ 'a \ bool" where "divides_aux qr \ snd qr = 0" lemma divides_aux_eq [simp]: "divides_aux (q, r) \ r = 0" by (simp add: divides_aux_def) lemma dvd_numeral_simp [simp]: "numeral m dvd numeral n \ divides_aux (divmod n m)" by (simp add: divmod_def mod_eq_0_iff_dvd) text \Generic computation of quotient and remainder\ lemma numeral_div_numeral [simp]: "numeral k div numeral l = fst (divmod k l)" by (simp add: fst_divmod) lemma numeral_mod_numeral [simp]: "numeral k mod numeral l = snd (divmod k l)" by (simp add: snd_divmod) lemma one_div_numeral [simp]: "1 div numeral n = fst (divmod num.One n)" by (simp add: fst_divmod) lemma one_mod_numeral [simp]: "1 mod numeral n = snd (divmod num.One n)" by (simp add: snd_divmod) text \Computing congruences modulo \2 ^ q\\ lemma cong_exp_iff_simps: "numeral n mod numeral Num.One = 0 \ True" "numeral (Num.Bit0 n) mod numeral (Num.Bit0 q) = 0 \ numeral n mod numeral q = 0" "numeral (Num.Bit1 n) mod numeral (Num.Bit0 q) = 0 \ False" "numeral m mod numeral Num.One = (numeral n mod numeral Num.One) \ True" "numeral Num.One mod numeral (Num.Bit0 q) = (numeral Num.One mod numeral (Num.Bit0 q)) \ True" "numeral Num.One mod numeral (Num.Bit0 q) = (numeral (Num.Bit0 n) mod numeral (Num.Bit0 q)) \ False" "numeral Num.One mod numeral (Num.Bit0 q) = (numeral (Num.Bit1 n) mod numeral (Num.Bit0 q)) \ (numeral n mod numeral q) = 0" "numeral (Num.Bit0 m) mod numeral (Num.Bit0 q) = (numeral Num.One mod numeral (Num.Bit0 q)) \ False" "numeral (Num.Bit0 m) mod numeral (Num.Bit0 q) = (numeral (Num.Bit0 n) mod numeral (Num.Bit0 q)) \ numeral m mod numeral q = (numeral n mod numeral q)" "numeral (Num.Bit0 m) mod numeral (Num.Bit0 q) = (numeral (Num.Bit1 n) mod numeral (Num.Bit0 q)) \ False" "numeral (Num.Bit1 m) mod numeral (Num.Bit0 q) = (numeral Num.One mod numeral (Num.Bit0 q)) \ (numeral m mod numeral q) = 0" "numeral (Num.Bit1 m) mod numeral (Num.Bit0 q) = (numeral (Num.Bit0 n) mod numeral (Num.Bit0 q)) \ False" "numeral (Num.Bit1 m) mod numeral (Num.Bit0 q) = (numeral (Num.Bit1 n) mod numeral (Num.Bit0 q)) \ numeral m mod numeral q = (numeral n mod numeral q)" by (auto simp add: case_prod_beta dest: arg_cong [of _ _ even]) end -hide_fact (open) div_less mod_less mod_less_eq_dividend mod_mult2_eq div_mult2_eq - -instantiation nat :: unique_euclidean_semiring_numeral +instantiation nat :: unique_euclidean_semiring_with_nat_division begin definition divmod_nat :: "num \ num \ nat \ nat" where divmod'_nat_def: "divmod_nat m n = (numeral m div numeral n, numeral m mod numeral n)" definition divmod_step_nat :: "nat \ nat \ nat \ nat \ nat" where "divmod_step_nat l qr = (let (q, r) = qr in if r \ l then (2 * q + 1, r - l) else (2 * q, r))" -instance by standard - (auto simp add: divmod'_nat_def divmod_step_nat_def div_greater_zero_iff div_mult2_eq mod_mult2_eq) +instance + by standard (simp_all add: divmod'_nat_def divmod_step_nat_def) end declare divmod_algorithm_code [where ?'a = nat, code] lemma Suc_0_div_numeral [simp]: fixes k l :: num shows "Suc 0 div numeral k = fst (divmod Num.One k)" by (simp_all add: fst_divmod) lemma Suc_0_mod_numeral [simp]: fixes k l :: num shows "Suc 0 mod numeral k = snd (divmod Num.One k)" by (simp_all add: snd_divmod) -instantiation int :: unique_euclidean_semiring_numeral +instantiation int :: unique_euclidean_semiring_with_nat_division begin definition divmod_int :: "num \ num \ int \ int" where "divmod_int m n = (numeral m div numeral n, numeral m mod numeral n)" definition divmod_step_int :: "int \ int \ int \ int \ int" where "divmod_step_int l qr = (let (q, r) = qr - in if r \ l then (2 * q + 1, r - l) + in if \l\ \ \r\ then (2 * q + 1, r - l) else (2 * q, r))" instance - by standard (auto intro: zmod_le_nonneg_dividend simp add: divmod_int_def divmod_step_int_def - pos_imp_zdiv_pos_iff zmod_zmult2_eq zdiv_zmult2_eq) + by standard (auto simp add: divmod_int_def divmod_step_int_def) end declare divmod_algorithm_code [where ?'a = int, code] context begin qualified definition adjust_div :: "int \ int \ int" where "adjust_div qr = (let (q, r) = qr in q + of_bool (r \ 0))" qualified lemma adjust_div_eq [simp, code]: "adjust_div (q, r) = q + of_bool (r \ 0)" by (simp add: adjust_div_def) qualified definition adjust_mod :: "num \ int \ int" where [simp]: "adjust_mod l r = (if r = 0 then 0 else numeral l - r)" lemma minus_numeral_div_numeral [simp]: "- numeral m div numeral n = - (adjust_div (divmod m n) :: int)" proof - have "int (fst (divmod m n)) = fst (divmod m n)" by (simp only: fst_divmod divide_int_def) auto then show ?thesis by (auto simp add: split_def Let_def adjust_div_def divides_aux_def divide_int_def) qed lemma minus_numeral_mod_numeral [simp]: "- numeral m mod numeral n = adjust_mod n (snd (divmod m n) :: int)" proof (cases "snd (divmod m n) = (0::int)") case True then show ?thesis by (simp add: mod_eq_0_iff_dvd divides_aux_def) next case False then have "int (snd (divmod m n)) = snd (divmod m n)" if "snd (divmod m n) \ (0::int)" by (simp only: snd_divmod modulo_int_def) auto then show ?thesis by (simp add: divides_aux_def adjust_div_def) (simp add: divides_aux_def modulo_int_def) qed lemma numeral_div_minus_numeral [simp]: "numeral m div - numeral n = - (adjust_div (divmod m n) :: int)" proof - have "int (fst (divmod m n)) = fst (divmod m n)" by (simp only: fst_divmod divide_int_def) auto then show ?thesis by (auto simp add: split_def Let_def adjust_div_def divides_aux_def divide_int_def) qed lemma numeral_mod_minus_numeral [simp]: "numeral m mod - numeral n = - adjust_mod n (snd (divmod m n) :: int)" proof (cases "snd (divmod m n) = (0::int)") case True then show ?thesis by (simp add: mod_eq_0_iff_dvd divides_aux_def) next case False then have "int (snd (divmod m n)) = snd (divmod m n)" if "snd (divmod m n) \ (0::int)" by (simp only: snd_divmod modulo_int_def) auto then show ?thesis by (simp add: divides_aux_def adjust_div_def) (simp add: divides_aux_def modulo_int_def) qed lemma minus_one_div_numeral [simp]: "- 1 div numeral n = - (adjust_div (divmod Num.One n) :: int)" using minus_numeral_div_numeral [of Num.One n] by simp lemma minus_one_mod_numeral [simp]: "- 1 mod numeral n = adjust_mod n (snd (divmod Num.One n) :: int)" using minus_numeral_mod_numeral [of Num.One n] by simp lemma one_div_minus_numeral [simp]: "1 div - numeral n = - (adjust_div (divmod Num.One n) :: int)" using numeral_div_minus_numeral [of Num.One n] by simp lemma one_mod_minus_numeral [simp]: "1 mod - numeral n = - adjust_mod n (snd (divmod Num.One n) :: int)" using numeral_mod_minus_numeral [of Num.One n] by simp end lemma divmod_BitM_2_eq [simp]: \divmod (Num.BitM m) (Num.Bit0 Num.One) = (numeral m - 1, (1 :: int))\ by (cases m) simp_all lemma div_positive_int: "k div l > 0" if "k \ l" and "l > 0" for k l :: int - using that div_positive [of l k] by blast + using that by (simp add: nonneg1_imp_zdiv_pos_iff) subsubsection \Dedicated simproc for calculation\ +lemma euclidean_size_nat_less_eq_iff: + \euclidean_size m \ euclidean_size n \ m \ n\ for m n :: nat + by simp + +lemma euclidean_size_int_less_eq_iff: + \euclidean_size k \ euclidean_size l \ \k\ \ \l\\ for k l :: int + by auto + text \ There is space for improvement here: the calculation itself could be carried out outside the logic, and a generic simproc (simplifier setup) for generic calculation would be helpful. \ simproc_setup numeral_divmod - ("0 div 0 :: 'a :: unique_euclidean_semiring_numeral" | "0 mod 0 :: 'a :: unique_euclidean_semiring_numeral" | - "0 div 1 :: 'a :: unique_euclidean_semiring_numeral" | "0 mod 1 :: 'a :: unique_euclidean_semiring_numeral" | + ("0 div 0 :: 'a :: unique_euclidean_semiring_with_nat_division" | "0 mod 0 :: 'a :: unique_euclidean_semiring_with_nat_division" | + "0 div 1 :: 'a :: unique_euclidean_semiring_with_nat_division" | "0 mod 1 :: 'a :: unique_euclidean_semiring_with_nat_division" | "0 div - 1 :: int" | "0 mod - 1 :: int" | - "0 div numeral b :: 'a :: unique_euclidean_semiring_numeral" | "0 mod numeral b :: 'a :: unique_euclidean_semiring_numeral" | + "0 div numeral b :: 'a :: unique_euclidean_semiring_with_nat_division" | "0 mod numeral b :: 'a :: unique_euclidean_semiring_with_nat_division" | "0 div - numeral b :: int" | "0 mod - numeral b :: int" | - "1 div 0 :: 'a :: unique_euclidean_semiring_numeral" | "1 mod 0 :: 'a :: unique_euclidean_semiring_numeral" | - "1 div 1 :: 'a :: unique_euclidean_semiring_numeral" | "1 mod 1 :: 'a :: unique_euclidean_semiring_numeral" | + "1 div 0 :: 'a :: unique_euclidean_semiring_with_nat_division" | "1 mod 0 :: 'a :: unique_euclidean_semiring_with_nat_division" | + "1 div 1 :: 'a :: unique_euclidean_semiring_with_nat_division" | "1 mod 1 :: 'a :: unique_euclidean_semiring_with_nat_division" | "1 div - 1 :: int" | "1 mod - 1 :: int" | - "1 div numeral b :: 'a :: unique_euclidean_semiring_numeral" | "1 mod numeral b :: 'a :: unique_euclidean_semiring_numeral" | + "1 div numeral b :: 'a :: unique_euclidean_semiring_with_nat_division" | "1 mod numeral b :: 'a :: unique_euclidean_semiring_with_nat_division" | "1 div - numeral b :: int" |"1 mod - numeral b :: int" | "- 1 div 0 :: int" | "- 1 mod 0 :: int" | "- 1 div 1 :: int" | "- 1 mod 1 :: int" | "- 1 div - 1 :: int" | "- 1 mod - 1 :: int" | "- 1 div numeral b :: int" | "- 1 mod numeral b :: int" | "- 1 div - numeral b :: int" | "- 1 mod - numeral b :: int" | - "numeral a div 0 :: 'a :: unique_euclidean_semiring_numeral" | "numeral a mod 0 :: 'a :: unique_euclidean_semiring_numeral" | - "numeral a div 1 :: 'a :: unique_euclidean_semiring_numeral" | "numeral a mod 1 :: 'a :: unique_euclidean_semiring_numeral" | + "numeral a div 0 :: 'a :: unique_euclidean_semiring_with_nat_division" | "numeral a mod 0 :: 'a :: unique_euclidean_semiring_with_nat_division" | + "numeral a div 1 :: 'a :: unique_euclidean_semiring_with_nat_division" | "numeral a mod 1 :: 'a :: unique_euclidean_semiring_with_nat_division" | "numeral a div - 1 :: int" | "numeral a mod - 1 :: int" | - "numeral a div numeral b :: 'a :: unique_euclidean_semiring_numeral" | "numeral a mod numeral b :: 'a :: unique_euclidean_semiring_numeral" | + "numeral a div numeral b :: 'a :: unique_euclidean_semiring_with_nat_division" | "numeral a mod numeral b :: 'a :: unique_euclidean_semiring_with_nat_division" | "numeral a div - numeral b :: int" | "numeral a mod - numeral b :: int" | "- numeral a div 0 :: int" | "- numeral a mod 0 :: int" | "- numeral a div 1 :: int" | "- numeral a mod 1 :: int" | "- numeral a div - 1 :: int" | "- numeral a mod - 1 :: int" | "- numeral a div numeral b :: int" | "- numeral a mod numeral b :: int" | "- numeral a div - numeral b :: int" | "- numeral a mod - numeral b :: int") = \ let val if_cong = the (Code.get_case_cong \<^theory> \<^const_name>\If\); fun successful_rewrite ctxt ct = let val thm = Simplifier.rewrite ctxt ct in if Thm.is_reflexive thm then NONE else SOME thm end; in fn phi => let val simps = Morphism.fact phi (@{thms div_0 mod_0 div_by_0 mod_by_0 div_by_1 mod_by_1 one_div_numeral one_mod_numeral minus_one_div_numeral minus_one_mod_numeral one_div_minus_numeral one_mod_minus_numeral numeral_div_numeral numeral_mod_numeral minus_numeral_div_numeral minus_numeral_mod_numeral numeral_div_minus_numeral numeral_mod_minus_numeral div_minus_minus mod_minus_minus Divides.adjust_div_eq of_bool_eq one_neq_zero numeral_neq_zero neg_equal_0_iff_equal arith_simps arith_special divmod_trivial - divmod_cancel divmod_steps divmod_step_eq fst_conv snd_conv numeral_One + divmod_cancel divmod_steps divmod_step_def fst_conv snd_conv numeral_One case_prod_beta rel_simps Divides.adjust_mod_def div_minus1_right mod_minus1_right - minus_minus numeral_times_numeral mult_zero_right mult_1_right} + minus_minus numeral_times_numeral mult_zero_right mult_1_right + euclidean_size_nat_less_eq_iff euclidean_size_int_less_eq_iff diff_nat_numeral nat_numeral} @ [@{lemma "0 = 0 \ True" by simp}]); fun prepare_simpset ctxt = HOL_ss |> Simplifier.simpset_map ctxt (Simplifier.add_cong if_cong #> fold Simplifier.add_simp simps) in fn ctxt => successful_rewrite (Simplifier.put_simpset (prepare_simpset ctxt) ctxt) end end \ subsubsection \Code generation\ definition divmod_nat :: "nat \ nat \ nat \ nat" where "divmod_nat m n = (m div n, m mod n)" lemma fst_divmod_nat [simp]: "fst (divmod_nat m n) = m div n" by (simp add: divmod_nat_def) lemma snd_divmod_nat [simp]: "snd (divmod_nat m n) = m mod n" by (simp add: divmod_nat_def) lemma divmod_nat_if [code]: "Divides.divmod_nat m n = (if n = 0 \ m < n then (0, m) else let (q, r) = Divides.divmod_nat (m - n) n in (Suc q, r))" by (simp add: prod_eq_iff case_prod_beta not_less le_div_geq le_mod_geq) lemma [code]: "m div n = fst (divmod_nat m n)" "m mod n = snd (divmod_nat m n)" by simp_all lemma [code]: fixes k :: int shows "k div 0 = 0" "k mod 0 = k" "0 div k = 0" "0 mod k = 0" "k div Int.Pos Num.One = k" "k mod Int.Pos Num.One = 0" "k div Int.Neg Num.One = - k" "k mod Int.Neg Num.One = 0" "Int.Pos m div Int.Pos n = (fst (divmod m n) :: int)" "Int.Pos m mod Int.Pos n = (snd (divmod m n) :: int)" "Int.Neg m div Int.Pos n = - (Divides.adjust_div (divmod m n) :: int)" "Int.Neg m mod Int.Pos n = Divides.adjust_mod n (snd (divmod m n) :: int)" "Int.Pos m div Int.Neg n = - (Divides.adjust_div (divmod m n) :: int)" "Int.Pos m mod Int.Neg n = - Divides.adjust_mod n (snd (divmod m n) :: int)" "Int.Neg m div Int.Neg n = (fst (divmod m n) :: int)" "Int.Neg m mod Int.Neg n = - (snd (divmod m n) :: int)" by simp_all code_identifier code_module Divides \ (SML) Arith and (OCaml) Arith and (Haskell) Arith subsection \Lemmas of doubtful value\ +class unique_euclidean_semiring_numeral = unique_euclidean_semiring_with_nat + linordered_semidom + + assumes div_less: "0 \ a \ a < b \ a div b = 0" + and mod_less: " 0 \ a \ a < b \ a mod b = a" + and div_positive: "0 < b \ b \ a \ a div b > 0" + and mod_less_eq_dividend: "0 \ a \ a mod b \ a" + and pos_mod_bound: "0 < b \ a mod b < b" + and pos_mod_sign: "0 < b \ 0 \ a mod b" + and mod_mult2_eq: "0 \ c \ a mod (b * c) = b * (a div b mod c) + a mod b" + and div_mult2_eq: "0 \ c \ a div (b * c) = a div b div c" + assumes discrete: "a < b \ a + 1 \ b" +begin + +lemma divmod_digit_1: + assumes "0 \ a" "0 < b" and "b \ a mod (2 * b)" + shows "2 * (a div (2 * b)) + 1 = a div b" (is "?P") + and "a mod (2 * b) - b = a mod b" (is "?Q") +proof - + from assms mod_less_eq_dividend [of a "2 * b"] have "b \ a" + by (auto intro: trans) + with \0 < b\ have "0 < a div b" by (auto intro: div_positive) + then have [simp]: "1 \ a div b" by (simp add: discrete) + with \0 < b\ have mod_less: "a mod b < b" by (simp add: pos_mod_bound) + define w where "w = a div b mod 2" + then have w_exhaust: "w = 0 \ w = 1" by auto + have mod_w: "a mod (2 * b) = a mod b + b * w" + by (simp add: w_def mod_mult2_eq ac_simps) + from assms w_exhaust have "w = 1" + using mod_less by (auto simp add: mod_w) + with mod_w have mod: "a mod (2 * b) = a mod b + b" by simp + have "2 * (a div (2 * b)) = a div b - w" + by (simp add: w_def div_mult2_eq minus_mod_eq_mult_div ac_simps) + with \w = 1\ have div: "2 * (a div (2 * b)) = a div b - 1" by simp + then show ?P and ?Q + by (simp_all add: div mod add_implies_diff [symmetric]) +qed + +lemma divmod_digit_0: + assumes "0 < b" and "a mod (2 * b) < b" + shows "2 * (a div (2 * b)) = a div b" (is "?P") + and "a mod (2 * b) = a mod b" (is "?Q") +proof - + define w where "w = a div b mod 2" + then have w_exhaust: "w = 0 \ w = 1" by auto + have mod_w: "a mod (2 * b) = a mod b + b * w" + by (simp add: w_def mod_mult2_eq ac_simps) + moreover have "b \ a mod b + b" + proof - + from \0 < b\ pos_mod_sign have "0 \ a mod b" by blast + then have "0 + b \ a mod b + b" by (rule add_right_mono) + then show ?thesis by simp + qed + moreover note assms w_exhaust + ultimately have "w = 0" by auto + with mod_w have mod: "a mod (2 * b) = a mod b" by simp + have "2 * (a div (2 * b)) = a div b - w" + by (simp add: w_def div_mult2_eq minus_mod_eq_mult_div ac_simps) + with \w = 0\ have div: "2 * (a div (2 * b)) = a div b" by simp + then show ?P and ?Q + by (simp_all add: div mod) +qed + +lemma mod_double_modulus: + assumes "m > 0" "x \ 0" + shows "x mod (2 * m) = x mod m \ x mod (2 * m) = x mod m + m" +proof (cases "x mod (2 * m) < m") + case True + thus ?thesis using assms using divmod_digit_0(2)[of m x] by auto +next + case False + hence *: "x mod (2 * m) - m = x mod m" + using assms by (intro divmod_digit_1) auto + hence "x mod (2 * m) = x mod m + m" + by (subst * [symmetric], subst le_add_diff_inverse2) (use False in auto) + thus ?thesis by simp +qed + +end + +hide_fact (open) div_less mod_less mod_less_eq_dividend mod_mult2_eq div_mult2_eq + +instance nat :: unique_euclidean_semiring_numeral + by standard + (auto simp add: div_greater_zero_iff div_mult2_eq mod_mult2_eq) + +instance int :: unique_euclidean_semiring_numeral + by standard (auto intro: zmod_le_nonneg_dividend simp add: + pos_imp_zdiv_pos_iff zmod_zmult2_eq zdiv_zmult2_eq) + lemma div_geq: "m div n = Suc ((m - n) div n)" if "0 < n" and " \ m < n" for m n :: nat by (rule le_div_geq) (use that in \simp_all add: not_less\) lemma mod_geq: "m mod n = (m - n) mod n" if "\ m < n" for m n :: nat by (rule le_mod_geq) (use that in \simp add: not_less\) lemma mod_eq_0D: "\q. m = d * q" if "m mod d = 0" for m d :: nat using that by (auto simp add: mod_eq_0_iff_dvd) lemma pos_mod_conj: "0 < b \ 0 \ a mod b \ a mod b < b" for a b :: int by simp lemma neg_mod_conj: "b < 0 \ a mod b \ 0 \ b < a mod b" for a b :: int by simp lemma zmod_eq_0_iff: "m mod d = 0 \ (\q. m = d * q)" for m d :: int by (auto simp add: mod_eq_0_iff_dvd) (* REVISIT: should this be generalized to all semiring_div types? *) lemma zmod_eq_0D [dest!]: "\q. m = d * q" if "m mod d = 0" for m d :: int using that by auto end diff --git a/src/HOL/Library/IArray.thy b/src/HOL/Library/IArray.thy --- a/src/HOL/Library/IArray.thy +++ b/src/HOL/Library/IArray.thy @@ -1,232 +1,234 @@ (* Title: HOL/Library/IArray.thy Author: Tobias Nipkow, TU Muenchen Author: Jose Divasón Author: Jesús Aransay *) section \Immutable Arrays with Code Generation\ theory IArray imports Main begin subsection \Fundamental operations\ text \Immutable arrays are lists wrapped up in an additional constructor. There are no update operations. Hence code generation can safely implement this type by efficient target language arrays. Currently only SML is provided. Could be extended to other target languages and more operations.\ context begin datatype 'a iarray = IArray "'a list" qualified primrec list_of :: "'a iarray \ 'a list" where "list_of (IArray xs) = xs" qualified definition of_fun :: "(nat \ 'a) \ nat \ 'a iarray" where [simp]: "of_fun f n = IArray (map f [0.. nat \ 'a" (infixl "!!" 100) where [simp]: "as !! n = IArray.list_of as ! n" qualified definition length :: "'a iarray \ nat" where [simp]: "length as = List.length (IArray.list_of as)" qualified definition all :: "('a \ bool) \ 'a iarray \ bool" where [simp]: "all p as \ (\a \ set (list_of as). p a)" qualified definition exists :: "('a \ bool) \ 'a iarray \ bool" where [simp]: "exists p as \ (\a \ set (list_of as). p a)" lemma of_fun_nth: "IArray.of_fun f n !! i = f i" if "i < n" using that by (simp add: map_nth) end subsection \Generic code equations\ lemma [code]: "size (as :: 'a iarray) = Suc (IArray.length as)" by (cases as) simp lemma [code]: "size_iarray f as = Suc (size_list f (IArray.list_of as))" by (cases as) simp lemma [code]: "rec_iarray f as = f (IArray.list_of as)" by (cases as) simp lemma [code]: "case_iarray f as = f (IArray.list_of as)" by (cases as) simp lemma [code]: "set_iarray as = set (IArray.list_of as)" by (cases as) auto lemma [code]: "map_iarray f as = IArray (map f (IArray.list_of as))" by (cases as) auto lemma [code]: "rel_iarray r as bs = list_all2 r (IArray.list_of as) (IArray.list_of bs)" by (cases as, cases bs) auto lemma list_of_code [code]: "IArray.list_of as = map (\n. as !! n) [0 ..< IArray.length as]" by (cases as) (simp add: map_nth) lemma [code]: "HOL.equal as bs \ HOL.equal (IArray.list_of as) (IArray.list_of bs)" by (cases as, cases bs) (simp add: equal) lemma [code]: "IArray.all p = Not \ IArray.exists (Not \ p)" by (simp add: fun_eq_iff) context includes term_syntax begin lemma [code]: "Code_Evaluation.term_of (as :: 'a::typerep iarray) = Code_Evaluation.Const (STR ''IArray.iarray.IArray'') (TYPEREP('a list \ 'a iarray)) <\> (Code_Evaluation.term_of (IArray.list_of as))" by (subst term_of_anything) rule end subsection \Auxiliary operations for code generation\ context begin qualified primrec tabulate :: "integer \ (integer \ 'a) \ 'a iarray" where "tabulate (n, f) = IArray (map (f \ integer_of_nat) [0.. nat_of_integer)" by simp qualified primrec sub' :: "'a iarray \ integer \ 'a" where "sub' (as, n) = as !! nat_of_integer n" lemma [code]: "IArray.sub' (IArray as, n) = as ! nat_of_integer n" by simp lemma [code]: "as !! n = IArray.sub' (as, integer_of_nat n)" by simp qualified definition length' :: "'a iarray \ integer" where [simp]: "length' as = integer_of_nat (List.length (IArray.list_of as))" lemma [code]: "IArray.length' (IArray as) = integer_of_nat (List.length as)" by simp lemma [code]: "IArray.length as = nat_of_integer (IArray.length' as)" by simp qualified definition exists_upto :: "('a \ bool) \ integer \ 'a iarray \ bool" where [simp]: "exists_upto p k as \ (\l. 0 \ l \ l < k \ p (sub' (as, l)))" lemma exists_upto_of_nat: "exists_upto p (of_nat n) as \ (\m (if k \ 0 then False else let l = k - 1 in p (sub' (as, l)) \ exists_upto p l as)" proof (cases "k \ 1") case False + then have \k \ 0\ + including integer.lifting by transfer simp then show ?thesis - by (auto simp add: not_le discrete) + by simp next case True then have less: "k \ 0 \ False" by simp define n where "n = nat_of_integer (k - 1)" with True have k: "k - 1 = of_nat n" "k = of_nat (Suc n)" by simp_all show ?thesis unfolding less Let_def k(1) unfolding k(2) exists_upto_of_nat using less_Suc_eq by auto qed lemma [code]: "IArray.exists p as \ exists_upto p (length' as) as" including integer.lifting by (simp, transfer) (auto, metis in_set_conv_nth less_imp_of_nat_less nat_int of_nat_0_le_iff) end subsection \Code Generation for SML\ text \Note that arrays cannot be printed directly but only by turning them into lists first. Arrays could be converted back into lists for printing if they were wrapped up in an additional constructor.\ code_reserved SML Vector code_printing type_constructor iarray \ (SML) "_ Vector.vector" | constant IArray \ (SML) "Vector.fromList" | constant IArray.all \ (SML) "Vector.all" | constant IArray.exists \ (SML) "Vector.exists" | constant IArray.tabulate \ (SML) "Vector.tabulate" | constant IArray.sub' \ (SML) "Vector.sub" | constant IArray.length' \ (SML) "Vector.length" subsection \Code Generation for Haskell\ text \We map \<^typ>\'a iarray\s in Isabelle/HOL to \Data.Array.IArray.array\ in Haskell. Performance mapping to \Data.Array.Unboxed.Array\ and \Data.Array.Array\ is similar.\ code_printing code_module "IArray" \ (Haskell) \ module IArray(IArray, tabulate, of_list, sub, length) where { import Prelude (Bool(True, False), not, Maybe(Nothing, Just), Integer, (+), (-), (<), fromInteger, toInteger, map, seq, (.)); import qualified Prelude; import qualified Data.Array.IArray; import qualified Data.Array.Base; import qualified Data.Ix; newtype IArray e = IArray (Data.Array.IArray.Array Integer e); tabulate :: (Integer, (Integer -> e)) -> IArray e; tabulate (k, f) = IArray (Data.Array.IArray.array (0, k - 1) (map (\i -> let fi = f i in fi `seq` (i, fi)) [0..k - 1])); of_list :: [e] -> IArray e; of_list l = IArray (Data.Array.IArray.listArray (0, (toInteger . Prelude.length) l - 1) l); sub :: (IArray e, Integer) -> e; sub (IArray v, i) = v `Data.Array.Base.unsafeAt` fromInteger i; length :: IArray e -> Integer; length (IArray v) = toInteger (Data.Ix.rangeSize (Data.Array.IArray.bounds v)); }\ for type_constructor iarray constant IArray IArray.tabulate IArray.sub' IArray.length' code_reserved Haskell IArray_Impl code_printing type_constructor iarray \ (Haskell) "IArray.IArray _" | constant IArray \ (Haskell) "IArray.of'_list" | constant IArray.tabulate \ (Haskell) "IArray.tabulate" | constant IArray.sub' \ (Haskell) "IArray.sub" | constant IArray.length' \ (Haskell) "IArray.length" end diff --git a/src/HOL/SMT.thy b/src/HOL/SMT.thy --- a/src/HOL/SMT.thy +++ b/src/HOL/SMT.thy @@ -1,898 +1,898 @@ (* Title: HOL/SMT.thy Author: Sascha Boehme, TU Muenchen Author: Jasmin Blanchette, VU Amsterdam *) section \Bindings to Satisfiability Modulo Theories (SMT) solvers based on SMT-LIB 2\ theory SMT imports Divides Numeral_Simprocs keywords "smt_status" :: diag begin subsection \A skolemization tactic and proof method\ lemma choices: "\Q. \x. \y ya. Q x y ya \ \f fa. \x. Q x (f x) (fa x)" "\Q. \x. \y ya yb. Q x y ya yb \ \f fa fb. \x. Q x (f x) (fa x) (fb x)" "\Q. \x. \y ya yb yc. Q x y ya yb yc \ \f fa fb fc. \x. Q x (f x) (fa x) (fb x) (fc x)" "\Q. \x. \y ya yb yc yd. Q x y ya yb yc yd \ \f fa fb fc fd. \x. Q x (f x) (fa x) (fb x) (fc x) (fd x)" "\Q. \x. \y ya yb yc yd ye. Q x y ya yb yc yd ye \ \f fa fb fc fd fe. \x. Q x (f x) (fa x) (fb x) (fc x) (fd x) (fe x)" "\Q. \x. \y ya yb yc yd ye yf. Q x y ya yb yc yd ye yf \ \f fa fb fc fd fe ff. \x. Q x (f x) (fa x) (fb x) (fc x) (fd x) (fe x) (ff x)" "\Q. \x. \y ya yb yc yd ye yf yg. Q x y ya yb yc yd ye yf yg \ \f fa fb fc fd fe ff fg. \x. Q x (f x) (fa x) (fb x) (fc x) (fd x) (fe x) (ff x) (fg x)" by metis+ lemma bchoices: "\Q. \x \ S. \y ya. Q x y ya \ \f fa. \x \ S. Q x (f x) (fa x)" "\Q. \x \ S. \y ya yb. Q x y ya yb \ \f fa fb. \x \ S. Q x (f x) (fa x) (fb x)" "\Q. \x \ S. \y ya yb yc. Q x y ya yb yc \ \f fa fb fc. \x \ S. Q x (f x) (fa x) (fb x) (fc x)" "\Q. \x \ S. \y ya yb yc yd. Q x y ya yb yc yd \ \f fa fb fc fd. \x \ S. Q x (f x) (fa x) (fb x) (fc x) (fd x)" "\Q. \x \ S. \y ya yb yc yd ye. Q x y ya yb yc yd ye \ \f fa fb fc fd fe. \x \ S. Q x (f x) (fa x) (fb x) (fc x) (fd x) (fe x)" "\Q. \x \ S. \y ya yb yc yd ye yf. Q x y ya yb yc yd ye yf \ \f fa fb fc fd fe ff. \x \ S. Q x (f x) (fa x) (fb x) (fc x) (fd x) (fe x) (ff x)" "\Q. \x \ S. \y ya yb yc yd ye yf yg. Q x y ya yb yc yd ye yf yg \ \f fa fb fc fd fe ff fg. \x \ S. Q x (f x) (fa x) (fb x) (fc x) (fd x) (fe x) (ff x) (fg x)" by metis+ ML \ fun moura_tac ctxt = Atomize_Elim.atomize_elim_tac ctxt THEN' SELECT_GOAL (Clasimp.auto_tac (ctxt addSIs @{thms choice choices bchoice bchoices}) THEN ALLGOALS (Metis_Tactic.metis_tac (take 1 ATP_Proof_Reconstruct.partial_type_encs) ATP_Proof_Reconstruct.default_metis_lam_trans ctxt [] ORELSE' blast_tac ctxt)) \ method_setup moura = \ Scan.succeed (SIMPLE_METHOD' o moura_tac) \ "solve skolemization goals, especially those arising from Z3 proofs" hide_fact (open) choices bchoices subsection \Triggers for quantifier instantiation\ text \ Some SMT solvers support patterns as a quantifier instantiation heuristics. Patterns may either be positive terms (tagged by "pat") triggering quantifier instantiations -- when the solver finds a term matching a positive pattern, it instantiates the corresponding quantifier accordingly -- or negative terms (tagged by "nopat") inhibiting quantifier instantiations. A list of patterns of the same kind is called a multipattern, and all patterns in a multipattern are considered conjunctively for quantifier instantiation. A list of multipatterns is called a trigger, and their multipatterns act disjunctively during quantifier instantiation. Each multipattern should mention at least all quantified variables of the preceding quantifier block. \ typedecl 'a symb_list consts Symb_Nil :: "'a symb_list" Symb_Cons :: "'a \ 'a symb_list \ 'a symb_list" typedecl pattern consts pat :: "'a \ pattern" nopat :: "'a \ pattern" definition trigger :: "pattern symb_list symb_list \ bool \ bool" where "trigger _ P = P" subsection \Higher-order encoding\ text \ Application is made explicit for constants occurring with varying numbers of arguments. This is achieved by the introduction of the following constant. \ definition fun_app :: "'a \ 'a" where "fun_app f = f" text \ Some solvers support a theory of arrays which can be used to encode higher-order functions. The following set of lemmas specifies the properties of such (extensional) arrays. \ lemmas array_rules = ext fun_upd_apply fun_upd_same fun_upd_other fun_upd_upd fun_app_def subsection \Normalization\ lemma case_bool_if[abs_def]: "case_bool x y P = (if P then x else y)" by simp lemmas Ex1_def_raw = Ex1_def[abs_def] lemmas Ball_def_raw = Ball_def[abs_def] lemmas Bex_def_raw = Bex_def[abs_def] lemmas abs_if_raw = abs_if[abs_def] lemmas min_def_raw = min_def[abs_def] lemmas max_def_raw = max_def[abs_def] lemma nat_zero_as_int: "0 = nat 0" by simp lemma nat_one_as_int: "1 = nat 1" by simp lemma nat_numeral_as_int: "numeral = (\i. nat (numeral i))" by simp lemma nat_less_as_int: "(<) = (\a b. int a < int b)" by simp lemma nat_leq_as_int: "(\) = (\a b. int a \ int b)" by simp lemma Suc_as_int: "Suc = (\a. nat (int a + 1))" by (rule ext) simp lemma nat_plus_as_int: "(+) = (\a b. nat (int a + int b))" by (rule ext)+ simp lemma nat_minus_as_int: "(-) = (\a b. nat (int a - int b))" by (rule ext)+ simp lemma nat_times_as_int: "(*) = (\a b. nat (int a * int b))" by (simp add: nat_mult_distrib) lemma nat_div_as_int: "(div) = (\a b. nat (int a div int b))" by (simp add: nat_div_distrib) lemma nat_mod_as_int: "(mod) = (\a b. nat (int a mod int b))" by (simp add: nat_mod_distrib) lemma int_Suc: "int (Suc n) = int n + 1" by simp lemma int_plus: "int (n + m) = int n + int m" by (rule of_nat_add) lemma int_minus: "int (n - m) = int (nat (int n - int m))" by auto lemma nat_int_comparison: fixes a b :: nat shows "(a = b) = (int a = int b)" and "(a < b) = (int a < int b)" and "(a \ b) = (int a \ int b)" by simp_all lemma int_ops: fixes a b :: nat shows "int 0 = 0" and "int 1 = 1" and "int (numeral n) = numeral n" and "int (Suc a) = int a + 1" and "int (a + b) = int a + int b" and "int (a - b) = (if int a < int b then 0 else int a - int b)" and "int (a * b) = int a * int b" and "int (a div b) = int a div int b" and "int (a mod b) = int a mod int b" by (auto intro: zdiv_int zmod_int) lemma int_if: fixes a b :: nat shows "int (if P then a else b) = (if P then int a else int b)" by simp subsection \Integer division and modulo for Z3\ text \ The following Z3-inspired definitions are overspecified for the case where \l = 0\. This Schönheitsfehler is corrected in the \div_as_z3div\ and \mod_as_z3mod\ theorems. \ definition z3div :: "int \ int \ int" where "z3div k l = (if l \ 0 then k div l else - (k div - l))" definition z3mod :: "int \ int \ int" where "z3mod k l = k mod (if l \ 0 then l else - l)" lemma div_as_z3div: "\k l. k div l = (if l = 0 then 0 else if l > 0 then z3div k l else z3div (- k) (- l))" by (simp add: z3div_def) lemma mod_as_z3mod: "\k l. k mod l = (if l = 0 then k else if l > 0 then z3mod k l else - z3mod (- k) (- l))" by (simp add: z3mod_def) subsection \Extra theorems for veriT reconstruction\ lemma verit_sko_forall: \(\x. P x) \ P (SOME x. \P x)\ using someI[of \\x. \P x\] by auto lemma verit_sko_forall': \P (SOME x. \P x) = A \ (\x. P x) = A\ by (subst verit_sko_forall) lemma verit_sko_forall'': \B = A \ (SOME x. P x) = A \ (SOME x. P x) = B\ by auto lemma verit_sko_forall_indirect: \x = (SOME x. \P x) \ (\x. P x) \ P x\ using someI[of \\x. \P x\] by auto lemma verit_sko_forall_indirect2: \x = (SOME x. \P x) \ (\x :: 'a. (P x = P' x)) \(\x. P' x) \ P x\ using someI[of \\x. \P x\] by auto lemma verit_sko_ex: \(\x. P x) \ P (SOME x. P x)\ using someI[of \\x. P x\] by auto lemma verit_sko_ex': \P (SOME x. P x) = A \ (\x. P x) = A\ by (subst verit_sko_ex) lemma verit_sko_ex_indirect: \x = (SOME x. P x) \ (\x. P x) \ P x\ using someI[of \\x. P x\] by auto lemma verit_sko_ex_indirect2: \x = (SOME x. P x) \ (\x. P x = P' x) \ (\x. P' x) \ P x\ using someI[of \\x. P x\] by auto lemma verit_Pure_trans: \P \ Q \ Q \ P\ by auto lemma verit_if_cong: assumes \b \ c\ and \c \ x \ u\ and \\ c \ y \ v\ shows \(if b then x else y) \ (if c then u else v)\ using assms if_cong[of b c x u] by auto lemma verit_if_weak_cong': \b \ c \ (if b then x else y) \ (if c then x else y)\ by auto lemma verit_or_neg: \(A \ B) \ B \ \A\ \(\A \ B) \ B \ A\ by auto lemma verit_subst_bool: \P \ f True \ f P\ by auto lemma verit_and_pos: \(a \ \(b \ c) \ A) \ \(a \ b \ c) \ A\ \(a \ b \ A) \ \(a \ b) \ A\ \(a \ A) \ \a \ A\ \(\a \ A) \ a \ A\ by blast+ lemma verit_or_pos: \A \ A' \ (c \ A) \ (\c \ A')\ \A \ A' \ (\c \ A) \ (c \ A')\ by blast+ lemma verit_la_generic: \(a::int) \ x \ a = x \ a \ x\ by linarith lemma verit_bfun_elim: \(if b then P True else P False) = P b\ \(\b. P' b) = (P' False \ P' True)\ \(\b. P' b) = (P' False \ P' True)\ by (cases b) (auto simp: all_bool_eq ex_bool_eq) lemma verit_eq_true_simplify: \(P = True) \ P\ by auto lemma verit_and_neg: \(a \ \b \ A) \ \(a \ b) \ A\ \(a \ A) \ \a \ A\ \(\a \ A) \ a \ A\ by blast+ lemma verit_forall_inst: \A \ B \ \A \ B\ \\A \ B \ A \ B\ \A \ B \ \B \ A\ \A \ \B \ B \ A\ \A \ B \ \A \ B\ \\A \ B \ A \ B\ by blast+ lemma verit_eq_transitive: \A = B \ B = C \ A = C\ \A = B \ C = B \ A = C\ \B = A \ B = C \ A = C\ \B = A \ C = B \ A = C\ by auto lemma verit_bool_simplify: \\(P \ Q) \ P \ \Q\ \\(P \ Q) \ \P \ \Q\ \\(P \ Q) \ \P \ \Q\ \(P \ (Q \ R)) \ ((P \ Q) \ R)\ \((P \ Q) \ Q) \ P \ Q\ \(Q \ (P \ Q)) \ (P \ Q)\ \ \This rule was inverted\ \P \ (P \ Q) \ P \ Q\ \(P \ Q) \ P \ P \ Q\ (* \\Additional rules:\ * \((P \ Q) \ P) \ P\ * \((P \ Q) \ Q) \ P \ Q\ * \(P \ Q) \ P\ *) unfolding not_imp imp_conjL by auto text \We need the last equation for \<^term>\\(\a b. \P a b)\\ lemma verit_connective_def: \ \the definition of XOR is missing as the operator is not generated by Isabelle\ \(A = B) \ ((A \ B) \ (B \ A))\ \(If A B C) = ((A \ B) \ (\A \ C))\ \(\x. P x) \ \(\x. \P x)\ \\(\x. P x) \ (\x. \P x)\ by auto lemma verit_ite_simplify: \(If True B C) = B\ \(If False B C) = C\ \(If A' B B) = B\ \(If (\A') B C) = (If A' C B)\ \(If c (If c A B) C) = (If c A C)\ \(If c C (If c A B)) = (If c C B)\ \(If A' True False) = A'\ \(If A' False True) \ \A'\ \(If A' True B') \ A'\B'\ \(If A' B' False) \ A'\B'\ \(If A' False B') \ \A'\B'\ \(If A' B' True) \ \A'\B'\ \x \ True \ x\ \x \ False \ x\ for B C :: 'a and A' B' C' :: bool by auto lemma verit_and_simplify1: \True \ b \ b\ \b \ True \ b\ \False \ b \ False\ \b \ False \ False\ \(c \ \c) \ False\ \(\c \ c) \ False\ \\\a = a\ by auto lemmas verit_and_simplify = conj_ac de_Morgan_conj disj_not1 lemma verit_or_simplify_1: \False \ b \ b\ \b \ False \ b\ \b \ \b\ \\b \ b\ by auto lemmas verit_or_simplify = disj_ac lemma verit_not_simplify: \\ \b \ b\ \\True \ False\ \\False \ True\ by auto lemma verit_implies_simplify: \(\a \ \b) \ (b \ a)\ \(False \ a) \ True\ \(a \ True) \ True\ \(True \ a) \ a\ \(a \ False) \ \a\ \(a \ a) \ True\ \(\a \ a) \ a\ \(a \ \a) \ \a\ \((a \ b) \ b) \ a \ b\ by auto lemma verit_equiv_simplify: \((\a) = (\b)) \ (a = b)\ \(a = a) \ True\ \(a = (\a)) \ False\ \((\a) = a) \ False\ \(True = a) \ a\ \(a = True) \ a\ \(False = a) \ \a\ \(a = False) \ \a\ \\\a \ a\ \(\ False) = True\ for a b :: bool by auto lemmas verit_eq_simplify = semiring_char_0_class.eq_numeral_simps eq_refl zero_neq_one num.simps neg_equal_zero equal_neg_zero one_neq_zero neg_equal_iff_equal lemma verit_minus_simplify: \(a :: 'a :: cancel_comm_monoid_add) - a = 0\ \(a :: 'a :: cancel_comm_monoid_add) - 0 = a\ \0 - (b :: 'b :: {group_add}) = -b\ \- (- (b :: 'b :: group_add)) = b\ by auto lemma verit_sum_simplify: \(a :: 'a :: cancel_comm_monoid_add) + 0 = a\ by auto lemmas verit_prod_simplify = (* already included: mult_zero_class.mult_zero_right mult_zero_class.mult_zero_left *) mult_1 mult_1_right lemma verit_comp_simplify1: \(a :: 'a ::order) < a \ False\ \a \ a\ \\(b' \ a') \ (a' :: 'b :: linorder) < b'\ by auto lemmas verit_comp_simplify = verit_comp_simplify1 le_numeral_simps le_num_simps less_numeral_simps less_num_simps zero_less_one zero_le_one less_neg_numeral_simps lemma verit_la_disequality: \(a :: 'a ::linorder) = b \ \a \ b \ \b \ a\ by auto context begin text \For the reconstruction, we need to keep the order of the arguments.\ named_theorems smt_arith_multiplication \Theorems to reconstruct arithmetic theorems.\ named_theorems smt_arith_combine \Theorems to reconstruct arithmetic theorems.\ named_theorems smt_arith_simplify \Theorems to combine theorems in the LA procedure\ lemmas [smt_arith_simplify] = div_add dvd_numeral_simp divmod_steps less_num_simps le_num_simps if_True if_False divmod_cancel - dvd_mult dvd_mult2 less_irrefl prod.case numeral_plus_one divmod_step_eq order.refl le_zero_eq + dvd_mult dvd_mult2 less_irrefl prod.case numeral_plus_one divmod_step_def order.refl le_zero_eq le_numeral_simps less_numeral_simps mult.right_neutral simp_thms divides_aux_eq mult_nonneg_nonneg dvd_imp_mod_0 dvd_add zero_less_one mod_mult_self4 numeral_mod_numeral divmod_trivial prod.sel mult.left_neutral div_pos_pos_trivial arith_simps div_add div_mult_self1 add_le_cancel_left add_le_same_cancel2 not_one_le_zero le_numeral_simps add_le_same_cancel1 zero_neq_one zero_le_one le_num_simps add_Suc mod_div_trivial nat.distinct mult_minus_right add.inverse_inverse distrib_left_numeral mult_num_simps numeral_times_numeral add_num_simps divmod_steps rel_simps if_True if_False numeral_div_numeral divmod_cancel prod.case - add_num_simps one_plus_numeral fst_conv divmod_step_eq arith_simps sub_num_simps dbl_inc_simps + add_num_simps one_plus_numeral fst_conv arith_simps sub_num_simps dbl_inc_simps dbl_simps mult_1 add_le_cancel_right left_diff_distrib_numeral add_uminus_conv_diff zero_neq_one zero_le_one One_nat_def add_Suc mod_div_trivial nat.distinct of_int_1 numerals numeral_One of_int_numeral add_uminus_conv_diff zle_diff1_eq add_less_same_cancel2 minus_add_distrib add_uminus_conv_diff mult.left_neutral semiring_class.distrib_right add_diff_cancel_left' add_diff_eq ring_distribs mult_minus_left minus_diff_eq lemma [smt_arith_simplify]: \\ (a' :: 'a :: linorder) < b' \ b' \ a'\ \\ (a' :: 'a :: linorder) \ b' \ b' < a'\ \(c::int) mod Numeral1 = 0\ \(a::nat) mod Numeral1 = 0\ \(c::int) div Numeral1 = c\ \a div Numeral1 = a\ \(c::int) mod 1 = 0\ \a mod 1 = 0\ \(c::int) div 1 = c\ \a div 1 = a\ \\(a' \ b') \ a' = b'\ by auto lemma div_mod_decomp: "A = (A div n) * n + (A mod n)" for A :: nat by auto lemma div_less_mono: fixes A B :: nat assumes "A < B" "0 < n" and mod: "A mod n = 0""B mod n = 0" shows "(A div n) < (B div n)" proof - show ?thesis using assms(1) apply (subst (asm) div_mod_decomp[of "A" n]) apply (subst (asm) div_mod_decomp[of "B" n]) unfolding mod by (use assms(2,3) in \auto simp: ac_simps\) qed lemma verit_le_mono_div: fixes A B :: nat assumes "A < B" "0 < n" shows "(A div n) + (if B mod n = 0 then 1 else 0) \ (B div n)" by (auto simp: ac_simps Suc_leI assms less_mult_imp_div_less div_le_mono less_imp_le_nat) lemmas [smt_arith_multiplication] = verit_le_mono_div[THEN mult_le_mono1, unfolded add_mult_distrib] div_le_mono[THEN mult_le_mono2, unfolded add_mult_distrib] lemma div_mod_decomp_int: "A = (A div n) * n + (A mod n)" for A :: int by auto lemma zdiv_mono_strict: fixes A B :: int assumes "A < B" "0 < n" and mod: "A mod n = 0""B mod n = 0" shows "(A div n) < (B div n)" proof - show ?thesis using assms(1) apply (subst (asm) div_mod_decomp_int[of A n]) apply (subst (asm) div_mod_decomp_int[of B n]) unfolding mod by (use assms(2,3) in \auto simp: ac_simps\) qed lemma verit_le_mono_div_int: fixes A B :: int assumes "A < B" "0 < n" shows "(A div n) + (if B mod n = 0 then 1 else 0) \ (B div n)" proof - have f2: "B div n = A div n \ A div n < B div n" by (metis (no_types) assms less_le zdiv_mono1) have "B div n \ A div n \ B mod n \ 0" using assms(1) by (metis Groups.add_ac(2) assms(2) eucl_rel_int eucl_rel_int_iff group_cancel.rule0 le_add_same_cancel2 not_le) then have "B mod n = 0 \ A div n + (if B mod n = 0 then 1 else 0) \ B div n" using f2 by (auto dest: zless_imp_add1_zle) then show ?thesis using assms zdiv_mono1 by auto qed lemma verit_less_mono_div_int2: fixes A B :: int assumes "A \ B" "0 < -n" shows "(A div n) \ (B div n)" using assms(1) assms(2) zdiv_mono1_neg by auto lemmas [smt_arith_multiplication] = verit_le_mono_div_int[THEN mult_left_mono, unfolded int_distrib] zdiv_mono1[THEN mult_left_mono, unfolded int_distrib] lemmas [smt_arith_multiplication] = arg_cong[of _ _ \\a :: nat. a div n * p\ for n p :: nat, THEN sym] arg_cong[of _ _ \\a :: int. a div n * p\ for n p :: int, THEN sym] lemma [smt_arith_combine]: "a < b \ c < d \ a + c + 2 \ b + d" "a < b \ c \ d \ a + c + 1 \ b + d" "a \ b \ c < d \ a + c + 1 \ b + d" for a b c :: int by auto lemma [smt_arith_combine]: "a < b \ c < d \ a + c + 2 \ b + d" "a < b \ c \ d \ a + c + 1 \ b + d" "a \ b \ c < d \ a + c + 1 \ b + d" for a b c :: nat by auto lemmas [smt_arith_combine] = add_strict_mono add_less_le_mono add_mono add_le_less_mono lemma [smt_arith_combine]: \m < n \ c = d \ m + c < n + d\ \m \ n \ c = d \ m + c \ n + d\ \c = d \ m < n \ m + c < n + d\ \c = d \ m \ n \ m + c \ n + d\ for m :: \'a :: ordered_cancel_ab_semigroup_add\ by (auto intro: ordered_cancel_ab_semigroup_add_class.add_strict_right_mono ordered_ab_semigroup_add_class.add_right_mono) lemma verit_negate_coefficient: \a \ (b :: 'a :: {ordered_ab_group_add}) \ -a \ -b\ \a < b \ -a > -b\ \a = b \ -a = -b\ by auto end lemma verit_ite_intro: \(if a then P (if a then a' else b') else Q) \ (if a then P a' else Q)\ \(if a then P' else Q' (if a then a' else b')) \ (if a then P' else Q' b')\ \A = f (if a then R else S) \ (if a then A = f R else A = f S)\ by auto lemma verit_ite_if_cong: fixes x y :: bool assumes "b=c" and "c \ True \ x = u" and "c \ False \ y = v" shows "(if b then x else y) \ (if c then u else v)" proof - have H: "(if b then x else y) = (if c then u else v)" using assms by (auto split: if_splits) show "(if b then x else y) \ (if c then u else v)" by (subst H) auto qed subsection \Setup\ ML_file \Tools/SMT/smt_util.ML\ ML_file \Tools/SMT/smt_failure.ML\ ML_file \Tools/SMT/smt_config.ML\ ML_file \Tools/SMT/smt_builtin.ML\ ML_file \Tools/SMT/smt_datatypes.ML\ ML_file \Tools/SMT/smt_normalize.ML\ ML_file \Tools/SMT/smt_translate.ML\ ML_file \Tools/SMT/smtlib.ML\ ML_file \Tools/SMT/smtlib_interface.ML\ ML_file \Tools/SMT/smtlib_proof.ML\ ML_file \Tools/SMT/smtlib_isar.ML\ ML_file \Tools/SMT/z3_proof.ML\ ML_file \Tools/SMT/z3_isar.ML\ ML_file \Tools/SMT/smt_solver.ML\ ML_file \Tools/SMT/cvc_interface.ML\ ML_file \Tools/SMT/lethe_proof.ML\ ML_file \Tools/SMT/lethe_isar.ML\ ML_file \Tools/SMT/lethe_proof_parse.ML\ ML_file \Tools/SMT/cvc_proof_parse.ML\ ML_file \Tools/SMT/verit_proof.ML\ ML_file \Tools/SMT/conj_disj_perm.ML\ ML_file \Tools/SMT/smt_replay_methods.ML\ ML_file \Tools/SMT/smt_replay.ML\ ML_file \Tools/SMT/smt_replay_arith.ML\ ML_file \Tools/SMT/z3_interface.ML\ ML_file \Tools/SMT/z3_replay_rules.ML\ ML_file \Tools/SMT/z3_replay_methods.ML\ ML_file \Tools/SMT/z3_replay.ML\ ML_file \Tools/SMT/lethe_replay_methods.ML\ ML_file \Tools/SMT/verit_replay_methods.ML\ ML_file \Tools/SMT/verit_replay.ML\ ML_file \Tools/SMT/smt_systems.ML\ subsection \Configuration\ text \ The current configuration can be printed by the command \smt_status\, which shows the values of most options. \ subsection \General configuration options\ text \ The option \smt_solver\ can be used to change the target SMT solver. The possible values can be obtained from the \smt_status\ command. \ declare [[smt_solver = z3]] text \ Since SMT solvers are potentially nonterminating, there is a timeout (given in seconds) to restrict their runtime. \ declare [[smt_timeout = 0]] text \ SMT solvers apply randomized heuristics. In case a problem is not solvable by an SMT solver, changing the following option might help. \ declare [[smt_random_seed = 1]] text \ In general, the binding to SMT solvers runs as an oracle, i.e, the SMT solvers are fully trusted without additional checks. The following option can cause the SMT solver to run in proof-producing mode, giving a checkable certificate. This is currently implemented only for veriT and Z3. \ declare [[smt_oracle = false]] text \ Each SMT solver provides several command-line options to tweak its behaviour. They can be passed to the solver by setting the following options. \ declare [[cvc4_options = ""]] declare [[cvc5_options = ""]] declare [[verit_options = ""]] declare [[z3_options = ""]] text \ The SMT method provides an inference mechanism to detect simple triggers in quantified formulas, which might increase the number of problems solvable by SMT solvers (note: triggers guide quantifier instantiations in the SMT solver). To turn it on, set the following option. \ declare [[smt_infer_triggers = false]] text \ Enable the following option to use built-in support for datatypes, codatatypes, and records in CVC4 and cvc5. Currently, this is implemented only in oracle mode. \ declare [[cvc_extensions = false]] text \ Enable the following option to use built-in support for div/mod, datatypes, and records in Z3. Currently, this is implemented only in oracle mode. \ declare [[z3_extensions = false]] subsection \Certificates\ text \ By setting the option \smt_certificates\ to the name of a file, all following applications of an SMT solver a cached in that file. Any further application of the same SMT solver (using the very same configuration) re-uses the cached certificate instead of invoking the solver. An empty string disables caching certificates. The filename should be given as an explicit path. It is good practice to use the name of the current theory (with ending \.certs\ instead of \.thy\) as the certificates file. Certificate files should be used at most once in a certain theory context, to avoid race conditions with other concurrent accesses. \ declare [[smt_certificates = ""]] text \ The option \smt_read_only_certificates\ controls whether only stored certificates should be used or invocation of an SMT solver is allowed. When set to \true\, no SMT solver will ever be invoked and only the existing certificates found in the configured cache are used; when set to \false\ and there is no cached certificate for some proposition, then the configured SMT solver is invoked. \ declare [[smt_read_only_certificates = false]] subsection \Tracing\ text \ The SMT method, when applied, traces important information. To make it entirely silent, set the following option to \false\. \ declare [[smt_verbose = true]] text \ For tracing the generated problem file given to the SMT solver as well as the returned result of the solver, the option \smt_trace\ should be set to \true\. \ declare [[smt_trace = false]] subsection \Schematic rules for Z3 proof reconstruction\ text \ Several prof rules of Z3 are not very well documented. There are two lemma groups which can turn failing Z3 proof reconstruction attempts into succeeding ones: the facts in \z3_rule\ are tried prior to any implemented reconstruction procedure for all uncertain Z3 proof rules; the facts in \z3_simp\ are only fed to invocations of the simplifier when reconstructing theory-specific proof steps. \ lemmas [z3_rule] = refl eq_commute conj_commute disj_commute simp_thms nnf_simps ring_distribs field_simps times_divide_eq_right times_divide_eq_left if_True if_False not_not NO_MATCH_def lemma [z3_rule]: "(P \ Q) = (\ (\ P \ \ Q))" "(P \ Q) = (\ (\ Q \ \ P))" "(\ P \ Q) = (\ (P \ \ Q))" "(\ P \ Q) = (\ (\ Q \ P))" "(P \ \ Q) = (\ (\ P \ Q))" "(P \ \ Q) = (\ (Q \ \ P))" "(\ P \ \ Q) = (\ (P \ Q))" "(\ P \ \ Q) = (\ (Q \ P))" by auto lemma [z3_rule]: "(P \ Q) = (Q \ \ P)" "(\ P \ Q) = (P \ Q)" "(\ P \ Q) = (Q \ P)" "(True \ P) = P" "(P \ True) = True" "(False \ P) = True" "(P \ P) = True" "(\ (A \ \ B)) \ (A \ B)" by auto lemma [z3_rule]: "((P = Q) \ R) = (R \ (Q = (\ P)))" by auto lemma [z3_rule]: "(\ True) = False" "(\ False) = True" "(x = x) = True" "(P = True) = P" "(True = P) = P" "(P = False) = (\ P)" "(False = P) = (\ P)" "((\ P) = P) = False" "(P = (\ P)) = False" "((\ P) = (\ Q)) = (P = Q)" "\ (P = (\ Q)) = (P = Q)" "\ ((\ P) = Q) = (P = Q)" "(P \ Q) = (Q = (\ P))" "(P = Q) = ((\ P \ Q) \ (P \ \ Q))" "(P \ Q) = ((\ P \ \ Q) \ (P \ Q))" by auto lemma [z3_rule]: "(if P then P else \ P) = True" "(if \ P then \ P else P) = True" "(if P then True else False) = P" "(if P then False else True) = (\ P)" "(if P then Q else True) = ((\ P) \ Q)" "(if P then Q else True) = (Q \ (\ P))" "(if P then Q else \ Q) = (P = Q)" "(if P then Q else \ Q) = (Q = P)" "(if P then \ Q else Q) = (P = (\ Q))" "(if P then \ Q else Q) = ((\ Q) = P)" "(if \ P then x else y) = (if P then y else x)" "(if P then (if Q then x else y) else x) = (if P \ (\ Q) then y else x)" "(if P then (if Q then x else y) else x) = (if (\ Q) \ P then y else x)" "(if P then (if Q then x else y) else y) = (if P \ Q then x else y)" "(if P then (if Q then x else y) else y) = (if Q \ P then x else y)" "(if P then x else if P then y else z) = (if P then x else z)" "(if P then x else if Q then x else y) = (if P \ Q then x else y)" "(if P then x else if Q then x else y) = (if Q \ P then x else y)" "(if P then x = y else x = z) = (x = (if P then y else z))" "(if P then x = y else y = z) = (y = (if P then x else z))" "(if P then x = y else z = y) = (y = (if P then x else z))" by auto lemma [z3_rule]: "0 + (x::int) = x" "x + 0 = x" "x + x = 2 * x" "0 * x = 0" "1 * x = x" "x + y = y + x" by auto lemma [z3_rule]: (* for def-axiom *) "P = Q \ P \ Q" "P = Q \ \ P \ \ Q" "(\ P) = Q \ \ P \ Q" "(\ P) = Q \ P \ \ Q" "P = (\ Q) \ \ P \ Q" "P = (\ Q) \ P \ \ Q" "P \ Q \ P \ \ Q" "P \ Q \ \ P \ Q" "P \ (\ Q) \ P \ Q" "(\ P) \ Q \ P \ Q" "P \ Q \ P \ (\ Q)" "P \ Q \ (\ P) \ Q" "P \ \ Q \ P \ Q" "\ P \ Q \ P \ Q" "P \ y = (if P then x else y)" "P \ (if P then x else y) = y" "\ P \ x = (if P then x else y)" "\ P \ (if P then x else y) = x" "P \ R \ \ (if P then Q else R)" "\ P \ Q \ \ (if P then Q else R)" "\ (if P then Q else R) \ \ P \ Q" "\ (if P then Q else R) \ P \ R" "(if P then Q else R) \ \ P \ \ Q" "(if P then Q else R) \ P \ \ R" "(if P then \ Q else R) \ \ P \ Q" "(if P then Q else \ R) \ P \ R" by auto hide_type (open) symb_list pattern hide_const (open) Symb_Nil Symb_Cons trigger pat nopat fun_app z3div z3mod end