diff --git a/thys/Irrational_Series_Erdos_Straus/Irrational_Series_Erdos_Straus.thy b/thys/Irrational_Series_Erdos_Straus/Irrational_Series_Erdos_Straus.thy --- a/thys/Irrational_Series_Erdos_Straus/Irrational_Series_Erdos_Straus.thy +++ b/thys/Irrational_Series_Erdos_Straus/Irrational_Series_Erdos_Straus.thy @@ -1,1984 +1,1968 @@ (* Title: Irrational_Series_Erdos_Straus.thy Author: Angeliki Koutsoukou-Argyraki and Wenda Li, University of Cambridge, UK. We formalise certain irrationality criteria for infinite series by P. Erdos and E.G. Straus. In particular, we formalise Theorem 2.1, Corollary 2.10 and Theorem 3.1 in [1]. The latter is an application of Theorem 2.1 involving the prime numbers. References: [1] P. Erdos and E.G. Straus, On the irrationality of certain series, Pacific Journal of Mathematics, Vol. 55, No 1, 1974 https://projecteuclid.org/euclid.pjm/1102911140 *) theory "Irrational_Series_Erdos_Straus" imports Prime_Number_Theorem.Prime_Number_Theorem Prime_Distribution_Elementary.PNT_Consequences begin section \Miscellaneous\ lemma suminf_comparison: assumes "summable f" and gf: "\n. norm (g n) \ f n" shows "suminf g \ suminf f" proof (rule suminf_le) show "g n \ f n" for n using gf[of n] by auto show "summable g" using assms summable_comparison_test' by blast show "summable f" using assms(1) . qed lemma tendsto_of_int_diff_0: assumes "(\n. f n - of_int(g n)) \ (0::real)" "\\<^sub>F n in sequentially. f n > 0" shows "\\<^sub>F n in sequentially. 0 \ g n" proof - have "\\<^sub>F n in sequentially. \f n - of_int(g n)\ < 1 / 2" using assms(1)[unfolded tendsto_iff,rule_format,of "1/2"] by auto then show ?thesis using assms(2) by eventually_elim linarith qed lemma eventually_mono_sequentially: assumes "eventually P sequentially" assumes "\x. P (x+k) \ Q (x+k)" shows "eventually Q sequentially" using sequentially_offset[OF assms(1),of k] apply (subst eventually_sequentially_seg[symmetric,of _ k]) apply (elim eventually_mono) by fact lemma frequently_eventually_at_top: fixes P Q::"'a::linorder \ bool" assumes "frequently P at_top" "eventually Q at_top" shows "frequently (\x. P x \ (\y\x. Q y) ) at_top" using assms unfolding frequently_def eventually_at_top_linorder by (metis (mono_tags, opaque_lifting) le_cases order_trans) lemma eventually_at_top_mono: fixes P Q::"'a::linorder \ bool" assumes event_P:"eventually P at_top" assumes PQ_imp:"\x. x\z \ \y\x. P y \ Q x" shows "eventually Q at_top" proof - obtain N where "\n\N. P n" by (meson event_P eventually_at_top_linorder) then have "Q x" when "x \ max N z" for x using PQ_imp that by auto then show ?thesis unfolding eventually_at_top_linorder by blast qed lemma frequently_at_top_elim: fixes P Q::"'a::linorder \ bool" assumes "\\<^sub>Fx in at_top. P x" assumes "\i. P i \ \j>i. Q j" shows "\\<^sub>Fx in at_top. Q x" using assms unfolding frequently_def eventually_at_top_linorder by (meson leD le_cases less_le_trans) lemma less_Liminf_iff: fixes X :: "_ \ _ :: complete_linorder" shows "Liminf F X < C \ (\yx. y \ X x) F)" by (force simp: not_less not_frequently not_le le_Liminf_iff simp flip: Not_eq_iff) lemma sequentially_even_odd_imp: assumes "\\<^sub>F N in sequentially. P (2*N)" "\\<^sub>F N in sequentially. P (2*N+1)" shows "\\<^sub>F n in sequentially. P n" proof - obtain N where N_P:"\x\N. P (2 * x) \ P (2 * x + 1)" using eventually_conj[OF assms] unfolding eventually_at_top_linorder by auto have "P n" when "n \ 2*N" for n proof - define n' where "n'= n div 2" then have "n' \ N" using that by auto then have "P (2 * n') \ P (2 * n' + 1)" using N_P by auto then show ?thesis unfolding n'_def by (cases "even n") auto qed then show ?thesis unfolding eventually_at_top_linorder by auto qed section \Theorem 2.1 and Corollary 2.10\ context fixes a b ::"nat\int " assumes a_pos: "\ n. a n >0 " and a_large: "\\<^sub>F n in sequentially. a n > 1" and ab_tendsto: "(\n. \b n\ / (a (n-1) * a n)) \ 0" begin private lemma aux_series_summable: "summable (\n. b n / (\k\n. a k))" proof - have "\e. e>0 \ \\<^sub>F x in sequentially. \b x\ / (a (x-1) * a x) < e" using ab_tendsto[unfolded tendsto_iff] apply (simp add: abs_mult flip: of_int_abs) by (subst (asm) (2) abs_of_pos,use \\ n. a n > 0\ in auto)+ from this[of 1] have "\\<^sub>F x in sequentially. \real_of_int(b x)\ < (a (x-1) * a x)" using \\ n. a n > 0\ by auto moreover have "\n. (\k\n. real_of_int (a k)) > 0" using a_pos by (auto intro!:linordered_semidom_class.prod_pos) ultimately have "\\<^sub>F n in sequentially. \b n\ / (\k\n. a k) < (a (n-1) * a n) / (\k\n. a k)" apply (elim eventually_mono) - by (auto simp add:field_simps) + by (auto simp:field_simps) moreover have "\b n\ / (\k\n. a k) = norm (b n / (\k\n. a k))" for n using \\n. (\k\n. real_of_int (a k)) > 0\[rule_format,of n] by auto ultimately have "\\<^sub>F n in sequentially. norm (b n / (\k\n. a k)) < (a (n-1) * a n) / (\k\n. a k)" by algebra moreover have "summable (\n. (a (n-1) * a n) / (\k\n. a k))" proof - obtain s where a_gt_1:"\ n\s. a n >1" using a_large[unfolded eventually_at_top_linorder] by auto define cc where "cc= (\k0" unfolding cc_def by (meson a_pos prod_pos) have "(\k\n+s. a k) \ cc * 2^n" for n proof - have "prod a {s.. 2^n" proof (induct n) case 0 then show ?case using a_gt_1 by auto next case (Suc n) - moreover have "a (s + Suc n) \ 2" - using a_gt_1 by (smt le_add1) + moreover have "a (s + Suc n) \ 2" + by (smt (verit, ccfv_threshold) a_gt_1 le_add1) ultimately show ?case apply (subst prod.atLeastLessThan_Suc,simp) using mult_mono'[of 2 "a (Suc (s + n))" " 2 ^ n" "prod a {s..cc>0\ unfolding cc_def by (simp add: atLeast0AtMost) qed then have "1/(\k\n+s. a k) \ 1/(cc * 2^n)" for n proof - assume asm:"\n. cc * 2 ^ n \ prod a {..n + s}" then have "real_of_int (cc * 2 ^ n) \ prod a {..n + s}" using of_int_le_iff by blast moreover have "prod a {..n + s} >0" using \cc>0\ by (simp add: a_pos prod_pos) ultimately show ?thesis using \cc>0\ by (auto simp:field_simps simp del:of_int_prod) qed moreover have "summable (\n. 1/(cc * 2^n))" proof - have "summable (\n. 1/(2::int)^n)" using summable_geometric[of "1/(2::int)"] by (simp add:power_one_over) from summable_mult[OF this,of "1/cc"] show ?thesis by auto qed ultimately have "summable (\n. 1 / (\k\n+s. a k))" apply (elim summable_comparison_test'[where N=0]) apply (unfold real_norm_def, subst abs_of_pos) - by (auto simp add: \\n. 0 < (\k\n. real_of_int (a k))\) + by (auto simp: \\n. 0 < (\k\n. real_of_int (a k))\) then have "summable (\n. 1 / (\k\n. a k))" apply (subst summable_iff_shift[where k=s,symmetric]) by simp then have "summable (\n. (a (n+1) * a (n+2)) / (\k\n+2. a k))" proof - assume asm:"summable (\n. 1 / real_of_int (prod a {..n}))" have "1 / real_of_int (prod a {..n}) = (a (n+1) * a (n+2)) / (\k\n+2. a k)" for n proof - have "a (Suc (Suc n)) \ 0" "a (Suc n) \0" using a_pos by (metis less_irrefl)+ then show ?thesis by (simp add: atLeast0_atMost_Suc atMost_atLeast0) qed then show ?thesis using asm by auto qed then show "summable (\n. (a (n-1) * a n) / (\k\n. a k))" apply (subst summable_iff_shift[symmetric,of _ 2]) by auto qed ultimately show ?thesis apply (elim summable_comparison_test_ev[rotated]) by (simp add: eventually_mono) qed private fun get_c::"(nat \ int) \ (nat \ int) \ int \ nat \ (nat \ int)" where "get_c a' b' B N 0 = round (B * b' N / a' N)"| "get_c a' b' B N (Suc n) = get_c a' b' B N n * a' (n+N) - B * b' (n+N)" lemma ab_rationality_imp: assumes ab_rational:"(\n. (b n / (\i \ n. a i))) \ \" shows "\ (B::int)>0. \ c::nat\ int. (\\<^sub>F n in sequentially. B*b n = c n * a n - c(n+1) \ \c(n+1)\ (\n. c (Suc n) / a n) \ 0" proof - have [simp]:"a n \ 0" for n using a_pos by (metis less_numeral_extra(3)) obtain A::int and B::int where AB_eq:"(\n. real_of_int (b n) / real_of_int (prod a {..n})) = A / B" and "B>0" proof - obtain q::rat where "(\n. real_of_int (b n) / real_of_int (prod a {..n})) = real_of_rat q" using ab_rational by (rule Rats_cases) simp moreover obtain A::int and B::int where "q = Rat.Fract A B" "B > 0" "coprime A B" by (rule Rat_cases) auto ultimately show ?thesis by (auto intro!: that[of A B] simp:of_rat_rat) qed define f where "f \ (\n. b n / real_of_int (prod a {..n}))" define R where "R \ (\N. (\n. B*b (n+N+1) / prod a {N..n+N+1}))" have all_e_ubound:"\e>0. \\<^sub>F M in sequentially. \n. \B*b (n+M+1) / prod a {M..n+M+1}\ < e/4 * 1/2^n" proof safe fix e::real assume "e>0" obtain N where N_a2: "\n \ N. a n \ 2" and N_ba: "\n \ N. \b n\ / (a (n-1) * a n) < e/(4*B)" proof - have "\\<^sub>F n in sequentially. \b n\ / (a (n - 1) * a n) < e/(4*B)" using order_topology_class.order_tendstoD[OF ab_tendsto,of "e/(4*B)"] \B>0\ \e>0\ by auto moreover have "\\<^sub>F n in sequentially. a n \ 2" using a_large by (auto elim: eventually_mono) ultimately have "\\<^sub>F n in sequentially. \b n\ / (a (n - 1) * a n) < e/(4*B) \ a n \ 2" by eventually_elim auto then show ?thesis unfolding eventually_at_top_linorder using that by auto qed have geq_N_bound:"\B*b (n+M+1) / prod a {M..n+M+1}\ < e/4 * 1/2^n" when "M\N" for n M proof - define D where "D = B*b (n+M+1)/ (a (n+M) * a (n+M+1))" have "\B*b (n+M+1) / prod a {M..n+M+1}\ = \D / prod a {M.." proof - have "{M..n+M+1} = {M.. {n+M,n+M+1}" by auto then have "prod a {M..n+M+1} = a (n+M) * a (n+M+1)* prod a {M..e/4 * (1/prod a {M.." proof - have "\D\ < e/4" unfolding D_def using N_ba[rule_format, of "n+M+1"] \B>0\ \M \ N\ \e>0\ a_pos by (auto simp:field_simps abs_mult abs_of_pos) from mult_strict_right_mono[OF this,of "1/prod a {M..e>0\ show ?thesis apply (auto simp:abs_prod abs_mult prod_pos) by (subst (2) abs_of_pos,auto)+ qed also have "... \ e/4 * 1/2^n" proof - have "prod a {M.. 2^n" proof (induct n) case 0 then show ?case by simp next case (Suc n) then show ?case using \M\N\ by (simp add: N_a2 mult.commute mult_mono' prod.atLeastLessThan_Suc) qed then have "real_of_int (prod a {M.. 2^n" using numeral_power_le_of_int_cancel_iff by blast - then show ?thesis using \e>0\ by (auto simp add:divide_simps) + then show ?thesis using \e>0\ by (auto simp:divide_simps) qed finally show ?thesis . qed show "\\<^sub>F M in sequentially. \n. \real_of_int (B * b (n + M + 1)) / real_of_int (prod a {M..n + M + 1})\ < e / 4 * 1 / 2 ^ n" apply (rule eventually_sequentiallyI[of N]) using geq_N_bound by blast qed have R_tendsto_0:"R \ 0" proof (rule tendstoI) fix e::real assume "e>0" show "\\<^sub>F x in sequentially. dist (R x) 0 < e" using all_e_ubound[rule_format,OF \e>0\] proof eventually_elim case (elim M) define g where "g = (\n. B*b (n+M+1) / prod a {M..n+M+1})" have g_lt:"\g n\ < e/4 * 1/2^n" for n using elim unfolding g_def by auto have \
: "summable (\n. (e/4) * (1/2)^n)" by simp then have g_abs_summable:"summable (\n. \g n\)" apply (elim summable_comparison_test') by (metis abs_idempotent g_lt less_eq_real_def power_one_over real_norm_def times_divide_eq_right) have "\\n. g n\ \ (\n. \g n\)" by (rule summable_rabs[OF g_abs_summable]) also have "... \(\n. e/4 * 1/2^n)" proof (rule suminf_comparison) show "summable (\n. e/4 * 1/2^n)" using \
unfolding power_divide by simp show "\n. norm \g n\ \ e / 4 * 1 / 2 ^ n" using g_lt less_eq_real_def by auto qed also have "... = (e/4) * (\n. (1/2)^n)" apply (subst suminf_mult[symmetric]) by (auto simp: algebra_simps power_divide) also have "... = e/2" by (simp add:suminf_geometric[of "1/2"]) finally have "\\n. g n\ \ e / 2" . then show "dist (R M) 0 < e" unfolding R_def g_def using \e>0\ by auto qed qed obtain N where R_N_bound:"\M \ N. \R M\ \ 1 / 4" and N_geometric:"\M\N. \n. \real_of_int (B * b (n + M + 1)) / (prod a {M..n + M + 1})\ < 1 / 2 ^ n" proof - obtain N1 where N1:"\M \ N1. \R M\ \ 1 / 4" using metric_LIMSEQ_D[OF R_tendsto_0,of "1/4"] all_e_ubound[rule_format,of 4,unfolded eventually_sequentially] by (auto simp:less_eq_real_def) obtain N2 where N2:"\M\N2. \n. \real_of_int (B * b (n + M + 1)) / (prod a {M..n + M + 1})\ < 1 / 2 ^ n" using all_e_ubound[rule_format,of 4,unfolded eventually_sequentially] by (auto simp:less_eq_real_def) define N where "N=max N1 N2" show ?thesis using that[of N] N1 N2 unfolding N_def by simp qed define C where "C = B * prod a {..nn. f n)" unfolding AB_eq f_def using \B>0\ by auto also have "... = B * prod a {..nn. f (n+N+1)))" using suminf_split_initial_segment[OF \summable f\, of "N+1"] by auto also have "... = B * prod a {..nn. f (n+N+1)))" using sum.atLeast0_lessThan_Suc by simp also have "... = C + B * b N / a N + (\n. B*b (n+N+1) / prod a {N..n+N+1})" proof - have "B * prod a {.. {N}" using ivl_disj_un_singleton(2) by blast then show ?thesis unfolding f_def by auto qed moreover have "B * prod a {..n. f (n+N+1)) = (\n. B*b (n+N+1) / prod a {N..n+N+1})" proof - have "summable (\n. f (n + N + 1))" using \summable f\ summable_iff_shift[of f "N+1"] by auto moreover have "prod a {.. {N..n + N + 1}" by auto then show ?thesis unfolding f_def apply simp apply (subst prod.union_disjoint) by auto qed ultimately show ?thesis apply (subst suminf_mult[symmetric]) - by (auto simp add: mult.commute mult.left_commute) + by (auto simp: mult.commute mult.left_commute) qed ultimately show ?thesis unfolding C_def by (auto simp:algebra_simps) qed also have "... = C +B * b N / a N + R N" unfolding R_def by simp finally show ?thesis . qed have R_bound:"\R M\ \ 1 / 4" and R_Suc:"R (Suc M) = a M * R M - B * b (Suc M) / a (Suc M)" when "M \ N" for M proof - define g where "g = (\n. B*b (n+M+1) / prod a {M..n+M+1})" have g_abs_summable:"summable (\n. \g n\)" proof - have "summable (\n. (1/2::real) ^ n)" by simp moreover have "\g n\ < 1/2^n" for n using N_geometric[rule_format,OF that] unfolding g_def by simp ultimately show ?thesis apply (elim summable_comparison_test') by (simp add: less_eq_real_def power_one_over) qed show "\R M\ \ 1 / 4" using R_N_bound[rule_format,OF that] . have "R M = (\n. g n)" unfolding R_def g_def by simp also have "... = g 0 + (\n. g (Suc n))" apply (subst suminf_split_head) using summable_rabs_cancel[OF g_abs_summable] by auto also have "... = g 0 + 1/a M * (\n. a M * g (Suc n))" apply (subst suminf_mult) - by (auto simp add: g_abs_summable summable_Suc_iff summable_rabs_cancel) + by (auto simp: g_abs_summable summable_Suc_iff summable_rabs_cancel) also have "... = g 0 + 1/a M * R (Suc M)" proof - have "a M * g (Suc n) = B * b (n + M + 2) / prod a {Suc M..n + M + 2}" for n proof - have "{M..Suc (Suc (M + n))} = {M} \ {Suc M..Suc (Suc (M + n))}" by auto then show ?thesis - unfolding g_def using \B>0\ by (auto simp add:algebra_simps) + unfolding g_def using \B>0\ by (auto simp:algebra_simps) qed then have "(\n. a M * g (Suc n)) = R (Suc M)" unfolding R_def by auto then show ?thesis by auto qed finally have "R M = g 0 + 1 / a M * R (Suc M)" . then have "R (Suc M) = a M * R M - g 0 * a M" - by (auto simp add:algebra_simps) + by (auto simp:algebra_simps) moreover have "{M..Suc M} = {M,Suc M}" by auto ultimately show "R (Suc M) = a M * R M - B * b (Suc M) / a (Suc M)" unfolding g_def by auto qed define c where "c = (\n. if n\N then get_c a b B N (n-N) else undefined)" have c_rec:"c (n+1) = c n * a n - B * b n" when "n \ N" for n unfolding c_def using that by (auto simp:Suc_diff_le) have c_R:"c (Suc n) / a n = R n" when "n \ N" for n using that proof (induct rule:nat_induct_at_least) case base have "\ c (N+1) / a N \ \ 1/2" proof - have "c N = round (B * b N / a N)" unfolding c_def by simp moreover have "c (N+1) / a N = c N - B * b N / a N" using a_pos[rule_format,of N] - by (auto simp add:c_rec[of N,simplified] divide_simps) + by (auto simp:c_rec[of N,simplified] divide_simps) ultimately show ?thesis using of_int_round_abs_le by auto qed moreover have "\R N\ \ 1 / 4" using R_bound[of N] by simp ultimately have "\c (N+1) / a N - R N \ < 1" by linarith moreover have "c (N+1) / a N - R N \ \" proof - have "c (N+1) / a N = c N - B * b N / a N" using a_pos[rule_format,of N] - by (auto simp add:c_rec[of N,simplified] divide_simps) + by (auto simp:c_rec[of N,simplified] divide_simps) moreover have " B * b N / a N + R N \ \" proof - have "C = B * (\nn {..n}" if "nB>0\ apply simp apply (subst prod.union_disjoint) by auto qed finally have "C = real_of_int (B * (\n \" using Ints_of_int by blast moreover note \A * prod a {.. ultimately show ?thesis by (metis Ints_diff Ints_of_int add.assoc add_diff_cancel_left') qed ultimately show ?thesis by (simp add: diff_diff_add) qed ultimately have "c (N+1) / a N - R N = 0" by (metis Ints_cases less_irrefl of_int_0 of_int_lessD) then show ?case by simp next case (Suc n) have "c (Suc (Suc n)) / a (Suc n) = c (Suc n) - B * b (Suc n) / a (Suc n)" apply (subst c_rec[of "Suc n",simplified]) - using \N \ n\ by (auto simp add: divide_simps) + using \N \ n\ by (auto simp: divide_simps) also have "... = a n * R n - B * b (Suc n) / a (Suc n)" using Suc by (auto simp: divide_simps) also have "... = R (Suc n)" using R_Suc[OF \N \ n\] by simp finally show ?case . qed have ca_tendsto_zero:"(\n. c (Suc n) / a n) \ 0" using R_tendsto_0 apply (elim filterlim_mono_eventually) using c_R by (auto intro!:eventually_sequentiallyI[of N]) have ca_bound:"\c (n + 1)\ < a n / 2" when "n \ N" for n proof - have "\c (Suc n)\ / a n = \c (Suc n) / a n\" using a_pos[rule_format,of n] by auto also have "... = \R n\" using c_R[OF that] by auto also have "... < 1/2" using R_bound[OF that] by auto finally have "\c (Suc n)\ / a n < 1/2" . then show ?thesis using a_pos[rule_format,of n] by auto qed (* (* the following part corresponds to (2.7) (2.8) in the original paper, but turns out to be not necessary. *) have c_round:"c n = round (B * b n / a n)" when "n \ N" for n proof (cases "n=N") case True then show ?thesis unfolding c_def by simp next case False with \n\N\ obtain n' where n_Suc:"n=Suc n'" and "n' \ N" by (metis le_eq_less_or_eq lessE less_imp_le_nat) have "B * b n / a n = c n - R n" proof - have "R n = c n - B * b n / a n" using c_R[OF \n'\N\,symmetric,folded n_Suc] R_Suc[OF \n'\N\,folded n_Suc] by (auto simp:field_simps) then show ?thesis by (auto simp:field_simps) qed then have "\B * b n / a n - c n\ = \R n\" by auto then have "\B * b n / a n - c n\ < 1/2" using R_bound[OF \n \ N\] by auto from round_unique'[OF this] show ?thesis by auto qed *) show "\B>0. \c. (\\<^sub>F n in sequentially. B * b n = c n * a n - c (n + 1) \ real_of_int \c (n + 1)\ < a n / 2) \ (\n. c (Suc n) / a n) \ 0" unfolding eventually_at_top_linorder apply (rule exI[of _ B],use \B>0\ in simp) apply (intro exI[of _c] exI[of _ N]) using c_rec ca_bound ca_tendsto_zero by fastforce qed private lemma imp_ab_rational: assumes "\ (B::int)>0. \ c::nat\ int. (\\<^sub>F n in sequentially. B*b n = c n * a n - c(n+1) \ \c(n+1)\n. (b n / (\i \ n. a i))) \ \" proof - obtain B::int and c::"nat\int" and N::nat where "B>0" and large_n:"\n\N. B * b n = c n * a n - c (n + 1) \ real_of_int \c (n + 1)\ < a n / 2 \ a n\2" proof - obtain B c where "B>0" and event1:"\\<^sub>F n in sequentially. B * b n = c n * a n - c (n + 1) \ real_of_int \c (n + 1)\ < real_of_int (a n) / 2" using assms by auto from eventually_conj[OF event1 a_large,unfolded eventually_at_top_linorder] obtain N where "\n\N. (B * b n = c n * a n - c (n + 1) \ real_of_int \c (n + 1)\ < real_of_int (a n) / 2) \ 2 \ a n" by fastforce then show ?thesis using that[of B N c] \B>0\ by auto qed define f where "f=(\n. real_of_int (b n) / real_of_int (prod a {..n}))" define S where "S = (\n. f n)" have "summable f" unfolding f_def by (rule aux_series_summable) define C where "C=B*prod a {..n (\n. (c (n+N) * a (n+N)) / prod a {N..n+N})" define h2 where "h2 \ (\n. c (n+N+1) / prod a {N..n+N})" have f_h12: "B * prod a {.. (\n. B * b (n+N))" define g2 where "g2 \ (\n. prod a {.. {N..n + N}) = prod a {.. {N..n + N}) = prod a {..n+N}" by (simp add: ivl_disj_un_one(4)) ultimately show ?thesis unfolding g2_def apply simp using a_pos by (metis less_irrefl) qed ultimately have "B*prod a {..nn. f (n+N)))" using suminf_split_initial_segment[OF \summable f\,of N] unfolding S_def by (auto simp:algebra_simps) also have "... = C + B*prod a {..n. f (n+N))" unfolding C_def by (auto simp:algebra_simps) also have "... = C + (\n. h1 n - h2 n)" apply (subst suminf_mult[symmetric]) using \summable f\ f_h12 by auto also have "... = C + h1 0" proof - have "(\n. \i\n. h1 i - h2 i) \ (\i. h1 i - h2 i)" proof (rule summable_LIMSEQ') have "(\i. h1 i - h2 i) = (\i. real_of_int (B * prod a {..i. h1 i - h2 i)" using \summable f\ by (simp add: summable_mult) qed moreover have "(\i\n. h1 i - h2 i) = h1 0 - h2 n" for n proof (induct n) case 0 then show ?case by simp next case (Suc n) have "(\i\Suc n. h1 i - h2 i) = (\i\n. h1 i - h2 i) + h1 (n+1) - h2 (n+1)" by auto also have "... = h1 0 - h2 n + h1 (n+1) - h2 (n+1)" using Suc by auto also have "... = h1 0 - h2 (n+1)" proof - have "h2 n = h1 (n+1)" unfolding h2_def h1_def apply (auto simp:prod.nat_ivl_Suc') using a_pos by (metis less_numeral_extra(3)) then show ?thesis by auto qed finally show ?case by simp qed ultimately have "(\n. h1 0 - h2 n) \ (\i. h1 i - h2 i)" by simp then have "h2 \ (h1 0 - (\i. h1 i - h2 i))" apply (elim metric_tendsto_imp_tendsto) by (auto intro!:eventuallyI simp add:dist_real_def) moreover have "h2 \ 0" proof - have h2_n:"\h2 n\ < (1 / 2)^(n+1)" for n proof - have "\h2 n\ = \c (n + N + 1)\ / prod a {N..n + N}" unfolding h2_def abs_divide using a_pos by (simp add: abs_of_pos prod_pos) also have "... < (a (N+n) / 2) / prod a {N..n + N}" unfolding h2_def apply (rule divide_strict_right_mono) - subgoal using large_n[rule_format,of "N+n"] by (auto simp add:algebra_simps) + subgoal using large_n[rule_format,of "N+n"] by (auto simp:algebra_simps) subgoal using a_pos by (simp add: prod_pos) done also have "... = 1 / (2*prod a {N.. (1/2)^(n+1)" proof (induct n) case 0 then show ?case by auto next case (Suc n) define P where "P=1 / real_of_int (2 * prod a {N.. ( (1 / 2) ^ (n + 1) ) / a (n+N) " apply (rule divide_right_mono) subgoal unfolding P_def using Suc by auto subgoal by (simp add: a_pos less_imp_le) done also have "... \ ( (1 / 2) ^ (n + 1) ) / 2 " apply (rule divide_left_mono) using large_n[rule_format,of "n+N",simplified] by auto also have "... = (1 / 2) ^ (n + 2)" by auto finally show ?case by simp qed finally show ?thesis . qed have "(\n. (1 / 2)^(n+1)) \ (0::real)" using tendsto_mult_right_zero[OF LIMSEQ_abs_realpow_zero2[of "1/2",simplified],of "1/2"] by auto then show ?thesis apply (elim Lim_null_comparison[rotated]) using h2_n less_eq_real_def by (auto intro!:eventuallyI) qed ultimately have "(\i. h1 i - h2 i) = h1 0" using LIMSEQ_unique by fastforce then show ?thesis by simp qed also have "... = C + c N" unfolding h1_def using a_pos by auto (metis less_irrefl) finally show ?thesis . qed then have "S = (C + real_of_int (c N)) / (B*prod a {..0 < B\ a_pos less_irrefl mult.commute mult_pos_pos nonzero_mult_div_cancel_right of_int_eq_0_iff prod_pos) moreover have "... \ \" unfolding C_def f_def by (intro Rats_divide Rats_add Rats_mult Rats_of_int Rats_sum) ultimately show "S \ \" by auto qed theorem theorem_2_1_Erdos_Straus : "(\n. (b n / (\i \ n. a i))) \ \ \ (\ (B::int)>0. \ c::nat\ int. (\\<^sub>F n in sequentially. B*b n = c n * a n - c(n+1) \ \c(n+1)\The following is a Corollary to Theorem 2.1. \ corollary corollary_2_10_Erdos_Straus: assumes ab_event:"\\<^sub>F n in sequentially. b n > 0 \ a (n+1) \ a n" and ba_lim_leq:"lim (\n. (b(n+1) - b n )/a n) \ 0" and ba_lim_exist:"convergent (\n. (b(n+1) - b n )/a n)" and "liminf (\n. a n / b n) = 0 " shows "(\n. (b n / (\i \ n. a i))) \ \" proof assume "(\n. (b n / (\i \ n. a i))) \ \" then obtain B c where "B>0" and abc_event:"\\<^sub>F n in sequentially. B * b n = c n * a n - c (n + 1) \ \c (n + 1)\ < a n / 2" and ca_vanish: "(\n. c (Suc n) / a n) \ 0" using ab_rationality_imp by auto have bac_close:"(\n. B * b n / a n - c n) \ 0" proof - have "\\<^sub>F n in sequentially. B * b n - c n * a n + c (n + 1) = 0" using abc_event by (auto elim!:eventually_mono) then have "\\<^sub>F n in sequentially. (B * b n - c n * a n + c (n+1)) / a n = 0 " apply eventually_elim by auto then have "\\<^sub>F n in sequentially. B * b n / a n - c n + c (n + 1) / a n = 0" apply eventually_elim using a_pos by (auto simp:divide_simps) (metis less_irrefl) then have "(\n. B * b n / a n - c n + c (n + 1) / a n) \ 0" by (simp add: eventually_mono tendsto_iff) from tendsto_diff[OF this ca_vanish] show ?thesis by auto qed have c_pos:"\\<^sub>F n in sequentially. c n > 0" proof - from bac_close have *:"\\<^sub>F n in sequentially. c n \ 0" apply (elim tendsto_of_int_diff_0) using ab_event a_large apply (eventually_elim) using \B>0\ by auto show ?thesis proof (rule ccontr) assume "\ (\\<^sub>F n in sequentially. c n > 0)" moreover have "\\<^sub>F n in sequentially. c (Suc n) \ 0 \ c n\0" using * eventually_sequentially_Suc[of "\n. c n\0"] by (metis (mono_tags, lifting) eventually_at_top_linorder le_Suc_eq) ultimately have "\\<^sub>F n in sequentially. c n = 0 \ c (Suc n) \ 0" using eventually_elim2 frequently_def by fastforce moreover have "\\<^sub>F n in sequentially. b n > 0 \ B * b n = c n * a n - c (n + 1)" using ab_event abc_event by eventually_elim auto ultimately have "\\<^sub>F n in sequentially. c n = 0 \ c (Suc n) \ 0 \ b n > 0 \ B * b n = c n * a n - c (n + 1)" using frequently_eventually_frequently by fastforce from frequently_ex[OF this] obtain n where "c n = 0" "c (Suc n) \ 0" "b n > 0" "B * b n = c n * a n - c (n + 1)" by auto then have "B * b n \ 0" by auto then show False using \b n>0\ \B > 0\ using mult_pos_pos not_le by blast qed qed have bc_epsilon:"\\<^sub>F n in sequentially. b (n+1) / b n > (c (n+1) - \) / c n" when "\>0" "\<1" for \::real proof - have "\\<^sub>F x in sequentially. \c (Suc x) / a x\ < \ / 2" using ca_vanish[unfolded tendsto_iff,rule_format, of "\/2"] \\>0\ by auto moreover then have "\\<^sub>F x in sequentially. \c (x+2) / a (x+1)\ < \ / 2" apply (subst (asm) eventually_sequentially_Suc[symmetric]) by simp moreover have "\\<^sub>F n in sequentially. B * b (n+1) = c (n+1) * a (n+1) - c (n + 2)" using abc_event apply (subst (asm) eventually_sequentially_Suc[symmetric]) by (auto elim:eventually_mono) moreover have "\\<^sub>F n in sequentially. c n > 0 \ c (n+1) > 0 \ c (n+2) > 0" proof - have "\\<^sub>F n in sequentially. 0 < c (Suc n)" using c_pos by (subst eventually_sequentially_Suc) simp moreover then have "\\<^sub>F n in sequentially. 0 < c (Suc (Suc n))" using c_pos by (subst eventually_sequentially_Suc) simp ultimately show ?thesis using c_pos by eventually_elim auto qed ultimately show ?thesis using ab_event abc_event proof eventually_elim case (elim n) define \\<^sub>0 \\<^sub>1 where "\\<^sub>0 = c (n+1) / a n" and "\\<^sub>1 = c (n+2) / a (n+1)" - have "\\<^sub>0 > 0" "\\<^sub>1 > 0" "\\<^sub>0 < \/2" "\\<^sub>1 < \/2" using a_pos elim by (auto simp add: \\<^sub>0_def \\<^sub>1_def) + have "\\<^sub>0 > 0" "\\<^sub>1 > 0" "\\<^sub>0 < \/2" "\\<^sub>1 < \/2" using a_pos elim by (auto simp: \\<^sub>0_def \\<^sub>1_def) have "(\ - \\<^sub>1) * c n > 0" - apply (rule mult_pos_pos) - using \\\<^sub>1 > 0\ \\\<^sub>1 < \/2\ \\>0\ elim by auto + using \\\<^sub>1 < \ / 2\ elim(4) that(1) by auto moreover have "\\<^sub>0 * (c (n+1) - \) > 0" - apply (rule mult_pos_pos[OF \\\<^sub>0 > 0\]) - using elim(4) that(2) by linarith + using \0 < \\<^sub>0\ elim(4) that(2) by auto ultimately have "(\ - \\<^sub>1) * c n + \\<^sub>0 * (c (n+1) - \) > 0" by auto - moreover have "c n - \\<^sub>0 > 0" using \\\<^sub>0 < \ / 2\ elim(4) that(2) by linarith + moreover have gt0: "c n - \\<^sub>0 > 0" using \\\<^sub>0 < \ / 2\ elim(4) that(2) by linarith moreover have "c n > 0" by (simp add: elim(4)) ultimately have "(c (n+1) - \) / c n < (c (n+1) - \\<^sub>1) / (c n - \\<^sub>0)" - by (auto simp add: field_simps) + by (auto simp: field_simps) also have "... \ (c (n+1) - \\<^sub>1) / (c n - \\<^sub>0) * (a (n+1) / a n)" proof - - have "(c (n+1) - \\<^sub>1) / (c n - \\<^sub>0) > 0" - by (smt \0 < (\ - \\<^sub>1) * real_of_int (c n)\ \0 < real_of_int (c n) - \\<^sub>0\ - divide_pos_pos elim(4) mult_le_0_iff of_int_less_1_iff that(2)) + have "(c (n+1) - \\<^sub>1) / (c n - \\<^sub>0) > 0" + using gt0 \\\<^sub>1 < \ / 2\ elim(4) that(2) by force moreover have "(a (n+1) / a n) \ 1" using a_pos elim(5) by auto ultimately show ?thesis by (metis mult_cancel_left1 mult_le_cancel_left_pos) qed also have "... = (B * b (n+1)) / (B * b n)" proof - have "B * b n = c n * a n - c (n + 1)" using elim by auto also have "... = a n * (c n - \\<^sub>0)" using a_pos[rule_format,of n] unfolding \\<^sub>0_def by (auto simp:field_simps) finally have "B * b n = a n * (c n - \\<^sub>0)" . moreover have "B * b (n+1) = a (n+1) * (c (n+1) - \\<^sub>1)" unfolding \\<^sub>1_def using a_pos[rule_format,of "n+1"] apply (subst \B * b (n + 1) = c (n + 1) * a (n + 1) - c (n + 2)\) by (auto simp:field_simps) ultimately show ?thesis by (simp add: mult.commute) qed also have "... = b (n+1) / b n" using \B>0\ by auto finally show ?case . qed qed have eq_2_11:"\\<^sub>F n in sequentially. b (n+1) > b n + (1 - \)^2 * a n / B" when "\>0" "\<1" "\ (\\<^sub>F n in sequentially. c (n+1) \ c n)" for \::real proof - have "\\<^sub>F x in sequentially. c x < c (Suc x) " using that(3) by (simp add:not_eventually frequently_elim1) moreover have "\\<^sub>F x in sequentially. \c (Suc x) / a x\ < \" using ca_vanish[unfolded tendsto_iff,rule_format, of \] \\>0\ by auto moreover have "\\<^sub>F n in sequentially. c n > 0 \ c (n+1) > 0" proof - have "\\<^sub>F n in sequentially. 0 < c (Suc n)" using c_pos by (subst eventually_sequentially_Suc) simp then show ?thesis using c_pos by eventually_elim auto qed ultimately show ?thesis using ab_event abc_event bc_epsilon[OF \\>0\ \\<1\] proof (elim frequently_rev_mp,eventually_elim) case (elim n) then have "c (n+1) / a n < \" using a_pos[rule_format,of n] by auto also have "... \ \ * c n" using elim(7) that(1) by auto finally have "c (n+1) / a n < \ * c n" . then have "c (n+1) / c n < \ * a n" using a_pos[rule_format,of n] elim by (auto simp:field_simps) then have "(1 - \) * a n < a n - c (n+1) / c n" by (auto simp:algebra_simps) then have "(1 - \)^2 * a n / B < (1 - \) * (a n - c (n+1) / c n) / B" apply (subst (asm) mult_less_cancel_right_pos[symmetric, of "(1-\)/B"]) using \\<1\ \B>0\ by (auto simp: divide_simps power2_eq_square mult_less_cancel_right_pos) then have "b n + (1 - \)^2 * a n / B < b n + (1 - \) * (a n - c (n+1) / c n) / B" using \B>0\ by auto also have "... = b n + (1 - \) * ((c n *a n - c (n+1)) / c n) / B" using elim by (auto simp:field_simps) also have "... = b n + (1 - \) * (b n / c n)" proof - have "B * b n = c n * a n - c (n + 1)" using elim by auto from this[symmetric] show ?thesis using \B>0\ by simp qed also have "... = (1+(1-\)/c n) * b n" by (auto simp:algebra_simps) also have "... = ((c n+1-\)/c n) * b n" using elim by (auto simp:divide_simps) also have "... \ ((c (n+1) -\)/c n) * b n" proof - define cp where "cp = c n+1" have "c (n+1) \ cp" unfolding cp_def using \c n < c (Suc n)\ by auto moreover have "c n>0" "b n>0" using elim by auto ultimately show ?thesis apply (fold cp_def) by (auto simp:divide_simps) qed also have "... < b (n+1)" using elim by (auto simp:divide_simps) finally show ?case . qed qed have "\\<^sub>F n in sequentially. c (n+1) \ c n" proof (rule ccontr) assume "\ (\\<^sub>F n in sequentially. c (n + 1) \ c n)" from eq_2_11[OF _ _ this,of "1/2"] have "\\<^sub>F n in sequentially. b (n+1) > b n + 1/4 * a n / B" by (auto simp:algebra_simps power2_eq_square) then have *:"\\<^sub>F n in sequentially. (b (n+1) - b n) / a n > 1 / (B * 4)" apply (elim frequently_elim1) subgoal for n using a_pos[rule_format,of n] by (auto simp:field_simps) done define f where "f = (\n. (b (n+1) - b n) / a n)" have "f \ lim f" using convergent_LIMSEQ_iff ba_lim_exist unfolding f_def by auto from this[unfolded tendsto_iff,rule_format, of "1 / (B*4)"] have "\\<^sub>F x in sequentially. \f x - lim f\ < 1 / (B * 4)" using \B>0\ by (auto simp:dist_real_def) moreover have "\\<^sub>F n in sequentially. f n > 1 / (B * 4)" using * unfolding f_def by auto ultimately have "\\<^sub>F n in sequentially. f n > 1 / (B * 4) \ \f n - lim f\ < 1 / (B * 4)" by (auto elim:frequently_eventually_frequently[rotated]) from frequently_ex[OF this] obtain n where "f n > 1 / (B * 4)" "\f n - lim f\ < 1 / (B * 4)" by auto moreover have "lim f \ 0" using ba_lim_leq unfolding f_def by auto ultimately show False by linarith qed then obtain N where N_dec:"\n\N. c (n+1) \ c n" by (meson eventually_at_top_linorder) define max_c where "max_c = (MAX n \ {..N}. c n)" have max_c:"c n \ max_c" for n proof (cases "n\N") case True then show ?thesis unfolding max_c_def by simp next case False then have "n\N" by auto then have "c n\c N" proof (induct rule:nat_induct_at_least) case base then show ?case by simp next case (Suc n) then have "c (n+1) \ c n" using N_dec by auto then show ?case using \c n \ c N\ by auto qed moreover have "c N \ max_c" unfolding max_c_def by auto ultimately show ?thesis by auto qed have "max_c > 0 " proof - obtain N where "\n\N. 0 < c n" using c_pos[unfolded eventually_at_top_linorder] by auto then have "c N > 0" by auto then show ?thesis using max_c[of N] by simp qed have ba_limsup_bound:"1/(B*(B+1)) \ limsup (\n. b n/a n)" "limsup (\n. b n/a n) \ max_c / B + 1 / (B+1)" proof - define f where "f = (\n. b n/a n)" from tendsto_mult_right_zero[OF bac_close,of "1/B"] have "(\n. f n - c n / B) \ 0" unfolding f_def using \B>0\ by (auto simp:algebra_simps) from this[unfolded tendsto_iff,rule_format,of "1/(B+1)"] have "\\<^sub>F x in sequentially. \f x - c x / B\ < 1 / (B+1)" using \B>0\ by auto then have *:"\\<^sub>F n in sequentially. 1/(B*(B+1)) \ ereal (f n) \ ereal (f n) \ max_c / B + 1 / (B+1)" using c_pos proof eventually_elim case (elim n) then have "f n - c n / B < 1 / (B+1)" by auto then have "f n < c n / B + 1 / (B+1)" by simp also have "... \ max_c / B + 1 / (B+1)" using max_c[of n] using \B>0\ by (auto simp:divide_simps) finally have *:"f n < max_c / B + 1 / (B+1)" . have "1/(B*(B+1)) = 1/B - 1 / (B+1)" using \B>0\ by (auto simp:divide_simps) also have "... \ c n/B - 1 / (B+1)" using \0 < c n\ \B>0\ by (auto,auto simp:divide_simps) also have "... < f n" using elim by auto finally have "1/(B*(B+1)) < f n" . with * show ?case by simp qed show "limsup f \ max_c / B + 1 / (B+1)" apply (rule Limsup_bounded) using * by (auto elim:eventually_mono) have "1/(B*(B+1)) \ liminf f" apply (rule Liminf_bounded) using * by (auto elim:eventually_mono) also have "liminf f \ limsup f" by (simp add: Liminf_le_Limsup) finally show "1/(B*(B+1)) \ limsup f" . qed have "0 < inverse (ereal (max_c / B + 1 / (B+1)))" using \max_c > 0\ \B>0\ by (simp add: pos_add_strict) also have "... \ inverse (limsup (\n. b n/a n))" proof (rule ereal_inverse_antimono[OF _ ba_limsup_bound(2)]) have "0<1/(B*(B+1))" using \B>0\ by auto also have "... \ limsup (\n. b n/a n)" using ba_limsup_bound(1) . finally show "0\limsup (\n. b n/a n)" using zero_ereal_def by auto qed also have "... = liminf (\n. inverse (ereal ( b n/a n)))" apply (subst Liminf_inverse_ereal[symmetric]) using a_pos ab_event by (auto elim!:eventually_mono simp:divide_simps) also have "... = liminf (\n. ( a n/b n))" apply (rule Liminf_eq) using a_pos ab_event apply (auto elim!:eventually_mono) by (metis less_int_code(1)) finally have "liminf (\n. ( a n/b n)) > 0" . then show False using \liminf (\n. a n / b n) = 0\ by simp qed end section\Some auxiliary results on the prime numbers. \ lemma nth_prime_nonzero[simp]:"nth_prime n \ 0" by (simp add: prime_gt_0_nat prime_nth_prime) lemma nth_prime_gt_zero[simp]:"nth_prime n >0" by (simp add: prime_gt_0_nat prime_nth_prime) lemma ratio_of_consecutive_primes: "(\n. nth_prime (n+1)/nth_prime n) \1" proof - define f where "f=(\x. real (nth_prime (Suc x)) /real (nth_prime x))" define g where "g=(\x. (real x * ln (real x)) / (real (Suc x) * ln (real (Suc x))))" have p_n:"(\x. real (nth_prime x) / (real x * ln (real x))) \ 1" using nth_prime_asymptotics[unfolded asymp_equiv_def,simplified] . moreover have p_sn:"(\n. real (nth_prime (Suc n)) / (real (Suc n) * ln (real (Suc n)))) \ 1" using nth_prime_asymptotics[unfolded asymp_equiv_def,simplified ,THEN LIMSEQ_Suc] . ultimately have "(\x. f x * g x) \ 1" using tendsto_divide[OF p_sn p_n] unfolding f_def g_def by (auto simp:algebra_simps) moreover have "g \ 1" unfolding g_def by real_asymp ultimately have "(\x. if g x = 0 then 0 else f x) \ 1" apply (drule_tac tendsto_divide[OF _ \g \ 1\]) by auto then have "f \ 1" proof (elim filterlim_mono_eventually) have "\\<^sub>F x in sequentially. (if g (x+3) = 0 then 0 else f (x+3)) = f (x+3)" unfolding g_def by auto then show "\\<^sub>F x in sequentially. (if g x = 0 then 0 else f x) = f x" apply (subst (asm) eventually_sequentially_seg) by simp qed auto then show ?thesis unfolding f_def by auto qed lemma nth_prime_double_sqrt_less: assumes "\ > 0" shows "\\<^sub>F n in sequentially. (nth_prime (2*n) - nth_prime n) / sqrt (nth_prime n) < n powr (1/2+\)" proof - define pp ll where "pp=(\n. (nth_prime (2*n) - nth_prime n) / sqrt (nth_prime n))" and "ll=(\x::nat. x * ln x)" have pp_pos:"pp (n+1) > 0" for n unfolding pp_def by simp have "(\x. nth_prime (2 * x)) \[sequentially] (\x. (2 * x) * ln (2 * x))" using nth_prime_asymptotics[THEN asymp_equiv_compose ,of "(*) 2" sequentially,unfolded comp_def] using mult_nat_left_at_top pos2 by blast also have "... \[sequentially] (\x. 2 *x * ln x)" by real_asymp finally have "(\x. nth_prime (2 * x)) \[sequentially] (\x. 2 *x * ln x)" . from this[unfolded asymp_equiv_def, THEN tendsto_mult_left,of 2] have "(\x. nth_prime (2 * x) / (x * ln x)) \ 2" unfolding asymp_equiv_def by auto moreover have *:"(\x. nth_prime x / (x * ln x)) \ 1" using nth_prime_asymptotics unfolding asymp_equiv_def by auto ultimately have "(\x. (nth_prime (2 * x) - nth_prime x) / ll x) \ 1" unfolding ll_def apply - apply (drule (1) tendsto_diff) apply (subst of_nat_diff,simp) by (subst diff_divide_distrib,simp) moreover have "(\x. sqrt (nth_prime x) / sqrt (ll x)) \ 1" unfolding ll_def using tendsto_real_sqrt[OF *] by (auto simp: real_sqrt_divide) ultimately have "(\x. pp x * (sqrt (ll x) / (ll x))) \ 1" apply - apply (drule (1) tendsto_divide,simp) by (auto simp:field_simps of_nat_diff pp_def) moreover have "\\<^sub>F x in sequentially. sqrt (ll x) / ll x = 1/sqrt (ll x)" apply (subst eventually_sequentially_Suc[symmetric]) by (auto intro!:eventuallyI simp:ll_def divide_simps) ultimately have "(\x. pp x / sqrt (ll x)) \ 1" apply (elim filterlim_mono_eventually) by (auto elim!:eventually_mono) (metis mult.right_neutral times_divide_eq_right) moreover have "(\x. sqrt (ll x) / x powr (1/2+\)) \ 0" unfolding ll_def using \\>0\ by real_asymp ultimately have "(\x. pp x / x powr (1/2+\) * (sqrt (ll x) / sqrt (ll x))) \ 0" apply - apply (drule (1) tendsto_mult) by (auto elim:filterlim_mono_eventually) moreover have "\\<^sub>F x in sequentially. sqrt (ll x) / sqrt (ll x) = 1" apply (subst eventually_sequentially_Suc[symmetric]) by (auto intro!:eventuallyI simp:ll_def ) ultimately have "(\x. pp x / x powr (1/2+\)) \ 0" apply (elim filterlim_mono_eventually) by (auto elim:eventually_mono) from tendstoD[OF this, of 1,simplified] show "\\<^sub>F x in sequentially. pp x < x powr (1 / 2 + \)" apply (elim eventually_mono_sequentially[of _ 1]) using pp_pos by auto qed section \Theorem 3.1\ text\Theorem 3.1 is an application of Theorem 2.1 with the sequences considered involving the prime numbers.\ theorem theorem_3_10_Erdos_Straus: fixes a::"nat \ int" assumes a_pos:"\ n. a n >0" and "mono a" and nth_1:"(\n. nth_prime n / (a n)^2) \ 0" and nth_2:"liminf (\n. a n / nth_prime n) = 0" shows "(\n. (nth_prime n / (\i \ n. a i))) \ \" proof assume asm:"(\n. (nth_prime n / (\i \ n. a i))) \ \" have a2_omega:"(\n. (a n)^2) \ \(\x. x * ln x)" proof - have "(\n. real (nth_prime n)) \ o(\n. real_of_int ((a n)\<^sup>2))" apply (rule smalloI_tendsto[OF nth_1]) using a_pos by (metis (mono_tags, lifting) less_int_code(1) not_eventuallyD of_int_0_eq_iff zero_eq_power2) moreover have "(\x. real (nth_prime x)) \ \(\x. real x * ln (real x))" using nth_prime_bigtheta by blast ultimately show ?thesis using landau_omega.small_big_trans smallo_imp_smallomega by blast qed have a_gt_1:"\\<^sub>F n in sequentially. 1 < a n" proof - have "\\<^sub>F x in sequentially. \x * ln x\ \ (a x)\<^sup>2" using a2_omega[unfolded smallomega_def,simplified,rule_format,of 1] by auto then have "\\<^sub>F x in sequentially. \(x+3) * ln (x+3)\ \ (a (x+3))\<^sup>2" apply (subst (asm) eventually_sequentially_seg[symmetric, of _ 3]) by simp then have "\\<^sub>F n in sequentially. 1 < a ( n+3)" proof (elim eventually_mono) fix x assume "\real (x + 3) * ln (real (x + 3))\ \ real_of_int ((a (x + 3))\<^sup>2)" moreover have "\real (x + 3) * ln (real (x + 3))\ > 3" proof - have "ln (real (x + 3)) > 1" - apply simp using ln3_gt_1 ln_gt_1 by force + using ln3_gt_1 ln_gt_1 by force moreover have "real(x+3) \ 3" by simp - ultimately have "(x+3)*ln (real (x + 3)) > 3*1 " - apply (rule_tac mult_le_less_imp_less) - by auto + ultimately have "(x+3)*ln (real (x + 3)) > 3*1" + by (smt (verit, best) mult_less_cancel_left1) then show ?thesis by auto qed - ultimately have "real_of_int ((a (x + 3))\<^sup>2) > 3" - by auto - then show "1 < a (x + 3)" - by (smt Suc3_eq_add_3 a_pos add.commute of_int_1 one_power2) + ultimately have "(a (x + 3))\<^sup>2 > 3" + by linarith + then show "1 < a (x + 3)" + by (smt (verit) assms(1) one_power2) qed then show ?thesis - apply (subst eventually_sequentially_seg[symmetric, of _ 3]) - by auto + using eventually_sequentially_seg[symmetric, of _ 3] + by blast qed obtain B::int and c where "B>0" and Bc_large:"\\<^sub>F n in sequentially. B * nth_prime n = c n * a n - c (n + 1) \ \c (n + 1)\ < a n / 2" and ca_vanish: "(\n. c (Suc n) / real_of_int (a n)) \ 0" proof - note a_gt_1 moreover have "(\n. real_of_int \int (nth_prime n)\ / real_of_int (a (n - 1) * a n)) \ 0" proof - define f where "f=(\n. nth_prime (n+1) / (a n * a (n+1)))" define g where "g=(\n. 2*nth_prime n / (a n)^2)" have "\\<^sub>F x in sequentially. norm (f x) \ g x" proof - have "\\<^sub>F n in sequentially. nth_prime (n+1) < 2*nth_prime n" using ratio_of_consecutive_primes[unfolded tendsto_iff ,rule_format,of 1,simplified] apply (elim eventually_mono) by (auto simp :divide_simps dist_norm) moreover have "\\<^sub>F n in sequentially. real_of_int (a n * a (n+1)) \ (a n)^2" apply (rule eventuallyI) using \mono a\ by (auto simp:power2_eq_square a_pos incseq_SucD) ultimately show ?thesis unfolding f_def g_def apply eventually_elim apply (subst norm_divide) apply (rule_tac linordered_field_class.frac_le) using a_pos[rule_format, THEN order.strict_implies_not_eq ] by auto qed moreover have "g \ 0 " using nth_1[THEN tendsto_mult_right_zero,of 2] unfolding g_def by auto ultimately have "f \ 0" using Lim_null_comparison[of f g sequentially] by auto then show ?thesis unfolding f_def by (rule_tac LIMSEQ_imp_Suc) auto qed moreover have "(\n. real_of_int (int (nth_prime n)) / real_of_int (prod a {..n})) \ \" using asm by simp ultimately have "\B>0. \c. (\\<^sub>F n in sequentially. B * int (nth_prime n) = c n * a n - c (n + 1) \ real_of_int \c (n + 1)\ < real_of_int (a n) / 2) \ (\n. real_of_int (c (Suc n)) / real_of_int (a n)) \ 0" using ab_rationality_imp[OF a_pos,of nth_prime] by fast then show thesis apply clarify apply (rule_tac c=c and B=B in that) by auto qed have bac_close:"(\n. B * nth_prime n / a n - c n) \ 0" proof - have "\\<^sub>F n in sequentially. B * nth_prime n - c n * a n + c (n + 1) = 0" using Bc_large by (auto elim!:eventually_mono) then have "\\<^sub>F n in sequentially. (B * nth_prime n - c n * a n + c (n+1)) / a n = 0 " by eventually_elim auto then have "\\<^sub>F n in sequentially. B * nth_prime n / a n - c n + c (n + 1) / a n = 0" apply eventually_elim using a_pos by (auto simp:divide_simps) (metis less_irrefl) then have "(\n. B * nth_prime n / a n - c n + c (n + 1) / a n) \ 0" by (simp add: eventually_mono tendsto_iff) from tendsto_diff[OF this ca_vanish] show ?thesis by auto qed have c_pos:"\\<^sub>F n in sequentially. c n > 0" proof - from bac_close have *:"\\<^sub>F n in sequentially. c n \ 0" apply (elim tendsto_of_int_diff_0) using a_gt_1 apply (eventually_elim) using \B>0\ by auto show ?thesis proof (rule ccontr) assume "\ (\\<^sub>F n in sequentially. c n > 0)" moreover have "\\<^sub>F n in sequentially. c (Suc n) \ 0 \ c n\0" using * eventually_sequentially_Suc[of "\n. c n\0"] by (metis (mono_tags, lifting) eventually_at_top_linorder le_Suc_eq) ultimately have "\\<^sub>F n in sequentially. c n = 0 \ c (Suc n) \ 0" using eventually_elim2 frequently_def by fastforce moreover have "\\<^sub>F n in sequentially. nth_prime n > 0 \ B * nth_prime n = c n * a n - c (n + 1)" using Bc_large by eventually_elim auto ultimately have "\\<^sub>F n in sequentially. c n = 0 \ c (Suc n) \ 0 \ B * nth_prime n = c n * a n - c (n + 1)" using frequently_eventually_frequently by fastforce from frequently_ex[OF this] obtain n where "c n = 0" "c (Suc n) \ 0" "B * nth_prime n = c n * a n - c (n + 1)" by auto then have "B * nth_prime n \ 0" by auto then show False using \B > 0\ by (simp add: mult_le_0_iff) qed qed have B_nth_prime:"\\<^sub>F n in sequentially. nth_prime n > B" proof - have "\\<^sub>F x in sequentially. B+1 \ nth_prime x" using nth_prime_at_top[unfolded filterlim_at_top_ge[where c="nat B+1"] ,rule_format,of "nat B + 1",simplified] apply (elim eventually_mono) using \B>0\ by auto then show ?thesis by (auto elim: eventually_mono) qed have bc_epsilon:"\\<^sub>F n in sequentially. nth_prime (n+1) / nth_prime n > (c (n+1) - \) / c n" when "\>0" "\<1" for \::real proof - have "\\<^sub>F x in sequentially. \c (Suc x) / a x\ < \ / 2" using ca_vanish[unfolded tendsto_iff,rule_format, of "\/2"] \\>0\ by auto moreover then have "\\<^sub>F x in sequentially. \c (x+2) / a (x+1)\ < \ / 2" apply (subst (asm) eventually_sequentially_Suc[symmetric]) by simp moreover have "\\<^sub>F n in sequentially. B * nth_prime (n+1) = c (n+1) * a (n+1) - c (n + 2)" using Bc_large apply (subst (asm) eventually_sequentially_Suc[symmetric]) by (auto elim:eventually_mono) moreover have "\\<^sub>F n in sequentially. c n > 0 \ c (n+1) > 0 \ c (n+2) > 0" proof - have "\\<^sub>F n in sequentially. 0 < c (Suc n)" using c_pos by (subst eventually_sequentially_Suc) simp moreover then have "\\<^sub>F n in sequentially. 0 < c (Suc (Suc n))" using c_pos by (subst eventually_sequentially_Suc) simp ultimately show ?thesis using c_pos by eventually_elim auto qed ultimately show ?thesis using Bc_large proof eventually_elim case (elim n) define \\<^sub>0 \\<^sub>1 where "\\<^sub>0 = c (n+1) / a n" and "\\<^sub>1 = c (n+2) / a (n+1)" have "\\<^sub>0 > 0" "\\<^sub>1 > 0" "\\<^sub>0 < \/2" "\\<^sub>1 < \/2" using a_pos elim \mono a\ - by (auto simp add: \\<^sub>0_def \\<^sub>1_def abs_of_pos) + by (auto simp: \\<^sub>0_def \\<^sub>1_def abs_of_pos) have "(\ - \\<^sub>1) * c n > 0" using \\\<^sub>1 > 0\ \\\<^sub>1 < \/2\ \\>0\ elim by auto - moreover have "\\<^sub>0 * (c (n+1) - \) > 0" + moreover have A: "\\<^sub>0 * (c (n+1) - \) > 0" using \\\<^sub>0 > 0\ elim(4) that(2) by force ultimately have "(\ - \\<^sub>1) * c n + \\<^sub>0 * (c (n+1) - \) > 0" by auto - moreover have "c n - \\<^sub>0 > 0" using \\\<^sub>0 < \ / 2\ elim(4) that(2) by linarith + moreover have B: "c n - \\<^sub>0 > 0" using \\\<^sub>0 < \ / 2\ elim(4) that(2) by linarith moreover have "c n > 0" by (simp add: elim(4)) ultimately have "(c (n+1) - \) / c n < (c (n+1) - \\<^sub>1) / (c n - \\<^sub>0)" - by (auto simp add:field_simps) + by (auto simp:field_simps) also have "... \ (c (n+1) - \\<^sub>1) / (c n - \\<^sub>0) * (a (n+1) / a n)" proof - - have "(c (n+1) - \\<^sub>1) / (c n - \\<^sub>0) > 0" - by (smt \0 < (\ - \\<^sub>1) * real_of_int (c n)\ \0 < real_of_int (c n) - \\<^sub>0\ - divide_pos_pos elim(4) mult_le_0_iff of_int_less_1_iff that(2)) + have "(c (n+1) - \\<^sub>1) / (c n - \\<^sub>0) > 0" + using A \0 < \\<^sub>0\ B \\\<^sub>1 < \ / 2\ divide_pos_pos that(1) by force moreover have "(a (n+1) / a n) \ 1" using a_pos \mono a\ by (simp add: mono_def) ultimately show ?thesis by (metis mult_cancel_left1 mult_le_cancel_left_pos) qed also have "... = (B * nth_prime (n+1)) / (B * nth_prime n)" proof - have "B * nth_prime n = c n * a n - c (n + 1)" using elim by auto also have "... = a n * (c n - \\<^sub>0)" using a_pos[rule_format,of n] unfolding \\<^sub>0_def by (auto simp:field_simps) finally have "B * nth_prime n = a n * (c n - \\<^sub>0)" . moreover have "B * nth_prime (n+1) = a (n+1) * (c (n+1) - \\<^sub>1)" unfolding \\<^sub>1_def using a_pos[rule_format,of "n+1"] apply (subst \B * nth_prime (n + 1) = c (n + 1) * a (n + 1) - c (n + 2)\) by (auto simp:field_simps) ultimately show ?thesis by (simp add: mult.commute) qed also have "... = nth_prime (n+1) / nth_prime n" using \B>0\ by auto finally show ?case . qed qed have c_ubound:"\x. \n. c n > x" proof (rule ccontr) assume " \ (\x. \n. x < c n)" then obtain ub where "\n. c n \ ub" "ub > 0" by (meson dual_order.trans int_one_le_iff_zero_less le_cases not_le) define pa where "pa = (\n. nth_prime n / a n)" have pa_pos:"\n. pa n > 0" unfolding pa_def by (simp add: a_pos) have "liminf (\n. 1 / pa n) = 0" using nth_2 unfolding pa_def by auto then have "(\y\<^sub>F x in sequentially. ereal (1 / pa x) \ y)" apply (subst less_Liminf_iff[symmetric]) using \0 < B\ \0 < ub\ by auto then have "\\<^sub>F x in sequentially. 1 / pa x < B/(ub+1)" by (meson frequently_mono le_less_trans less_ereal.simps(1)) then have "\\<^sub>F x in sequentially. B*pa x > (ub+1)" apply (elim frequently_elim1) by (metis \0 < ub\ mult.left_neutral of_int_0_less_iff pa_pos pos_divide_less_eq pos_less_divide_eq times_divide_eq_left zless_add1_eq) moreover have "\\<^sub>F x in sequentially. c x \ ub" using \\n. c n \ ub\ by simp ultimately have "\\<^sub>F x in sequentially. B*pa x - c x > 1" by (elim frequently_rev_mp eventually_mono) linarith moreover have "(\n. B * pa n - c n) \0" unfolding pa_def using bac_close by auto from tendstoD[OF this,of 1] have "\\<^sub>F n in sequentially. \B * pa n - c n\ < 1" by auto ultimately have "\\<^sub>F x in sequentially. B*pa x - c x > 1 \ \B * pa x - c x\ < 1" using frequently_eventually_frequently by blast then show False by (simp add: frequently_def) qed have eq_2_11:"\\<^sub>F n in sequentially. c (n+1)>c n \ nth_prime (n+1) > nth_prime n + (1 - \)^2 * a n / B" when "\>0" "\<1" for \::real proof - have "\\<^sub>F x in sequentially. \c (Suc x) / a x\ < \" using ca_vanish[unfolded tendsto_iff,rule_format, of \] \\>0\ by auto moreover have "\\<^sub>F n in sequentially. c n > 0 \ c (n+1) > 0" proof - have "\\<^sub>F n in sequentially. 0 < c (Suc n)" using c_pos by (subst eventually_sequentially_Suc) simp then show ?thesis using c_pos by eventually_elim auto qed ultimately show ?thesis using Bc_large bc_epsilon[OF \\>0\ \\<1\] proof (eventually_elim, rule_tac impI) case (elim n) assume "c n < c (n + 1)" have "c (n+1) / a n < \" using a_pos[rule_format,of n] using elim(1,2) by auto also have "... \ \ * c n" using elim(2) that(1) by auto finally have "c (n+1) / a n < \ * c n" . then have "c (n+1) / c n < \ * a n" using a_pos[rule_format,of n] elim by (auto simp:field_simps) then have "(1 - \) * a n < a n - c (n+1) / c n" by (auto simp:algebra_simps) then have "(1 - \)^2 * a n / B < (1 - \) * (a n - c (n+1) / c n) / B" apply (subst (asm) mult_less_cancel_right_pos[symmetric, of "(1-\)/B"]) using \\<1\ \B>0\ by (auto simp: divide_simps power2_eq_square mult_less_cancel_right_pos) then have "nth_prime n + (1 - \)^2 * a n / B < nth_prime n + (1 - \) * (a n - c (n+1) / c n) / B" using \B>0\ by auto also have "... = nth_prime n + (1 - \) * ((c n *a n - c (n+1)) / c n) / B" using elim by (auto simp:field_simps) also have "... = nth_prime n + (1 - \) * (nth_prime n / c n)" proof - have "B * nth_prime n = c n * a n - c (n + 1)" using elim by auto from this[symmetric] show ?thesis using \B>0\ by simp qed also have "... = (1+(1-\)/c n) * nth_prime n" by (auto simp:algebra_simps) also have "... = ((c n+1-\)/c n) * nth_prime n" using elim by (auto simp:divide_simps) also have "... \ ((c (n+1) -\)/c n) * nth_prime n" proof - define cp where "cp = c n+1" have "c (n+1) \ cp" unfolding cp_def using \c n < c (n + 1)\ by auto moreover have "c n>0" "nth_prime n>0" using elim by auto ultimately show ?thesis apply (fold cp_def) by (auto simp:divide_simps) qed also have "... < nth_prime (n+1)" using elim by (auto simp:divide_simps) finally show "real (nth_prime n) + (1 - \)\<^sup>2 * real_of_int (a n) / real_of_int B < real (nth_prime (n + 1))" . qed qed have c_neq_large:"\\<^sub>F n in sequentially. c (n+1) \ c n" proof (rule ccontr) assume "\ (\\<^sub>F n in sequentially. c (n + 1) \ c n)" then have that:"\\<^sub>F n in sequentially. c (n + 1) = c n" unfolding frequently_def . have "\\<^sub>F x in sequentially. (B * int (nth_prime x) = c x * a x - c (x + 1) \ \real_of_int (c (x + 1))\ < real_of_int (a x) / 2) \ 0 < c x \ B < int (nth_prime x) \ (c (x+1)>c x \ nth_prime (x+1) > nth_prime x + a x / (2* B))" using Bc_large c_pos B_nth_prime eq_2_11[of "1-1/ sqrt 2",simplified] by eventually_elim (auto simp:divide_simps) then have "\\<^sub>F m in sequentially. nth_prime (m+1) > (1+1/(2*B))*nth_prime m" proof (elim frequently_eventually_at_top[OF that, THEN frequently_at_top_elim]) fix n assume "c (n + 1) = c n \ (\y\n. (B * int (nth_prime y) = c y * a y - c (y + 1) \ \real_of_int (c (y + 1))\ < real_of_int (a y) / 2) \ 0 < c y \ B < int (nth_prime y) \ (c y < c (y + 1) \ real (nth_prime y) + real_of_int (a y) / real_of_int (2 * B) < real (nth_prime (y + 1))))" then have "c (n + 1) = c n" and Bc_eq:"\y\n. B * int (nth_prime y) = c y * a y - c (y + 1) \ 0 < c y \ \real_of_int (c (y + 1))\ < real_of_int (a y) / 2 \ B < int (nth_prime y) \ (c y < c (y + 1) \ real (nth_prime y) + real_of_int (a y) / real_of_int (2 * B) < real (nth_prime (y + 1)))" by auto obtain m where "n c n" "c nN. N > n \ c N > c n" using c_ubound[rule_format, of "MAX x\{..n}. c x"] by (metis Max_ge atMost_iff dual_order.trans finite_atMost finite_imageI image_eqI linorder_not_le order_refl) then obtain N where "N>n" "c N>c n" by auto define A m where "A={m. n (m+1)\N \ c (m+1) > c n}" and "m = Min A" have "finite A" unfolding A_def by (metis (no_types, lifting) A_def add_leE finite_nat_set_iff_bounded_le mem_Collect_eq) moreover have "N-1\A" unfolding A_def - using \c n < c N\ \n < N\ \c (n + 1) = c n\ - by (smt Suc_diff_Suc Suc_eq_plus1 Suc_leI Suc_pred add.commute - add_diff_inverse_nat add_leD1 diff_is_0_eq' mem_Collect_eq nat_add_left_cancel_less - zero_less_one) + using \c n < c N\ \n < N\ \c (n + 1) = c n\ nat_less_le by force ultimately have "m\A" using Min_in unfolding m_def by auto then have "n0" unfolding m_def A_def by auto moreover have "c m \ c n" proof (rule ccontr) - assume " \ c m \ c n" - then have "m-1\A" using \m\A\ \c (n + 1) = c n\ - unfolding A_def - by auto (smt One_nat_def Suc_eq_plus1 Suc_lessI less_diff_conv) - from Min_le[OF \finite A\ this,folded m_def] \m>0\ show False by auto + assume "\ c m \ c n" + then have "m-1\A" + using \m\A\ \c (n + 1) = c n\ le_eq_less_or_eq less_diff_conv by (fastforce simp: A_def) + from Min_le[OF \finite A\ this,folded m_def] \m>0\ show False by auto qed ultimately show ?thesis using that[of m] by auto qed have "(1 + 1 / (2 * B)) * nth_prime m < nth_prime m + a m / (2*B)" proof - have "nth_prime m < a m" proof - have "B * int (nth_prime m) < c m * (a m - 1)" using Bc_eq[rule_format,of m] \c m \ c n\ \c n < c (m + 1)\ \n < m\ by (auto simp:algebra_simps) also have "... \ c n * (a m - 1)" by (simp add: \c m \ c n\ a_pos mult_right_mono) finally have "B * int (nth_prime m) < c n * (a m - 1)" . moreover have "c n\B" proof - - have " B * int (nth_prime n) = c n * (a n - 1)" "B < int (nth_prime n)" - and c_a:"\real_of_int (c (n + 1))\ < real_of_int (a n) / 2" + have B: "B * int (nth_prime n) = c n * (a n - 1)" "B < int (nth_prime n)" + and c_a: "\real_of_int (c (n + 1))\ < real_of_int (a n) / 2" using Bc_eq[rule_format,of n] \c (n + 1) = c n\ by (auto simp:algebra_simps) from this(1) have " c n dvd (B * int (nth_prime n))" by simp moreover have "coprime (c n) (int (nth_prime n))" proof - have "c n < int (nth_prime n)" proof (rule ccontr) assume "\ c n < int (nth_prime n)" then have asm:"c n \ int (nth_prime n)" by auto then have "a n > 2 * nth_prime n" using c_a \c (n + 1) = c n\ by auto then have "a n -1 \ 2 * nth_prime n" by simp then have "a n - 1 > 2 * B" using \B < int (nth_prime n)\ by auto from mult_le_less_imp_less[OF asm this] \B>0\ have "int (nth_prime n) * (2 * B) < c n * (a n - 1)" by auto - then show False using \B * int (nth_prime n) = c n * (a n - 1)\ - by (smt \0 < B\ \B < int (nth_prime n)\ combine_common_factor - mult.commute mult_pos_pos) + then show False using B + by (smt (verit, best) \0 < B\ mult.commute mult_right_mono) qed then have "\ nth_prime n dvd c n" by (simp add: Bc_eq zdvd_not_zless) then have "coprime (int (nth_prime n)) (c n)" by (auto intro!:prime_imp_coprime_int) then show ?thesis using coprime_commute by blast qed ultimately have "c n dvd B" using coprime_dvd_mult_left_iff by auto then show ?thesis using \0 < B\ zdvd_imp_le by blast qed moreover have "c n > 0 " using Bc_eq by blast ultimately show ?thesis - using \B>0\ by (smt a_pos mult_mono) + using \B>0\ by (smt (verit) a_pos mult_mono) qed then show ?thesis using \B>0\ by (auto simp:field_simps) qed also have "... < nth_prime (m+1)" using Bc_eq[rule_format, of m] \n \c m \ c n\ \c n < c (m+1)\ by linarith finally show "\j>n. (1 + 1 / real_of_int (2 * B)) * real (nth_prime j) < real (nth_prime (j + 1))" using \m>n\ by auto qed then have "\\<^sub>F m in sequentially. nth_prime (m+1)/nth_prime m > (1+1/(2*B))" by (auto elim:frequently_elim1 simp:field_simps) moreover have "\\<^sub>F m in sequentially. nth_prime (m+1)/nth_prime m < (1+1/(2*B))" using ratio_of_consecutive_primes[unfolded tendsto_iff,rule_format,of "1/(2*B)"] \B>0\ unfolding dist_real_def by (auto elim!:eventually_mono simp:algebra_simps) ultimately show False by (simp add: eventually_mono frequently_def) qed have c_gt_half:"\\<^sub>F N in sequentially. card {n\{N..<2*N}. c n > c (n+1)} > N / 2" proof - define h where "h=(\n. (nth_prime (2*n) - nth_prime n) / sqrt (nth_prime n))" have "\\<^sub>F n in sequentially. h n < n / 2" proof - have "\\<^sub>F n in sequentially. h n < n powr (5/6)" using nth_prime_double_sqrt_less[of "1/3"] unfolding h_def by auto moreover have "\\<^sub>F n in sequentially. n powr (5/6) < (n /2)" by real_asymp ultimately show ?thesis by eventually_elim auto qed moreover have "\\<^sub>F n in sequentially. sqrt (nth_prime n) / a n < 1 / (2*B)" using nth_1[THEN tendsto_real_sqrt,unfolded tendsto_iff ,rule_format,of "1/(2*B)"] \B>0\ a_pos by (auto simp:real_sqrt_divide abs_of_pos) ultimately have "\\<^sub>F x in sequentially. c (x+1) \ c x \ sqrt (nth_prime x) / a x < 1 / (2*B) \ h x < x / 2 \ (c (x+1)>c x \ nth_prime (x+1) > nth_prime x + a x / (2* B))" using c_neq_large B_nth_prime eq_2_11[of "1-1/ sqrt 2",simplified] by eventually_elim (auto simp:divide_simps) then show ?thesis proof (elim eventually_at_top_mono) fix N assume "N\1" and N_asm:"\y\N. c (y + 1) \ c y \ sqrt (real (nth_prime y)) / real_of_int (a y) < 1 / real_of_int (2 * B) \ h y < y / 2 \ (c y < c (y + 1) \ real (nth_prime y) + real_of_int (a y) / real_of_int (2 * B) < real (nth_prime (y + 1)))" define S where "S={n \ {N..<2 * N}. c n < c (n + 1)}" define g where "g=(\n. (nth_prime (n+1) - nth_prime n) / sqrt (nth_prime n))" define f where "f=(\n. nth_prime (n+1) - nth_prime n)" have g_gt_1:"g n>1" when "n\N" "c n < c (n + 1)" for n proof - have "nth_prime n + sqrt (nth_prime n) < nth_prime (n+1)" proof - have "nth_prime n + sqrt (nth_prime n) < nth_prime n + a n / (2*B)" using N_asm[rule_format,OF \n\N\] a_pos by (auto simp:field_simps) also have "... < nth_prime (n+1)" using N_asm[rule_format,OF \n\N\] \c n < c (n + 1)\ by auto finally show ?thesis . qed then show ?thesis unfolding g_def using \c n < c (n + 1)\ by auto qed have g_geq_0:"g n \ 0" for n unfolding g_def by auto have "finite S" "\x\S. x\N \ c x sum g S" proof (induct S) case empty then show ?case by auto next case (insert x F) moreover have "g x>1" proof - have "c x < c (x+1)" "x\N" using insert(4) by auto then show ?thesis using g_gt_1 by auto qed ultimately show ?case by simp qed also have "... \ sum g {N..<2*N}" apply (rule sum_mono2) unfolding S_def using g_geq_0 by auto also have "... \ sum (\n. f n/sqrt (nth_prime N)) {N..<2*N}" unfolding f_def g_def by (auto intro!:sum_mono divide_left_mono) also have "... = sum f {N..<2*N} / sqrt (nth_prime N)" unfolding sum_divide_distrib[symmetric] by auto also have "... = (nth_prime (2*N) - nth_prime N) / sqrt (nth_prime N)" proof - have "sum f {N..<2 * N} = nth_prime (2 * N) - nth_prime N" proof (induct N) case 0 then show ?case by simp next case (Suc N) have ?case if "N=0" proof - have "sum f {Suc N..<2 * Suc N} = sum f {1}" using that by (simp add: numeral_2_eq_2) also have "... = nth_prime 2 - nth_prime 1" unfolding f_def by (simp add:numeral_2_eq_2) also have "... = nth_prime (2 * Suc N) - nth_prime (Suc N)" using that by auto finally show ?thesis . qed moreover have ?case if "N\0" proof - have "sum f {Suc N..<2 * Suc N} = sum f {N..<2 * Suc N} - f N" apply (subst (2) sum.atLeast_Suc_lessThan) using that by auto also have "... = sum f {N..<2 * N}+ f (2*N) + f(2*N+1) - f N" by auto also have "... = nth_prime (2 * Suc N) - nth_prime (Suc N)" using Suc unfolding f_def by auto finally show ?thesis . qed ultimately show ?case by blast qed then show ?thesis by auto qed also have "... = h N" unfolding h_def by auto also have "... < N/2" using N_asm by auto finally have "card S < N/2" . define T where "T={n \ {N..<2 * N}. c n > c (n + 1)}" have "T \ S = {N..<2 * N}" "T \ S = {}" "finite T" unfolding T_def S_def using N_asm by fastforce+ then have "card T + card S = card {N..<2 * N}" using card_Un_disjoint \finite S\ by metis also have "... = N" by simp finally have "card T + card S = N" . with \card S < N/2\ show "card T > N/2" by linarith qed qed text\Inequality (3.5) in the original paper required a slight modification: \ have a_gt_plus:"\\<^sub>F n in sequentially. c n > c (n+1) \a (n+1) > a n + (a n - c(n+1) - 1) / c (n+1)" proof - note a_gt_1[THEN eventually_all_ge_at_top] c_pos[THEN eventually_all_ge_at_top] moreover have "\\<^sub>F n in sequentially. B * int (nth_prime (n+1)) = c (n+1) * a (n+1) - c (n + 2)" using Bc_large apply (subst (asm) eventually_sequentially_Suc[symmetric]) by (auto elim:eventually_mono) moreover have "\\<^sub>F n in sequentially. B * int (nth_prime n) = c n * a n - c (n + 1) \ \c (n + 1)\ < a n / 2" using Bc_large by (auto elim:eventually_mono) ultimately show ?thesis apply (eventually_elim) proof (rule impI) fix n assume "\y\n. 1 < a y" "\y\n. 0 < c y" and Suc_n_eq:"B * int (nth_prime (n + 1)) = c (n + 1) * a (n + 1) - c (n + 2)" and "B * int (nth_prime n) = c n * a n - c (n + 1) \ real_of_int \c (n + 1)\ < real_of_int (a n) / 2" and "c (n + 1) < c n" then have n_eq:"B * int (nth_prime n) = c n * a n - c (n + 1)" and c_less_a: "real_of_int \c (n + 1)\ < real_of_int (a n) / 2" by auto from \\y\n. 1 < a y\ \\y\n. 0 < c y\ have *:"a n>1" "a (n+1) > 1" "c n > 0" "c (n+1) > 0" "c (n+2) > 0" by auto then have "(1+1/c (n+1))* (a n - 1)/a (n+1) = (c (n+1)+1) * ((a n - 1) / (c (n+1) * a (n+1)))" by (auto simp:field_simps) also have "... \ c n * ((a n - 1) / (c (n+1) * a (n+1)))" - apply (rule mult_right_mono) - subgoal using \c (n + 1) < c n\ by auto - subgoal by (smt \0 < c (n + 1)\ a_pos divide_nonneg_pos mult_pos_pos of_int_0_le_iff - of_int_0_less_iff) - done + by (smt (verit) "*"(4) \c (n + 1) < c n\ a_pos divide_nonneg_nonneg mult_mono mult_nonneg_nonneg of_int_0_le_iff of_int_le_iff) also have "... = (c n * (a n - 1)) / (c (n+1) * a (n+1))" by auto also have "... < (c n * (a n - 1)) / (c (n+1) * a (n+1) - c (n+2))" apply (rule divide_strict_left_mono) subgoal using \c (n+2) > 0\ by auto unfolding Suc_n_eq[symmetric] using * \B>0\ by auto also have "... < (c n * a n - c (n+1)) / (c (n+1) * a (n+1) - c (n+2))" apply (rule frac_less) unfolding Suc_n_eq[symmetric] using * \B>0\ \c (n + 1) < c n\ by (auto simp:algebra_simps) also have "... = nth_prime n / nth_prime (n+1)" unfolding Suc_n_eq[symmetric] n_eq[symmetric] using \B>0\ by auto also have "... < 1" by auto finally have "(1 + 1 / real_of_int (c (n + 1))) * real_of_int (a n - 1) / real_of_int (a (n + 1)) < 1 " . then show "a n + (a n - c (n + 1) - 1) / (c (n + 1)) < (a (n + 1))" using * by (auto simp:field_simps) qed qed have a_gt_1:"\\<^sub>F n in sequentially. c n > c (n+1) \ a (n+1) > a n + 1" using Bc_large a_gt_plus c_pos[THEN eventually_all_ge_at_top] apply eventually_elim proof (rule impI) fix n assume "c (n + 1) < c n \ a n + (a n - c (n + 1) - 1) / c (n + 1) < a (n + 1)" "c (n + 1) < c n" and B_eq:"B * int (nth_prime n) = c n * a n - c (n + 1) \ \real_of_int (c (n + 1))\ < real_of_int (a n) / 2" and c_pos:"\y\n. 0 < c y" from this(1,2) have "a n + (a n - c (n + 1) - 1) / c (n + 1) < a (n + 1)" by auto moreover have "a n - 2 * c (n+1) > 0" using B_eq c_pos[rule_format,of "n+1"] by auto then have "a n - 2 * c (n+1) \ 1" by simp then have "(a n - c (n + 1) - 1) / c (n + 1) \ 1" using c_pos[rule_format,of "n+1"] by (auto simp:field_simps) ultimately show "a n + 1 < a (n + 1)" by auto qed text\The following corresponds to inequality (3.6) in the paper, which had to be slightly corrected: \ have a_gt_sqrt:"\\<^sub>F n in sequentially. c n > c (n+1) \ a (n+1) > a n + (sqrt n - 2)" proof - have a_2N:"\\<^sub>F N in sequentially. a (2*N) \ N /2 +1" using c_gt_half a_gt_1[THEN eventually_all_ge_at_top] proof eventually_elim case (elim N) define S where "S={n \ {N..<2 * N}. c (n + 1) < c n}" define f where "f = (\n. a (Suc n) - a n)" have f_1:"\x\S. f x\1" and f_0:"\x. f x\0" subgoal using elim unfolding S_def f_def by auto subgoal using \mono a\[THEN incseq_SucD] unfolding f_def by auto done have "N / 2 < card S" using elim unfolding S_def by auto also have "... \ sum f S" unfolding of_int_sum apply (rule sum_bounded_below[of _ 1,simplified]) using f_1 by auto also have "... \ sum f {N..<2 * N}" unfolding of_int_sum apply (rule sum_mono2) unfolding S_def using f_0 by auto also have "... = a (2*N) - a N" unfolding of_int_sum f_def of_int_diff apply (rule sum_Suc_diff') by auto finally have "N / 2 < a (2*N) - a N" . then show ?case using a_pos[rule_format,of N] by linarith qed have a_n4:"\\<^sub>F n in sequentially. a n > n/4" proof - obtain N where a_N:"\n\N. a (2*n) \ n /2+1" using a_2N unfolding eventually_at_top_linorder by auto have "a n>n/4" when "n\2*N" for n proof - define n' where "n'=n div 2" have "n'\N" unfolding n'_def using that by auto have "n/4 < n' /2+1" unfolding n'_def by auto also have "... \ a (2*n')" using a_N \n'\N\ by auto also have "... \a n" unfolding n'_def apply (cases "even n") subgoal by simp subgoal by (simp add: assms(2) incseqD) done finally show ?thesis . qed then show ?thesis unfolding eventually_at_top_linorder by auto qed have c_sqrt:"\\<^sub>F n in sequentially. c n < sqrt n / 4" proof - have "\\<^sub>F x in sequentially. x>1" by simp moreover have "\\<^sub>F x in sequentially. real (nth_prime x) / (real x * ln (real x)) < 2" using nth_prime_asymptotics[unfolded asymp_equiv_def,THEN order_tendstoD(2),of 2] by simp ultimately have "\\<^sub>F n in sequentially. c n < B*8 *ln n + 1" using a_n4 Bc_large proof eventually_elim case (elim n) from this(4) have "c n=(B*nth_prime n+c (n+1))/a n" using a_pos[rule_format,of n] by (auto simp:divide_simps) also have "... = (B*nth_prime n)/a n+c (n+1)/a n" by (auto simp:divide_simps) also have "... < (B*nth_prime n)/a n + 1" proof - have "c (n+1)/a n < 1" using elim(4) by auto then show ?thesis by auto qed also have "... < B*8 * ln n + 1" proof - have "B*nth_prime n < 2*B*n*ln n" using \real (nth_prime n) / (real n * ln (real n)) < 2\ \B>0\ \ 1 < n\ by (auto simp:divide_simps) moreover have "real n / 4 < real_of_int (a n)" by fact ultimately have "(B*nth_prime n) / a n < (2*B*n*ln n) / (n/4)" apply (rule_tac frac_less) using \B>0\ \ 1 < n\ by auto also have "... = B*8 * ln n" using \ 1 < n\ by auto finally show ?thesis by auto qed finally show ?case . qed moreover have "\\<^sub>F n in sequentially. B*8 *ln n + 1 < sqrt n / 4" by real_asymp ultimately show ?thesis by eventually_elim auto qed have "\\<^sub>F n in sequentially. 0 < c (n+1)" "\\<^sub>F n in sequentially. c (n+1) < sqrt (n+1) / 4" "\\<^sub>F n in sequentially. n > 4" "\\<^sub>F n in sequentially. (n - 4) / sqrt (n + 1) + 1 > sqrt n" subgoal using c_pos[THEN eventually_all_ge_at_top] by eventually_elim auto subgoal using c_sqrt[THEN eventually_all_ge_at_top] by eventually_elim (use le_add1 in blast) subgoal by simp subgoal by real_asymp done then show ?thesis using a_gt_plus a_n4 apply eventually_elim proof (rule impI) fix n assume asm:"0 < c (n + 1)" "c (n + 1) < sqrt (real (n + 1)) / 4" and a_ineq:"c (n + 1) < c n \ a n + (a n - c (n + 1) - 1) / c (n + 1) < a (n + 1)" "c (n + 1) < c n" and "n / 4 < a n" "n > 4" and n_neq:" sqrt (real n) < real (n - 4) / sqrt (real (n + 1)) + 1" have "(n-4) / sqrt(n+1) = (n/4 - 1)/ (sqrt (real (n + 1)) / 4)" using \n>4\ by (auto simp:divide_simps) also have "... < (a n - 1) / c (n + 1)" apply (rule frac_less) using \n > 4\ \n / 4 < a n\ \0 < c (n + 1)\ \c (n + 1) < sqrt (real (n + 1)) / 4\ by auto also have "... - 1 = (a n - c (n + 1) - 1) / c (n + 1)" using \0 < c (n + 1)\ by (auto simp:field_simps) also have "a n + ... < a (n+1)" using a_ineq by auto finally have "a n + ((n - 4) / sqrt (n + 1) - 1) < a (n + 1)" by simp moreover have "(n - 4) / sqrt (n + 1) - 1 > sqrt n - 2" using n_neq[THEN diff_strict_right_mono,of 2] \n>4\ by (auto simp:algebra_simps of_nat_diff) ultimately show "real_of_int (a n) + (sqrt (real n) - 2) < real_of_int (a (n + 1))" by argo qed qed text\The following corresponds to inequality $ a_{2N} > N^{3/2}/2$ in the paper, which had to be slightly corrected: \ have a_2N_sqrt:"\\<^sub>F N in sequentially. a (2*N) > real N * (sqrt (real N)/2 - 1)" using c_gt_half a_gt_sqrt[THEN eventually_all_ge_at_top] eventually_gt_at_top[of 4] proof eventually_elim case (elim N) define S where "S={n \ {N..<2 * N}. c (n + 1) < c n}" define f where "f = (\n. a (Suc n) - a n)" have f_N:"\x\S. f x\sqrt N - 2" proof fix x assume "x\S" then have "sqrt (real x) - 2 < f x" "x\N" using elim unfolding S_def f_def by auto moreover have "sqrt x - 2 \ sqrt N - 2" using \x\N\ by simp ultimately show "sqrt (real N) - 2 \ real_of_int (f x)" by argo qed have f_0:"\x. f x\0" using \mono a\[THEN incseq_SucD] unfolding f_def by auto have "(N / 2) * (sqrt N - 2) < card S * (sqrt N - 2)" apply (rule mult_strict_right_mono) subgoal using elim unfolding S_def by auto subgoal using \N>4\ by (metis diff_gt_0_iff_gt numeral_less_real_of_nat_iff real_sqrt_four real_sqrt_less_iff) done also have "... \ sum f S" unfolding of_int_sum apply (rule sum_bounded_below) using f_N by auto also have "... \ sum f {N..<2 * N}" unfolding of_int_sum apply (rule sum_mono2) unfolding S_def using f_0 by auto also have "... = a (2*N) - a N" unfolding of_int_sum f_def of_int_diff apply (rule sum_Suc_diff') by auto finally have "real N / 2 * (sqrt (real N) - 2) < real_of_int (a (2 * N) - a N)" . then have "real N / 2 * (sqrt (real N) - 2) < a (2 * N)" using a_pos[rule_format,of N] by linarith then show ?case by (auto simp:field_simps) qed text\The following part is required to derive the final contradiction of the proof.\ have a_n_sqrt:"\\<^sub>F n in sequentially. a n > (((n-1)/2) powr (3/2) - (n-1)) /2" proof (rule sequentially_even_odd_imp) define f where "f=(\N. ((real (2 * N - 1) / 2) powr (3 / 2) - real (2 * N - 1)) / 2)" define g where "g=(\N. real N * (sqrt (real N) / 2 - 1))" have "\\<^sub>F N in sequentially. g N > f N" unfolding f_def g_def by real_asymp moreover have "\\<^sub>F N in sequentially. a (2 * N) > g N" unfolding g_def using a_2N_sqrt . ultimately show "\\<^sub>F N in sequentially. f N < a (2 * N)" by eventually_elim auto next define f where "f=(\N. ((real (2 * N + 1 - 1) / 2) powr (3 / 2) - real (2 * N + 1 - 1)) / 2)" define g where "g=(\N. real N * (sqrt (real N) / 2 - 1))" have "\\<^sub>F N in sequentially. g N = f N" using eventually_gt_at_top[of 0] apply eventually_elim unfolding f_def g_def by (auto simp:algebra_simps powr_half_sqrt[symmetric] powr_mult_base) moreover have "\\<^sub>F N in sequentially. a (2 * N) > g N" unfolding g_def using a_2N_sqrt . moreover have "\\<^sub>F N in sequentially. a (2 * N + 1) \ a (2*N)" apply (rule eventuallyI) using \mono a\ by (simp add: incseqD) ultimately show "\\<^sub>F N in sequentially. f N < (a (2 * N + 1))" by eventually_elim auto qed have a_nth_prime_gt:"\\<^sub>F n in sequentially. a n / nth_prime n > 1" proof - define f where "f=(\n::nat. (((n-1)/2) powr (3/2) - (n-1)) /2)" have "\\<^sub>F x in sequentially. real (nth_prime x) / (real x * ln (real x)) < 2" using nth_prime_asymptotics[unfolded asymp_equiv_def,THEN order_tendstoD(2),of 2] by simp from this eventually_gt_at_top[of 1] have "\\<^sub>F n in sequentially. real (nth_prime n) < 2*(real n * ln n)" by eventually_elim (auto simp:field_simps) moreover have *:"\\<^sub>F N in sequentially. f N >0 " unfolding f_def by real_asymp moreover have " \\<^sub>F n in sequentially. f n < a n" using a_n_sqrt unfolding f_def . ultimately have "\\<^sub>F n in sequentially. a n / nth_prime n > f n / (2*(real n * ln n))" proof eventually_elim case (elim n) then show ?case by (auto intro: frac_less2) qed moreover have "\\<^sub>F n in sequentially. (f n)/ (2*(real n * ln n)) > 1" unfolding f_def by real_asymp ultimately show ?thesis by eventually_elim argo qed have a_nth_prime_lt:"\\<^sub>F n in sequentially. a n / nth_prime n < 1" proof - have "liminf (\x. a x / nth_prime x) < 1" using nth_2 by auto from this[unfolded less_Liminf_iff] show ?thesis - apply (auto elim!:frequently_elim1) - by (meson divide_less_eq_1 ereal_less_eq(7) leD leI - nth_prime_nonzero of_nat_eq_0_iff of_nat_less_0_iff order.trans) + by (smt (verit) ereal_less(3) frequently_elim1 le_less_trans) qed from a_nth_prime_gt a_nth_prime_lt show False by (simp add: eventually_mono frequently_def) qed section\Acknowledgements\ text\A.K.-A. and W.L. were supported by the ERC Advanced Grant ALEXANDRIA (Project 742178) funded by the European Research Council and led by Professor Lawrence Paulson at the University of Cambridge, UK.\ end \ No newline at end of file diff --git a/thys/Lovasz_Local/Lovasz_Local_Lemma.thy b/thys/Lovasz_Local/Lovasz_Local_Lemma.thy --- a/thys/Lovasz_Local/Lovasz_Local_Lemma.thy +++ b/thys/Lovasz_Local/Lovasz_Local_Lemma.thy @@ -1,706 +1,706 @@ (* Theory: Lovasz_Local_Lemma Author: Chelsea Edmonds *) section \Lovasz Local Lemma \ theory Lovasz_Local_Lemma imports Basic_Method "HOL-Real_Asymp.Real_Asymp" Indep_Events Digraph_Extensions begin subsection \Random Lemmas on Product Operator \ lemma prod_constant_ge: fixes y :: "'b :: {comm_monoid_mult, linordered_semidom}" assumes "card A \ k" assumes "y \ 0" and "y < 1" shows "(\x\A. y) \ y ^ k" using assms power_decreasing by fastforce lemma (in linordered_idom) prod_mono3: assumes "finite J" "I \ J" "\i. i \ J \ 0 \ f i" "(\i. i \ J \ f i \ 1)" shows "prod f J \ prod f I" proof - have "prod f J \ (\i\J. if i \ I then f i else 1)" using assms by (intro prod_mono) auto also have "\ = prod f I" using \finite J\ \I \ J\ by (simp add: prod.If_cases Int_absorb1) finally show ?thesis . qed lemma bij_on_ss_image: assumes "A \ B" assumes "bij_betw g B B'" shows "g ` A \ B'" using assms by (auto simp add: bij_betw_apply subsetD) lemma bij_on_ss_proper_image: assumes "A \ B" assumes "bij_betw g B B'" shows "g ` A \ B'" by (smt (verit, ccfv_SIG) assms bij_betw_iff_bijections bij_betw_subset leD psubsetD psubsetI subsetI) subsection \Dependency Graph Concept \ text \Uses directed graphs. The pair\_digraph locale was sufficient as multi-edges are irrelevant \ locale dependency_digraph = pair_digraph "G :: nat pair_pre_digraph" + prob_space "M :: 'a measure" for G M + fixes F :: "nat \ 'a set" assumes vss: "F ` (pverts G) \ events" assumes mis: "\ i. i \ (pverts G) \ mutual_indep_events (F i) F ((pverts G) - ({i} \ neighborhood i))" begin lemma dep_graph_indiv_nh_indep: assumes "A \ pverts G" "B \ pverts G" assumes "B \ neighborhood A" assumes "A \ B" assumes "prob (F B) \ 0" shows "\

((F A) | (F B)) = prob (F A)" proof- have "B \ {A} \ neighborhood A" using assms(3) assms(4) by auto then have "B \ (pverts G - ({A} \ neighborhood A))" using assms(2) by auto moreover have "mutual_indep_events (F A) F (pverts G - ({A} \ neighborhood A))" using mis assms by auto ultimately show ?thesis using assms(5) assms(1) assms(2) vss mutual_indep_ev_cond_single by auto qed lemma mis_subset: assumes "i \ pverts G" assumes "A \ pverts G" shows "mutual_indep_events (F i) F (A - ({i} \ neighborhood i))" proof (cases "A \ ({i} \ neighborhood i)") case True then have "A - ({i} \ neighborhood i) = {}" by auto then show ?thesis using mutual_indep_ev_empty vss assms(1) by blast next case False then have "A - ({i} \ neighborhood i) \ pverts G - ({i} \ neighborhood i)" using assms(2) by auto then show ?thesis using mutual_indep_ev_subset mis assms(1) by blast qed lemma dep_graph_indep_events: assumes "A \ pverts G" assumes "\ Ai. Ai \ A \ out_degree G Ai = 0" shows "indep_events F A" proof - have "\ Ai. Ai \ A \ (mutual_indep_events (F Ai) F (A - {Ai}))" proof - fix Ai assume ain: "Ai \ A" then have "(neighborhood Ai) = {}" using assms(2) neighborhood_empty_iff by simp moreover have "mutual_indep_events (F Ai) F (A - ({Ai} \ neighborhood Ai))" using mis_subset[of Ai A] ain assms(1) by auto ultimately show "mutual_indep_events (F Ai) F (A - {Ai})" by simp qed then show ?thesis using mutual_indep_ev_set_all[of F A] vss by auto qed end subsection \Lovasz Local General Lemma \ context prob_space begin lemma compl_sets_index: assumes "F ` A \ events" shows "(\ i. space M - F i) ` A \ events" proof (intro subsetI) fix x assume "x \ (\i. space M - F i) ` A" then obtain i where xeq: "x = space M - F i" and "i \ A" by blast then have "F i \ events" using assms by auto thus "x \ events" using sets.compl_sets xeq by simp qed lemma lovasz_inductive_base: assumes "dependency_digraph G M F" assumes "\ Ai . Ai \ A \ g Ai \ 0 \ g Ai < 1" assumes "\ Ai. Ai \ A \ (prob (F Ai) \ (g Ai) * (\ Aj \ pre_digraph.neighborhood G Ai. (1 - (g Aj))))" assumes "Ai \ A" assumes "pverts G = A" shows "prob (F Ai) \ g Ai" proof - have genprod: "\ S. S \ A \ (\Aj \ S . (1 - (g Aj))) \ 1" using assms(2) by (smt (verit) prod_le_1 subsetD) interpret dg: dependency_digraph G M F using assms(1) by simp have "dg.neighborhood Ai \ A" using assms(3) dg.neighborhood_wf assms(5) by simp then show ?thesis using genprod assms mult_left_le by (smt (verit)) qed lemma lovasz_inductive_base_set: assumes "N \ A" assumes "\ Ai . Ai \ A \ g Ai \ 0 \ g Ai < 1" assumes "\ Ai. Ai \ A \ (prob (F Ai) \ (g Ai) * (\ Aj \ N. (1 - (g Aj))))" assumes "Ai \ A" shows "prob (F Ai) \ g Ai" proof - have genprod: "\ S. S \ A \ (\Aj \ S . (1 - (g Aj))) \ 1" using assms(2) by (smt (verit) prod_le_1 subsetD) then show ?thesis using genprod assms mult_left_le by (smt (verit)) qed lemma split_prob_lt_helper: assumes dep_graph: "dependency_digraph G M F" assumes dep_graph_verts: "pverts G = A" assumes fbounds: "\ i . i \ A \ f i \ 0 \ f i < 1" assumes prob_Ai: "\ Ai. Ai \ A \ prob (F Ai) \ (f Ai) * (\ Aj \ pre_digraph.neighborhood G Ai . (1 - (f Aj)))" assumes aiin: "Ai \ A" assumes "N \ pre_digraph.neighborhood G Ai" assumes "\ P1 P2. \

(F Ai | \Aj\S. space M - F Aj) = P1/P2 \ P1 \ prob (F Ai)\ P2 \ (\ Aj \ N . (1 - (f Aj)))" shows "\

(F Ai | \Aj\S. space M - F Aj) \ f Ai" proof - interpret dg: dependency_digraph G M F using assms(1) by simp have lt1: "\ Aj. Aj \ A \ (1 - (f Aj)) \ 1" using assms(3) by auto have gt0: "\ Aj. Aj \ A \ (1 - (f Aj)) > 0" using assms(3) by auto then have prodgt0: "\ S'. S' \ A \ (\ Aj \ S' . (1 - f Aj)) > 0" using prod_pos by (metis subsetD) obtain P1 P2 where peq: "\

(F Ai | \Aj\S. space M - F Aj) = P1/P2" and "P1 \ prob (F Ai)" and p2gt: "P2 \ (\ Aj \ N . (1 - (f Aj)))" using assms(7) by auto then have "P1 \ (f Ai) * (\ Aj \ pre_digraph.neighborhood G Ai . (1 - (f Aj)))" using prob_Ai aiin by fastforce moreover have "P2 \ (\ Aj \ dg.neighborhood Ai . (1 - (f Aj)))" using assms(6) gt0 dg.neighborhood_wf dep_graph_verts subset_iff lt1 dg.neighborhood_finite p2gt by (smt (verit, ccfv_threshold) prod_mono3) ultimately have "P1/P2 \ ((f Ai) * (\ Aj \ dg.neighborhood Ai . (1 - (f Aj)))/(\ Aj \ dg.neighborhood Ai . (1 - (f Aj))))" using frac_le[of "(f Ai) * (\ Aj \ dg.neighborhood Ai . (1 - (f Aj)))" "P1" "(\ Aj \ dg.neighborhood Ai . (1 - (f Aj)))"] prodgt0[of "dg.neighborhood Ai"] assms(3) dg.neighborhood_wf[of Ai] by (simp add: assms(2) bounded_measure finite_measure_compl assms(5)) then show ?thesis using prodgt0[of "dg.neighborhood Ai"] dg.neighborhood_wf[of Ai] assms(2) peq by (metis divide_eq_imp rel_simps(70)) qed lemma lovasz_inequality: assumes finS: "finite S" assumes sevents: "F ` S \ events" assumes S_subset: "S \ A - {Ai}" assumes prob2: "prob (\ Aj \ S . (space M - (F Aj))) > 0" assumes irange: "i \ {0.. N)" assumes s2_def: "S2 = S - S1" assumes ne_cond: "i > 0 \ S2 \ {}" assumes hyps: "\ B. B \ S \ g i \ A \ B \ A - {g i} \ B \ {} \ 0 < prob (\Aj\B. space M - F Aj) \ \

(F (g i) | \Aj\B. space M - F Aj) \ f (g i)" shows "\

((space M - F (g i)) | (\ ((\ i. space M - F i) ` g ` {0.. ((\ i. space M - F i) ` S2)))) \ (1 - f (g i))" proof - let ?c = "(\ i. space M - F i)" define S1ss where "S1ss = g ` {0.. {0.. {0.. S1ss" using bb S1ss_def irange by (smt (verit, best) bij_betw_iff_bijections image_iff subset_eq) have ginotin2: "g i \ S2" unfolding s2_def using irange bb by (simp add: bij_betwE) have giS: "g i \ S" using irange bij_betw_imp_surj_on imageI Int_iff s1_def bb by blast have "{0.. {0.. S1" unfolding S1ss_def using irange bb bij_on_ss_proper_image by meson then have sss: "S1ss \ S2 \ S" using s1_def s2_def by blast moreover have xsiin: "g i \ A"using irange using giS S_subset by (metis DiffE in_mono) moreover have ne: "S1ss \ S2 \ {}" using ne_cond S1ss_def by auto moreover have "S1ss \ S2 \ A - {g i}" using S_subset sss ginotin1 ginotin2 by auto moreover have gt02: "0 < prob (\ (?c ` (S1ss \ S2)))" using finS prob2 sevents prob_inter_ss_lt_index[of S ?c "S1ss \ S2"] ne sss compl_sets_index[of F S] by fastforce ultimately have ltfAi: "\

(F (g i) | \ (?c ` (S1ss \ S2))) \ f (g i)" using hyps[of "S1ss \ S2"] by blast have "?c ` (S1ss \ S2) \ events" using sss \S1ss \ S1\ compl_subset_in_events sevents s1_def s2_def by fastforce then have "\ (?c ` (S1ss \ S2)) \ events" using Inter_event_ss sss by (meson \S1ss \ S2 \ {}\ finite_imageI finite_subset image_is_empty finS subset_iff_psubset_eq) moreover have "F (g i) \ events" using xsiin giS sevents by auto ultimately have "\

(?c (g i) | \ (?c ` (S1ss \ S2))) \ 1 - f (g i)" using cond_prob_neg[of "\ (?c ` (S1ss \ S2))" "F (g i)"] gt02 xsiin ltfAi by simp then show "\

(?c (g i) | (\ (?c ` g ` {0.. (?c ` S2)))) \ (1 - f (g i))" by (simp add: S1ss_def image_Un) qed text \The main helper lemma \ lemma lovasz_inductive: assumes finA: "finite A" assumes Aevents: "F ` A \ events" assumes fbounds: "\ i . i \ A \ f i \ 0 \ f i < 1" assumes dep_graph: "dependency_digraph G M F" assumes dep_graph_verts: "pverts G = A" assumes prob_Ai: "\ Ai. Ai \ A \ prob (F Ai) \ (f Ai) * (\ Aj \ pre_digraph.neighborhood G Ai . (1 - (f Aj)))" assumes Ai_in: "Ai \ A" assumes S_subset: "S \ A - {Ai}" assumes S_nempty: "S \ {}" assumes prob2: "prob (\ Aj \ S . (space M - (F Aj))) > 0" shows "\

((F Ai) | (\ Aj \ S . (space M - (F Aj)))) \ f Ai" proof - let ?c = "\ i. space M - F i" have ceq: "\ A. ?c ` A = ((-) (space M)) ` (F ` A)" by auto interpret dg: dependency_digraph G M F using assms(4) by simp have finS: "finite S" using assms finite_subset by (metis finite_Diff) show "\

(( F Ai) | (\ Aj \ S . (space M - (F Aj)))) \ f Ai" using finS Ai_in S_subset S_nempty prob2 proof (induct S arbitrary: Ai rule: finite_psubset_induct ) case (psubset S) define S1 where "S1 = (S \ dg.neighborhood Ai)" define S2 where "S2 = S - S1" have "\ s . s \ S2 \ s \ A - ({Ai} \ dg.neighborhood Ai)" using S1_def S2_def psubset.prems(2) by blast then have s2ssmis: "S2 \ A - ({Ai} \ dg.neighborhood Ai)" by auto have sevents: "F ` S \ events" using assms(2) psubset.prems(2) by auto then have s1events: "F ` S1 \ events" using S1_def by auto have finS2: "finite S2" and finS1: "finite S1" using S2_def S1_def by (simp_all add: psubset(1)) have "mutual_indep_set (F Ai) (F ` S2)" using dg.mis[of Ai] mutual_indep_ev_subset s2ssmis psubset.prems(1) dep_graph_verts mutual_indep_iff by auto then have mis2: "mutual_indep_set (F Ai) (?c ` S2)" using mutual_indep_events_compl[of "F ` S2" "F Ai"] finS2 ceq[of S2] by simp have scompl_ev: "?c ` S \ events" using compl_sets_index sevents by simp then have s2cev: "?c ` S2 \ events" using S2_def scompl_ev by blast have "(\ Aj \ S . space M - (F Aj)) \ (\ Aj \ S2 . space M - (F Aj))" unfolding S2_def using Diff_subset image_mono Inter_anti_mono by blast then have "S2 \ {} \ prob (\ Aj \ S2 . space M - (F Aj)) \ 0" using psubset.prems(4) s2cev finS2 Inter_event_ss[of "?c ` S2"] finite_measure_mono[of "\ (?c ` S)" "\(?c ` S2)"] by simp then have s2prob_eq: "S2 \ {} \ \

((F Ai) | (\ (?c ` S2))) = prob (F Ai)" using assms(2) mutual_indep_cond_full[of " F Ai" "?c ` S2"] psubset.prems(1) s2cev finS2 mis2 by simp show ?case proof (cases "S1 = {}") case True then show ?thesis using lovasz_inductive_base[of G F A f Ai] psubset.prems(3) S2_def assms(3) assms(4) psubset.prems(1) prob_Ai s2prob_eq dep_graph_verts by (simp) next case s1F: False then have csgt0: "card S1 > 0" using s1F finS1 card_gt_0_iff by blast obtain g where bb: "bij_betw g {0..i. i \ {0.. 1 - f (g i) \ 0" using S1_def psubset.prems(2) bb bij_betw_apply assms(3) by fastforce have s1ss: "S1 \ dg.neighborhood Ai" using S1_def by auto moreover have "\ P1 P2. \

(F Ai | \Aj\S. space M - F Aj) = P1/P2 \ P1 \ prob (F Ai) \ P2 \ (\ Aj \ S1 . (1 - (f Aj)))" proof (cases "S2 = {}") case True then have Seq: "S1 = S" using S1_def S2_def by auto have inter_eventsS: "(\ Aj \ S . (space M - (F Aj))) \ events" using psubset.prems assms by (meson measure_notin_sets zero_less_measure_iff) then have peq: "\

((F Ai) | (\ Aj \ S1 . ?c Aj)) = prob ((\ Aj \ S1 . ?c Aj) \ (F Ai))/prob ((\ (?c ` S1)))" (is "\

((F Ai) | (\ Aj \ S1 . ?c Aj)) = ?Num/?Den") using cond_prob_ev_def[of "(\ Aj \ S1 . (space M - (F Aj)))" "F Ai"] using Seq psubset.prems(1) assms(2) by blast have "?Num \ prob (F Ai)" using finite_measure_mono assms(2) psubset.prems(1) by simp moreover have "?Den \ (\ Aj \ S1 . (1 - (f Aj)))" proof - have pcond: "prob (\(?c ` S1)) = prob (?c (g 0)) * (\i \ {1..(?c (g i) | (\(?c ` g ` {0.. i. i \ {1.. \

(?c (g i) | (\(?c ` g ` {0.. (1 - (f (g i)))" using lovasz_inequality[of S1 F A Ai _ S1 g S1 "{}" f] sevents finS psubset.prems(2) psubset.prems(4) bb psubset.hyps(2)[of _ "g _"] Seq by fastforce have "(\i. i \ {1.. 1 - f (g i) \ 0)" using igt0 by simp then have "(\i \ {1..<(card S1)} . \

(?c (g i) | (\(?c ` g ` {0.. (\i \ {1..<(card S1)} . (1 - (f (g i))))" using ineq prod_mono by (smt(verit, ccfv_threshold)) moreover have "prob (?c (g 0)) \ (1 - f (g 0))" proof - have g0in: "g 0 \ A" using bb csgt0 using psubset.prems(2) bij_betwE Seq by fastforce then have "prob (?c (g 0)) = 1 - prob (F (g 0))" using Aevents by (simp add: prob_compl) then show ?thesis using lovasz_inductive_base[of G F A f "g 0"] prob_Ai assms(4) dep_graph_verts fbounds g0in by auto qed - moreover have "0 \ (\i = 1.. (\i = 1..(?c ` S1)) \ (1 - (f (g 0))) * (\i \ {1..<(card S1)} . (1 - (f (g i))))" using pcond igt0 mult_mono'[of "(1 - (f (g 0)))" ] by fastforce moreover have "{0.. {1..(?c ` S1)) \ (\i \ {0..<(card S1)} . (1 - (f (g i))))" by auto moreover have "(\i \ {0..<(card S1)} . (1 - (f (g i)))) = (\i \ S1 . (1 - (f (i))))" using prod.reindex_bij_betw bb by simp ultimately show ?thesis by simp qed ultimately show ?thesis using peq Seq by blast next case s2F: False have s2inter: "\ (?c ` S2) \ events" using s2F finS2 s2cev Inter_event_ss[of "?c ` S2"] by auto have split: "(\ Aj \ S . (?c Aj)) = (\ (?c `S1)) \ (\ (?c ` S2))" using S1_def S2_def by auto then have "\

(F Ai | (\ Aj \ S . (?c Aj))) = \

(F Ai | (\ (?c `S1)) \ (\ (?c ` S2)))" by simp moreover have s2n0: "prob (\ (?c ` S2)) \ 0" using psubset.prems(4) S2_def by (metis Int_lower2 split finite_measure_mono measure_le_0_iff s2inter semiring_norm(137)) moreover have "\ (?c ` S1) \ events" using finS1 S1_def scompl_ev s1F Inter_event_ss[of "(?c ` S1)"] by auto ultimately have peq: "\

(F Ai | (\ Aj \ S . (?c Aj))) = \

(F Ai \ (\ (?c `S1)) | \ (?c ` S2))/ \

(\ (?c `S1) | \ (?c `S2))" (is "\

(F Ai | (\ Aj \ S . (?c Aj))) = ?Num/?Den") using cond_prob_dual_intersect[of "F Ai" "\ (?c `S1)" "\ (?c `S2)"] assms(2) psubset.prems(1) s2inter by fastforce have "?Num \ \

(F Ai | \ (?c `S2))" using cond_prob_inter_set_lt[of "F Ai" "\ (?c `S2)" "?c ` S1"] using s1events finS1 psubset.prems(1) assms(2) s2inter finite_imageI[of S1 F] by blast then have "?Num \ prob (F Ai)" using s2F s2prob_eq by auto moreover have "?Den \ (\ Aj \ S1 . (1 - (f Aj)))" using psubset.hyps proof - have "prob (\(?c ` S2)) > 0" using s2n0 by (meson zero_less_measure_iff) then have pcond: "\

(\ (?c `S1) | \ (?c `S2)) = (\i = 0..(?c (g i) | (\ (?c ` g ` {0.. (?c ` S2)))))" using prob_cond_Inter_index_cond_compl_fn[of S1 "?c ` S2" F] s1F finS1 s2cev finS2 s2F s1events bb by auto have "\ i. i \ {0.. \

(?c (g i) | (\ (?c ` g ` {0.. (?c ` S2)))) \ (1 - f (g i))" using lovasz_inequality[of S F A Ai _ S1 g "dg.neighborhood Ai" S2 f] S1_def S2_def sevents finS psubset.prems(2) psubset.prems(4) bb psubset.hyps(2)[of _ "g _"] psubset(1) s2F by meson then have c1: "\

(\ (?c `S1) | \ (?c `S2)) \ (\i = 0..(\ (?c `S1) | \ (?c `S2)) \ (\i \ {0..i \ {0..x \ S1 . (1 - f x))" using bb using prod.reindex_bij_betw by fastforce ultimately show ?thesis by simp qed ultimately show ?thesis using peq by blast qed ultimately show ?thesis by (intro split_prob_lt_helper[of G F A]) (simp_all add: dep_graph dep_graph_verts fbounds psubset.prems(1) prob_Ai) qed qed qed text \The main lemma \ theorem lovasz_local_general: assumes "A \ {}" assumes "F ` A \ events" assumes "finite A" assumes "\ Ai . Ai \ A \ f Ai \ 0 \ f Ai < 1" assumes "dependency_digraph G M F" assumes "\ Ai. Ai \ A \ (prob (F Ai) \ (f Ai) * (\ Aj \ pre_digraph.neighborhood G Ai. (1 - (f Aj))))" assumes "pverts G = A" shows "prob (\ Ai \ A . (space M - (F Ai))) \ (\ Ai \ A . (1 - f Ai))" "(\ Ai \ A . (1 - f Ai)) > 0" proof - show gt0: "(\ Ai \ A . (1 - f Ai)) > 0" using assms(4) by (simp add: prod_pos) let ?c = "\ i. space M - F i" interpret dg: dependency_digraph G M F using assms(5) by simp have general: "\Ai S. Ai \ A \ S \ A - {Ai} \ S \ {} \ prob (\ Aj \ S . (?c Aj)) > 0 \ \

(F Ai | (\ Aj \ S . (?c Aj))) \ f Ai" using assms lovasz_inductive[of A F f G] by simp have base: "\ Ai. Ai \ A \ prob (F Ai) \ f Ai" using lovasz_inductive_base assms(4) assms(6) assms(5) assms(7) by blast show "prob (\ Ai \ A . (?c Ai)) \ (\ Ai \ A . (1 - f Ai))" using assms(3) assms(1) assms(2) assms(4) general base proof (induct A rule: finite_ne_induct) case (singleton x) then show ?case using singleton.prems singleton prob_compl by auto next case (insert x X) define Ax where "Ax = ?c ` (insert x X)" have xie: "F x \ events" using insert.prems by simp have A'ie: "\(?c ` X) \ events" using insert.prems insert.hyps by auto have "(\Ai S. Ai \ insert x X \ S \ insert x X - {Ai} \ S \ {} \ prob (\ Aj \ S . (?c Aj)) > 0 \ \

(F Ai | \ (?c ` S)) \ f Ai)" using insert.prems by simp then have "(\Ai S. Ai \ X \ S \ X - {Ai} \ S \ {} \ prob (\ Aj \ S . (?c Aj)) > 0 \ \

(F Ai | \ (?c ` S)) \ f Ai)" by auto then have A'gt: "(\Ai\X. 1 - f Ai) \ prob (\ (?c ` X))" using insert.hyps(4) insert.prems(2) insert.prems(1) insert.prems(4) by auto then have "prob (\(?c ` X)) > 0" using insert.hyps insert.prems prod_pos basic_trans_rules(22) diff_gt_0_iff_gt by (metis (no_types, lifting) insert_Diff insert_subset subset_insertI) then have "\

((?c x) | (\(?c ` X))) = 1 - \

(F x | (\(?c ` X)))" using cond_prob_neg[of "\(?c ` X)" "F x"] xie A'ie by simp moreover have "\

(F x | (\(?c ` X))) \ f x" using insert.prems(3)[of x X] insert.hyps(2) insert(3) A'gt \0 < prob (\ (?c ` X))\ by fastforce ultimately have pnxgt: "\

((?c x) | (\(?c ` X))) \ 1 - f x" by simp have xgt0: "1 - f x \ 0" using insert.prems(2)[of x] by auto have "prob (\ Ax) = prob ((?c x) \ \(?c ` X))" using Ax_def by simp also have "... = prob (\(?c ` X)) * \

((?c x) | (\(?c ` X)))" using prob_intersect_B xie A'ie by simp also have "... \ (\Ai\X. 1 - f Ai) * (1 - f x)" using A'gt pnxgt mult_left_le \0 < prob (\(?c ` X))\ xgt0 mult_mono by (smt(verit)) finally have "prob (\ Ax) \ (\Ai\insert x X. 1 - f Ai)" by (simp add: local.insert(1) local.insert(3) mult.commute) then show ?case using Ax_def by auto qed qed subsection \Lovasz Corollaries and Variations \ corollary lovasz_local_general_positive: assumes "A \ {}" assumes "F ` A \ events" assumes "finite A" assumes "\ Ai . Ai \ A \ f Ai \ 0 \ f Ai < 1" assumes "dependency_digraph G M F" assumes "\ Ai. Ai \ A \ (prob (F Ai) \ (f Ai) * (\ Aj \ pre_digraph.neighborhood G Ai. (1 - (f Aj))))" assumes "pverts G = A" shows "prob (\ Ai \ A . (space M - (F Ai))) > 0" using assms lovasz_local_general(1)[of A F f G] lovasz_local_general(2)[of A F f G] by simp theorem lovasz_local_symmetric_dep_graph: fixes e :: real fixes d :: nat assumes "A \ {}" assumes "F ` A \ events" assumes "finite A" assumes "dependency_digraph G M F" assumes "\ Ai. Ai \ A \ out_degree G Ai \ d" assumes "\ Ai. Ai \ A \ prob (F Ai) \ p" assumes "exp(1)* p * (d + 1) \ 1" (* e should be euler's number \ using exponential function? *) assumes "pverts G = A" shows "prob (\ Ai \ A . (space M - (F Ai))) > 0" proof (cases "d = 0") case True interpret g: dependency_digraph G M F using assms(4) by simp (* Because all have mutual independence \ complete independence *) have "indep_events F A" using g.dep_graph_indep_events[of A] assms(8) assms(5) True by simp moreover have "p < 1" proof - have "exp (1) * p \ 1" using assms(7) True by simp then show ?thesis using exp_gt_one less_1_mult linorder_neqE_linordered_idom rel_simps(68) verit_prod_simplify(2) by (smt (verit) mult_le_cancel_left1) qed ultimately show ?thesis using complete_indep_bound3[of A F] assms(2) assms(1) assms(3) assms(6) by force next case False define f :: "nat \ real" where "f \ (\ Ai . 1 /(d + 1))" then have fbounds: "\ Ai. f Ai \ 0 \ f Ai < 1" using f_def False by simp interpret dg: dependency_digraph G M F using assms(4) by auto (* Showing bound is the most work *) have "\ Ai. Ai \ A \ prob (F Ai) \ (f Ai) * (\ Aj \ dg.neighborhood Ai . (1 - (f Aj)))" proof - fix Ai assume ain: "Ai \ A" have d_boundslt1: "(1/(d + 1)) < 1" and d_boundsgt0: "(1/(d + 1))> 0" using False by fastforce+ have d_bounds2: "(1 - (1 /(d + 1)))^d < 1" using False by(simp add: field_simps) (smt (verit) of_nat_0_le_iff power_mono_iff) have d_bounds0: "(1 - (1 /(d + 1)))^d > 0" using False by (simp) have "exp(1) > (1 + 1/d) powr d" using exp_1_gt_powr False by simp then have "exp(1) > (1 + 1/d)^d" using False by (simp add: powr_realpow zero_compare_simps(2)) moreover have "1/(1+ 1/d)^d = (1 - (1/(d+1)))^d" proof - have "1/(1+ 1/d)^d = 1/((d/d) + 1/d)^d" by (simp add: field_simps) then show ?thesis by (simp add: field_simps) qed ultimately have exp_lt: "1/exp(1) < (1 - (1 /(d + 1)))^d" by (metis d_bounds0 frac_less2 less_eq_real_def of_nat_zero_less_power_iff power_eq_if zero_less_divide_1_iff) then have "(1 /(d + 1))* (1 - (1 /(d + 1)))^d > (1 /(d + 1))*(1/exp(1))" using exp_lt mult_strict_left_mono[of "1/exp(1)" "(1 - (1 /(d + 1)))^d" "(1/(d+1))"] d_boundslt1 by simp then have "(1 /(d + 1))* (1 - (1 /(d + 1)))^d > (1/((d+1)*exp(1)))" by auto then have gtp: "(1 /(d + 1))* (1 - (1 /(d + 1)))^d > p" by (smt (verit, ccfv_SIG) d_boundslt1 d_boundsgt0 assms(7) divide_divide_eq_left divide_less_cancel divide_less_eq divide_nonneg_nonpos nonzero_mult_div_cancel_left not_exp_le_zero) have "card (dg.neighborhood Ai) \ d" using assms(5) dg.out_degree_neighborhood ain by auto then have "(\ Aj \ dg.neighborhood Ai . (1 - (1 /(d + 1)))) \ (1 - (1 /(d + 1)))^d" using prod_constant_ge[of "dg.neighborhood Ai" "d" "1 - (1/d+1)"] using d_boundslt1 by auto then have "(1 /(d + 1)) * (\ Aj \ dg.neighborhood Ai . (1 - (1 /(d + 1)))) \ (1 /(d + 1))* (1 - (1 /(d + 1)))^d" by (simp add: divide_right_mono) then have "(1 /(d + 1)) * (\ Aj \ dg.neighborhood Ai . (1 - (1 /(d + 1)))) > p" using gtp by simp then show "prob (F Ai) \ f Ai * (\ Aj \ dg.neighborhood Ai . (1 - f Aj))" using assms(6) \Ai \ A\ f_def by force qed then show ?thesis using lovasz_local_general_positive[of A F f G] assms(4) assms(1) assms(2) assms(3) assms(8) fbounds by auto qed corollary lovasz_local_symmetric4gt: fixes e :: real fixes d :: nat assumes "A \ {}" assumes "F ` A \ events" assumes "finite A" assumes "dependency_digraph G M F" assumes "\ Ai. Ai \ A \ out_degree G Ai \ d" assumes "\ Ai. Ai \ A \ prob (F Ai) \ p" assumes "4 * p * d \ 1" (* only works if d \ge 3 *) assumes "d \ 3" assumes "pverts G = A" shows "prob (\ Ai \ A . (space M - F Ai)) > 0" proof - have "exp(1)* p * (d + 1) \ 1" proof (cases "p = 0") case True then show ?thesis by simp next case False then have pgt: "p > 0" using assms(1) assms(6) assms(3) ex_min_if_finite less_eq_real_def by (meson basic_trans_rules(23) basic_trans_rules(24) linorder_neqE_linordered_idom measure_nonneg) have "3 * (d + 1) \ 4 * d" by (simp add: field_simps assms(8)) then have "exp(1) * (d + 1) \ 4 *d" using exp_le exp_gt_one[of 1] assms(8) by (smt (verit, del_insts) Num.of_nat_simps(2) Num.of_nat_simps(5) le_add2 le_eq_less_or_eq mult_right_mono nat_less_real_le numeral.simps(3) numerals(1) of_nat_numeral) then have "exp(1) * (d + 1) * p \ 4 *d *p" using pgt by simp then show ?thesis using assms(7) by (simp add: field_simps) qed then show ?thesis using assms lovasz_local_symmetric_dep_graph[of A F G d p] by auto qed lemma lovasz_local_symmetric4: fixes e :: real fixes d :: nat assumes "A \ {}" assumes "F ` A \ events" assumes "finite A" assumes "dependency_digraph G M F" assumes "\ Ai. Ai \ A \ out_degree G Ai \ d" assumes "\ Ai. Ai \ A \ prob (F Ai) \ p" assumes "4 * p * d \ 1" assumes "d \ 1" assumes "pverts G = A" shows "prob (\ Ai \ A . (space M - F Ai)) > 0" proof (cases "d \ 3") case True then show ?thesis using lovasz_local_symmetric4gt assms by presburger next case d3: False define f :: "nat \ real" where "f \ (\ Ai . 1 /(d + 1))" then have fbounds: "\ Ai. f Ai \ 0 \ f Ai < 1" using f_def assms(8) by simp interpret dg: dependency_digraph G M F using assms(4) by auto have "\ Ai. Ai \ A \ prob (F Ai) \ (f Ai) * (\ Aj \ dg.neighborhood Ai . (1 - (f Aj)))" proof - fix Ai assume ain: "Ai \ A" have d_boundslt1: "(1/(d + 1)) < 1" and d_boundsgt0: "(1/(d + 1))> 0" using assms by fastforce+ have plt: "1/(4*d) \ p" using assms(7) assms(8) by (metis (mono_tags, opaque_lifting) Num.of_nat_simps(5) bot_nat_0.not_eq_extremum le_numeral_extra(2) more_arith_simps(11) mult_of_nat_commute nat_0_less_mult_iff of_nat_0_less_iff of_nat_numeral pos_divide_less_eq rel_simps(51) verit_comp_simplify(3)) then have gtp: "(1 /(d + 1))* (1 - (1 /(d + 1)))^d \ p" proof (cases "d = 1") case False then have "d = 2" using d3 assms(8) by auto then show ?thesis using plt by (simp add: field_simps) qed (simp) have "card (dg.neighborhood Ai) \ d" using assms(5) dg.out_degree_neighborhood ain by auto then have "(\ Aj \ dg.neighborhood Ai . (1 - (1 /(d + 1)))) \ (1 - (1 /(d + 1)))^d" using prod_constant_ge[of "dg.neighborhood Ai" "d" "1 - (1/d+1)"] using d_boundslt1 by auto then have "(1 /(d + 1)) * (\ Aj \ dg.neighborhood Ai . (1 - (1 /(d + 1)))) \ (1 /(d + 1))* (1 - (1 /(d + 1)))^d" by (simp add: divide_right_mono) then have "(1 /(d + 1)) * (\ Aj \ dg.neighborhood Ai . (1 - (1 /(d + 1)))) \ p" using gtp by simp then show "prob (F Ai) \ f Ai * (\ Aj \ dg.neighborhood Ai . (1 - f Aj))" using assms(6) \Ai \ A\ f_def by force qed then show ?thesis using lovasz_local_general_positive[of A F f G] assms(4) assms(1) assms(2) assms(3) assms(9) fbounds by auto qed text \Converting between dependency graph and indexed set representation of mutual independence \ lemma (in pair_digraph) g_Ai_simplification: assumes "Ai \ A" assumes "g Ai \ A - {Ai}" assumes "pverts G = A" assumes "parcs G = {e \ A \ A . snd e \ (A - ({fst e} \ (g (fst e))))}" shows "g Ai = A - ({Ai} \ neighborhood Ai)" proof - have "g Ai = A - ({Ai} \ {v \ A . v \ (A - ({Ai} \ (g (Ai))))})" using assms(2) by auto then have "g Ai = A - ({Ai} \ {v \ A . (Ai, v) \ parcs G})" using Collect_cong assms(1) mem_Collect_eq assms(3) assms(4) by auto then show "g Ai = A - ({Ai} \ neighborhood Ai)" unfolding neighborhood_def using assms(3) by simp qed lemma define_dep_graph_set: assumes "A \ {}" assumes "F ` A \ events" assumes "finite A" assumes "\ Ai. Ai \ A \ g Ai \ A - {Ai} \ mutual_indep_events (F Ai) F (g Ai)" shows "dependency_digraph \ pverts = A, parcs = {e \ A \ A . snd e \ (A - ({fst e} \ (g (fst e))))} \ M F" (is "dependency_digraph ?G M F") proof - interpret pd: pair_digraph ?G using assms(3)by (unfold_locales) auto have "\ Ai. Ai \ A \ g Ai \ A - {Ai}" using assms(4) by simp then have "\ i. i \ A \ g i = A - ({i} \ pd.neighborhood i)" using pd.g_Ai_simplification[of _ A g] pd.pair_digraph by auto then have "dependency_digraph ?G M F" using assms(2) assms(4) by (unfold_locales) auto then show ?thesis by simp qed lemma define_dep_graph_deg_bound: assumes "A \ {}" assumes "F ` A \ events" assumes "finite A" assumes "\ Ai. Ai \ A \ g Ai \ A - {Ai} \ card (g Ai) \ card A - d - 1 \ mutual_indep_events (F Ai) F (g Ai)" shows "\ Ai. Ai \ A \ out_degree \ pverts = A, parcs = {e \ A \ A . snd e \ (A - ({fst e} \ (g (fst e))))} \ Ai \ d" (is "\ Ai. Ai \ A \ out_degree (with_proj ?G) Ai \ d") proof - interpret pd: dependency_digraph ?G M F using assms define_dep_graph_set by simp show "\ Ai. Ai \ A \ out_degree ?G Ai \ d" proof - fix Ai assume a: "Ai \ A" then have geq: "g Ai = A - ({Ai} \ pd.neighborhood Ai)" using assms(4)[of Ai] pd.pair_digraph pd.g_Ai_simplification[of Ai A g ] by simp then have pss: "g Ai \ A" using a by auto then have "card (g Ai) = card (A - ({Ai} \ pd.neighborhood Ai))" using assms(4) geq by argo moreover have ss: "({Ai} \ pd.neighborhood Ai) \ A" using pd.neighborhood_wf a by simp moreover have "finite ({Ai} \ pd.neighborhood Ai)" using calculation(2) assms(3) finite_subset by auto moreover have "Ai \ pd.neighborhood Ai" using pd.neighborhood_self_not by simp moreover have "card {Ai} = 1" using is_singleton_altdef by auto moreover have cardss: "card ({Ai} \ pd.neighborhood Ai) = 1 + card (pd.neighborhood Ai)" using calculation(5) calculation(4) card_Un_disjoint pd.neighborhood_finite by auto ultimately have eq: "card (g Ai) = card A - 1 - card (pd.neighborhood Ai)" using card_Diff_subset[of "({Ai} \ pd.neighborhood Ai)" A] assms(3) by presburger have ggt: "\ Ai. Ai \ A \ card (g Ai) \ int (card A) - int d - 1" using assms(4) by fastforce have "card (pd.neighborhood Ai) = card A - 1 - card (g Ai)" using cardss assms(3) card_mono diff_add_inverse diff_diff_cancel diff_le_mono ss eq by (metis (no_types, lifting)) moreover have "card A \ (1 + card (g Ai))" using pss assms(3) card_seteq not_less_eq_eq by auto ultimately have "card (pd.neighborhood Ai) = int (card A) - 1 - int (card (g Ai))" by auto moreover have "int (card (g Ai)) \ (card A) - (int d) - 1" using ggt a by simp ultimately show "out_degree ?G Ai \ d" using pd.out_degree_neighborhood by simp qed qed lemma obtain_dependency_graph: assumes "A \ {}" assumes "F ` A \ events" assumes "finite A" assumes "\ Ai. Ai \ A \ (\ S . S \ A - {Ai} \ card S \ card A - d - 1 \ mutual_indep_events (F Ai) F S)" obtains G where "dependency_digraph G M F" "pverts G = A" "\ Ai. Ai \ A \ out_degree G Ai \ d" proof - obtain g where gdef: "\ Ai. Ai \ A \ g Ai \ A - {Ai} \ card (g Ai) \ card A - d - 1 \ mutual_indep_events (F Ai) F (g Ai)" using assms(4) by metis then show ?thesis using define_dep_graph_set[of A F g] define_dep_graph_deg_bound[of A F g d]that assms by auto qed text \This is the variation of the symmetric version most commonly in use \ theorem lovasz_local_symmetric: fixes d :: nat assumes "A \ {}" assumes "F ` A \ events" assumes "finite A" assumes "\ Ai. Ai \ A \ (\ S . S \ A - {Ai} \ card S \ card A - d - 1 \ mutual_indep_events (F Ai) F S)" assumes "\ Ai. Ai \ A \ prob (F Ai) \ p" assumes "exp(1)* p * (d + 1) \ 1" shows "prob (\ Ai \ A . (space M - (F Ai))) > 0" proof - obtain G where odg: "dependency_digraph G M F" "pverts G = A" "\ Ai. Ai \ A \ out_degree G Ai \ d" using assms obtain_dependency_graph by metis then show ?thesis using odg assms lovasz_local_symmetric_dep_graph[of A F G d p] by auto qed lemma lovasz_local_symmetric4_set: fixes d :: nat assumes "A \ {}" assumes "F ` A \ events" assumes "finite A" assumes "\ Ai. Ai \ A \ (\ S . S \ A - {Ai} \ card S \ card A - d - 1 \ mutual_indep_events (F Ai) F S)" assumes "\ Ai. Ai \ A \ prob (F Ai) \ p" assumes "4 * p * d \ 1" assumes "d \ 1" shows "prob (\ Ai \ A . (space M - F Ai)) > 0" proof - obtain G where odg: "dependency_digraph G M F" "pverts G = A" "\ Ai. Ai \ A \ out_degree G Ai \ d" using assms obtain_dependency_graph by metis then show ?thesis using odg assms lovasz_local_symmetric4[of A F G d p] by auto qed end end \ No newline at end of file diff --git a/thys/Modular_arithmetic_LLL_and_HNF_algorithms/HNF_Mod_Det_Algorithm.thy b/thys/Modular_arithmetic_LLL_and_HNF_algorithms/HNF_Mod_Det_Algorithm.thy --- a/thys/Modular_arithmetic_LLL_and_HNF_algorithms/HNF_Mod_Det_Algorithm.thy +++ b/thys/Modular_arithmetic_LLL_and_HNF_algorithms/HNF_Mod_Det_Algorithm.thy @@ -1,381 +1,381 @@ section \Formalization of an efficient Hermite normal form algorithm\ text \We formalize a version of the Hermite normal form algorithm based on reductions modulo the determinant. This avoids the growth of the intermediate coefficients.\ subsection \Implementation of the algorithm using generic modulo operation\ text \Exception on generic modulo: currently in Hermite-reduce-above, ordinary div/mod is used, since that is our choice for the complete set of residues.\ theory HNF_Mod_Det_Algorithm imports Jordan_Normal_Form.Gauss_Jordan_IArray_Impl Show.Show_Instances Jordan_Normal_Form.Determinant_Impl Jordan_Normal_Form.Show_Matrix LLL_Basis_Reduction.LLL_Certification Smith_Normal_Form.SNF_Algorithm_Euclidean_Domain Smith_Normal_Form.SNF_Missing_Lemmas Uniqueness_Hermite_JNF Matrix_Change_Row begin subsubsection \Echelon form algorithm\ fun make_first_column_positive :: "int mat \ int mat" where "make_first_column_positive A = ( Matrix.mat (dim_row A) (dim_col A) \ \ Create a matrix of the same dimensions \ (\(i,j). if A $$(i,0) < 0 then - A $$(i,j) else A $$(i,j) ) )" locale mod_operation = fixes generic_mod :: "int \ int \ int" (infixl "gmod" 70) and generic_div :: "int \ int \ int" (infixl "gdiv" 70) begin text \Version for reducing all elements\ fun reduce :: "nat \ nat \ int \ int mat \ int mat" where "reduce a b D A = (let Aaj = A$$(a,0); Abj = A $$ (b,0) in if Aaj = 0 then A else case euclid_ext2 Aaj Abj of (p,q,u,v,d) \ \ \ p*Aaj + q * Abj = d, u = - Abj/d, v = Aaj/d \ Matrix.mat (dim_row A) (dim_col A) \ \ Create a matrix of the same dimensions \ (\(i,k). if i = a then let r = (p*A$$(a,k) + q*A$$(b,k)) in if k = 0 then if D dvd r then D else r else r gmod D \ \ Row a is multiplied by p and added row b multiplied by q, modulo D\ else if i = b then let r = u * A$$(a,k) + v * A$$(b,k) in if k = 0 then r else r gmod D \ \ Row b is multiplied by v and added row a multiplied by u, modulo D\ else A$$(i,k) \ \ All the other rows remain unchanged\ ) )" text \Version for reducing, with abs-checking\ fun reduce_abs :: "nat \ nat \ int \ int mat \ int mat" where "reduce_abs a b D A = (let Aaj = A$$(a,0); Abj = A $$ (b,0) in if Aaj = 0 then A else case euclid_ext2 Aaj Abj of (p,q,u,v,d) \ \ \ p*Aaj + q * Abj = d, u = - Abj/d, v = Aaj/d \ Matrix.mat (dim_row A) (dim_col A) \ \ Create a matrix of the same dimensions \ (\(i,k). if i = a then let r = (p*A$$(a,k) + q*A$$(b,k)) in if abs r > D then if k = 0 \ D dvd r then D else r gmod D else r else if i = b then let r = u * A$$(a,k) + v * A$$(b,k) in if abs r > D then r gmod D else r else A$$(i,k) \ \ All the other rows remain unchanged\ ) )" definition reduce_impl :: "nat \ nat \ int \ int mat \ int mat" where "reduce_impl a b D A = (let row_a = Matrix.row A a; Aaj = row_a $v 0 in if Aaj = 0 then A else let row_b = Matrix.row A b; Abj = row_b $v 0 in case euclid_ext2 Aaj Abj of (p,q,u,v,d) \ let row_a' = (\ k ak. let r = (p * ak + q * row_b $v k) in if k = 0 then if D dvd r then D else r else r gmod D); row_b' = (\ k bk. let r = u * row_a $v k + v * bk in if k = 0 then r else r gmod D) in change_row a row_a' (change_row b row_b' A) )" definition reduce_abs_impl :: "nat \ nat \ int \ int mat \ int mat" where "reduce_abs_impl a b D A = (let row_a = Matrix.row A a; Aaj = row_a $v 0 in if Aaj = 0 then A else let row_b = Matrix.row A b; Abj = row_b $v 0 in case euclid_ext2 Aaj Abj of (p,q,u,v,d) \ let row_a' = (\ k ak. let r = (p * ak + q * row_b $v k) in if abs r > D then if k = 0 \ D dvd r then D else r gmod D else r); row_b' = (\ k bk. let r = u * row_a $v k + v * bk in if abs r > D then r gmod D else r) in change_row a row_a' (change_row b row_b' A) )" lemma reduce_impl: "a < nr \ b < nr \ 0 < nc \ a \ b \ A \ carrier_mat nr nc \ reduce_impl a b D A = reduce a b D A" unfolding reduce_impl_def reduce.simps Let_def apply (intro if_cong[OF _ refl], force) apply (intro prod.case_cong refl, force) apply (intro eq_matI, auto) done lemma reduce_abs_impl: "a < nr \ b < nr \ 0 < nc \ a \ b \ A \ carrier_mat nr nc \ reduce_abs_impl a b D A = reduce_abs a b D A" unfolding reduce_abs_impl_def reduce_abs.simps Let_def apply (intro if_cong[OF _ refl], force) apply (intro prod.case_cong refl, force) apply (intro eq_matI, auto) done (* This functions reduce the elements below the position (a,0), given a list of positions of non-zero positions as input*) fun reduce_below :: "nat \ nat list \ int \ int mat \ int mat" where "reduce_below a [] D A = A" | "reduce_below a (x # xs) D A = reduce_below a xs D (reduce a x D A)" fun reduce_below_impl :: "nat \ nat list \ int \ int mat \ int mat" where "reduce_below_impl a [] D A = A" | "reduce_below_impl a (x # xs) D A = reduce_below_impl a xs D (reduce_impl a x D A)" lemma reduce_impl_carrier[simp,intro]: "A \ carrier_mat m n \ reduce_impl a b D A \ carrier_mat m n" unfolding reduce_impl_def Let_def by (auto split: prod.splits) lemma reduce_below_impl: "a < nr \ 0 < nc \ (\ b. b \ set bs \ b < nr) \ a \ set bs \ A \ carrier_mat nr nc \ reduce_below_impl a bs D A = reduce_below a bs D A" proof (induct bs arbitrary: A) case (Cons b bs A) show ?case by (simp del: reduce.simps, subst reduce_impl[of _ nr _ nc], (insert Cons, auto simp del: reduce.simps)[5], rule Cons(1), insert Cons(2-), auto simp: Let_def split: prod.splits) qed simp fun reduce_below_abs :: "nat \ nat list \ int \ int mat \ int mat" where "reduce_below_abs a [] D A = A" | "reduce_below_abs a (x # xs) D A = reduce_below_abs a xs D (reduce_abs a x D A)" fun reduce_below_abs_impl :: "nat \ nat list \ int \ int mat \ int mat" where "reduce_below_abs_impl a [] D A = A" | "reduce_below_abs_impl a (x # xs) D A = reduce_below_abs_impl a xs D (reduce_abs_impl a x D A)" lemma reduce_abs_impl_carrier[simp,intro]: "A \ carrier_mat m n \ reduce_abs_impl a b D A \ carrier_mat m n" unfolding reduce_abs_impl_def Let_def by (auto split: prod.splits) lemma reduce_abs_below_impl: "a < nr \ 0 < nc \ (\ b. b \ set bs \ b < nr) \ a \ set bs \ A \ carrier_mat nr nc \ reduce_below_abs_impl a bs D A = reduce_below_abs a bs D A" proof (induct bs arbitrary: A) case (Cons b bs A) show ?case by (simp del: reduce_abs.simps, subst reduce_abs_impl[of _ nr _ nc], (insert Cons, auto simp del: reduce_abs.simps)[5], rule Cons(1), insert Cons(2-), auto simp: Let_def split: prod.splits) qed simp text \This function outputs a matrix in echelon form via reductions modulo the determinant\ function FindPreHNF :: "bool \ int \ int mat \ int mat" where "FindPreHNF abs_flag D A = (let m = dim_row A; n = dim_col A in if m < 2 \ n = 0 then A else \ \ No operations are carried out if m = 1 \ let non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. 0 then A else let i = non_zero_positions ! 0 \ \ Select the first non-zero position below the first element\ in swaprows 0 i A ); Reduce = (if abs_flag then reduce_below_abs else reduce_below) in if n < 2 then Reduce 0 non_zero_positions D A' \ \ If n = 1, then we have to reduce the column \ else let (A_UL,A_UR,A_DL,A_DR) = split_block (Reduce 0 non_zero_positions D (make_first_column_positive A')) 1 1; sub_PreHNF = FindPreHNF abs_flag D A_DR in four_block_mat A_UL A_UR A_DL sub_PreHNF)" by pat_completeness auto termination proof (relation "Wellfounded.measure (\(abs_flag,D,A). dim_col A)") show "wf (Wellfounded.measure (\(abs_flag,D, A). dim_col A))" by auto fix abs_flag D A m n nz A' R xd A'_UL y A'_UR ya A'_DL A'_DR assume m: "m = dim_row A" and n:"n = dim_col A" and m2: "\ (m < 2 \ n = 0)" and nz_def: "nz = filter (\i. A $$ (i, 0) \ 0) [1.. 0 then A else let i = nz ! 0 in swaprows 0 i A)" and R_def: "R = (if abs_flag then reduce_below_abs else reduce_below)" and n2: "\ n < 2" and "xd = split_block (R 0 nz D (make_first_column_positive A')) 1 1" and "(A'_UL, y) = xd" and "(A'_UR, ya) = y" and "(A'_DL, A'_DR) = ya" hence A'_split: "(A'_UL, A'_UR, A'_DL, A'_DR) = split_block (R 0 nz D (make_first_column_positive A')) 1 1" by force have dr_mk1: "dim_row (make_first_column_positive A) = dim_row A" for A by auto have dr_mk2: "dim_col (make_first_column_positive A) = dim_col A" for A by auto have r1: "reduce_below a xs D A \ carrier_mat m n" if "A \ carrier_mat m n" for A a xs using that by (induct a xs D A rule: reduce_below.induct, auto simp add: Let_def euclid_ext2_def) hence R: "(reduce_below 0 nz D (make_first_column_positive A')) \ carrier_mat m n" using A'_def m n by (metis carrier_matI index_mat_swaprows(2,3) dr_mk1 dr_mk2) have "reduce_below_abs a xs D A \ carrier_mat m n" if "A \ carrier_mat m n" for A a xs using that by (induct a xs D A rule: reduce_below_abs.induct, auto simp add: Let_def euclid_ext2_def) hence R2: "(reduce_below_abs 0 nz D (make_first_column_positive A')) \ carrier_mat m n" using A'_def m n by (metis carrier_matI index_mat_swaprows(2,3) dr_mk1 dr_mk2) have "A'_DR \ carrier_mat (m-1) (n-1)" by (cases abs_flag; rule split_block(4)[OF A'_split[symmetric]],insert m2 n2 m n R_def R R2, auto) thus "((abs_flag, D, A'_DR),abs_flag, D, A) \ Wellfounded.measure (\(abs_flag,D, A). dim_col A)" using n2 m2 n m by auto qed lemma FindPreHNF_code: "FindPreHNF abs_flag D A = (let m = dim_row A; n = dim_col A in if m < 2 \ n = 0 then A else let non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. 0 then A else let i = non_zero_positions ! 0 in swaprows 0 i A ); Reduce_impl = (if abs_flag then reduce_below_abs_impl else reduce_below_impl) in if n < 2 then Reduce_impl 0 non_zero_positions D A' else let (A_UL,A_UR,A_DL,A_DR) = split_block (Reduce_impl 0 non_zero_positions D (make_first_column_positive A')) 1 1; sub_PreHNF = FindPreHNF abs_flag D A_DR in four_block_mat A_UL A_UR A_DL sub_PreHNF)" (is "?lhs = ?rhs") proof - let ?f = "\R. (if dim_row A < 2 \ dim_col A = 0 then A else if dim_col A < 2 then R 0 (filter (\i. A $$ (i, 0) \ 0) [1.. 0 then A else swaprows 0 (filter (\i. A $$ (i, 0) \ 0) [1..i. A $$ (i, 0) \ 0) [1.. 0 then A else swaprows 0 (filter (\i. A $$ (i, 0) \ 0) [1.. four_block_mat A_UL A_UR A_DL (FindPreHNF abs_flag D A_DR))" have M_carrier: "make_first_column_positive (if A $$ (0, 0) \ 0 then A else swaprows 0 (filter (\i. A $$ (i, 0) \ 0) [1.. carrier_mat (dim_row A) (dim_col A)" - by (smt (z3) index_mat_swaprows(2) index_mat_swaprows(3) make_first_column_positive.simps mat_carrier) + by (smt (verit) index_mat_swaprows(2) index_mat_swaprows(3) make_first_column_positive.simps mat_carrier) have *: "0 \ set (filter (\i. A $$ (i, 0) \ 0) [1.. x. split_block x 1 1"]; (subst reduce_abs_below_impl[where nr = "dim_row A" and nc = "dim_col A"])), (auto)[9]) (insert M_carrier *, blast+) also have "... = ?f (if abs_flag then reduce_below_abs_impl else reduce_below_impl)" using True by presburger finally show ?thesis using True unfolding FindPreHNF.simps[of abs_flag D A] Let_def by blast next case False have "?f (if abs_flag then reduce_below_abs else reduce_below) = ?f reduce_below" using False by presburger also have "... = ?f reduce_below_impl" by ((intro if_cong refl prod.case_cong arg_cong[of _ _ "\ x. split_block x 1 1"]; (subst reduce_below_impl[where nr = "dim_row A" and nc = "dim_col A"])), (auto)[9]) (insert M_carrier *, blast+) also have "... = ?f (if abs_flag then reduce_below_abs_impl else reduce_below_impl)" using False by presburger finally show ?thesis using False unfolding FindPreHNF.simps[of abs_flag D A] Let_def by blast qed finally show ?thesis by blast qed end declare mod_operation.FindPreHNF_code[code] declare mod_operation.reduce_below_impl.simps[code] declare mod_operation.reduce_impl_def[code] declare mod_operation.reduce_below_abs_impl.simps[code] declare mod_operation.reduce_abs_impl_def[code] subsubsection \From echelon form to Hermite normal form\ text \From here on, we define functions to transform a matrix in echelon form into its Hermite normal form. Essentially, we are defining the functions that are available in the AFP entry Hermite (which uses HOL Analysis + mod-type) in the JNF matrix representation.\ (*Find the first nonzero element of row l (A is upper triangular)*) definition find_fst_non0_in_row :: "nat \ int mat \ nat option" where "find_fst_non0_in_row l A = (let is = [l ..< dim_col A]; Ais = filter (\j. A $$ (l, j) \ 0) is in case Ais of [] \ None | _ \ Some (Ais!0))" primrec Hermite_reduce_above where "Hermite_reduce_above (A::int mat) 0 i j = A" | "Hermite_reduce_above A (Suc n) i j = (let Aij = A $$ (i,j); Anj = A $$ (n,j) in Hermite_reduce_above (addrow (- (Anj div Aij)) n i A) n i j)" definition Hermite_of_row_i :: "int mat \ nat \ int mat" where "Hermite_of_row_i A i = ( case find_fst_non0_in_row i A of None \ A | Some j \ let Aij = A $$(i,j) in if Aij < 0 then Hermite_reduce_above (multrow i (-1) A) i i j else Hermite_reduce_above A i i j)" primrec Hermite_of_list_of_rows where "Hermite_of_list_of_rows A [] = A" | "Hermite_of_list_of_rows A (a#xs) = Hermite_of_list_of_rows (Hermite_of_row_i A a) xs" text \We combine the previous functions to assemble the algorithm\ definition (in mod_operation) "Hermite_mod_det abs_flag A = (let m = dim_row A; n = dim_col A; D = abs(det_int A); A' = A @\<^sub>r D \\<^sub>m 1\<^sub>m n; E = FindPreHNF abs_flag D A'; H = Hermite_of_list_of_rows E [0..Some examples of execution\ declare mod_operation.Hermite_mod_det_def[code] value "let B = mat_of_rows_list 4 ([[0,3,1,4],[7,1,0,0],[8,0,19,16],[2,0,0,3::int]]) in show (mod_operation.Hermite_mod_det (mod) True B)" (* sage: import sage.matrix.matrix_integer_dense_hnf as matrix_integer_dense_hnf sage: A = matrix(ZZ, [[0,3,1,4],[7,1,0,0],[8,0,19,16],[2,0,0,3]]) sage: A [ 0 3 1 4] [ 7 1 0 0] [ 8 0 19 16] [ 2 0 0 3] sage: H, U = matrix_integer_dense_hnf.hnf_with_transformation(A); H [ 1 0 0 672] [ 0 1 0 660] [ 0 0 1 706] [ 0 0 0 1341] sage: *) value "let B = mat_of_rows_list 7 ([ [ 1, 17, -41, -1, 1, 0, 0], [ 0, -1, 2, 0, -6, 2, 1], [ 9, 2, 1, 1, -2, 2, -5], [ -1, -3, -1, 0, -9, 0, 0], [ 9, -1, -9, 0, 0, 0, 1], [ 1, -1, 1, 0, 1, -8, 0], [ 1, -1, 0, -2, -1, -1, 0::int]]) in show (mod_operation.Hermite_mod_det (mod) True B)" (* sage: import sage.matrix.matrix_integer_dense_hnf as matrix_integer_dense_hnf sage: A = random_matrix(ZZ,7,7); A [ 1 17 -41 -1 1 0 0] [ 0 -1 2 0 -6 2 1] [ 9 2 1 1 -2 2 -5] [ -1 -3 -1 0 -9 0 0] [ 9 -1 -9 0 0 0 1] [ 1 -1 1 0 1 -8 0] [ 1 -1 0 -2 -1 -1 0] sage: H, U = matrix_integer_dense_hnf.hnf_with_transformation(A); H [ 1 0 0 0 0 1 191934] [ 0 1 0 0 0 0 435767] [ 0 0 1 0 0 1 331950] [ 0 0 0 1 0 0 185641] [ 0 0 0 0 1 0 38022] [ 0 0 0 0 0 2 477471] [ 0 0 0 0 0 0 565304] *) end \ No newline at end of file diff --git a/thys/Modular_arithmetic_LLL_and_HNF_algorithms/HNF_Mod_Det_Soundness.thy b/thys/Modular_arithmetic_LLL_and_HNF_algorithms/HNF_Mod_Det_Soundness.thy --- a/thys/Modular_arithmetic_LLL_and_HNF_algorithms/HNF_Mod_Det_Soundness.thy +++ b/thys/Modular_arithmetic_LLL_and_HNF_algorithms/HNF_Mod_Det_Soundness.thy @@ -1,11568 +1,11572 @@ subsection \Soundness of the algorithm\ theory HNF_Mod_Det_Soundness imports HNF_Mod_Det_Algorithm Signed_Modulo begin hide_const(open) Determinants.det Determinants2.upper_triangular Finite_Cartesian_Product.row Finite_Cartesian_Product.rows Finite_Cartesian_Product.vec subsubsection \Results connecting lattices and Hermite normal form\ text \The following results will also be useful for proving the soundness of the certification approach.\ lemma of_int_mat_hom_int_id[simp]: fixes A::"int mat" shows "of_int_hom.mat_hom A = A" unfolding map_mat_def by auto definition "is_sound_HNF algorithm associates res = (\A. let (P,H) = algorithm A; m = dim_row A; n = dim_col A in P \ carrier_mat m m \ H \ carrier_mat m n \ invertible_mat P \ A = P * H \ Hermite_JNF associates res H)" lemma HNF_A_eq_HNF_PA: fixes A::"'a::{bezout_ring_div,normalization_euclidean_semiring,unique_euclidean_ring} mat" assumes A: "A \ carrier_mat n n" and inv_A: "invertible_mat A" and inv_P: "invertible_mat P" and P: "P \ carrier_mat n n" and sound_HNF: "is_sound_HNF HNF associates res" and P1_H1: "(P1,H1) = HNF (P*A)" and P2_H2: "(P2,H2) = HNF A" shows "H1 = H2" proof - obtain inv_P where P_inv_P: "inverts_mat P inv_P" and inv_P_P: "inverts_mat inv_P P" and inv_P: "inv_P \ carrier_mat n n" using P inv_P obtain_inverse_matrix by blast have P1: "P1 \ carrier_mat n n" using P1_H1 sound_HNF unfolding is_sound_HNF_def Let_def by (metis (no_types, lifting) P carrier_matD(1) index_mult_mat(2) old.prod.case) have H1: "H1 \ carrier_mat n n" using P1_H1 sound_HNF unfolding is_sound_HNF_def Let_def by (metis (no_types, lifting) A P carrier_matD(1) carrier_matD(2) case_prodD index_mult_mat(2,3)) have invertible_inv_P: "invertible_mat inv_P" using P_inv_P inv_P inv_P_P invertible_mat_def square_mat.simps by blast have P_A_P1_H1: "P * A = P1 * H1" using P1_H1 sound_HNF unfolding is_sound_HNF_def Let_def by (metis (mono_tags, lifting) case_prod_conv) hence "A = inv_P * (P1 * H1)" - by (smt A P inv_P_P inv_P assoc_mult_mat carrier_matD(1) inverts_mat_def left_mult_one_mat) + by (smt (verit) A P inv_P_P inv_P assoc_mult_mat carrier_matD(1) inverts_mat_def left_mult_one_mat) hence A_inv_P_P1_H1: "A = (inv_P * P1) * H1" - by (smt P P1_H1 assoc_mult_mat carrier_matD(1) fst_conv index_mult_mat(2) inv_P - is_sound_HNF_def prod.sel(2) sound_HNF split_beta) + using H1 P1 inv_P by fastforce have A_P2_H2: "A = P2 * H2" using P2_H2 sound_HNF unfolding is_sound_HNF_def Let_def by (metis (mono_tags, lifting) case_prod_conv) have invertible_inv_P_P1: "invertible_mat (inv_P * P1)" proof (rule invertible_mult_JNF[OF inv_P P1 invertible_inv_P]) show "invertible_mat P1" - by (smt P1_H1 is_sound_HNF_def prod.sel(1) sound_HNF split_beta) + by (smt (verit) P1_H1 is_sound_HNF_def prod.sel(1) sound_HNF split_beta) qed show ?thesis proof (rule Hermite_unique_JNF[OF A _ H1 _ _ A_inv_P_P1_H1 A_P2_H2 inv_A invertible_inv_P_P1]) show "inv_P * P1 \ carrier_mat n n" by (metis carrier_matD(1) carrier_matI index_mult_mat(2) inv_P invertible_inv_P_P1 invertible_mat_def square_mat.simps) show "P2 \ carrier_mat n n" - by (smt A P2_H2 carrier_matD(1) is_sound_HNF_def prod.sel(1) sound_HNF split_beta) + by (smt (verit) A P2_H2 carrier_matD(1) is_sound_HNF_def prod.sel(1) sound_HNF split_beta) show "H2 \ carrier_mat n n" - by (smt A P2_H2 carrier_matD(1) carrier_matD(2) is_sound_HNF_def prod.sel(2) sound_HNF split_beta) + by (smt (verit) A P2_H2 carrier_matD(1) carrier_matD(2) is_sound_HNF_def prod.sel(2) sound_HNF split_beta) show "invertible_mat P2" - by (smt P2_H2 is_sound_HNF_def prod.sel(1) sound_HNF split_beta) + by (smt (verit) P2_H2 is_sound_HNF_def prod.sel(1) sound_HNF split_beta) show "Hermite_JNF associates res H1" - by (smt P1_H1 is_sound_HNF_def prod.sel(2) sound_HNF split_beta) + by (smt (verit) P1_H1 is_sound_HNF_def prod.sel(2) sound_HNF split_beta) show "Hermite_JNF associates res H2" - by (smt P2_H2 is_sound_HNF_def prod.sel(2) sound_HNF split_beta) + by (smt (verit) P2_H2 is_sound_HNF_def prod.sel(2) sound_HNF split_beta) qed qed context vec_module begin lemma mat_mult_invertible_lattice_eq: assumes fs: "set fs \ carrier_vec n" and gs: "set gs \ carrier_vec n" and P: "P \ carrier_mat m m" and invertible_P: "invertible_mat P" and length_fs: "length fs = m" and length_gs: "length gs = m" and prod: "mat_of_rows n fs = (map_mat of_int P) * mat_of_rows n gs" shows "lattice_of fs = lattice_of gs" proof thm mat_mult_sub_lattice show "lattice_of fs \ lattice_of gs" by (rule mat_mult_sub_lattice[OF fs gs _ prod],simp add: length_fs length_gs P) next obtain inv_P where P_inv_P: "inverts_mat P inv_P" and inv_P_P: "inverts_mat inv_P P" and inv_P: "inv_P \ carrier_mat m m" using P invertible_P obtain_inverse_matrix by blast have "of_int_hom.mat_hom (inv_P) * mat_of_rows n fs = of_int_hom.mat_hom (inv_P) * ((map_mat of_int P) * mat_of_rows n gs)" using prod by auto also have "... = of_int_hom.mat_hom (inv_P) * (map_mat of_int P) * mat_of_rows n gs" - by (smt P assoc_mult_mat inv_P length_gs map_carrier_mat mat_of_rows_carrier(1)) + by (smt (verit) P assoc_mult_mat inv_P length_gs map_carrier_mat mat_of_rows_carrier(1)) also have "... = of_int_hom.mat_hom (inv_P * P) * mat_of_rows n gs" by (metis P inv_P of_int_hom.mat_hom_mult) also have "... = mat_of_rows n gs" by (metis carrier_matD(1) inv_P inv_P_P inverts_mat_def left_mult_one_mat' length_gs mat_of_rows_carrier(2) of_int_hom.mat_hom_one) finally have prod: "mat_of_rows n gs = of_int_hom.mat_hom (inv_P) * mat_of_rows n fs" .. show "lattice_of gs \ lattice_of fs" by (rule mat_mult_sub_lattice[OF gs fs _ prod], simp add: length_fs length_gs inv_P) qed end context fixes n :: nat begin interpretation vec_module "TYPE(int)" . lemma lattice_of_HNF: assumes sound_HNF: "is_sound_HNF HNF associates res" and P1_H1: "(P,H) = HNF (mat_of_rows n fs)" and fs: "set fs \ carrier_vec n" and len: "length fs = m" shows "lattice_of fs = lattice_of (rows H)" proof (rule mat_mult_invertible_lattice_eq[OF fs]) have H: "H \ carrier_mat m n" using sound_HNF P1_H1 unfolding is_sound_HNF_def Let_def by (metis (mono_tags, lifting) assms(4) mat_of_rows_carrier(2) mat_of_rows_carrier(3) prod.sel(2) split_beta) have H_rw: "mat_of_rows n (Matrix.rows H) = H" using mat_of_rows_rows H by fast have PH_fs_init: "mat_of_rows n fs = P * H" using sound_HNF P1_H1 unfolding is_sound_HNF_def Let_def by (metis (mono_tags, lifting) case_prodD) show "mat_of_rows n fs = of_int_hom.mat_hom P * mat_of_rows n (Matrix.rows H)" unfolding H_rw of_int_mat_hom_int_id using PH_fs_init by simp show "set (Matrix.rows H) \ carrier_vec n" using H rows_carrier by blast show "P \ carrier_mat m m" using sound_HNF P1_H1 unfolding is_sound_HNF_def Let_def by (metis (no_types, lifting) len case_prodD mat_of_rows_carrier(2)) show "invertible_mat P" using sound_HNF P1_H1 unfolding is_sound_HNF_def Let_def by (metis (no_types, lifting) case_prodD) show "length fs = m" using len by simp show "length (Matrix.rows H) = m" using H by auto qed end context LLL_with_assms begin (*For this proof, it seems that is not necessary fs_init to be a list of independent vectors. The context assumes it, though.*) lemma certification_via_eq_HNF: assumes sound_HNF: "is_sound_HNF HNF associates res" and P1_H1: "(P1,H1) = HNF (mat_of_rows n fs_init)" and P2_H2: "(P2,H2) = HNF (mat_of_rows n gs)" and H1_H2: "H1 = H2" (*The HNF are equal*) and gs: "set gs \ carrier_vec n" and len_gs: "length gs = m" shows "lattice_of gs = lattice_of fs_init" "LLL_with_assms n m gs \" proof - have "lattice_of fs_init = lattice_of (rows H1)" by (rule lattice_of_HNF[OF sound_HNF P1_H1 fs_init], simp add: len) also have "... = lattice_of (rows H2)" using H1_H2 by auto also have "... = lattice_of gs" by (rule lattice_of_HNF[symmetric, OF sound_HNF P2_H2 gs len_gs]) finally show "lattice_of gs = lattice_of fs_init" .. have invertible_P1: "invertible_mat P1" using sound_HNF P1_H1 unfolding is_sound_HNF_def by (metis (mono_tags, lifting) case_prodD) have invertible_P2: "invertible_mat P2" using sound_HNF P2_H2 unfolding is_sound_HNF_def by (metis (mono_tags, lifting) case_prodD) have P2: "P2 \ carrier_mat m m" using sound_HNF P2_H2 unfolding is_sound_HNF_def by (metis (no_types, lifting) len_gs case_prodD mat_of_rows_carrier(2)) obtain inv_P2 where P2_inv_P2: "inverts_mat P2 inv_P2" and inv_P2_P2: "inverts_mat inv_P2 P2" and inv_P2: "inv_P2 \ carrier_mat m m" using P2 invertible_P2 obtain_inverse_matrix by blast have P1: "P1 \ carrier_mat m m" using sound_HNF P1_H1 unfolding is_sound_HNF_def by (metis (no_types, lifting) len case_prodD mat_of_rows_carrier(2)) have H1: "H1 \ carrier_mat m n" using sound_HNF P1_H1 unfolding is_sound_HNF_def by (metis (no_types, lifting) case_prodD len mat_of_rows_carrier(2) mat_of_rows_carrier(3)) have H2: "H2 \ carrier_mat m n" using sound_HNF P2_H2 unfolding is_sound_HNF_def by (metis (no_types, lifting) len_gs case_prodD mat_of_rows_carrier(2) mat_of_rows_carrier(3)) have P2_H2: "P2 * H2 = mat_of_rows n gs" - by (smt P2_H2 sound_HNF case_prodD is_sound_HNF_def) + by (smt (verit) P2_H2 sound_HNF case_prodD is_sound_HNF_def) have P1_H1_fs: "P1 * H1 = mat_of_rows n fs_init" - by (smt P1_H1 sound_HNF case_prodD is_sound_HNF_def) + by (smt (verit) P1_H1 sound_HNF case_prodD is_sound_HNF_def) obtain inv_P1 where P1_inv_P1: "inverts_mat P1 inv_P1" and inv_P1_P1: "inverts_mat inv_P1 P1" and inv_P1: "inv_P1 \ carrier_mat m m" using P1 invertible_P1 obtain_inverse_matrix by blast show "LLL_with_assms n m gs \" proof (rule LLL_change_basis(2)[OF gs len_gs]) show "P1 * inv_P2 \ carrier_mat m m" using P1 inv_P2 by auto have "mat_of_rows n fs_init = P1 * H1" using sound_HNF P2_H2 unfolding is_sound_HNF_def by (metis (mono_tags, lifting) P1_H1 case_prodD) also have "... = P1 * inv_P2 * P2 * H1" - by (smt P1 P2 assoc_mult_mat carrier_matD(1) inv_P2 inv_P2_P2 inverts_mat_def right_mult_one_mat) + by (smt (verit) P1 P2 assoc_mult_mat carrier_matD(1) inv_P2 inv_P2_P2 inverts_mat_def right_mult_one_mat) also have "... = P1 * inv_P2 * P2 * H2" using H1_H2 by blast also have "... = P1 * inv_P2 * (P2 * H2)" using H2 P2 \P1 * inv_P2 \ carrier_mat m m\ assoc_mult_mat by blast also have "... = P1 * (inv_P2 * P2 * H2)" by (metis H2 \P1 * H1 = P1 * inv_P2 * P2 * H1\ \P1 * inv_P2 * P2 * H2 = P1 * inv_P2 * (P2 * H2)\ H1_H2 carrier_matD(1) inv_P2 inv_P2_P2 inverts_mat_def left_mult_one_mat) also have "... = P1 * (inv_P2 * (P2 * H2))" using H2 P2 inv_P2 by auto also have "... = P1 * inv_P2 * mat_of_rows n gs" using P2_H2 \P1 * (inv_P2 * P2 * H2) = P1 * (inv_P2 * (P2 * H2))\ \P1 * inv_P2 * (P2 * H2) = P1 * (inv_P2 * P2 * H2)\ by auto finally show "mat_of_rows n fs_init = P1 * inv_P2 * mat_of_rows n gs" . show "P2 * inv_P1 \ carrier_mat m m" using P2 inv_P1 by auto have "mat_of_rows n gs = P2 * H2" using sound_HNF P2_H2 unfolding is_sound_HNF_def by metis also have "... = P2 * inv_P1 * P1 * H2" - by (smt P1 P2 assoc_mult_mat carrier_matD(1) inv_P1 inv_P1_P1 inverts_mat_def right_mult_one_mat) + by (smt (verit) P1 P2 assoc_mult_mat carrier_matD(1) inv_P1 inv_P1_P1 inverts_mat_def right_mult_one_mat) also have "... = P2 * inv_P1 * P1 * H1" using H1_H2 by blast also have "... = P2 * inv_P1 * (P1 * H1)" using H1 P1 \P2 * inv_P1 \ carrier_mat m m\ assoc_mult_mat by blast also have "... = P2 * (inv_P1 * P1 * H1)" by (metis H2 \P2 * H2 = P2 * inv_P1 * P1 * H2\ \P2 * inv_P1 * P1 * H1 = P2 * inv_P1 * (P1 * H1)\ H1_H2 carrier_matD(1) inv_P1 inv_P1_P1 inverts_mat_def left_mult_one_mat) also have "... = P2 * (inv_P1 * (P1 * H1))" using H1 P1 inv_P1 by auto also have "... = P2 * inv_P1 * mat_of_rows n fs_init" using P1_H1_fs \P2 * (inv_P1 * P1 * H1) = P2 * (inv_P1 * (P1 * H1))\ \P2 * inv_P1 * (P1 * H1) = P2 * (inv_P1 * P1 * H1)\ by auto finally show "mat_of_rows n gs = P2 * inv_P1 * mat_of_rows n fs_init" . qed qed end text \Now, we need to generalize some lemmas.\ context vec_module begin (*Generalized version of thm vec_space.finsum_index, now in vec_module*) lemma finsum_index: assumes i: "i < n" and f: "f \ A \ carrier_vec n" and A: "A \ carrier_vec n" shows "finsum V f A $ i = sum (\x. f x $ i) A" using A f proof (induct A rule: infinite_finite_induct) case empty then show ?case using i by simp next case (insert x X) then have Xf: "finite X" and xX: "x \ X" and x: "x \ carrier_vec n" and X: "X \ carrier_vec n" and fx: "f x \ carrier_vec n" and f: "f \ X \ carrier_vec n" by auto have i2: "i < dim_vec (finsum V f X)" using i finsum_closed[OF f] by auto have ix: "i < dim_vec x" using x i by auto show ?case unfolding finsum_insert[OF Xf xX f fx] unfolding sum.insert[OF Xf xX] unfolding index_add_vec(1)[OF i2] using insert lincomb_def by auto qed (insert i, auto) (*Generalized version of thm vec_space.mat_of_rows_mult_as_finsum, now in vec_module*) lemma mat_of_rows_mult_as_finsum: assumes "v \ carrier_vec (length lst)" "\ i. i < length lst \ lst ! i \ carrier_vec n" defines "f l \ sum (\ i. if l = lst ! i then v $ i else 0) {0..v v = lincomb f (set lst)" proof - from assms have "\ i < length lst. lst ! i \ carrier_vec n" by blast note an = all_nth_imp_all_set[OF this] hence slc:"set lst \ carrier_vec n" by auto hence dn [simp]:"\ x. x \ set lst \ dim_vec x = n" by auto have dl [simp]:"dim_vec (lincomb f (set lst)) = n" using an by (simp add: slc) show ?thesis proof show "dim_vec (mat_of_cols n lst *\<^sub>v v) = dim_vec (lincomb f (set lst))" using assms(1,2) by auto fix i assume i:"i < dim_vec (lincomb f (set lst))" hence i':"i < n" by auto with an have fcarr:"(\v. f v \\<^sub>v v) \ set lst \ carrier_vec n" by auto from i' have "(mat_of_cols n lst *\<^sub>v v) $ i = row (mat_of_cols n lst) i \ v" by auto also have "\ = (\ia = 0.. = (\ia = 0.. = (\x\set lst. f x * x $ i)" unfolding f_def sum_distrib_right apply (subst sum.swap) apply(rule sum.cong[OF refl]) unfolding if_distrib if_distribR mult_zero_left sum.delta[OF finite_set] by auto also have "\ = (\x\set lst. (f x \\<^sub>v x) $ i)" apply(rule sum.cong[OF refl],subst index_smult_vec) using i slc by auto also have "\ = (\\<^bsub>V\<^esub>v\set lst. f v \\<^sub>v v) $ i" unfolding finsum_index[OF i' fcarr slc] by auto finally show "(mat_of_cols n lst *\<^sub>v v) $ i = lincomb f (set lst) $ i" by (auto simp:lincomb_def) qed qed lemma lattice_of_altdef_lincomb: assumes "set fs \ carrier_vec n" shows "lattice_of fs = {y. \f. lincomb (of_int \ f) (set fs) = y}" unfolding lincomb_def lattice_of_altdef[OF assms] image_def by auto end context vec_module begin (*Generalized version of thm idom_vec.lincomb_as_lincomb_list, now in vec_module*) lemma lincomb_as_lincomb_list: fixes ws f assumes s: "set ws \ carrier_vec n" shows "lincomb f (set ws) = lincomb_list (\i. if \jv. v \ set ws \ v \ carrier_vec n" using snoc.prems(1) by auto then have ws: "set ws \ carrier_vec n" by auto have hyp: "lincomb f (set ws) = lincomb_list ?f ws" by (intro snoc.hyps ws) show ?case proof (cases "a\set ws") case True have g_length: "?g (length ws) = 0\<^sub>v n" using True by (auto, metis in_set_conv_nth nth_append) have "(map ?g [0..v n]" using g_length by simp finally have map_rw: "(map ?g [0..v n]" . have "M.sumlist (map ?g2 [0..v n " by (metis M.r_zero calculation hyp lincomb_closed lincomb_list_def ws) also have "... = M.sumlist (map ?g [0..v n])" by (rule M.sumlist_snoc[symmetric], auto simp add: nth_append) finally have summlist_rw: "M.sumlist (map ?g2 [0..v n])" . have "lincomb f (set (ws @ [a])) = lincomb f (set ws)" using True unfolding lincomb_def by (simp add: insert_absorb) thus ?thesis unfolding hyp lincomb_list_def map_rw summlist_rw by auto next case False have g_length: "?g (length ws) = f a \\<^sub>v a" using False by (auto simp add: nth_append) have "(map ?g [0..\<^sub>v a)]" using g_length by simp finally have map_rw: "(map ?g [0..\<^sub>v a)]" . have summlist_rw: "M.sumlist (map ?g2 [0..\<^bsub>V\<^esub>v\set (a # ws). f v \\<^sub>v v)" unfolding lincomb_def .. also have "... = (\\<^bsub>V\<^esub>v\ insert a (set ws). f v \\<^sub>v v)" by simp also have "... = (f a \\<^sub>v a) + (\\<^bsub>V\<^esub>v\ (set ws). f v \\<^sub>v v)" proof (rule finsum_insert) show "finite (set ws)" by auto show "a \ set ws" using False by auto show "(\v. f v \\<^sub>v v) \ set ws \ carrier_vec n" using snoc.prems(1) by auto show "f a \\<^sub>v a \ carrier_vec n" using snoc.prems by auto qed also have "... = (f a \\<^sub>v a) + lincomb f (set ws)" unfolding lincomb_def .. also have "... = (f a \\<^sub>v a) + lincomb_list ?f ws" using hyp by auto also have "... = lincomb_list ?f ws + (f a \\<^sub>v a)" using M.add.m_comm lincomb_list_carrier snoc.prems by auto also have "... = lincomb_list (\i. if \j carrier_vec n" using snoc.prems by (auto simp add: nth_append) show "f a \\<^sub>v a \ carrier_vec n" using snoc.prems by auto qed finally show ?thesis . qed qed auto end context begin interpretation vec_module "TYPE(int)" . lemma lattice_of_cols_as_mat_mult: assumes A: "A \ carrier_mat n nc" (*Integer matrix*) shows "lattice_of (cols A) = {y\carrier_vec (dim_row A). \x\carrier_vec (dim_col A). A *\<^sub>v x = y}" proof - let ?ws = "cols A" have set_cols_in: "set (cols A) \ carrier_vec n" using A unfolding cols_def by auto have "lincomb (of_int \ f)(set ?ws) \ carrier_vec (dim_row A)" for f using lincomb_closed A by (metis (full_types) carrier_matD(1) cols_dim lincomb_closed) moreover have "\x\carrier_vec (dim_col A). A *\<^sub>v x = lincomb (of_int \ f) (set (cols A))" for f proof - let ?g = "(\v. of_int (f v))" let ?g' = "(\i. if \j f) (set (cols A)) = lincomb ?g (set ?ws)" unfolding o_def by auto also have "... = lincomb_list ?g' ?ws" by (rule lincomb_as_lincomb_list[OF set_cols_in]) also have "... = mat_of_cols n ?ws *\<^sub>v vec (length ?ws) ?g'" by (rule lincomb_list_as_mat_mult, insert set_cols_in A, auto) also have "... = A *\<^sub>v (vec (length ?ws) ?g')" using mat_of_cols_cols A by auto finally show ?thesis by auto qed moreover have "\f. A *\<^sub>v x = lincomb (of_int \ f) (set (cols A))" if Ax: "A *\<^sub>v x \ carrier_vec (dim_row A)" and x: "x \ carrier_vec (dim_col A)" for x proof - let ?c = "\i. x $ i" have x_vec: "vec (length ?ws) ?c = x" using x by auto have "A *\<^sub>v x = mat_of_cols n ?ws *\<^sub>v vec (length ?ws) ?c" using mat_of_cols_cols A x_vec by auto also have "... = lincomb_list ?c ?ws" by (rule lincomb_list_as_mat_mult[symmetric], insert set_cols_in A, auto) also have "... = lincomb (mk_coeff ?ws ?c) (set ?ws)" by (rule lincomb_list_as_lincomb, insert set_cols_in A, auto) finally show ?thesis by auto qed ultimately show ?thesis unfolding lattice_of_altdef_lincomb[OF set_cols_in] by (metis (mono_tags, opaque_lifting)) qed corollary lattice_of_as_mat_mult: assumes fs: "set fs \ carrier_vec n" shows "lattice_of fs = {y\carrier_vec n. \x\carrier_vec (length fs). (mat_of_cols n fs) *\<^sub>v x = y}" proof - have cols_eq: "cols (mat_of_cols n fs) = fs" using cols_mat_of_cols[OF fs] by simp have m: "(mat_of_cols n fs) \ carrier_mat n (length fs)" using mat_of_cols_carrier(1) by auto show ?thesis using lattice_of_cols_as_mat_mult[OF m] unfolding cols_eq using m by auto qed end context vec_space begin lemma lin_indpt_cols_imp_det_not_0: fixes A::"'a mat" assumes A: "A \ carrier_mat n n" and li: "lin_indpt (set (cols A))" and d: "distinct (cols A)" shows "det A \ 0" using A li d det_rank_iff lin_indpt_full_rank by blast corollary lin_indpt_rows_imp_det_not_0: fixes A::"'a mat" assumes A: "A \ carrier_mat n n" and li: "lin_indpt (set (rows A))" and d: "distinct (rows A)" shows "det A \ 0" using A li d det_rank_iff lin_indpt_full_rank by (metis (full_types) Determinant.det_transpose cols_transpose transpose_carrier_mat) end context LLL begin lemma eq_lattice_imp_mat_mult_invertible_cols: assumes fs: "set fs \ carrier_vec n" and gs: "set gs \ carrier_vec n" and ind_fs: "lin_indep fs" (*fs is a basis*) and length_fs: "length fs = n" and length_gs: "length gs = n" (*For the moment, only valid for square matrices*) and l: "lattice_of fs = lattice_of gs" shows "\Q \ carrier_mat n n. invertible_mat Q \ mat_of_cols n fs = mat_of_cols n gs * Q" proof (cases "n=0") case True show ?thesis by (rule bexI[of _ "1\<^sub>m 0"], insert True assms, auto) next case False hence n: "0 carrier_mat n n" by (simp add: length_fs carrier_matI) let ?f = "(\i. SOME x. x\carrier_vec (length gs) \ (mat_of_cols n gs) *\<^sub>v x = fs ! i)" let ?cols_Q = "map ?f [0.. carrier_mat n n" using length_fs by auto show fs_gs_Q: "mat_of_cols n fs = mat_of_cols n gs * ?Q" proof (rule mat_col_eqI) fix j assume j: "j < dim_col (mat_of_cols n gs * ?Q)" have j2: "j lattice_of gs" using fs l basis_in_latticeI j by auto have fs_j_carrier_vec: "fs ! j \ carrier_vec n" using fs_j_in_gs gs lattice_of_as_mat_mult by blast let ?x = "SOME x. x\carrier_vec (length gs) \ (mat_of_cols n gs) *\<^sub>v x = fs ! j" have "?x\carrier_vec (length gs) \ (mat_of_cols n gs) *\<^sub>v ?x = fs ! j" by (rule someI_ex, insert fs_j_in_gs lattice_of_as_mat_mult[OF gs], auto) hence x: "?x \ carrier_vec (length gs)" and gs_x: "(mat_of_cols n gs) *\<^sub>v ?x = fs ! j" by blast+ have "col ?Q j = ?cols_Q ! j" proof (rule col_mat_of_cols) show "j < length (map ?f [0.. carrier_vec n" using x length_gs by auto finally show "map ?f [0.. carrier_vec n" . qed also have "... = ?f ([0..v ?x" using gs_x by auto also have "... = (mat_of_cols n gs) *\<^sub>v (col ?Q j)" unfolding col_Qj_x by simp also have "... = col (mat_of_cols n gs * ?Q) j" by (rule col_mult2[symmetric, OF _ Q j2], insert length_gs mat_of_cols_def, auto) finally show "col (mat_of_cols n fs) j = col (mat_of_cols n gs * ?Q) j" . qed (insert length_gs gs, auto) show "invertible_mat ?Q" (* Sketch of the proof: 1) fs = gs * Q, proved previously 2) gs = fs * Q', similar proof as the previous one. 3) fs = fs * Q' * Q 4) fs * (?Q' * ?Q - 1\<^sub>m n) = 0\<^sub>m n n and hence (?Q' * ?Q - 1\<^sub>m n) = 0 since fs independent 5) det ?Q' = det ?Q = det 1 = 1, then det ?Q = \1 and ?Q invertible since the determinant divides a unit. *) proof - let ?f' = "(\i. SOME x. x\carrier_vec (length fs) \ (mat_of_cols n fs) *\<^sub>v x = gs ! i)" let ?cols_Q' = "map ?f' [0.. carrier_mat n n" using length_gs by auto have gs_fs_Q': "mat_of_cols n gs = mat_of_cols n fs * ?Q'" proof (rule mat_col_eqI) fix j assume j: "j < dim_col (mat_of_cols n fs * ?Q')" have j2: "j lattice_of fs" using gs l basis_in_latticeI j by auto have gs_j_carrier_vec: "gs ! j \ carrier_vec n" using gs_j_in_fs fs lattice_of_as_mat_mult by blast let ?x = "SOME x. x\carrier_vec (length fs) \ (mat_of_cols n fs) *\<^sub>v x = gs ! j" have "?x\carrier_vec (length fs) \ (mat_of_cols n fs) *\<^sub>v ?x = gs ! j" by (rule someI_ex, insert gs_j_in_fs lattice_of_as_mat_mult[OF fs], auto) hence x: "?x \ carrier_vec (length fs)" and fs_x: "(mat_of_cols n fs) *\<^sub>v ?x = gs ! j" by blast+ have "col ?Q' j = ?cols_Q' ! j" proof (rule col_mat_of_cols) show "j < length (map ?f' [0.. carrier_vec n" using x length_fs by auto finally show "map ?f' [0.. carrier_vec n" . qed also have "... = ?f' ([0..v ?x" using fs_x by auto also have "... = (mat_of_cols n fs) *\<^sub>v (col ?Q' j)" unfolding col_Qj_x by simp also have "... = col (mat_of_cols n fs * ?Q') j" by (rule col_mult2[symmetric, OF _ Q' j2], insert length_fs mat_of_cols_def, auto) finally show "col (mat_of_cols n gs) j = col (mat_of_cols n fs * ?Q') j" . qed (insert length_fs fs, auto) have det_fs_not_zero: "rat_of_int (det (mat_of_cols n fs)) \ 0" proof - let ?A = "(of_int_hom.mat_hom (mat_of_cols n fs)):: rat mat" have "rat_of_int (det (mat_of_cols n fs)) = det ?A" by simp moreover have "det ?A \ 0" proof (rule gs.lin_indpt_cols_imp_det_not_0[of ?A]) have c_eq: "(set (cols ?A)) = set (RAT fs)" by (metis assms(3) cof_vec_space.lin_indpt_list_def cols_mat_of_cols fs mat_of_cols_map) show "?A \ carrier_mat n n" by (simp add: fs_carrier) show "gs.lin_indpt (set (cols ?A))" using ind_RAT_fs c_eq by auto show "distinct (cols ?A)" by (metis ind_fs cof_vec_space.lin_indpt_list_def cols_mat_of_cols fs mat_of_cols_map) qed ultimately show ?thesis by auto qed have Q'Q: "?Q' * ?Q \ carrier_mat n n" using Q Q' mult_carrier_mat by blast have fs_fs_Q'Q: "mat_of_cols n fs = mat_of_cols n fs * ?Q' * ?Q" using gs_fs_Q' fs_gs_Q by presburger hence "0\<^sub>m n n = mat_of_cols n fs * ?Q' * ?Q - mat_of_cols n fs" using length_fs by auto also have "... = mat_of_cols n fs * ?Q' * ?Q - mat_of_cols n fs * 1\<^sub>m n" using fs_carrier by auto also have "... = mat_of_cols n fs * (?Q' * ?Q) - mat_of_cols n fs * 1\<^sub>m n" using Q Q' fs_carrier by auto also have "... = mat_of_cols n fs * (?Q' * ?Q - 1\<^sub>m n)" by (rule mult_minus_distrib_mat[symmetric, OF fs_carrier Q'Q], auto) finally have "mat_of_cols n fs * (?Q' * ?Q - 1\<^sub>m n) = 0\<^sub>m n n" .. have "det (?Q' * ?Q) = 1" - by (smt Determinant.det_mult Q Q' Q'Q fs_fs_Q'Q assoc_mult_mat det_fs_not_zero + by (smt (verit) Determinant.det_mult Q Q' Q'Q fs_fs_Q'Q assoc_mult_mat det_fs_not_zero fs_carrier mult_cancel_left2 of_int_code(2)) hence det_Q'_Q_1: "det ?Q * det ?Q' = 1" by (metis (no_types, lifting) Determinant.det_mult Groups.mult_ac(2) Q Q') hence "det ?Q = 1 \ det ?Q = -1" by (rule pos_zmult_eq_1_iff_lemma) thus ?thesis using invertible_iff_is_unit_JNF[OF Q] by fastforce qed qed qed corollary eq_lattice_imp_mat_mult_invertible_rows: assumes fs: "set fs \ carrier_vec n" and gs: "set gs \ carrier_vec n" and ind_fs: "lin_indep fs" (*fs is a basis*) and length_fs: "length fs = n" and length_gs: "length gs = n" (*For the moment, only valid for square matrices*) and l: "lattice_of fs = lattice_of gs" shows "\P \ carrier_mat n n. invertible_mat P \ mat_of_rows n fs = P * mat_of_rows n gs" proof - obtain Q where Q: "Q \ carrier_mat n n" and inv_Q: "invertible_mat Q" and fs_gs_Q: "mat_of_cols n fs = mat_of_cols n gs * Q" using eq_lattice_imp_mat_mult_invertible_cols[OF assms] by auto have "invertible_mat Q\<^sup>T" by (simp add: inv_Q invertible_mat_transpose) moreover have "mat_of_rows n fs = Q\<^sup>T * mat_of_rows n gs" using fs_gs_Q by (metis Matrix.transpose_mult Q length_gs mat_of_cols_carrier(1) transpose_mat_of_cols) moreover have "Q\<^sup>T \ carrier_mat n n" using Q by auto ultimately show ?thesis by blast qed end subsubsection \Missing results\ text \This is a new definition for upper triangular matrix, valid for rectangular matrices. This definition will allow us to prove that echelon form implies upper triangular for any matrix.\ definition "upper_triangular' A = (\i < dim_row A. \ j A $$ (i,j) = 0)" lemma upper_triangular'D[elim] : "upper_triangular' A \ j j < i \ i < dim_row A \ A $$ (i,j) = 0" unfolding upper_triangular'_def by auto lemma upper_triangular'I[intro] : "(\i j. j j < i \ i < dim_row A \ A $$ (i,j) = 0) \ upper_triangular' A" unfolding upper_triangular'_def by auto lemma prod_list_abs(*[simp]?*): fixes xs:: "int list" shows "prod_list (map abs xs) = abs (prod_list xs)" by (induct xs, auto simp add: abs_mult) lemma euclid_ext2_works: assumes "euclid_ext2 a b = (p,q,u,v,d)" shows "p*a+q*b = d" and "d = gcd a b" and "gcd a b * u = -b" and "gcd a b * v = a" and "u = -b div gcd a b" and "v = a div gcd a b" using assms unfolding euclid_ext2_def by (auto simp add: bezout_coefficients_fst_snd) lemma res_function_euclidean2: "res_function (\b n::'a::{unique_euclidean_ring}. n mod b)" proof- have "n mod b = n" if "b=0" for n b::"'a :: unique_euclidean_ring" using that by auto hence "res_function_euclidean = (\b n::'a. n mod b)" by (unfold fun_eq_iff res_function_euclidean_def, auto) thus ?thesis using res_function_euclidean by auto qed lemma mult_row_1_id: fixes A:: "'a::semiring_1^'n^'m" shows "mult_row A b 1 = A" unfolding mult_row_def by vector text \Results about appending rows\ lemma row_append_rows1: assumes A: "A \ carrier_mat m n" and B: "B \ carrier_mat p n" assumes i: "i < dim_row A" shows "Matrix.row (A @\<^sub>r B) i = Matrix.row A i" proof (rule eq_vecI) have AB_carrier[simp]: "(A @\<^sub>r B) \ carrier_mat (m+p) n" by (rule carrier_append_rows[OF A B]) thus "dim_vec (Matrix.row (A @\<^sub>r B) i) = dim_vec (Matrix.row A i)" using A B by (auto, insert carrier_matD(2), blast) fix j assume j: "j < dim_vec (Matrix.row A i)" have "Matrix.row (A @\<^sub>r B) i $v j = (A @\<^sub>r B) $$ (i, j)" by (metis AB_carrier Matrix.row_def j A carrier_matD(2) index_row(2) index_vec) also have "... = (if i < dim_row A then A $$ (i, j) else B $$ (i - m, j))" by (rule append_rows_nth, insert assms j, auto) also have "... = A$$ (i,j)" using i by simp finally show "Matrix.row (A @\<^sub>r B) i $v j = Matrix.row A i $v j" using i j by simp qed lemma row_append_rows2: assumes A: "A \ carrier_mat m n" and B: "B \ carrier_mat p n" assumes i: "i \ {m..r B) i = Matrix.row B (i - m)" proof (rule eq_vecI) have AB_carrier[simp]: "(A @\<^sub>r B) \ carrier_mat (m+p) n" by (rule carrier_append_rows[OF A B]) thus "dim_vec (Matrix.row (A @\<^sub>r B) i) = dim_vec (Matrix.row B (i-m))" using A B by (auto, insert carrier_matD(2), blast) fix j assume j: "j < dim_vec (Matrix.row B (i-m))" have "Matrix.row (A @\<^sub>r B) i $v j = (A @\<^sub>r B) $$ (i, j)" by (metis AB_carrier Matrix.row_def j B carrier_matD(2) index_row(2) index_vec) also have "... = (if i < dim_row A then A $$ (i, j) else B $$ (i - m, j))" by (rule append_rows_nth, insert assms j, auto) also have "... = B $$ (i - m, j)" using i A by simp finally show "Matrix.row (A @\<^sub>r B) i $v j = Matrix.row B (i-m) $v j" using i j A B by auto qed lemma rows_append_rows: assumes A: "A \ carrier_mat m n" and B: "B \ carrier_mat p n" shows "Matrix.rows (A @\<^sub>r B) = Matrix.rows A @ Matrix.rows B" proof - have AB_carrier: "(A @\<^sub>r B) \ carrier_mat (m+p) n" by (rule carrier_append_rows, insert A B, auto) hence 1: "dim_row (A @\<^sub>r B) = dim_row A + dim_row B" using A B by blast moreover have "Matrix.row (A @\<^sub>r B) i = (Matrix.rows A @ Matrix.rows B) ! i" if i: "i < dim_row (A @\<^sub>r B)" for i proof (cases "ir B) i = Matrix.row A i" using A True B row_append_rows1 by blast also have "... = Matrix.rows A ! i" unfolding Matrix.rows_def using True by auto also have "... = (Matrix.rows A @ Matrix.rows B) ! i" using True by (simp add: nth_append) finally show ?thesis . next case False have i_mp: "i < m + p" using AB_carrier A B i by fastforce have "Matrix.row (A @\<^sub>r B) i = Matrix.row B (i-m)" using A False B i row_append_rows2 i_mp - by (smt AB_carrier atLeastLessThan_iff carrier_matD(1) le_add1 + by (smt (verit) AB_carrier atLeastLessThan_iff carrier_matD(1) le_add1 linordered_semidom_class.add_diff_inverse row_append_rows2) also have "... = Matrix.rows B ! (i-m)" unfolding Matrix.rows_def using False i A 1 by auto also have "... = (Matrix.rows A @ Matrix.rows B) ! (i-m+m)" by (metis add_diff_cancel_right' A carrier_matD(1) length_rows not_add_less2 nth_append) also have "... = (Matrix.rows A @ Matrix.rows B) ! i" using False A by auto finally show ?thesis . qed ultimately show ?thesis unfolding list_eq_iff_nth_eq by auto qed lemma append_rows_nth2: assumes A': "A' \ carrier_mat m n" and B: "B \ carrier_mat p n" and A_def: "A = (A' @\<^sub>r B)" and a: "a carrier_mat m n" and B: "B \ carrier_mat p n" and A_def: "A = (A' @\<^sub>r B)" and a: "a\m" and ap: "a < m + p" and j: "jResults about submatrices\ lemma pick_first_id: assumes i: "i {0.. carrier_mat m n" and i: "im" and k2: "k2\n" shows "(submatrix H {0..m" and kn: "k2\n" using k1 k2 by simp+ - have card_mk: "card {i. i < m \ i < k1} = k1" using km - by (smt Collect_cong card_Collect_less_nat le_eq_less_or_eq nat_less_induct nat_neq_iff) - have card_nk: "card {i. i < n \ i < k2} = k2" using kn - by (smt Collect_cong card_Collect_less_nat le_eq_less_or_eq nat_less_induct nat_neq_iff) + then have "{i. i < m \ i < k1} = {.. i < k2} = {.. i < k1} = k1" and card_nk: "card {i. i < n \ i < k2} = k2" + by auto show ?thesis proof- have pick_j: "pick ?J j = j" by (rule pick_first_id[OF j]) have pick_i: "pick ?I i = i" by (rule pick_first_id[OF i]) have "submatrix H ?I ?J $$ (i, j) = H $$ (pick ?I i, pick ?J j)" by (rule submatrix_index, insert H i j card_mk card_nk, auto) also have "... = H $$ (i,j)" using pick_i pick_j by simp finally show ?thesis . qed qed lemma submatrix_carrier_first: assumes H: "H \ carrier_mat m n" and k1: "k1 \ m" and k2: "k2 \ n" shows"submatrix H {0.. carrier_mat k1 k2" proof - have km: "k1\m" and kn: "k2\n" using k1 k2 by simp+ - have card_mk: "card {i. i < m \ i < k1} = k1" using km - by (smt Collect_cong card_Collect_less_nat le_eq_less_or_eq nat_less_induct nat_neq_iff) - have card_nk: "card {i. i < n \ i < k2} = k2" using kn - by (smt Collect_cong card_Collect_less_nat le_eq_less_or_eq nat_less_induct nat_neq_iff) + then have "{i. i < m \ i < k1} = {.. i < k2} = {.. i < k1} = k1" and card_nk: "card {i. i < n \ i < k2} = k2" + by auto show ?thesis - by (smt Collect_cong H atLeastLessThan_iff card_mk card_nk carrier_matD + by (smt (verit) Collect_cong H atLeastLessThan_iff card_mk card_nk carrier_matD carrier_matI dim_submatrix zero_order(1)) qed lemma Units_eq_invertible_mat: assumes "A \ carrier_mat n n" shows "A \ Group.Units (ring_mat TYPE('a::comm_ring_1) n b) = invertible_mat A" (is "?lhs = ?rhs") proof - interpret m: ring "ring_mat TYPE('a) n b" by (rule ring_mat) show ?thesis proof assume "?lhs" thus "?rhs" unfolding Group.Units_def by (insert assms, auto simp add: ring_mat_def invertible_mat_def inverts_mat_def) next assume "?rhs" from this obtain B where AB: "A * B = 1\<^sub>m n" and BA: "B * A = 1\<^sub>m n" and B: "B \ carrier_mat n n" by (metis assms carrier_matD(1) inverts_mat_def obtain_inverse_matrix) hence "\x\carrier (ring_mat TYPE('a) n b). x \\<^bsub>ring_mat TYPE('a) n b\<^esub> A = \\<^bsub>ring_mat TYPE('a) n b\<^esub> \ A \\<^bsub>ring_mat TYPE('a) n b\<^esub> x = \\<^bsub>ring_mat TYPE('a) n b\<^esub>" unfolding ring_mat_def by auto thus "?lhs" unfolding Group.Units_def using assms unfolding ring_mat_def by auto qed qed lemma map_first_rows_index: assumes "A \ carrier_mat M n" and "m \ M" and "i carrier_mat (m+p) n" and B: "B \ carrier_mat p n" and eq: "\i\{m..j [0..r B" (is "_ = ?A' @\<^sub>r _") proof (rule eq_matI) have A': "?A' \ carrier_mat m n" by (simp add: mat_of_rows_def) hence A'B: "?A' @\<^sub>r B \ carrier_mat (m+p) n" using B by blast show "dim_row A = dim_row (?A' @\<^sub>r B)" and "dim_col A = dim_col (?A' @\<^sub>r B)" using A'B A by auto fix i j assume i: "i < dim_row (?A' @\<^sub>r B)" and j: "j < dim_col (?A' @\<^sub>r B)" have jn: "jr B) $$ (i, j)" proof (cases "ir B) $$ (i, j) = ?A' $$ (i,j)" by (metis (no_types, lifting) Nat.add_0_right True append_rows_def diff_zero i index_mat_four_block index_zero_mat(3) j length_map length_upt mat_of_rows_carrier(2)) also have "... = ?xs ! i $v j" by (rule mat_of_rows_index, insert i True j, auto simp add: append_rows_def) also have "... = A $$ (i,j)" by (rule map_first_rows_index, insert assms A True i jn, auto) finally show ?thesis .. next case False have "(?A' @\<^sub>r B) $$ (i, j) = B $$ (i-m,j)" - by (smt (z3) A' carrier_matD(1) False append_rows_def i index_mat_four_block j jn length_map + by (smt (verit) A' carrier_matD(1) False append_rows_def i index_mat_four_block j jn length_map length_upt mat_of_rows_carrier(2,3)) also have "... = A $$ (i,j)" by (metis False append_rows_def B eq atLeastLessThan_iff carrier_matD(1) diff_zero i index_mat_four_block(2) index_zero_mat(2) jn le_add1 length_map length_upt linordered_semidom_class.add_diff_inverse mat_of_rows_carrier(2)) finally show ?thesis .. qed qed lemma invertible_mat_first_column_not0: fixes A::"'a :: comm_ring_1 mat" assumes A: "A \ carrier_mat n n" and inv_A: "invertible_mat A" and n0: "0 (0\<^sub>v n)" proof (rule ccontr) assume " \ col A 0 \ 0\<^sub>v n" hence col_A0: "col A 0 = 0\<^sub>v n" by simp have "(det A dvd 1)" using inv_A invertible_iff_is_unit_JNF[OF A] by auto hence 1: "det A \ 0" by auto have "det A = (\i carrier_mat n n" and "B \ carrier_mat n n" and "invertible_mat P" and "invertible_mat (map_mat rat_of_int B)" shows "invertible_mat (map_mat rat_of_int A)" by (metis (no_types, opaque_lifting) assms dvd_field_iff invertible_iff_is_unit_JNF invertible_mult_JNF map_carrier_mat not_is_unit_0 of_int_hom.hom_0 of_int_hom.hom_det of_int_hom.mat_hom_mult) lemma echelon_form_JNF_intro: assumes "(\i \ (\j. j < dim_row A \ j>i \ \ is_zero_row_JNF j A))" and "(\i j. i j \ (is_zero_row_JNF i A) \ \ (is_zero_row_JNF j A) \ ((LEAST n. A $$ (i, n) \ 0) < (LEAST n. A $$ (j, n) \ 0)))" shows "echelon_form_JNF A" using assms unfolding echelon_form_JNF_def by simp lemma echelon_form_submatrix: assumes ef_H: "echelon_form_JNF H" and H: "H \ carrier_mat m n" and k: "k \ min m n" shows "echelon_form_JNF (submatrix H {0..m" and kn: "k\n" using k by simp+ - have card_mk: "card {i. i < m \ i < k} = k" using km - by (smt Collect_cong card_Collect_less_nat le_eq_less_or_eq nat_less_induct nat_neq_iff) - have card_nk: "card {i. i < n \ i < k} = k" using kn - by (smt Collect_cong card_Collect_less_nat le_eq_less_or_eq nat_less_induct nat_neq_iff) + then have "{i. i < m \ i < k} = {.. i < k} = {.. i < k} = k" and card_nk: "card {i. i < n \ i < k} = k" + by auto have H_ij: "H $$ (i,j) = (submatrix H ?I ?I) $$ (i,j)" if i: "i carrier_mat k k" using H dim_submatrix[of H "{0.. is_zero_row_JNF j ?H" define a where "a = (LEAST n. ?H $$ (j,n) \ 0)" have H'_ja: "?H $$ (j,a) \ 0" by (metis (mono_tags) LeastI j_not0_H' a_def is_zero_row_JNF_def) have a: "a < dim_col ?H" - by (smt j_not0_H' a_def is_zero_row_JNF_def linorder_neqE_nat not_less_Least order_trans_rules(19)) + by (smt (verit) j_not0_H' a_def is_zero_row_JNF_def linorder_neqE_nat not_less_Least order_trans_rules(19)) have j_not0_H: "\ is_zero_row_JNF j H" by (metis H' H'_ja H_ij a assms(2) basic_trans_rules(19) carrier_matD is_zero_row_JNF_def j kn le_eq_less_or_eq) hence i_not0_H: "\ is_zero_row_JNF i H" using ef_H j ij unfolding echelon_form_JNF_def by (metis H' \\ is_zero_row_JNF j H\ assms(2) carrier_matD(1) ij j km not_less_iff_gr_or_eq order.strict_trans order_trans_rules(21)) hence least_ab: "(LEAST n. H $$ (i, n) \ 0) < (LEAST n. H $$ (j, n) \ 0)" using jm using j_not0_H assms(2) echelon_form_JNF_def ef_H ij by blast define b where "b = (LEAST n. H $$ (i, n) \ 0)" have H_ib: "H $$ (i, b) \ 0" by (metis (mono_tags, lifting) LeastI b_def i_not0_H is_zero_row_JNF_def) have b: "b < dim_col ?H" using least_ab a unfolding a_def b_def by (metis (mono_tags, lifting) H' H'_ja H_ij a_def carrier_matD dual_order.strict_trans j nat_neq_iff not_less_Least) have H'_ib: "?H $$ (i,b) \ 0" using H_ib b H_ij H' ij j by (metis H' carrier_matD dual_order.strict_trans ij j) hence "\ is_zero_row_JNF i ?H" using b is_zero_row_JNF_def by blast thus False using iH'_0 by contradiction qed next fix i j assume ij: "i < j" and j: "j < dim_row ?H" have jm: "j is_zero_row_JNF i ?H" and not0_jH': "\ is_zero_row_JNF j ?H" define a where "a = (LEAST n. ?H $$ (i, n) \ 0)" define b where "b = (LEAST n. ?H $$ (j, n) \ 0)" have H'_ia: "?H $$ (i,a) \ 0" by (metis (mono_tags) LeastI_ex a_def is_zero_row_JNF_def not0_iH') have H'_jb: "?H $$ (j,b) \ 0" by (metis (mono_tags) LeastI_ex b_def is_zero_row_JNF_def not0_jH') have a: "a < dim_row ?H" - by (smt H' a_def carrier_matD is_zero_row_JNF_def less_trans linorder_neqE_nat not0_iH' not_less_Least) + by (smt (verit) H' a_def carrier_matD is_zero_row_JNF_def less_trans linorder_neqE_nat not0_iH' not_less_Least) have b: "b < dim_row ?H" - by (smt H' b_def carrier_matD is_zero_row_JNF_def less_trans linorder_neqE_nat not0_jH' not_less_Least) + by (smt (verit) H' b_def carrier_matD is_zero_row_JNF_def less_trans linorder_neqE_nat not0_jH' not_less_Least) have a_eq: "a = (LEAST n. H $$ (i, n) \ 0)" - by (smt H' H'_ia H_ij LeastI_ex a a_def carrier_matD(1) ij j linorder_neqE_nat not_less_Least order_trans_rules(19)) + by (smt (verit) H' H'_ia H_ij LeastI_ex a a_def carrier_matD(1) ij j linorder_neqE_nat not_less_Least order_trans_rules(19)) have b_eq: "b = (LEAST n. H $$ (j, n) \ 0)" - by (smt H' H'_jb H_ij LeastI_ex b b_def carrier_matD(1) ij j linorder_neqE_nat not_less_Least order_trans_rules(19)) + by (smt (verit) H' H'_jb H_ij LeastI_ex b b_def carrier_matD(1) ij j linorder_neqE_nat not_less_Least order_trans_rules(19)) have not0_iH: "\ is_zero_row_JNF i H" by (metis H' H'_ia H_ij a H carrier_matD ij is_zero_row_JNF_def j kn le_eq_less_or_eq order.strict_trans) have not0_jH: "\ is_zero_row_JNF j H" by (metis H' H'_jb H_ij b H carrier_matD is_zero_row_JNF_def j kn le_eq_less_or_eq order.strict_trans) show "(LEAST n. ?H $$ (i, n) \ 0) < (LEAST n. ?H $$ (j, n) \ 0)" unfolding a_def[symmetric] b_def[symmetric] a_eq b_eq using not0_iH not0_jH ef_H ij jm H unfolding echelon_form_JNF_def by auto qed qed lemma HNF_submatrix: assumes HNF_H: "Hermite_JNF associates res H" and H: "H \ carrier_mat m n" and k: "k \ min m n" shows "Hermite_JNF associates res (submatrix H {0..m" and kn: "k\n" using k by simp+ - have card_mk: "card {i. i < m \ i < k} = k" using km - by (smt Collect_cong card_Collect_less_nat le_eq_less_or_eq nat_less_induct nat_neq_iff) - have card_nk: "card {i. i < n \ i < k} = k" using kn - by (smt Collect_cong card_Collect_less_nat le_eq_less_or_eq nat_less_induct nat_neq_iff) + then have "{i. i < m \ i < k} = {.. i < k} = {.. i < k} = k" and card_nk: "card {i. i < n \ i < k} = k" + by auto have H_ij: "H $$ (i,j) = (submatrix H ?I ?I) $$ (i,j)" if i: "i carrier_mat k k" using H dim_submatrix[of H "{0.. 0) \ associates" and HNF2: "(\j 0) \ res (?H $$ (i, LEAST n. ?H $$ (i, n) \ 0)))" if i: "i is_zero_row_JNF i ?H" for i proof - define a where "a = (LEAST n. ?H $$ (i, n) \ 0)" have im: "i 0" by (metis (mono_tags) LeastI_ex a_def is_zero_row_JNF_def not0_iH') have a: "a < dim_row ?H" - by (smt H' a_def carrier_matD is_zero_row_JNF_def less_trans linorder_neqE_nat not0_iH' not_less_Least) + by (smt (verit) H' a_def carrier_matD is_zero_row_JNF_def less_trans linorder_neqE_nat not0_iH' not_less_Least) have a_eq: "a = (LEAST n. H $$ (i, n) \ 0)" - by (smt H' H'_ia H_ij LeastI_ex a a_def carrier_matD(1) i linorder_neqE_nat not_less_Least order_trans_rules(19)) + by (smt (verit) H' H'_ia H_ij LeastI_ex a a_def carrier_matD(1) i linorder_neqE_nat not_less_Least order_trans_rules(19)) have H'_ia_H_ia: "?H $$ (i, a) = H $$ (i, a)" by (metis H' H_ij a carrier_matD(1) i) have not'_iH: "\ is_zero_row_JNF i H" by (metis H' H'_ia H'_ia_H_ia a assms(2) carrier_matD(1) carrier_matD(2) is_zero_row_JNF_def kn order.strict_trans2) thus "?H $$ (i, LEAST n. ?H $$ (i, n) \ 0) \ associates" using im by (metis H'_ia_H_ia Hermite_JNF_def a_def a_eq HNF_H H carrier_matD(1)) show "(\j 0) \ res (?H $$ (i, LEAST n. ?H $$ (i, n) \ 0)))" proof - { fix nn :: nat have ff1: "\n. ?H $$ (n, a) = H $$ (n, a) \ \ n < k" by (metis (no_types) H' H_ij a carrier_matD(1)) have ff2: "i < k" by (metis H' carrier_matD(1) that(1)) then have "H $$ (nn, a) \ res (H $$ (i, a)) \ H $$ (nn, a) \ res (?H $$ (i, a))" using ff1 by (metis (no_types)) moreover { assume "H $$ (nn, a) \ res (?H $$ (i, a))" then have "?H $$ (nn, a) = H $$ (nn, a) \ ?H $$ (nn, a) \ res (?H $$ (i, a))" by presburger then have "\ nn < i \ ?H $$ (nn, LEAST n. ?H $$ (i, n) \ 0) \ res (?H $$ (i, LEAST n. ?H $$ (i, n) \ 0))" using ff2 ff1 a_def order.strict_trans by blast } ultimately have "\ nn < i \ ?H $$ (nn, LEAST n. ?H $$ (i, n) \ 0) \ res (?H $$ (i, LEAST n. ?H $$ (i, n) \ 0))" using Hermite_JNF_def a_eq assms(1) assms(2) im not'_iH by blast } then show ?thesis by meson qed qed show ?thesis using HNF1 HNF2 ef_H' CS_res CS_ass unfolding Hermite_JNF_def by blast qed lemma HNF_of_HNF_id: fixes H :: "int mat" assumes HNF_H: "Hermite_JNF associates res H" and H: "H \ carrier_mat n n" and H_P1_H1: "H = P1 * H1" and inv_P1: "invertible_mat P1" and H1: "H1 \ carrier_mat n n" and P1: "P1 \ carrier_mat n n" and HNF_H1: "Hermite_JNF associates res H1" and inv_H: "invertible_mat (map_mat rat_of_int H)" shows "H1 = H" proof (rule HNF_unique_generalized_JNF[OF H P1 H1 _ H H_P1_H1]) show "H = (1\<^sub>m n) * H" using H by auto qed (insert assms, auto) (*Some of the following lemmas could be moved outside this context*) context fixes n :: nat begin interpretation vec_module "TYPE(int)" . lemma lattice_is_monotone: fixes S T assumes S: "set S \ carrier_vec n" assumes T: "set T \ carrier_vec n" assumes subs: "set S \ set T" shows "lattice_of S \ lattice_of T" proof - have "\fa. lincomb fa (set T) = lincomb f (set S)" for f proof - let ?f = "\i. if i \ set T - set S then 0 else f i" have set_T_eq: "set T = set S \ (set T - set S)" using subs by blast have l0: "lincomb ?f (set T - set S) = 0\<^sub>v n" by (rule lincomb_zero, insert T, auto) have "lincomb ?f (set T) = lincomb ?f (set S \ (set T - set S))" using set_T_eq by simp also have "... = lincomb ?f (set S) + lincomb ?f (set T - set S)" by (rule lincomb_union, insert S T subs, auto) also have "... = lincomb ?f (set S)" using l0 by (auto simp add: S) also have "... = lincomb f (set S)" using S by fastforce finally show ?thesis by blast qed thus ?thesis unfolding lattice_of_altdef_lincomb[OF S] lattice_of_altdef_lincomb[OF T] by auto qed lemma lattice_of_append: assumes fs: "set fs \ carrier_vec n" assumes gs: "set gs \ carrier_vec n" shows "lattice_of (fs @ gs) = lattice_of (gs @ fs)" proof - have fsgs: "set (fs @ gs) \ carrier_vec n" using fs gs by auto have gsfs: "set (gs @ fs) \ carrier_vec n" using fs gs by auto show ?thesis unfolding lattice_of_altdef_lincomb[OF fsgs] lattice_of_altdef_lincomb[OF gsfs] by auto (metis Un_commute)+ qed lemma lattice_of_append_cons: assumes fs: "set fs \ carrier_vec n" and v: "v \ carrier_vec n" shows "lattice_of (v # fs) = lattice_of (fs @ [v])" proof - have v_fs: "set (v # fs) \ carrier_vec n" using fs v by auto hence fs_v: "set (fs @ [v]) \ carrier_vec n" by simp show ?thesis unfolding lattice_of_altdef_lincomb[OF v_fs] lattice_of_altdef_lincomb[OF fs_v] by auto qed lemma already_in_lattice_subset: assumes fs: "set fs \ carrier_vec n" and inlattice: "v \ lattice_of fs" and v: "v \ carrier_vec n" shows "lattice_of (v # fs) \ lattice_of fs" proof (cases "v\set fs") case True then show ?thesis by (metis fs lattice_is_monotone set_ConsD subset_code(1)) next case False note v_notin_fs = False obtain g where v_g: "lincomb g (set fs) = v" using lattice_of_altdef_lincomb[OF fs] inlattice by auto have v_fs: "set (v # fs) \ carrier_vec n" using v fs by auto have "\fa. lincomb fa (set fs) = lincomb f (insert v (set fs))" for f proof - have smult_rw: "f v \\<^sub>v (lincomb g (set fs)) = lincomb (\w. f v * g w) (set fs)" by (rule lincomb_smult[symmetric, OF fs]) have "lincomb f (insert v (set fs)) = f v \\<^sub>v v + lincomb f (set fs)" by (rule lincomb_insert2[OF _ fs _ v_notin_fs v], auto) also have "... = f v \\<^sub>v (lincomb g (set fs)) + lincomb f (set fs)" using v_g by simp also have "... = lincomb (\w. f v * g w) (set fs) + lincomb f (set fs)" unfolding smult_rw by auto also have "... = lincomb (\w. (\w. f v * g w) w + f w) (set fs)" by (rule lincomb_sum[symmetric, OF _ fs], simp) finally show ?thesis by auto qed thus ?thesis unfolding lattice_of_altdef_lincomb[OF v_fs] lattice_of_altdef_lincomb[OF fs] by auto qed lemma already_in_lattice: assumes fs: "set fs \ carrier_vec n" and inlattice: "v \ lattice_of fs" and v: "v \ carrier_vec n" shows "lattice_of fs = lattice_of (v # fs)" proof - have dir1: "lattice_of fs \ lattice_of (v # fs)" by (intro lattice_is_monotone, insert fs v, auto) moreover have dir2: "lattice_of (v # fs) \ lattice_of fs" by (rule already_in_lattice_subset[OF assms]) ultimately show ?thesis by auto qed lemma already_in_lattice_append: assumes fs: "set fs \ carrier_vec n" and inlattice: "lattice_of gs \ lattice_of fs" and gs: "set gs \ carrier_vec n" shows "lattice_of fs = lattice_of (fs @ gs)" using assms proof (induct gs arbitrary: fs) case Nil then show ?case by auto next case (Cons a gs) note fs = Cons.prems(1) note inlattice = Cons.prems(2) note gs = Cons.prems(3) have gs_in_fs: "lattice_of gs \ lattice_of fs" by (meson basic_trans_rules(23) gs lattice_is_monotone local.Cons(3) set_subset_Cons) have a: "a \ lattice_of (fs @ gs)" using basis_in_latticeI fs gs gs_in_fs local.Cons(1) local.Cons(3) by auto have "lattice_of (fs @ a # gs) = lattice_of ((a # gs) @ fs)" by (rule lattice_of_append, insert fs gs, auto) also have "... = lattice_of (a # (gs @ fs))" by auto also have "... = lattice_of (a # (fs @ gs))" by (rule lattice_of_eq_set, insert gs fs, auto) also have "... = lattice_of (fs @ gs)" by (rule already_in_lattice[symmetric, OF _ a], insert fs gs, auto) also have "... = lattice_of fs" by (rule Cons.hyps[symmetric, OF fs gs_in_fs], insert gs, auto) finally show ?case .. qed lemma zero_in_lattice: assumes fs_carrier: "set fs \ carrier_vec n" shows "0\<^sub>v n \ lattice_of fs" proof - have "\f. lincomb (\v. 0 * f v) (set fs) = 0\<^sub>v n" using fs_carrier lincomb_closed lincomb_smult lmult_0 by presburger hence "lincomb (\i. 0) (set fs) = 0\<^sub>v n" by fastforce thus ?thesis unfolding lattice_of_altdef_lincomb[OF fs_carrier] by auto qed lemma lattice_zero_rows_subset: assumes H: "H \ carrier_mat a n" shows "lattice_of (Matrix.rows (0\<^sub>m m n)) \ lattice_of (Matrix.rows H)" proof let ?fs = "Matrix.rows (0\<^sub>m m n)" let ?gs = "Matrix.rows H" have fs_carrier: "set ?fs \ carrier_vec n" unfolding Matrix.rows_def by auto have gs_carrier: "set ?gs \ carrier_vec n" using H unfolding Matrix.rows_def by auto fix x assume x: "x \ lattice_of (Matrix.rows (0\<^sub>m m n))" obtain f where fx: "lincomb (of_int \ f) (set (Matrix.rows (0\<^sub>m m n))) = x" using x lattice_of_altdef_lincomb[OF fs_carrier] by blast have "lincomb (of_int \ f) (set (Matrix.rows (0\<^sub>m m n))) = 0\<^sub>v n" unfolding lincomb_def by (rule M.finsum_all0, unfold Matrix.rows_def, auto) hence "x = 0\<^sub>v n" using fx by auto thus "x \ lattice_of (Matrix.rows H)" using zero_in_lattice[OF gs_carrier] by auto qed (*TODO: move outside this context (the previous lemmas too)*) lemma lattice_of_append_zero_rows: assumes H': "H' \ carrier_mat m n" and H: "H = H' @\<^sub>r (0\<^sub>m m n)" shows "lattice_of (Matrix.rows H) = lattice_of (Matrix.rows H')" proof - have "Matrix.rows H = Matrix.rows H' @ Matrix.rows (0\<^sub>m m n)" by (unfold H, rule rows_append_rows[OF H'], auto) also have "lattice_of ... = lattice_of (Matrix.rows H')" proof (rule already_in_lattice_append[symmetric]) show "lattice_of (Matrix.rows (0\<^sub>m m n)) \ lattice_of (Matrix.rows H')" by (rule lattice_zero_rows_subset[OF H']) qed (insert H', auto simp add: Matrix.rows_def) finally show ?thesis . qed end text \Lemmas about echelon form\ lemma echelon_form_JNF_1xn: assumes "A\carrier_mat m n" and "m<2" shows "echelon_form_JNF A" using assms unfolding echelon_form_JNF_def is_zero_row_JNF_def by fastforce lemma echelon_form_JNF_mx1: assumes "A\carrier_mat m n" and "n<2" and "\i \ {1.. carrier_mat m 0" shows "echelon_form_JNF A" using assms unfolding echelon_form_JNF_def is_zero_row_JNF_def by auto lemma echelon_form_JNF_first_column_0: assumes eA: "echelon_form_JNF A" and A: "A \ carrier_mat m n" and i0: "0 0" hence nz_iA: "\ is_zero_row_JNF i A" using n0 A unfolding is_zero_row_JNF_def by auto hence nz_0A: "\ is_zero_row_JNF 0 A" using eA A unfolding echelon_form_JNF_def using i0 im by auto have "(LEAST n. A $$ (0, n) \ 0) < (LEAST n. A $$ (i, n) \ 0)" using nz_iA nz_0A eA A unfolding echelon_form_JNF_def using i0 im by blast moreover have "(LEAST n. A $$ (i, n) \ 0) = 0" using Ai0 by simp ultimately show False by auto qed lemma is_zero_row_JNF_multrow[simp]: fixes A::"'a::comm_ring_1 mat" assumes "ij'ia \ (\j \ is_zero_row_JNF j (multrow i (- 1) A))" unfolding is_zero_row_JNF_def by simp have Least_eq: "(LEAST n. multrow i (- 1) A $$ (ia, n) \ 0) = (LEAST n. A $$ (ia, n) \ 0)" if ia: "ia < dim_row A" and nz_ia_mrA: "\ is_zero_row_JNF ia (multrow i (- 1) A)" for ia proof (rule Least_equality) have nz_ia_A: "\ is_zero_row_JNF ia A" using nz_ia_mrA ia by auto have Least_Aian_n: "(LEAST n. A $$ (ia, n) \ 0) < dim_col A" - by (smt dual_order.strict_trans is_zero_row_JNF_def not_less_Least not_less_iff_gr_or_eq nz_ia_A) + by (smt (verit) dual_order.strict_trans is_zero_row_JNF_def not_less_Least not_less_iff_gr_or_eq nz_ia_A) show "multrow i (- 1) A $$ (ia, LEAST n. A $$ (ia, n) \ 0) \ 0" - by (smt LeastI Least_Aian_n class_cring.cring_simprules(22) equation_minus_iff ia + by (smt (verit) LeastI Least_Aian_n class_cring.cring_simprules(22) equation_minus_iff ia index_mat_multrow(1) is_zero_row_JNF_def mult_minus1 nz_ia_A) show " \y. multrow i (- 1) A $$ (ia, y) \ 0 \ (LEAST n. A $$ (ia, n) \ 0) \ y" by (metis (mono_tags, lifting) Least_Aian_n class_cring.cring_simprules(22) ia index_mat_multrow(1) leI mult_minus1 order.strict_trans wellorder_Least_lemma(2)) qed have "(LEAST n. multrow i (- 1) A $$ (ia, n) \ 0) < (LEAST n. multrow i (- 1) A $$ (j, n) \ 0)" if ia_j: "ia < j" and j: "j < dim_row A" and nz_ia_A: "\ is_zero_row_JNF ia A" and nz_j_A: "\ is_zero_row_JNF j A" for ia j proof - have ia: "ia < dim_row A" using ia_j j by auto show ?thesis using Least_eq[OF ia] Least_eq[OF j] nz_ia_A nz_j_A is_zero_row_JNF_multrow[OF ia] is_zero_row_JNF_multrow[OF j] eA ia_j j unfolding echelon_form_JNF_def by simp qed thus "\ia j. ia < j \ j < dim_row (multrow i (- 1) A) \ \ is_zero_row_JNF ia (multrow i (- 1) A) \ \ is_zero_row_JNF j (multrow i (- 1) A) \ (LEAST n. multrow i (- 1) A $$ (ia, n) \ 0) < (LEAST n. multrow i (- 1) A $$ (j, n) \ 0)" by auto qed (*The following lemma is already in HOL Analysis (thm echelon_form_imp_upper_triagular), but only for square matrices. We prove it here for rectangular matrices.*) thm echelon_form_imp_upper_triagular (*First we prove an auxiliary statement*) lemma echelon_form_JNF_least_position_ge_diagonal: assumes eA: "echelon_form_JNF A" and A: "A: carrier_mat m n" and nz_iA: "\ is_zero_row_JNF i A" and im: "i(LEAST n. A $$ (i,n) \ 0)" using nz_iA im proof (induct i rule: less_induct) case (less i) note nz_iA = less.prems(1) note im = less.prems(2) show ?case proof (cases "i=0") case True show ?thesis using True by blast next case False show ?thesis proof (rule ccontr) assume " \ i \ (LEAST n. A $$ (i, n) \ 0)" hence i_least: "i > (LEAST n. A $$ (i, n) \ 0)" by auto have nz_i1A: "\ is_zero_row_JNF (i-1) A" using nz_iA im False A eA unfolding echelon_form_JNF_def by (metis Num.numeral_nat(7) Suc_pred carrier_matD(1) gr_implies_not0 lessI linorder_neqE_nat order.strict_trans) have "i-1\(LEAST n. A $$ (i-1,n) \ 0)" by (rule less.hyps, insert im nz_i1A False, auto) moreover have "(LEAST n. A $$ (i,n) \ 0) > (LEAST n. A $$ (i-1,n) \ 0)" using nz_i1A nz_iA im False A eA unfolding echelon_form_JNF_def by auto ultimately show False using i_least by auto qed qed qed lemma echelon_form_JNF_imp_upper_triangular: assumes eA: "echelon_form_JNF A" shows "upper_triangular A" proof fix i j assume ji: "j carrier_mat (dim_row A) (dim_col A)" by auto show "A $$ (i,j) = 0" proof (cases "is_zero_row_JNF i A") case False have "i\ (LEAST n. A $$(i,n) \ 0)" by (rule echelon_form_JNF_least_position_ge_diagonal[OF eA A False i]) then show ?thesis using ji not_less_Least order.strict_trans2 by blast next case True (* Problem detected: at this point, we don't know if j < dim_col A. That is, upper_triangular definition only works for matrices \ carrier_mat m n with n\m. The definition is: - upper_triangular A \ \i < dim_row A. \ j < i. A $$ (i,j) = 0 But we need here: - upper_triangular A \ \i < dim_row A. \ j < dim_col A. j < i \ A $$ (i,j) = 0 Anyway, the existing definition makes sense since upper triangular is usually restricted to square matrices. *) then show ?thesis unfolding is_zero_row_JNF_def oops (*We do the same with the new definition upper_triangular'*) lemma echelon_form_JNF_imp_upper_triangular: assumes eA: "echelon_form_JNF A" shows "upper_triangular' A" proof fix i j assume ji: "j carrier_mat (dim_row A) (dim_col A)" by auto show "A $$ (i,j) = 0" proof (cases "is_zero_row_JNF i A") case False have "i\ (LEAST n. A $$(i,n) \ 0)" by (rule echelon_form_JNF_least_position_ge_diagonal[OF eA A False i]) then show ?thesis using ji not_less_Least order.strict_trans2 by blast next case True then show ?thesis unfolding is_zero_row_JNF_def using j by auto qed qed lemma upper_triangular_append_zero: assumes uH: "upper_triangular' H" and H: "H \ carrier_mat (m+m) n" and mn: "n\m" shows "H = mat_of_rows n (map (Matrix.row H) [0..r 0\<^sub>m m n" (is "_ = ?H' @\<^sub>r 0\<^sub>m m n") proof have H': "?H' \ carrier_mat m n" using H uH by auto have H'0: "(?H' @\<^sub>r 0\<^sub>m m n) \ carrier_mat (m+m) n" by (simp add: H') thus dr: "dim_row H = dim_row (?H' @\<^sub>r 0\<^sub>m m n)" using H H' by (simp add: append_rows_def) show dc: "dim_col H = dim_col (?H' @\<^sub>r 0\<^sub>m m n)" using H H' by (simp add: append_rows_def) fix i j assume i: "i < dim_row (?H' @\<^sub>r 0\<^sub>m m n)" and j: "j < dim_col (?H' @\<^sub>r 0\<^sub>m m n)" show "H $$ (i, j) = (?H' @\<^sub>r 0\<^sub>m m n) $$ (i, j)" proof (cases "ir 0\<^sub>m m n) $$ (i, j)" - by (smt False H' append_rows_def assms(2) carrier_matD(1) carrier_matD(2) dc imn + by (smt (verit) False H' append_rows_def assms(2) carrier_matD(1) carrier_matD(2) dc imn index_mat_four_block(1,3) index_zero_mat j less_diff_conv2 linorder_not_less) finally show ?thesis . qed qed subsubsection \The algorithm is sound\ lemma find_fst_non0_in_row: assumes A: "A \ carrier_mat m n" and res: "find_fst_non0_in_row l A = Some j" shows "A $$ (l,j) \ 0" "l \ j" "j < dim_col A" proof - let ?xs = "filter (\j. A $$ (l, j) \ 0) [l ..< dim_col A]" from res[unfolded find_fst_non0_in_row_def Let_def] have xs: "?xs \ []" by (cases ?xs, auto) have j_in_xs: "j \ set ?xs" using res unfolding find_fst_non0_in_row_def Let_def by (metis (no_types, lifting) length_greater_0_conv list.case(2) list.exhaust nth_mem option.simps(1) xs) show "A $$ (l,j) \ 0" "l \ j" "j < dim_col A" using j_in_xs by auto+ qed lemma find_fst_non0_in_row_zero_before: assumes A: "A \ carrier_mat m n" and res: "find_fst_non0_in_row l A = Some j" shows "\j'\{l.. []" by (cases ?xs, auto) have j_in_xs: "j \ set ?xs" using res unfolding find_fst_non0_in_row_def Let_def by (metis (no_types, lifting) length_greater_0_conv list.case(2) list.exhaust nth_mem option.simps(1) xs) have j_xs0: "j = ?xs ! 0" - by (smt res[unfolded find_fst_non0_in_row_def Let_def] list.case(2) list.exhaust option.inject xs) + by (smt (verit) res[unfolded find_fst_non0_in_row_def Let_def] list.case(2) list.exhaust option.inject xs) show "\j'\{l.. 0" have j'j: "j' set ?xs" by (metis (mono_tags, lifting) A Set.member_filter j' Alj' res atLeastLessThan_iff filter_set find_fst_non0_in_row(3) nat_SN.gt_trans set_upt) have l_rw: "[l..j. A $$ (l, j) \ 0) ([l ..j. A $$ (l, j) \ 0) [l .. carrier_mat m n" and res: "find_fst_non0_in_row l A = Some j" and "j' \ {l.. carrier_mat m n" and ut_A: "upper_triangular' A" and res: "find_fst_non0_in_row l A = Some j" and lm: "l 0)" proof (rule Least_equality[symmetric]) show " A $$ (l, j) \ 0" using res find_fst_non0_in_row(1) by blast show "\y. A $$ (l, y) \ 0 \ j \ y" proof (rule ccontr) fix y assume Aly: "A $$ (l, y) \ 0" and jy: " \ j \ y " have yn: "y < n" by (metis A jy carrier_matD(2) find_fst_non0_in_row(3) leI less_imp_le_nat nat_SN.compat res) have "A $$(l,y) = 0" proof (cases "y\{l.. carrier_mat m n" and lm: "lj\{l..{l.. None" from this obtain j where r: "find_fst_non0_in_row l A = Some j" by blast hence "A $$ (l,j) \ 0" and "l\j" and "j carrier_mat m n" and ut_A: "upper_triangular' A" and lm: "l {l.. None" from this obtain j where r: "find_fst_non0_in_row l A = Some j" by blast hence "A $$ (l,j) \ 0" and "j is_zero_row_JNF l A" unfolding is_zero_row_JNF_def using lm A by auto thus False using rhs by contradiction qed qed lemma make_first_column_positive_preserves_dimensions: shows [simp]: "dim_row (make_first_column_positive A) = dim_row A" and [simp]: "dim_col (make_first_column_positive A) = dim_col A" by (auto) lemma make_first_column_positive_works: assumes "A\carrier_mat m n" and i: "i 0" and "j A $$ (i,0) < 0 \ (make_first_column_positive A) $$ (i,j) = - A $$ (i,j)" and "j A $$ (i,0) \ 0 \ (make_first_column_positive A) $$ (i,j) = A $$ (i,j)" using assms by auto lemma make_first_column_positive_invertible: shows "\P. invertible_mat P \ P \ carrier_mat (dim_row A) (dim_row A) \ make_first_column_positive A = P * A" proof - let ?P = "Matrix.mat (dim_row A) (dim_row A) (\(i,j). if i = j then if A $$(i,0) < 0 then - 1 else 1 else 0::int)" have "invertible_mat ?P" proof - have "(map abs (diag_mat ?P)) = replicate (length ((map abs (diag_mat ?P)))) 1" by (rule replicate_length_same[symmetric], auto simp add: diag_mat_def) hence m_rw: "(map abs (diag_mat ?P)) = replicate (dim_row A) 1" by (auto simp add: diag_mat_def) have "Determinant.det ?P = prod_list (diag_mat ?P)" by (rule det_upper_triangular, auto) also have "abs ... = prod_list (map abs (diag_mat ?P))" unfolding prod_list_abs by blast also have " ... = prod_list (replicate (dim_row A) 1)" using m_rw by simp also have "... = 1" by auto finally have "\Determinant.det ?P\ = 1" by blast hence "Determinant.det ?P dvd 1" by fastforce thus ?thesis using invertible_iff_is_unit_JNF mat_carrier by blast (*Thanks to the new bridge*) qed moreover have "make_first_column_positive A = ?P * A" (is "?M = _") proof (rule eq_matI) show "dim_row ?M = dim_row (?P * A)" and "dim_col ?M = dim_col (?P * A)" by auto fix i j assume i: "i < dim_row (?P * A)" and j: "j < dim_col (?P * A)" have set_rw: "{0..ia \ {0.. col A j" using i j by auto also have "... = (\ia = 0..ia \ insert i ({0..ia \ {0.. carrier_mat (dim_row A) (dim_row A)" by auto ultimately show ?thesis by blast qed locale proper_mod_operation = mod_operation + assumes dvd_gdiv_mult_right[simp]: "b > 0 \ b dvd a \ (a gdiv b) * b = a" and gmod_gdiv: "y > 0 \ x gmod y = x - x gdiv y * y" and dvd_imp_gmod_0: "0 < a \ a dvd b \ b gmod a = 0" and gmod_0_imp_dvd: "a gmod b = 0 \ b dvd a" and gmod_0[simp]: "n gmod 0 = n" "n > 0 \ 0 gmod n = 0" begin lemma reduce_alt_def_not0: assumes "A $$ (a,0) \ 0" and pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A $$ (b,0))" shows "reduce a b D A = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then let r = (p*A$$(a,k) + q*A$$(b,k)) in if k = 0 then if D dvd r then D else r else r gmod D else if i = b then let r = u * A$$(a,k) + v * A$$(b,k) in if k = 0 then r else r gmod D else A$$(i,k))" (is "_ = ?rhs") and "reduce_abs a b D A = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then let r = (p*A$$(a,k) + q*A$$(b,k)) in if abs r > D then if k = 0 \ D dvd r then D else r gmod D else r else if i = b then let r = u * A$$(a,k) + v * A$$(b,k) in if abs r > D then r gmod D else r else A$$(i,k))" (is "_ = ?rhs_abs") proof - have "reduce a b D A = (case euclid_ext2 (A$$(a,0)) (A $$ (b,0)) of (p,q,u,v,d) \ Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then let r = (p*A$$(a,k) + q*A$$(b,k)) in if k = 0 then if D dvd r then D else r else r gmod D else if i = b then let r = u * A$$(a,k) + v * A$$(b,k) in if k = 0 then r else r gmod D else A$$(i,k) ))" using assms by auto also have "... = ?rhs" unfolding reduce.simps Let_def by (rule eq_matI, insert pquvd) (metis (no_types, lifting) split_conv)+ finally show "reduce a b D A = ?rhs" . have "reduce_abs a b D A = (case euclid_ext2 (A$$(a,0)) (A $$ (b,0)) of (p,q,u,v,d) \ Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then let r = (p*A$$(a,k) + q*A$$(b,k)) in if abs r > D then if k = 0 \ D dvd r then D else r gmod D else r else if i = b then let r = u * A$$(a,k) + v * A$$(b,k) in if abs r > D then r gmod D else r else A$$(i,k) ))" using assms by auto also have "... = ?rhs_abs" unfolding reduce.simps Let_def by (rule eq_matI, insert pquvd) (metis (no_types, lifting) split_conv)+ finally show "reduce_abs a b D A = ?rhs_abs" . qed lemma reduce_preserves_dimensions: shows [simp]: "dim_row (reduce a b D A) = dim_row A" and [simp]: "dim_col (reduce a b D A) = dim_col A" and [simp]: "dim_row (reduce_abs a b D A) = dim_row A" and [simp]: "dim_col (reduce_abs a b D A) = dim_col A" by (auto simp add: Let_def split_beta) lemma reduce_carrier: assumes "A \ carrier_mat m n" shows "(reduce a b D A) \ carrier_mat m n" and "(reduce_abs a b D A) \ carrier_mat m n" by (insert assms, auto simp add: Let_def split_beta) lemma reduce_gcd: assumes A: "A \ carrier_mat m n" and a: "a 0" shows "(reduce a b D A) $$ (a,0) = (let r = gcd (A$$(a,0)) (A$$(b,0)) in if D dvd r then D else r)" (is "?lhs = ?rhs") and "(reduce_abs a b D A) $$ (a,0) = (let r = gcd (A$$(a,0)) (A$$(b,0)) in if D < r then if D dvd r then D else r gmod D else r)" (is "?lhs_abs = ?rhs_abs") proof - obtain p q u v d where pquvd: "euclid_ext2 (A$$(a,0)) (A$$(b,0)) = (p,q,u,v,d)" using prod_cases5 by blast have "p * A $$ (a, 0) + q * A $$ (b, 0) = d" using Aaj pquvd is_bezout_ext_euclid_ext2 unfolding is_bezout_ext_def - by (smt Pair_inject bezout_coefficients_fst_snd euclid_ext2_def) + by (smt (verit) Pair_inject bezout_coefficients_fst_snd euclid_ext2_def) also have " ... = gcd (A$$(a,0)) (A$$(b,0))" by (metis euclid_ext2_def pquvd prod.sel(2)) finally have pAaj_qAbj_gcd: "p * A $$ (a, 0) + q * A $$ (b, 0) = gcd (A$$(a,0)) (A$$(b,0))" . let ?f = "(\(i, k). if i = a then let r = p * A $$ (a, k) + q * A $$ (b, k) in if k = 0 then if D dvd r then D else r else r gmod D else if i = b then let r = u * A $$ (a, k) + v * A $$ (b, k) in if k = 0 then r else r gmod D else A $$ (i, k))" have "(reduce a b D A) $$ (a,0) = Matrix.mat (dim_row A) (dim_col A) ?f $$ (a, 0)" using Aaj pquvd by auto also have "... = (let r = p * A $$ (a, 0) + q * A $$ (b, 0) in if (0::nat) = 0 then if D dvd r then D else r else r gmod D)" using A a j by auto also have "... = (if D dvd gcd (A$$(a,0)) (A$$(b,0)) then D else gcd (A$$(a,0)) (A$$(b,0)))" by (simp add: pAaj_qAbj_gcd) finally show "?lhs = ?rhs" by auto let ?g = "(\(i, k). if i = a then let r = p * A $$ (a, k) + q * A $$ (b, k) in if D < \r\ then if k = 0 \ D dvd r then D else r gmod D else r else if i = b then let r = u * A $$ (a, k) + v * A $$ (b, k) in if D < \r\ then r gmod D else r else A $$ (i, k))" have "(reduce_abs a b D A) $$ (a,0) = Matrix.mat (dim_row A) (dim_col A) ?g $$ (a, 0)" using Aaj pquvd by auto also have "... = (let r = p * A $$ (a, 0) + q * A $$ (b, 0) in if D < \r\ then if (0::nat) = 0 \ D dvd r then D else r gmod D else r)" using A a j by auto also have "... = (if D < \gcd (A$$(a,0)) (A$$(b,0))\ then if D dvd gcd (A$$(a,0)) (A$$(b,0)) then D else gcd (A$$(a,0)) (A$$(b,0)) gmod D else gcd (A$$(a,0)) (A$$(b,0)))" by (simp add: pAaj_qAbj_gcd) finally show "?lhs_abs = ?rhs_abs" by auto qed lemma reduce_preserves: assumes A: "A \ carrier_mat m n" and j: "j 0" and ib: "i\b" and ia: "i\a" and im: "i carrier_mat m n" and a: "a b" and Aaj: "A $$ (a,0) \ 0" and D: "D \ 0" shows "(reduce a b D A) $$ (b,0) = 0" (is "?thesis1") and "(reduce_abs a b D A) $$ (b,0) = 0" (is "?thesis2") proof - obtain p q u v d where pquvd: "euclid_ext2 (A$$(a,0)) (A$$(b,0)) = (p,q,u,v,d)" using prod_cases5 by blast hence u: "u = - (A$$(b,0)) div gcd (A$$(a,0)) (A$$(b,0))" using euclid_ext2_works[OF pquvd] by auto have v: "v = A$$(a,0) div gcd (A$$(a,0)) (A$$(b,0))" using euclid_ext2_works[OF pquvd] by auto have uv0: "u * A$$(a,0) + v * A$$(b,0) = 0" using u v proof - have "\i ia. gcd (ia::int) i * (ia div gcd ia i) = ia" by (meson dvd_mult_div_cancel gcd_dvd1) then have "v * - A $$ (b, 0) = u * A $$ (a, 0)" by (metis (no_types) dvd_minus_iff dvd_mult_div_cancel gcd_dvd2 minus_minus mult.assoc mult.commute u v) then show ?thesis by simp qed let ?f = "(\(i, k). if i = a then let r = p * A $$ (a, k) + q * A $$ (b, k) in if k = 0 then if D dvd r then D else r else r gmod D else if i = b then let r = u * A $$ (a, k) + v * A $$ (b, k) in if k = 0 then r else r gmod D else A $$ (i, k))" have "(reduce a b D A) $$ (b,0) = Matrix.mat (dim_row A) (dim_col A) ?f $$ (b, 0)" using Aaj pquvd by auto also have "... = (let r = u * A$$(a,0) + v * A$$(b,0) in r)" using A a j ab b by auto also have "... = 0" using uv0 D - by (smt (z3) gmod_0(1) gmod_0(2)) + by (smt (verit) gmod_0(1) gmod_0(2)) finally show ?thesis1 . let ?g = "(\(i, k). if i = a then let r = p * A $$ (a, k) + q * A $$ (b, k) in if D < \r\ then if k = 0 \ D dvd r then D else r gmod D else r else if i = b then let r = u * A $$ (a, k) + v * A $$ (b, k) in if D < \r\ then r gmod D else r else A $$ (i, k))" have "(reduce_abs a b D A) $$ (b,0) = Matrix.mat (dim_row A) (dim_col A) ?g $$ (b, 0)" using Aaj pquvd by auto also have "... = (let r = u * A$$(a,0) + v * A$$(b,0) in if D < \r\ then r gmod D else r)" using A a j ab b by auto also have "... = 0" using uv0 D by simp finally show ?thesis2 . qed end text \Let us show the key lemma: operations modulo determinant don't modify the (integer) row span.\ context LLL_with_assms begin lemma lattice_of_kId_subset_fs_init: assumes k_det: "k = Determinant.det (mat_of_rows n fs_init)" and mn: "m=n" shows "lattice_of (Matrix.rows (k \\<^sub>m (1\<^sub>m m))) \ lattice_of fs_init" proof - let ?Z = "(mat_of_rows n fs_init)" let ?RAT = "of_int_hom.mat_hom :: int mat \ rat mat" have RAT_fs_init: "?RAT (mat_of_rows n fs_init) \ carrier_mat n n" using len map_carrier_mat mat_of_rows_carrier(1) mn by blast have det_RAT_fs_init: "Determinant.det (?RAT ?Z) \ 0" proof (rule gs.lin_indpt_rows_imp_det_not_0[OF RAT_fs_init]) have rw: "Matrix.rows (?RAT (mat_of_rows n fs_init)) = RAT fs_init" by (metis cof_vec_space.lin_indpt_list_def fs_init lin_dep mat_of_rows_map rows_mat_of_rows) thus "gs.lin_indpt (set (Matrix.rows (?RAT (mat_of_rows n fs_init))))" by (insert lin_dep, simp add: cof_vec_space.lin_indpt_list_def) show "distinct (Matrix.rows (?RAT (mat_of_rows n fs_init)))" using rw cof_vec_space.lin_indpt_list_def lin_dep by auto qed obtain inv_Z where inverts_Z: "inverts_mat (?RAT ?Z) inv_Z" and inv_Z: "inv_Z \ carrier_mat m m" by (metis mn det_RAT_fs_init dvd_field_iff invertible_iff_is_unit_JNF len map_carrier_mat mat_of_rows_carrier(1) obtain_inverse_matrix) have det_rat_Z_k: "Determinant.det (?RAT ?Z) = rat_of_int k" using k_det of_int_hom.hom_det by blast have "?RAT ?Z * adj_mat (?RAT ?Z) = Determinant.det (?RAT ?Z) \\<^sub>m 1\<^sub>m n" by (rule adj_mat[OF RAT_fs_init]) hence "inv_Z * (?RAT ?Z * adj_mat (?RAT ?Z)) = inv_Z * (Determinant.det (?RAT ?Z) \\<^sub>m 1\<^sub>m n)" by simp hence k_inv_Z_eq_adj: "(rat_of_int k) \\<^sub>m inv_Z = adj_mat (?RAT ?Z)" - by (smt Determinant.mat_mult_left_right_inverse RAT_fs_init adj_mat(1,3) mn + by (smt (verit) Determinant.mat_mult_left_right_inverse RAT_fs_init adj_mat(1,3) mn carrier_matD det_RAT_fs_init det_rat_Z_k gs.det_nonzero_congruence inv_Z inverts_Z inverts_mat_def mult_smult_assoc_mat smult_carrier_mat) have adj_mat_Z: "adj_mat (?RAT ?Z) $$ (i,j) \ \" if i: "i \" proof (rule Ints_det) fix ia ja assume ia: "ia < dim_row (mat_delete (?RAT ?Z) j i)" and ja: "ja < dim_col (mat_delete (?RAT ?Z) j i)" have "(mat_delete (?RAT ?Z) j i) $$ (ia, ja) = (?RAT ?Z) $$ (insert_index j ia, insert_index i ja)" by (rule mat_delete_index[symmetric], insert i j mn len ia ja RAT_fs_init, auto) also have "... = rat_of_int (?Z $$ (insert_index j ia, insert_index i ja))" by (rule index_map_mat, insert i j ia ja, auto simp add: insert_index_def) also have "... \ \" using Ints_of_int by blast finally show "(mat_delete (?RAT ?Z) j i) $$ (ia, ja) \ \" . qed have "adj_mat (?RAT ?Z) $$ (i,j) = Determinant.cofactor (?RAT ?Z) j i" unfolding adj_mat_def by (simp add: len i j) also have "... = (- 1) ^ (j + i) * Determinant.det (mat_delete (?RAT ?Z) j i)" unfolding Determinant.cofactor_def by auto also have "... \ \" using det_mat_delete_Z by auto finally show ?thesis . qed have kinvZ_in_Z: "((rat_of_int k) \\<^sub>m inv_Z) $$ (i,j) \ \" if i: "i\<^sub>m (1\<^sub>m m)) = Determinant.det (?RAT ?Z) \\<^sub>m (inv_Z * ?RAT ?Z)" (is "?lhs = ?rhs") proof - have "(inv_Z * ?RAT ?Z) = (1\<^sub>m m)" by (metis Determinant.mat_mult_left_right_inverse RAT_fs_init mn carrier_matD(1) inv_Z inverts_Z inverts_mat_def) from this have "?rhs = rat_of_int k \\<^sub>m (1\<^sub>m m)" using det_rat_Z_k by auto also have "... = ?lhs" by auto finally show ?thesis .. qed also have "... = (Determinant.det (?RAT ?Z) \\<^sub>m inv_Z) * ?RAT ?Z" by (metis RAT_fs_init mn inv_Z mult_smult_assoc_mat) also have "... = ((rat_of_int k) \\<^sub>m inv_Z) * ?RAT ?Z" by (simp add: k_det) finally have r': "?RAT (k \\<^sub>m (1\<^sub>m m)) = ((rat_of_int k) \\<^sub>m inv_Z) * ?RAT ?Z" . have r: "(k \\<^sub>m (1\<^sub>m m)) = ((map_mat int_of_rat ((rat_of_int k) \\<^sub>m inv_Z))) * ?Z" proof - have "?RAT ((map_mat int_of_rat ((rat_of_int k) \\<^sub>m inv_Z))) = ((rat_of_int k) \\<^sub>m inv_Z)" proof (rule eq_matI, auto) fix i j assume i: "i < dim_row inv_Z" and j: "j < dim_col inv_Z" have "((rat_of_int k) \\<^sub>m inv_Z) $$ (i,j) = (rat_of_int k * inv_Z $$ (i, j))" using index_smult_mat i j by auto hence kinvZ_in_Z': "... \ \" using kinvZ_in_Z i j inv_Z mn by simp show "rat_of_int (int_of_rat (rat_of_int k * inv_Z $$ (i, j))) = rat_of_int k * inv_Z $$ (i, j)" by (rule int_of_rat, insert kinvZ_in_Z', auto) qed hence "?RAT (k \\<^sub>m (1\<^sub>m m)) = ?RAT ((map_mat int_of_rat ((rat_of_int k) \\<^sub>m inv_Z))) * ?RAT ?Z" using r' by simp also have "... = ?RAT ((map_mat int_of_rat ((rat_of_int k) \\<^sub>m inv_Z)) * ?Z)" by (metis RAT_fs_init adj_mat(1) k_inv_Z_eq_adj map_carrier_mat of_int_hom.mat_hom_mult) finally show ?thesis by (rule of_int_hom.mat_hom_inj) qed show ?thesis proof (rule mat_mult_sub_lattice[OF _ fs_init]) have rw: "of_int_hom.mat_hom (map_mat int_of_rat ((rat_of_int k) \\<^sub>m inv_Z)) = map_mat int_of_rat ((rat_of_int k) \\<^sub>m inv_Z)" by auto have "mat_of_rows n (Matrix.rows (k \\<^sub>m 1\<^sub>m m)) = (k \\<^sub>m (1\<^sub>m m))" by (metis mn index_one_mat(3) index_smult_mat(3) mat_of_rows_rows) also have "... = of_int_hom.mat_hom (map_mat int_of_rat ((rat_of_int k) \\<^sub>m inv_Z)) * mat_of_rows n fs_init" using r rw by auto finally show "mat_of_rows n (Matrix.rows (k \\<^sub>m 1\<^sub>m m)) = of_int_hom.mat_hom (map_mat int_of_rat ((rat_of_int k) \\<^sub>m inv_Z)) * mat_of_rows n fs_init" . show "set (Matrix.rows (k \\<^sub>m 1\<^sub>m m)) \ carrier_vec n"using mn unfolding Matrix.rows_def by auto show "map_mat int_of_rat (rat_of_int k \\<^sub>m inv_Z) \ carrier_mat (length (Matrix.rows (k \\<^sub>m 1\<^sub>m m))) (length fs_init)" using len fs_init by (simp add: inv_Z) qed qed end context LLL_with_assms begin lemma lattice_of_append_det_preserves: assumes k_det: "k = abs (Determinant.det (mat_of_rows n fs_init))" and mn: "m = n" and A: "A = (mat_of_rows n fs_init) @\<^sub>r (k \\<^sub>m (1\<^sub>m m))" shows "lattice_of (Matrix.rows A) = lattice_of fs_init" proof - have "Matrix.rows (mat_of_rows n fs_init @\<^sub>r k \\<^sub>m 1\<^sub>m m) = (Matrix.rows (mat_of_rows n fs_init) @ Matrix.rows (k \\<^sub>m (1\<^sub>m m)))" by (rule rows_append_rows, insert fs_init len mn, auto) also have "... = (fs_init @ Matrix.rows (k \\<^sub>m (1\<^sub>m m)))" by (simp add: fs_init) finally have rw: "Matrix.rows (mat_of_rows n fs_init @\<^sub>r k \\<^sub>m 1\<^sub>m m) = (fs_init @ Matrix.rows (k \\<^sub>m (1\<^sub>m m)))" . have "lattice_of (Matrix.rows A) = lattice_of (fs_init @ Matrix.rows (k \\<^sub>m (1\<^sub>m m)))" by (rule arg_cong[of _ _ lattice_of], auto simp add: A rw) also have "... = lattice_of fs_init" proof (cases "k = Determinant.det (mat_of_rows n fs_init)") case True then show ?thesis by (rule already_in_lattice_append[symmetric, OF fs_init lattice_of_kId_subset_fs_init[OF _ mn]], insert mn, auto simp add: Matrix.rows_def) next case False hence k2: "k = -Determinant.det (mat_of_rows n fs_init)" using k_det by auto have l: "lattice_of (Matrix.rows (- k \\<^sub>m 1\<^sub>m m)) \ lattice_of fs_init" by (rule lattice_of_kId_subset_fs_init[OF _ mn], insert k2, auto) have l2: "lattice_of (Matrix.rows (- k \\<^sub>m 1\<^sub>m m)) = lattice_of (Matrix.rows (k \\<^sub>m 1\<^sub>m m))" proof (rule mat_mult_invertible_lattice_eq) let ?P = "(- 1::int) \\<^sub>m 1\<^sub>m m" show P: "?P \ carrier_mat m m" by simp have "det ?P = 1 \ det ?P = -1" unfolding det_smult by (auto simp add: minus_1_power_even) - hence "det ?P dvd 1" by (smt minus_dvd_iff one_dvd) + hence "det ?P dvd 1" by (smt (verit) minus_dvd_iff one_dvd) thus " invertible_mat ?P" unfolding invertible_iff_is_unit_JNF[OF P] . have "(- k \\<^sub>m 1\<^sub>m m) = ?P * (k \\<^sub>m 1\<^sub>m m)" unfolding mat_diag_smult[symmetric] unfolding mat_diag_diag by auto thus " mat_of_rows n (Matrix.rows (- k \\<^sub>m 1\<^sub>m m)) = of_int_hom.mat_hom ?P * mat_of_rows n (Matrix.rows (k \\<^sub>m 1\<^sub>m m))" by (metis mn index_one_mat(3) index_smult_mat(3) mat_of_rows_rows of_int_mat_hom_int_id) show " set (Matrix.rows (- k \\<^sub>m 1\<^sub>m m)) \ carrier_vec n" and "set (Matrix.rows (k \\<^sub>m 1\<^sub>m m)) \ carrier_vec n" using assms(2) one_carrier_mat set_rows_carrier smult_carrier_mat by blast+ qed (insert mn, auto) hence l2: "lattice_of (Matrix.rows (k \\<^sub>m 1\<^sub>m m)) \ lattice_of fs_init" using l by auto show ?thesis by (rule already_in_lattice_append[symmetric, OF fs_init l2], insert mn one_carrier_mat set_rows_carrier smult_carrier_mat, blast) qed finally show ?thesis . qed text \This is another key lemma. Here, $A$ is the initial matrix @{text "(mat_of_rows n fs_init)"} augmented with $m$ rows $(k,0,\dots,0),(0,k,0,\dots,0), \dots , (0,\dots,0,k)$ where $k$ is the determinant of @{text "(mat_of_rows n fs_init)"}. With the algorithm of the article, we obtain @{text "H = H' @\<^sub>r (0\<^sub>m m n)"} by means of an invertible matrix $P$ (which is computable). Then, $H$ is the HNF of $A$. The lemma shows that $H'$ is the HNF of @{text "(mat_of_rows n fs_init)"} and that there exists an invertible matrix to carry out the transformation.\ lemma Hermite_append_det_id: assumes k_det: "k = abs (Determinant.det (mat_of_rows n fs_init))" and mn: "m = n" and A: "A = (mat_of_rows n fs_init) @\<^sub>r (k \\<^sub>m (1\<^sub>m m))" and H': "H'\ carrier_mat m n" and H_append: "H = H' @\<^sub>r (0\<^sub>m m n)" and P: "P \ carrier_mat (m+m) (m+m)" and inv_P: "invertible_mat P" and A_PH: "A = P * H" and HNF_H: "Hermite_JNF associates res H" shows "Hermite_JNF associates res H'" and "(\P'. invertible_mat P' \ P' \ carrier_mat m m \ (mat_of_rows n fs_init) = P' * H')" proof - have A_carrier: "A \ carrier_mat (m+m) n" using A mn len by auto let ?A' = "(mat_of_rows n fs_init)" let ?H' = "submatrix H {0..m" by (simp add: mn) have H: "H \ carrier_mat (m + m) n" using H_append H' by auto have submatrix_carrier: "submatrix H {0.. carrier_mat m n" by (rule submatrix_carrier_first[OF H], auto) have H'_eq: "H' = ?H'" proof (rule eq_matI) fix i j assume i: "i < dim_row ?H'" and j: "j < dim_col ?H'" have im: "im m n) $$ (i - m, j))" unfolding H_append by (rule append_rows_nth[OF H'], insert im jn, auto) also have "... = H' $$ (i,j)" using H' im jn by simp finally show "H' $$ (i, j) = ?H' $$ (i, j)" .. qed (insert H' submatrix_carrier, auto) show HNF_H': "Hermite_JNF associates res H'" unfolding H'_eq mn by (rule HNF_submatrix[OF HNF_H H], insert nm, simp) have L_fs_init_A: "lattice_of (fs_init) = lattice_of (Matrix.rows A)" by (rule lattice_of_append_det_preserves[symmetric, OF k_det mn A]) have L_H'_H: "lattice_of (Matrix.rows H') = lattice_of (Matrix.rows H)" using H_append H' lattice_of_append_zero_rows by blast have L_A_H: "lattice_of (Matrix.rows A) = lattice_of (Matrix.rows H)" proof (rule mat_mult_invertible_lattice_eq[OF _ _ P inv_P]) show "set (Matrix.rows A) \ carrier_vec n" using A_carrier set_rows_carrier by blast show "set (Matrix.rows H) \ carrier_vec n" using H set_rows_carrier by blast show "length (Matrix.rows A) = m + m" using A_carrier by auto show "length (Matrix.rows H) = m + m" using H by auto show "mat_of_rows n (Matrix.rows A) = of_int_hom.mat_hom P * mat_of_rows n (Matrix.rows H)" by (metis A_carrier H A_PH carrier_matD(2) mat_of_rows_rows of_int_mat_hom_int_id) qed have L_fs_init_H': "lattice_of fs_init = lattice_of (Matrix.rows H')" using L_fs_init_A L_A_H L_H'_H by auto have exists_P2: "\P2. P2 \ carrier_mat n n \ invertible_mat P2 \ mat_of_rows n (Matrix.rows H') = P2 * H'" by (rule exI[of _ "1\<^sub>m n"], insert H' mn, auto) have exist_P': "\P'\carrier_mat n n. invertible_mat P' \ mat_of_rows n fs_init = P' * mat_of_rows n (Matrix.rows H')" by (rule eq_lattice_imp_mat_mult_invertible_rows[OF fs_init _ lin_dep len[unfolded mn] _ L_fs_init_H'], insert H' mn set_rows_carrier, auto) thus "\P'. invertible_mat P' \ P' \ carrier_mat m m \ (mat_of_rows n fs_init) = P' * H'" by (metis mn H' carrier_matD(2) mat_of_rows_rows) qed end context proper_mod_operation begin (* Perform the modulo D operation to reduce the element A$$(a,j), assuming A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m m))*) definition "reduce_element_mod_D (A::int mat) a j D m = (if j = 0 then if D dvd A$$(a,j) then addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A else A else addrow (-((A$$(a,j) gdiv D))) a (j + m) A)" definition "reduce_element_mod_D_abs (A::int mat) a j D m = (if j = 0 \ D dvd A$$(a,j) then addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A else addrow (-((A$$(a,j) gdiv D))) a (j + m) A)" lemma reduce_element_mod_D_preserves_dimensions: shows [simp]: "dim_row (reduce_element_mod_D A a j D m) = dim_row A" and [simp]: "dim_col (reduce_element_mod_D A a j D m) = dim_col A" and [simp]: "dim_row (reduce_element_mod_D_abs A a j D m) = dim_row A" and [simp]: "dim_col (reduce_element_mod_D_abs A a j D m) = dim_col A" by (auto simp add: reduce_element_mod_D_def reduce_element_mod_D_abs_def Let_def split_beta) lemma reduce_element_mod_D_carrier: shows "reduce_element_mod_D A a j D m \ carrier_mat (dim_row A) (dim_col A)" and "reduce_element_mod_D_abs A a j D m \ carrier_mat (dim_row A) (dim_col A)" by auto lemma reduce_element_mod_D_invertible_mat: assumes A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and A': "A' \ carrier_mat m n" and a: "an" shows "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D A a j D m = P * A" (is ?thesis1) and "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D_abs A a j D m = P * A" (is ?thesis2) unfolding atomize_conj proof (rule conjI; cases "j = 0 \ D dvd A$$(a,j)") case True let ?P = "addrow_mat (m+n) (- (A $$ (a, j) gdiv D) + 1) a (j + m)" have A: "A \ carrier_mat (m + n) n" using A_def A' mn by auto have "reduce_element_mod_D A a j D m = addrow (- (A $$ (a, j) gdiv D) + 1) a (j + m) A" unfolding reduce_element_mod_D_def using True by auto also have "... = ?P * A" by (rule addrow_mat[OF A], insert j mn, auto) finally have "reduce_element_mod_D A a j D m = ?P * A" . moreover have P: "?P \ carrier_mat (m+n) (m+n)" by simp moreover have inv_P: "invertible_mat ?P" by (metis addrow_mat_carrier a det_addrow_mat dvd_mult_right invertible_iff_is_unit_JNF mult.right_neutral not_add_less2 semiring_gcd_class.gcd_dvd1) ultimately show ?thesis1 by blast have "reduce_element_mod_D_abs A a j D m = addrow (- (A $$ (a, j) gdiv D) + 1) a (j + m) A" unfolding reduce_element_mod_D_abs_def using True by auto also have "... = ?P * A" by (rule addrow_mat[OF A], insert j mn, auto) finally have "reduce_element_mod_D_abs A a j D m = ?P * A" . thus ?thesis2 using P inv_P by blast next case False note nc1 = False let ?P = "addrow_mat (m+n) (- (A $$ (a, j) gdiv D)) a (j + m)" have A: "A \ carrier_mat (m + n) n" using A_def A' mn by auto have P: "?P \ carrier_mat (m+n) (m+n)" by simp have inv_P: "invertible_mat ?P" by (metis addrow_mat_carrier a det_addrow_mat dvd_mult_right invertible_iff_is_unit_JNF mult.right_neutral not_add_less2 semiring_gcd_class.gcd_dvd1) show ?thesis1 proof (cases "j = 0") case True have "reduce_element_mod_D A a j D m = A" unfolding reduce_element_mod_D_def using True nc1 by auto thus ?thesis1 by (metis A_def A' carrier_append_rows invertible_mat_one left_mult_one_mat one_carrier_mat smult_carrier_mat) next case False have "reduce_element_mod_D A a j D m = addrow (- (A $$ (a, j) gdiv D)) a (j + m) A" unfolding reduce_element_mod_D_def using False by auto also have "... = ?P * A" by (rule addrow_mat[OF A], insert j mn, auto) finally have "reduce_element_mod_D A a j D m = ?P * A" . thus ?thesis using P inv_P by blast qed have "reduce_element_mod_D_abs A a j D m = addrow (- (A $$ (a, j) gdiv D)) a (j + m) A" unfolding reduce_element_mod_D_abs_def using False by auto also have "... = ?P * A" by (rule addrow_mat[OF A], insert j mn, auto) finally have "reduce_element_mod_D_abs A a j D m = ?P * A" . thus ?thesis2 using P inv_P by blast qed lemma reduce_element_mod_D_append: assumes A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and A': "A' \ carrier_mat m n" and a: "an" shows "reduce_element_mod_D A a j D m = mat_of_rows n [Matrix.row (reduce_element_mod_D A a j D m) i. i \ [0..r (D \\<^sub>m (1\<^sub>m n))" (is "?lhs = ?A' @\<^sub>r ?D") and "reduce_element_mod_D_abs A a j D m = mat_of_rows n [Matrix.row (reduce_element_mod_D_abs A a j D m) i. i \ [0..r (D \\<^sub>m (1\<^sub>m n))" (is "?lhs_abs = ?A'_abs @\<^sub>r ?D") unfolding atomize_conj proof (rule conjI; rule eq_matI) let ?xs = "(map (Matrix.row (reduce_element_mod_D A a j D m)) [0.. carrier_mat (m+n) n" and lhs_carrier_abs: "?lhs_abs \ carrier_mat (m+n) n" by (metis (no_types, lifting) add.comm_neutral append_rows_def A_def A' carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_element_mod_D_preserves_dimensions)+ have map_A_carrier[simp]: "?A' \ carrier_mat m n" and map_A_carrier_abs[simp]: "?A'_abs \ carrier_mat m n" by (simp add: mat_of_rows_def)+ have AD_carrier[simp]: "?A' @\<^sub>r ?D \ carrier_mat (m+n) n" and AD_carrier_abs[simp]: "?A'_abs @\<^sub>r ?D \ carrier_mat (m+n) n" by (rule carrier_append_rows, insert lhs_carrier mn, auto) show "dim_row (?lhs) = dim_row (?A' @\<^sub>r ?D)" and "dim_col (?lhs) = dim_col (?A' @\<^sub>r ?D)" "dim_row (?lhs_abs) = dim_row (?A'_abs @\<^sub>r ?D)" and "dim_col (?lhs_abs) = dim_col (?A'_abs @\<^sub>r ?D)" using lhs_carrier lhs_carrier_abs AD_carrier AD_carrier_abs unfolding carrier_mat_def by simp+ show "?lhs $$ (i, ja) = (?A' @\<^sub>r ?D) $$ (i, ja)" if i: "i < dim_row (?A' @\<^sub>r ?D)" and ja: "ja < dim_col (?A' @\<^sub>r ?D)" for i ja proof (cases "ir ?D) $$ (i, ja) = ?A' $$ (i,ja)" by (metis (no_types, lifting) Nat.add_0_right True append_rows_def diff_zero i index_mat_four_block index_zero_mat(3) ja length_map length_upt mat_of_rows_carrier(2)) also have "... = ?xs ! i $v ja" by (rule mat_of_rows_index, insert i True ja , auto simp add: append_rows_def) also have "... = ?lhs $$ (i,ja)" by (rule map_first_rows_index, insert assms lhs_carrier True i ja_n, auto) finally show ?thesis .. next case False have ja_n: "ja < n" by (metis Nat.add_0_right append_rows_def index_mat_four_block(3) index_zero_mat(3) ja mat_of_rows_carrier(3)) have "(?A' @\<^sub>r ?D) $$ (i, ja) =?D $$ (i-m,ja)" - by (smt False Nat.add_0_right map_A_carrier append_rows_def carrier_matD i + by (smt (verit) False Nat.add_0_right map_A_carrier append_rows_def carrier_matD i index_mat_four_block index_zero_mat(3) ja_n) also have "... = ?lhs $$ (i,ja)" by (metis (no_types, lifting) False Nat.add_0_right map_A_carrier append_rows_def A_def A' a carrier_matD i index_mat_addrow(1) index_mat_four_block(1,2) index_zero_mat(3) ja_n lhs_carrier reduce_element_mod_D_def reduce_element_mod_D_preserves_dimensions) finally show ?thesis .. qed fix i ja assume i: "i < dim_row (?A'_abs @\<^sub>r ?D)" and ja: "ja < dim_col (?A'_abs @\<^sub>r ?D)" have ja_n: "ja < n" by (metis Nat.add_0_right append_rows_def index_mat_four_block(3) index_zero_mat(3) ja mat_of_rows_carrier(3)) show "?lhs_abs $$ (i, ja) = (?A'_abs @\<^sub>r ?D) $$ (i, ja)" proof (cases "ir ?D) $$ (i, ja) = ?A'_abs $$ (i,ja)" by (metis (no_types, lifting) Nat.add_0_right True append_rows_def diff_zero i index_mat_four_block index_zero_mat(3) ja length_map length_upt mat_of_rows_carrier(2)) also have "... = ?xs_abs ! i $v ja" by (rule mat_of_rows_index, insert i True ja , auto simp add: append_rows_def) also have "... = ?lhs_abs $$ (i,ja)" by (rule map_first_rows_index, insert assms lhs_carrier_abs True i ja_n, auto) finally show ?thesis .. next case False have "(?A'_abs @\<^sub>r ?D) $$ (i, ja) = ?D $$ (i-m,ja)" - by (smt False Nat.add_0_right map_A_carrier_abs append_rows_def carrier_matD i + by (smt (verit) False Nat.add_0_right map_A_carrier_abs append_rows_def carrier_matD i index_mat_four_block index_zero_mat(3) ja_n) also have "... = ?lhs_abs $$ (i,ja)" by (metis (no_types, lifting) False Nat.add_0_right map_A_carrier_abs append_rows_def A_def A' a carrier_matD i index_mat_addrow(1) index_mat_four_block(1,2) index_zero_mat(3) ja_n lhs_carrier_abs reduce_element_mod_D_abs_def reduce_element_mod_D_preserves_dimensions) finally show ?thesis .. qed qed lemma reduce_append_rows_eq: assumes A': "A' \ carrier_mat m n" and A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and a: "a 0" shows "reduce a x D A = mat_of_rows n [Matrix.row ((reduce a x D A)) i. i \ [0..r D \\<^sub>m 1\<^sub>m n" (is ?thesis1) and "reduce_abs a x D A = mat_of_rows n [Matrix.row ((reduce_abs a x D A)) i. i \ [0..r D \\<^sub>m 1\<^sub>m n" (is ?thesis2) unfolding atomize_conj proof (rule conjI; rule matrix_append_rows_eq_if_preserves) let ?reduce_ax = "reduce a x D A" let ?reduce_abs = "reduce_abs a x D A" obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) have A: "A: carrier_mat (m+n) n" by (simp add: A_def A') show D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" and "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by simp+ show "?reduce_ax \ carrier_mat (m + n) n" "?reduce_abs \ carrier_mat (m + n) n" by (metis Nat.add_0_right append_rows_def A' A_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2) index_zero_mat(3) reduce_preserves_dimensions)+ show "\i\{m..ja\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" and "\i\{m..ja\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" unfolding atomize_conj proof (rule conjI; rule+) fix i ja assume i: "i \ {m.. a" using i a by auto have i_not_x: "i \ x" using i xm by auto have "?reduce_ax $$ (i,ja) = A $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using ja_dc i_dr i_not_a i_not_x by auto also have "... = (if i < dim_row A' then A' $$(i,ja) else (D \\<^sub>m (1\<^sub>m n))$$(i-m,ja))" by (unfold A_def, rule append_rows_nth[OF A' D1 _ ja], insert A i_dr, simp) also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" using i A' by auto finally show "?reduce_ax $$ (i,ja) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" . have "?reduce_abs $$ (i,ja) = A $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using ja_dc i_dr i_not_a i_not_x by auto also have "... = (if i < dim_row A' then A' $$(i,ja) else (D \\<^sub>m (1\<^sub>m n))$$(i-m,ja))" by (unfold A_def, rule append_rows_nth[OF A' D1 _ ja], insert A i_dr, simp) also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" using i A' by auto finally show "?reduce_abs $$ (i,ja) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" . qed qed fun reduce_row_mod_D where "reduce_row_mod_D A a [] D m = A" | "reduce_row_mod_D A a (x # xs) D m = reduce_row_mod_D (reduce_element_mod_D A a x D m) a xs D m" fun reduce_row_mod_D_abs where "reduce_row_mod_D_abs A a [] D m = A" | "reduce_row_mod_D_abs A a (x # xs) D m = reduce_row_mod_D_abs (reduce_element_mod_D_abs A a x D m) a xs D m" lemma reduce_row_mod_D_preserves_dimensions: shows [simp]: "dim_row (reduce_row_mod_D A a xs D m) = dim_row A" and [simp]: "dim_col (reduce_row_mod_D A a xs D m) = dim_col A" by (induct A a xs D m rule: reduce_row_mod_D.induct, auto) lemma reduce_row_mod_D_preserves_dimensions_abs: shows [simp]: "dim_row (reduce_row_mod_D_abs A a xs D m) = dim_row A" and [simp]: "dim_col (reduce_row_mod_D_abs A a xs D m) = dim_col A" by (induct A a xs D m rule: reduce_row_mod_D_abs.induct, auto) lemma reduce_row_mod_D_invertible_mat: assumes A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and A': "A' \ carrier_mat m n" and a: "aj\set xs. jn" shows "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_row_mod_D A a xs D m = P * A" using assms proof (induct A a xs D m arbitrary: A' rule: reduce_row_mod_D.induct) case (1 A a D m) show ?case by (rule exI[of _ "1\<^sub>m (m+n)"], insert "1.prems", auto simp add: append_rows_def) next case (2 A a x xs D m) let ?reduce_xs = "(reduce_element_mod_D A a x D m)" have 1: "reduce_row_mod_D A a (x # xs) D m = reduce_row_mod_D ?reduce_xs a xs D m" by simp have "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D A a x D m = P * A" by (rule reduce_element_mod_D_invertible_mat, insert "2.prems", auto) from this obtain P where P: "P \ carrier_mat (m+n) (m+n)" and inv_P: "invertible_mat P" and R_P: "reduce_element_mod_D A a x D m = P * A" by auto have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ reduce_row_mod_D ?reduce_xs a xs D m = P * ?reduce_xs" proof (rule "2.hyps") let ?A' = "mat_of_rows n [Matrix.row (reduce_element_mod_D A a x D m) i. i \ [0..r (D \\<^sub>m (1\<^sub>m n))" by (rule reduce_element_mod_D_append, insert "2.prems", auto) qed (insert "2.prems", auto) from this obtain P2 where P2: "P2 \ carrier_mat (m + n) (m + n)" and inv_P2: "invertible_mat P2" and R_P2: "reduce_row_mod_D ?reduce_xs a xs D m = P2 * ?reduce_xs" by auto have "invertible_mat (P2 * P)" using P P2 inv_P inv_P2 invertible_mult_JNF by blast moreover have "(P2 * P) \ carrier_mat (m+n) (m+n)" using P2 P by auto moreover have "reduce_row_mod_D A a (x # xs) D m = (P2 * P) * A" - by (smt P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv + by (smt (verit) P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv index_mult_mat reduce_row_mod_D_preserves_dimensions) ultimately show ?case by blast qed lemma reduce_row_mod_D_abs_invertible_mat: assumes A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and A': "A' \ carrier_mat m n" and a: "aj\set xs. jn" shows "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_row_mod_D_abs A a xs D m = P * A" using assms proof (induct A a xs D m arbitrary: A' rule: reduce_row_mod_D_abs.induct) case (1 A a D m) show ?case by (rule exI[of _ "1\<^sub>m (m+n)"], insert "1.prems", auto simp add: append_rows_def) next case (2 A a x xs D m) let ?reduce_xs = "(reduce_element_mod_D_abs A a x D m)" have 1: "reduce_row_mod_D_abs A a (x # xs) D m = reduce_row_mod_D_abs ?reduce_xs a xs D m" by simp have "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D_abs A a x D m = P * A" by (rule reduce_element_mod_D_invertible_mat, insert "2.prems", auto) from this obtain P where P: "P \ carrier_mat (m+n) (m+n)" and inv_P: "invertible_mat P" and R_P: "reduce_element_mod_D_abs A a x D m = P * A" by auto have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ reduce_row_mod_D_abs ?reduce_xs a xs D m = P * ?reduce_xs" proof (rule "2.hyps") let ?A' = "mat_of_rows n [Matrix.row (reduce_element_mod_D_abs A a x D m) i. i \ [0..r (D \\<^sub>m (1\<^sub>m n))" by (rule reduce_element_mod_D_append, insert "2.prems", auto) qed (insert "2.prems", auto) from this obtain P2 where P2: "P2 \ carrier_mat (m + n) (m + n)" and inv_P2: "invertible_mat P2" and R_P2: "reduce_row_mod_D_abs ?reduce_xs a xs D m = P2 * ?reduce_xs" by auto have "invertible_mat (P2 * P)" using P P2 inv_P inv_P2 invertible_mult_JNF by blast moreover have "(P2 * P) \ carrier_mat (m+n) (m+n)" using P2 P by auto moreover have "reduce_row_mod_D_abs A a (x # xs) D m = (P2 * P) * A" - by (smt P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv + by (smt (verit) P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv index_mult_mat reduce_row_mod_D_preserves_dimensions_abs) ultimately show ?case by blast qed end context proper_mod_operation begin lemma dvd_gdiv_mult_left[simp]: assumes "b > 0" "b dvd a" shows "b * (a gdiv b) = a" using dvd_gdiv_mult_right[OF assms] by (auto simp: ac_simps) lemma reduce_element_mod_D: assumes A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and A': "A' \ carrier_mat m n" and a: "a\m" and j: "jn" and D: "D > 0" shows "reduce_element_mod_D A a j D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k = j then if j = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" (is "_ = ?A") and "reduce_element_mod_D_abs A a j D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k = j then if j = 0 \ D dvd A$$(i,k) then D else A$$(i,k) gmod D else A$$(i,k))" (is "_ = ?A_abs") unfolding atomize_conj proof (rule conjI; rule eq_matI) have A: "A \ carrier_mat (m+n) n" using A_def A' by simp have dr: "dim_row ?A = dim_row ?A_abs" and dc: "dim_col ?A = dim_col ?A_abs" by auto have 1: "reduce_element_mod_D A a j D m $$ (i, ja) = ?A $$ (i, ja)" (is ?thesis1) and 2: "reduce_element_mod_D_abs A a j D m $$ (i, ja) = ?A_abs $$ (i, ja)" (is ?thesis2) if i: "i < dim_row ?A" and ja: "ja < dim_col ?A" for i ja unfolding atomize_conj proof (rule conjI; cases "i=a") case False have "reduce_element_mod_D A a j D m = (if j = 0 then if D dvd A$$(a,j) then addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A else A else addrow (-((A$$(a,j) gdiv D))) a (j + m) A)" unfolding reduce_element_mod_D_def by simp also have "... $$ (i,ja) = A $$ (i, ja)" unfolding mat_addrow_def using False ja i by auto also have "... = ?A $$ (i,ja)" using False using i ja by auto finally show ?thesis1 . have "reduce_element_mod_D_abs A a j D m $$ (i,ja) = A $$ (i, ja)" unfolding reduce_element_mod_D_abs_def mat_addrow_def using False ja i by auto also have "... = ?A_abs $$ (i,ja)" using False using i ja by auto finally show ?thesis2 . next case True note ia = True have "reduce_element_mod_D A a j D m = (if j = 0 then if D dvd A$$(a,j) then addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A else A else addrow (-((A$$(a,j) gdiv D))) a (j + m) A)" unfolding reduce_element_mod_D_def by simp also have "... $$ (i,ja) = ?A $$ (i,ja)" proof (cases "ja = j") case True note ja_j = True have "A $$ (j + m, ja) = (D \\<^sub>m (1\<^sub>m n)) $$ (j,ja)" by (rule append_rows_nth2[OF A' _ A_def ], insert j ja A mn, auto) also have "... = D * (1\<^sub>m n) $$ (j,ja)" by (rule index_smult_mat, insert ja j A mn, auto) also have "... = D" by (simp add: True j mn) finally have A_ja_jaD: "A $$ (j + m, ja) = D" . show ?thesis proof (cases "j=0 \ D dvd A$$(a,j)") case True have 1: "reduce_element_mod_D A a j D m = addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A " using True ia ja_j unfolding reduce_element_mod_D_def by auto also have "... $$(i,ja) = (- (A $$ (a, j) gdiv D) + 1) * A $$ (j + m, ja) + A $$ (i, ja)" unfolding mat_addrow_def using True ja_j ia using A i j by auto also have "... = D" proof - have "A $$ (i, ja) + D * - (A $$ (i, ja) gdiv D) = 0" using True ia ja_j D by force then show ?thesis by (metis A_ja_jaD ab_semigroup_add_class.add_ac(1) add.commute add_right_imp_eq ia int_distrib(2) ja_j more_arith_simps(3) mult.commute mult_cancel_right1) qed also have "... = ?A $$ (i,ja)" using True ia A i j ja_j by auto finally show ?thesis using True 1 by auto next case False show ?thesis proof (cases "ja=0") case True then show ?thesis using False i ja ja_j by force next case False have "?A $$ (i,ja) = A $$ (i, ja) gmod D" using True ia A i j False by auto also have "... = A $$ (i, ja) - ((A $$ (i, ja) gdiv D) * D)" by (subst gmod_gdiv[OF D], auto) also have "... = - (A $$ (a, j) gdiv D) * A $$ (j + m, ja) + A $$ (i, ja)" unfolding A_ja_jaD by (simp add: True ia) finally show ?thesis using A False True i ia j by auto qed qed next case False have "A $$ (j + m, ja) = (D \\<^sub>m (1\<^sub>m n)) $$ (j,ja)" by (rule append_rows_nth2[OF A' _ A_def ], insert j mn ja A, auto) also have "... = D * (1\<^sub>m n) $$ (j,ja)" by (rule index_smult_mat, insert ja j A mn, auto) also have "... = 0" using False using A a mn ja j by force finally have A_am_ja0: "A $$ (j + m, ja) = 0" . then show ?thesis using False i ja by fastforce qed finally show ?thesis1 . have "reduce_element_mod_D_abs A a j D m = (if j = 0 \ D dvd A$$(a,j) then addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A else addrow (-((A$$(a,j) gdiv D))) a (j + m) A)" unfolding reduce_element_mod_D_abs_def by simp also have "... $$ (i,ja) = ?A_abs $$ (i,ja)" proof (cases "ja = j") case True note ja_j = True have "A $$ (j + m, ja) = (D \\<^sub>m (1\<^sub>m n)) $$ (j,ja)" by (rule append_rows_nth2[OF A' _ A_def ], insert j ja A mn, auto) also have "... = D * (1\<^sub>m n) $$ (j,ja)" by (rule index_smult_mat, insert ja j A mn, auto) also have "... = D" by (simp add: True j mn) finally have A_ja_jaD: "A $$ (j + m, ja) = D" . show ?thesis proof (cases "j=0 \ D dvd A$$(a,j)") case True have 1: "reduce_element_mod_D_abs A a j D m = addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A " using True ia ja_j unfolding reduce_element_mod_D_abs_def by auto also have "... $$(i,ja) = (- (A $$ (a, j) gdiv D) + 1) * A $$ (j + m, ja) + A $$ (i, ja)" unfolding mat_addrow_def using True ja_j ia using A i j by auto also have "... = D" proof - have "A $$ (i, ja) + D * - (A $$ (i, ja) gdiv D) = 0" using True ia ja_j D by force then show ?thesis by (metis A_ja_jaD ab_semigroup_add_class.add_ac(1) add.commute add_right_imp_eq ia int_distrib(2) ja_j more_arith_simps(3) mult.commute mult_cancel_right1) qed also have "... = ?A_abs $$ (i,ja)" using True ia A i j ja_j by auto finally show ?thesis using True 1 by auto next case False have i: "i\<^sub>m (1\<^sub>m n)) $$ (j,ja)" by (rule append_rows_nth2[OF A' _ A_def ], insert j mn ja A, auto) also have "... = D * (1\<^sub>m n) $$ (j,ja)" by (rule index_smult_mat, insert ja j A mn, auto) also have "... = 0" using False using A a mn ja j by force finally have A_am_ja0: "A $$ (j + m, ja) = 0" . then show ?thesis using False i ja by fastforce qed finally show ?thesis2 . qed from this show "\i ja. i ja < dim_col ?A \ reduce_element_mod_D A a j D m $$ (i, ja) = ?A $$ (i, ja)" and "\i ja. i ja < dim_col ?A_abs \ reduce_element_mod_D_abs A a j D m $$ (i, ja) = ?A_abs $$ (i, ja)" using dr dc by auto next show "dim_row (reduce_element_mod_D A a j D m) = dim_row ?A" and "dim_col (reduce_element_mod_D A a j D m) = dim_col ?A" "dim_row (reduce_element_mod_D_abs A a j D m) = dim_row ?A_abs" and "dim_col (reduce_element_mod_D_abs A a j D m) = dim_col ?A_abs" by auto qed lemma reduce_row_mod_D: assumes A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and A': "A' \ carrier_mat m n" and a: "aj\set xs. jn" and "D > 0" shows "reduce_row_mod_D A a xs D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k \ set xs then if k = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" using assms proof (induct A a xs D m arbitrary: A' rule: reduce_row_mod_D.induct) case (1 A a D m) then show ?case by force next case (2 A a x xs D m) let ?reduce_xs = "(reduce_element_mod_D A a x D m)" have 1: "reduce_row_mod_D A a (x # xs) D m = reduce_row_mod_D ?reduce_xs a xs D m" by simp have 2: "reduce_element_mod_D A a j D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k = j then if j = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" if "j(i,k). if i = a \ k \ set xs then if k=0 then if D dvd ?reduce_xs $$ (i, k) then D else ?reduce_xs $$ (i, k) else ?reduce_xs $$ (i, k) gmod D else ?reduce_xs $$ (i, k))" proof (rule "2.hyps") let ?A' = "mat_of_rows n [Matrix.row (reduce_element_mod_D A a x D m) i. i \ [0..r (D \\<^sub>m (1\<^sub>m n))" by (rule reduce_element_mod_D_append, insert "2.prems", auto) qed (insert "2.prems", auto) also have "... = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k \ set (x # xs) then if k = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" (is "?lhs = ?rhs") proof (rule eq_matI) show "dim_row ?lhs = dim_row ?rhs" and "dim_col ?lhs = dim_col ?rhs" by auto fix i j assume i: "i j \ set xs") case True note ia_jxs = True have j_not_x: "j\x" using "2.prems"(5) True by auto show ?thesis proof (cases "j=0 \ D dvd ?reduce_xs $$(i,j)") case True have "?lhs $$ (i,j) = D" using True i j ia_jxs by auto also have "... = ?rhs $$ (i,j)" using i j j_not_x - by (smt "2" calculation dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2) xn) + by (smt (verit) "2" calculation dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2) xn) finally show ?thesis . next case False note nc1 = False show ?thesis proof (cases "j=0") case True then show ?thesis - by (smt (z3) "2" False case_prod_conv dim_col_mat(1) dim_row_mat(1) i index_mat(1) j j_not_x xn) + by (smt (verit) "2" False case_prod_conv dim_col_mat(1) dim_row_mat(1) i index_mat(1) j j_not_x xn) next case False have "?lhs $$ (i,j) = ?reduce_xs $$ (i, j) gmod D" using True False i j by auto also have "... = A $$ (i,j) gmod D" using 2[OF xn] j_not_x i j by auto also have "... = ?rhs $$ (i,j)" using i j j_not_x \D > 0\ using False True dim_col_mat(1) dim_row_mat(1) index_mat(1) list.set_intros(2) old.prod.case by auto finally show ?thesis . qed qed next case False show ?thesis using 2 i j xn - by (smt False dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2)) + by (smt (verit) False dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2)) qed qed finally show ?case using 1 by simp qed lemma reduce_row_mod_D_abs: assumes A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and A': "A' \ carrier_mat m n" and a: "aj\set xs. jn" and "D > 0" shows "reduce_row_mod_D_abs A a xs D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k \ set xs then if k = 0 \ D dvd A$$(i,k) then D else A$$(i,k) gmod D else A$$(i,k))" using assms proof (induct A a xs D m arbitrary: A' rule: reduce_row_mod_D_abs.induct) case (1 A a D m) then show ?case by force next case (2 A a x xs D m) let ?reduce_xs = "(reduce_element_mod_D_abs A a x D m)" have 1: "reduce_row_mod_D_abs A a (x # xs) D m = reduce_row_mod_D_abs ?reduce_xs a xs D m" by simp have 2: "reduce_element_mod_D_abs A a j D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k = j then if j = 0 \ D dvd A$$(i,k) then D else A$$(i,k) gmod D else A$$(i,k))" if "j(i,k). if i = a \ k \ set xs then if k=0 \ D dvd ?reduce_xs $$ (i, k) then D else ?reduce_xs $$ (i, k) gmod D else ?reduce_xs $$ (i, k))" proof (rule "2.hyps") let ?A' = "mat_of_rows n [Matrix.row (reduce_element_mod_D_abs A a x D m) i. i \ [0..r (D \\<^sub>m (1\<^sub>m n))" by (rule reduce_element_mod_D_append, insert "2.prems", auto) qed (insert "2.prems", auto) also have "... = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k \ set (x # xs) then if k = 0 \ D dvd A$$(i,k) then D else A$$(i,k) gmod D else A$$(i,k))" (is "?lhs = ?rhs") proof (rule eq_matI) show "dim_row ?lhs = dim_row ?rhs" and "dim_col ?lhs = dim_col ?rhs" by auto fix i j assume i: "i j \ set xs") case True note ia_jxs = True have j_not_x: "j\x" using "2.prems"(5) True by auto show ?thesis proof (cases "j=0 \ D dvd ?reduce_xs $$(i,j)") case True have "?lhs $$ (i,j) = D" using True i j ia_jxs by auto also have "... = ?rhs $$ (i,j)" using i j j_not_x - by (smt "2" calculation dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2) xn) + by (smt (verit) "2" calculation dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2) xn) finally show ?thesis . next case False have "?lhs $$ (i,j) = ?reduce_xs $$ (i, j) gmod D" using True False i j by auto also have "... = A $$ (i,j) gmod D" using 2[OF xn] j_not_x i j by auto also have "... = ?rhs $$ (i,j)" using i j j_not_x \D > 0\ using "2" False True dim_col_mat(1) dim_row_mat(1) index_mat(1) list.set_intros(2) old.prod.case xn by auto finally show ?thesis . qed next case False show ?thesis using 2 i j xn - by (smt False dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2)) + by (smt (verit) False dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2)) qed qed finally show ?case using 1 by simp qed end text \Now, we prove some transfer rules to connect B\'ezout matrices in HOL Analysis and JNF\ (*Connecting Bezout Matrix in HOL Analysis (thm bezout_matrix_def) and JNF (thm bezout_matrix_JNF_def)*) lemma HMA_bezout_matrix[transfer_rule]: shows "((Mod_Type_Connect.HMA_M :: _ \ 'a :: {bezout_ring} ^ 'n :: mod_type ^ 'm :: mod_type \ _) ===> (Mod_Type_Connect.HMA_I :: _ \ 'm \ _) ===> (Mod_Type_Connect.HMA_I :: _ \ 'm \ _) ===> (Mod_Type_Connect.HMA_I :: _ \ 'n \ _) ===> (=) ===> (Mod_Type_Connect.HMA_M)) (bezout_matrix_JNF) (bezout_matrix)" proof (intro rel_funI, goal_cases) case (1 A A' a a' b b' j j' bezout bezout') note HMA_AA'[transfer_rule] = "1"(1) note HMI_aa'[transfer_rule] = "1"(2) note HMI_bb'[transfer_rule] = "1"(3) note HMI_jj'[transfer_rule] = "1"(4) note eq_bezout'[transfer_rule] = "1"(5) show ?case unfolding Mod_Type_Connect.HMA_M_def Mod_Type_Connect.from_hma\<^sub>m_def proof (rule eq_matI) let ?A = "Matrix.mat CARD('m) CARD('m) (\(i, j). bezout_matrix A' a' b' j' bezout' $h mod_type_class.from_nat i $h mod_type_class.from_nat j)" show "dim_row (bezout_matrix_JNF A a b j bezout) = dim_row ?A" and "dim_col (bezout_matrix_JNF A a b j bezout) = dim_col ?A" using Mod_Type_Connect.dim_row_transfer_rule[OF HMA_AA'] unfolding bezout_matrix_JNF_def by auto fix i ja assume i: "i < dim_row ?A" and ja: "ja < dim_col ?A" let ?i = "mod_type_class.from_nat i :: 'm" let ?ja = "mod_type_class.from_nat ja :: 'm" have i_A: "i < dim_row A" using HMA_AA' Mod_Type_Connect.dim_row_transfer_rule i by fastforce have ja_A: "ja < dim_row A" using Mod_Type_Connect.dim_row_transfer_rule[OF HMA_AA'] ja by fastforce have HMA_I_ii'[transfer_rule]: "Mod_Type_Connect.HMA_I i ?i" unfolding Mod_Type_Connect.HMA_I_def using from_nat_not_eq i by auto have HMA_I_ja'[transfer_rule]: "Mod_Type_Connect.HMA_I ja ?ja" unfolding Mod_Type_Connect.HMA_I_def using from_nat_not_eq ja by auto have Aaj: "A' $h a' $h j' = A $$ (a,j)" unfolding index_hma_def[symmetric] by (transfer, simp) have Abj: "A' $h b' $h j' = A $$ (b, j)" unfolding index_hma_def[symmetric] by (transfer, simp) have "?A $$ (i, ja) = bezout_matrix A' a' b' j' bezout' $h ?i $h ?ja" using i ja by auto also have "... = (let (p, q, u, v, d) = bezout' (A' $h a' $h j') (A' $h b' $h j') in if ?i = a' \ ?ja = a' then p else if ?i = a' \ ?ja = b' then q else if ?i = b' \ ?ja = a' then u else if ?i = b' \ ?ja = b' then v else if ?i = ?ja then 1 else 0)" unfolding bezout_matrix_def by auto also have "... = (let (p, q, u, v, d) = bezout (A $$ (a, j)) (A $$ (b, j)) in if i = a \ ja = a then p else if i = a \ ja = b then q else if i = b \ ja = a then u else if i = b \ ja = b then v else if i = ja then 1 else 0)" unfolding eq_bezout' Aaj Abj by (transfer, simp) also have "... = bezout_matrix_JNF A a b j bezout $$ (i,ja)" unfolding bezout_matrix_JNF_def using i_A ja_A by auto finally show "bezout_matrix_JNF A a b j bezout $$ (i, ja) = ?A $$ (i, ja)" .. qed qed (*thm invertible_bezout_matrix must be transferred from HOL Analysis to JNF*) context begin private lemma invertible_bezout_matrix_JNF_mod_type: fixes A::"'a::{bezout_ring_div} mat" assumes "A \ carrier_mat CARD('m::mod_type) CARD('n::mod_type)" assumes ib: "is_bezout_ext bezout" and a_less_b: "a < b" and b: "b 0" shows "invertible_mat (bezout_matrix_JNF A a b j bezout)" proof - define A' where "A' = (Mod_Type_Connect.to_hma\<^sub>m A :: 'a ^'n :: mod_type ^'m :: mod_type)" define a' where "a' = (Mod_Type.from_nat a :: 'm)" define b' where "b' = (Mod_Type.from_nat b :: 'm)" define j' where "j' = (Mod_Type.from_nat j :: 'n)" have AA'[transfer_rule]: "Mod_Type_Connect.HMA_M A A'" unfolding Mod_Type_Connect.HMA_M_def using assms A'_def by auto have aa'[transfer_rule]: "Mod_Type_Connect.HMA_I a a'" unfolding Mod_Type_Connect.HMA_I_def a'_def using assms using from_nat_not_eq order.strict_trans by blast have bb'[transfer_rule]: "Mod_Type_Connect.HMA_I b b'" unfolding Mod_Type_Connect.HMA_I_def b'_def using assms using from_nat_not_eq order.strict_trans by blast have jj'[transfer_rule]: "Mod_Type_Connect.HMA_I j j'" unfolding Mod_Type_Connect.HMA_I_def j'_def using assms using from_nat_not_eq order.strict_trans by blast have [transfer_rule]: "bezout = bezout" .. have [transfer_rule]: "Mod_Type_Connect.HMA_M (bezout_matrix_JNF A a b j bezout) (bezout_matrix A' a' b' j' bezout)" by transfer_prover have "invertible (bezout_matrix A' a' b' j' bezout)" proof (rule invertible_bezout_matrix[OF ib]) show "a' < b'" using a_less_b by (simp add: a'_def b b'_def from_nat_mono) show "A' $h a' $h j' \ 0" unfolding index_hma_def[symmetric] using aj by (transfer, simp) qed thus ?thesis by (transfer, simp) qed private lemma invertible_bezout_matrix_JNF_nontriv_mod_ring: fixes A::"'a::{bezout_ring_div} mat" assumes "A \ carrier_mat CARD('m::nontriv mod_ring) CARD('n::nontriv mod_ring)" assumes ib: "is_bezout_ext bezout" and a_less_b: "a < b" and b: "b 0" shows "invertible_mat (bezout_matrix_JNF A a b j bezout)" - using assms invertible_bezout_matrix_JNF_mod_type by (smt CARD_mod_ring) + using assms invertible_bezout_matrix_JNF_mod_type by (smt (verit) CARD_mod_ring) (*We internalize both sort constraints in one step*) lemmas invertible_bezout_matrix_JNF_internalized = invertible_bezout_matrix_JNF_nontriv_mod_ring[unfolded CARD_mod_ring, internalize_sort "'m::nontriv", internalize_sort "'c::nontriv"] context fixes m::nat and n::nat assumes local_typedef1: "\(Rep :: ('b \ int)) Abs. type_definition Rep Abs {0..(Rep :: ('c \ int)) Abs. type_definition Rep Abs {0..1" and n: "n>1" begin lemma type_to_set1: shows "class.nontriv TYPE('b)" (is ?a) and "m=CARD('b)" (is ?b) proof - from local_typedef1 obtain Rep::"('b \ int)" and Abs where t: "type_definition Rep Abs {0.. int)" and Abs where t: "type_definition Rep Abs {0.. carrier_mat m n" assumes ib: "is_bezout_ext bezout" and a_less_b: "a < b" and b: "b 0" shows "invertible_mat (bezout_matrix_JNF A a b j bezout)" using invertible_bezout_matrix_JNF_internalized[OF type_to_set2(1) type_to_set(1), where ?'aa = 'b] using assms using type_to_set1(2) type_to_set2(2) local_typedef1 m by blast end (*Canceling the first local type definitions*) context begin (*Canceling the first*) private lemma invertible_bezout_matrix_JNF_cancelled_first: "\Rep Abs. type_definition Rep Abs {0.. {0.. {} \ 1 < m \ 1 < n \ (A::'a::bezout_ring_div mat) \ carrier_mat m n \ is_bezout_ext bezout \ a < b \ b < m \ j < n \ A $$ (a, j) \ 0 \ invertible_mat (bezout_matrix_JNF A a b j bezout)" using invertible_bezout_matrix_JNF_nontriv_mod_ring_aux[cancel_type_definition] by blast (*Canceling the second*) private lemma invertible_bezout_matrix_JNF_cancelled_both: "{0.. {} \ {0.. {} \ 1 < m \ 1 < n \ 1 < m \ 1 < n \ (A::'a::bezout_ring_div mat) \ carrier_mat m n \ is_bezout_ext bezout \ a < b \ b < m \ j < n \ A $$ (a, j) \ 0 \ invertible_mat (bezout_matrix_JNF A a b j bezout)" using invertible_bezout_matrix_JNF_cancelled_first[cancel_type_definition] by blast (*The final result in JNF*) lemma invertible_bezout_matrix_JNF': fixes A::"'a::{bezout_ring_div} mat" assumes "A \ carrier_mat m n" assumes ib: "is_bezout_ext bezout" and a_less_b: "a < b" and b: "b1" (* Required from the mod_type restrictions*) and aj: "A $$ (a, j) \ 0" shows "invertible_mat (bezout_matrix_JNF A a b j bezout)" using invertible_bezout_matrix_JNF_cancelled_both assms by auto (*Trick: we want to get rid out the "n>1" assumption, which has appeared since CARD('m::mod_type)>1. Given an mx1 matrix, we just append another column and the bezout_matrix is the same, so it will also be invertible by the previous transfered theorem *) lemma invertible_bezout_matrix_JNF_n1: fixes A::"'a::{bezout_ring_div} mat" assumes A: "A \ carrier_mat m n" assumes ib: "is_bezout_ext bezout" and a_less_b: "a < b" and b: "b 0" shows "invertible_mat (bezout_matrix_JNF A a b j bezout)" proof - let ?A = "A @\<^sub>c (0\<^sub>m m n)" have "(A @\<^sub>c 0\<^sub>m m n) $$ (a, j) = (if j < dim_col A then A $$ (a, j) else (0\<^sub>m m n) $$ (a, j - n))" by (rule append_cols_nth[OF A], insert assms, auto) also have "... = A $$ (a,j)" using assms by auto finally have Aaj: "(A @\<^sub>c 0\<^sub>m m n) $$ (a, j) = A $$ (a,j)" . have "(A @\<^sub>c 0\<^sub>m m n) $$ (b, j) = (if j < dim_col A then A $$ (b, j) else (0\<^sub>m m n) $$ (b, j - n))" by (rule append_cols_nth[OF A], insert assms, auto) also have "... = A $$ (b,j)" using assms by auto finally have Abj: "(A @\<^sub>c 0\<^sub>m m n) $$ (b, j) = A $$ (b, j)" . have dr: "dim_row A = dim_row ?A" by (simp add: append_cols_def) have dc: "dim_col ?A = 2" by (metis Suc_1 append_cols_def A n1 carrier_matD(2) index_mat_four_block(3) index_zero_mat(3) plus_1_eq_Suc) have bz_eq: "bezout_matrix_JNF A a b j bezout = bezout_matrix_JNF ?A a b j bezout" unfolding bezout_matrix_JNF_def Aaj Abj dr by auto have "invertible_mat (bezout_matrix_JNF ?A a b j bezout)" by (rule invertible_bezout_matrix_JNF', insert assms Aaj Abj dr dc, auto) thus ?thesis using bz_eq by simp qed (*The final result in JNF without requiring n>1*) corollary invertible_bezout_matrix_JNF: fixes A::"'a::{bezout_ring_div} mat" assumes "A \ carrier_mat m n" assumes ib: "is_bezout_ext bezout" and a_less_b: "a < b" and b: "b 0" shows "invertible_mat (bezout_matrix_JNF A a b j bezout)" using invertible_bezout_matrix_JNF_n1 invertible_bezout_matrix_JNF' assms by (metis One_nat_def gr_implies_not0 less_Suc0 not_less_iff_gr_or_eq) end end text \We continue with the soundness of the algorithm\ lemma bezout_matrix_JNF_mult_eq: assumes A': "A' \ carrier_mat m n" and a: "a\m" and b: "b\m" and ab: "a \ b" and A_def: "A = A' @\<^sub>r B" and B: "B \ carrier_mat n n" assumes pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,j)) (A$$(b,j))" shows "Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then (p*A$$(a,k) + q*A$$(b,k)) else if i = b then u * A$$(a,k) + v * A$$(b,k) else A$$(i,k) ) = (bezout_matrix_JNF A a b j euclid_ext2) * A" (is "?A = ?BM * A") proof (rule eq_matI) have A: "A \ carrier_mat (m+n) n" using A_def A' B by simp hence A_carrier: "?A \ carrier_mat (m+n) n" by auto show dr: "dim_row ?A = dim_row (?BM * A)" and dc: "dim_col ?A = dim_col (?BM * A)" unfolding bezout_matrix_JNF_def by auto fix i ja assume i: "i < dim_row (?BM * A)" and ja: "ja < dim_col (?BM * A)" let ?f = "\ia. (bezout_matrix_JNF A a b j euclid_ext2) $$ (i,ia) * A $$ (ia,ja)" have dv: "dim_vec (col A ja) = m+n" using A by auto have i_dr: "i col A ja" by (rule index_mult_mat, insert i ja, auto) also have "... = (\ia = 0..ia = 0..ia \ ({a,b} \ ({0.. {0.. i" using True x by blast have x_dr: "x < dim_row A" using x A by auto have "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) = 0" unfolding bezout_matrix_JNF_def unfolding index_mat(1)[OF i_dr x_dr] using x_not_i x by auto thus "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) * A $$ (x, ja) = 0" by auto qed have fa: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, a) = p" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr a_dr] using True pquvd by (auto, metis split_conv) have fb: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, b) = q" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr b_dr] using True pquvd ab by (auto, metis split_conv) have "sum ?f {a,b} + sum ?f ({0.. {0.. i" using True x by blast have x_dr: "x < dim_row A" using x A by auto have "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) = 0" unfolding bezout_matrix_JNF_def unfolding index_mat(1)[OF i_dr x_dr] using x_not_i x by auto thus "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) * A $$ (x, ja) = 0" by auto qed have fa: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, a) = u" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr a_dr] using True i_not_a pquvd by (auto, metis split_conv) have fb: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, b) = v" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr b_dr] using True i_not_a pquvd ab by (auto, metis split_conv) have "sum ?f {a,b} + sum ?f ({0.. {0.. i" using x by blast have x_dr: "x < dim_row A" using x A by auto have "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) = 0" unfolding bezout_matrix_JNF_def unfolding index_mat(1)[OF i_dr x_dr] using x_not_i x by auto thus "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) * A $$ (x, ja) = 0" by auto qed have fa: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, a) = 0" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr a_dr] using False i_not_a pquvd by auto have fb: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, b) = 0" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr b_dr] using False i_not_a pquvd by auto have "sum ?f ({0.. carrier_mat m n" and a: "a b" and A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and a_less_b: "a < b" and mn: "m\n" and D_ge0: "D > 0" shows "\P. invertible_mat P \ P \ carrier_mat (m+n) (m+n) \ (reduce a b D A) = P * A" (is ?thesis1) proof - obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(b,0))" by (metis prod_cases5) let ?A = "Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then (p*A$$(a,k) + q*A$$(b,k)) else if i = b then u * A$$(a,k) + v * A$$(b,k) else A$$(i,k) )" have D: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by auto have A: "A \ carrier_mat (m+n) n" using A_def A' by simp hence A_carrier: "?A \ carrier_mat (m+n) n" by auto let ?BM = "bezout_matrix_JNF A a b 0 euclid_ext2" have A'_BZ_A: "?A = ?BM * A" by (rule bezout_matrix_JNF_mult_eq[OF A' _ _ ab A_def D pquvd], insert a b, auto) have invertible_bezout: "invertible_mat ?BM" by (rule invertible_bezout_matrix_JNF[OF A is_bezout_ext_euclid_ext2 a_less_b _ j Aaj], insert a_less_b b, auto) have BM: "?BM \ carrier_mat (m+n) (m+n)" unfolding bezout_matrix_JNF_def using A by auto define xs where "xs = [0..r D \\<^sub>m 1\<^sub>m n" proof (rule matrix_append_rows_eq_if_preserves[OF A_carrier D], rule+) fix i j assume i: "i \ {m..\<^sub>m (1\<^sub>m n))$$(i-m,j))" by (unfold A_def, rule append_rows_nth[OF A' D _ j], insert i, auto) also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, j)" using i A' by auto finally show "?A $$ (i,j) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, j)" . qed have reduce_a_eq: "?reduce_a = Matrix.mat (dim_row ?A) (dim_col ?A) (\(i, k). if i = a \ k \ set xs then if k = 0 then if D dvd ?A$$(i,k) then D else ?A $$ (i, k) else ?A $$ (i, k) gmod D else ?A $$ (i, k))" by (rule reduce_row_mod_D[OF A_A'_D _ a _], insert xs_def mn D_ge0, auto) have reduce_a: "?reduce_a \ carrier_mat (m+n) n" using reduce_a_eq A by auto have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ ?reduce_a = P * ?A" by (rule reduce_row_mod_D_invertible_mat[OF A_A'_D _ a], insert xs_def mn, auto) from this obtain P where P: "P \ carrier_mat (m + n) (m + n)" and inv_P: "invertible_mat P" and reduce_a_PA: "?reduce_a = P * ?A" by blast define ys where "ys = [1..r D \\<^sub>m 1\<^sub>m n" proof (rule matrix_append_rows_eq_if_preserves[OF reduce_a D], rule+) fix i ja assume i: "i \ {m..a" and i_not_b: "i\b" using i a b by auto have "?reduce_a $$ (i,ja) = ?A $$ (i, ja)" unfolding reduce_a_eq using i i_not_a i_not_b ja A by auto also have "... = A $$ (i,ja)" using i i_not_a i_not_b ja A by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" - by (smt D append_rows_nth A' A_def atLeastLessThan_iff + by (smt (verit) D append_rows_nth A' A_def atLeastLessThan_iff carrier_matD(1) i ja less_irrefl_nat nat_SN.compat) finally show "?reduce_a $$ (i,ja) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" . qed have reduce_b_eq: "?reduce_b = Matrix.mat (dim_row ?reduce_a) (dim_col ?reduce_a) (\(i, k). if i = b \ k \ set ys then if k = 0 then if D dvd ?reduce_a$$(i,k) then D else ?reduce_a $$ (i, k) else ?reduce_a $$ (i, k) gmod D else ?reduce_a $$ (i, k))" by (rule reduce_row_mod_D[OF reduce_a_B'_D _ b _ _ mn], unfold ys_def, insert D_ge0, auto) have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ ?reduce_b = P * ?reduce_a" by (rule reduce_row_mod_D_invertible_mat[OF reduce_a_B'_D _ b _ mn], insert ys_def, auto) from this obtain Q where Q: "Q \ carrier_mat (m + n) (m + n)" and inv_Q: "invertible_mat Q" and reduce_b_Q_reduce: "?reduce_b = Q * ?reduce_a" by blast have reduce_b_eq_reduce: "?reduce_b = (reduce a b D A)" proof (rule eq_matI) show dr_eq: "dim_row ?reduce_b = dim_row (reduce a b D A)" and dc_eq: "dim_col ?reduce_b = dim_col (reduce a b D A)" using reduce_preserves_dimensions by auto fix i ja assume i: "ia \ i\b)") case True have "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt True dr_eq dc_eq i index_mat(1) ja prod.simps(2) reduce_row_mod_D_preserves_dimensions) + by (smt (verit) True dr_eq dc_eq i index_mat(1) ja prod.simps(2) reduce_row_mod_D_preserves_dimensions) also have "... = ?A $$ (i,ja)" - by (smt A True carrier_matD(2) dim_col_mat(1) dim_row_mat(1) i index_mat(1) ja_n + by (smt (verit) A True carrier_matD(2) dim_col_mat(1) dim_row_mat(1) i index_mat(1) ja_n reduce_a_eq reduce_preserves_dimensions(1) split_conv) also have "... = A $$ (i,ja)" using A True im ja_n by auto also have "... = (reduce a b D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using im ja_n A True by auto finally show ?thesis . next case False note a_or_b = False show ?thesis proof (cases "i=a") case True note ia = True hence i_not_b: "i\b" using ab by auto show ?thesis proof - have ja_in_xs: "ja \ set xs" unfolding xs_def using True ja_n im a A unfolding set_filter by auto have 1: "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) + by (smt (verit) ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) reduce_b_eq reduce_row_mod_D_preserves_dimensions(2)) show ?thesis proof (cases "ja = 0 \ D dvd p*A$$(a,ja) + q*A$$(b,ja)") case True have "?reduce_a $$ (i,ja) = D" unfolding reduce_a_eq using True ab a_or_b i_not_b ja_n im a A ja_in_xs False by auto also have "... = (reduce a b D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using True a_or_b i_not_b ja_n im A False by auto finally show ?thesis using 1 by simp next case False note nc1 = False show ?thesis proof (cases "ja=0") case True then show ?thesis - by (smt (z3) "1" A assms(3) assms(7) dim_col_mat(1) dim_row_mat(1) euclid_ext2_works i ia im index_mat(1) + by (smt (verit) "1" A assms(3) assms(7) dim_col_mat(1) dim_row_mat(1) euclid_ext2_works i ia im index_mat(1) ja ja_in_xs old.prod.case pquvd reduce_gcd reduce_preserves_dimensions reduce_a_eq) next case False have "?reduce_a $$ (i,ja) = ?A $$ (i, ja) gmod D" unfolding reduce_a_eq using True ab a_or_b i_not_b ja_n im a A ja_in_xs False by auto also have "... = (reduce a b D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using True a_or_b i_not_b ja_n im A False by auto finally show ?thesis using 1 by simp qed qed qed next case False note i_not_a = False have i_drb: "i set ys") case True note ja_in_ys = True hence ja_not0: "ja \ 0" unfolding ys_def by auto have "?reduce_b $$ (i,ja) = (if ja = 0 then if D dvd ?reduce_a$$(i,ja) then D else ?reduce_a $$ (i, ja) else ?reduce_a $$ (i, ja) gmod D)" unfolding reduce_b_eq using i_not_a True ja ja_in_ys - by (smt i_dra ja_dra a_or_b index_mat(1) prod.simps(2)) + by (smt (verit) i_dra ja_dra a_or_b index_mat(1) prod.simps(2)) also have "... = (if ja = 0 then if D dvd ?reduce_a$$(i,ja) then D else ?A $$ (i, ja) else ?A $$ (i, ja) gmod D)" unfolding reduce_a_eq using True ab a_or_b ib False ja_n im a A ja_in_ys by auto also have "... = (reduce a b D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using True ja_not0 False a_or_b ib ja_n im A using i_not_a by auto finally show ?thesis . next case False hence ja0:"ja = 0" using ja_n unfolding ys_def by auto have rw0: "u * A $$ (a, ja) + v * A $$ (b, ja) = 0" unfolding euclid_ext2_works[OF pquvd[symmetric]] ja0 - by (smt euclid_ext2_works[OF pquvd[symmetric]] more_arith_simps(11) mult.commute mult_minus_left) + by (smt (verit) euclid_ext2_works[OF pquvd[symmetric]] more_arith_simps(11) mult.commute mult_minus_left) have "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt False a_or_b dc_eq dim_row_mat(1) dr_eq i index_mat(1) ja + by (smt (verit) False a_or_b dc_eq dim_row_mat(1) dr_eq i index_mat(1) ja prod.simps(2) reduce_b_eq reduce_row_mod_D_preserves_dimensions(2)) also have "... = ?A $$ (i, ja)" unfolding reduce_a_eq using False ab a_or_b i_not_a ja_n im a A by auto also have "... = u * A $$ (a, ja) + v * A $$ (b, ja)" by (smt (verit, ccfv_SIG) A \ja = 0\ assms(3) assms(5) carrier_matD(2) i ib index_mat(1) old.prod.case reduce_preserves_dimensions(1)) also have "... = (reduce a b D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using False a_or_b i_not_a ja_n im A ja0 by auto finally show ?thesis . qed qed qed qed have inv_QPBM: "invertible_mat (Q * P * ?BM)" by (meson BM P Q inv_P inv_Q invertible_bezout invertible_mult_JNF mult_carrier_mat) moreover have "(Q*P*?BM) \ carrier_mat (m + n) (m + n)" using BM P Q by auto moreover have "(reduce a b D A) = (Q*P*?BM) * A" proof - have "?BM * A = ?A" using A'_BZ_A by auto hence "P * (?BM * A) = ?reduce_a" using reduce_a_PA by auto hence "Q * (P * (?BM * A)) = ?reduce_b" using reduce_b_Q_reduce by auto thus ?thesis using reduce_b_eq_reduce - by (smt A A'_BZ_A A_carrier BM P Q assoc_mult_mat mn mult_carrier_mat reduce_a_PA) + by (smt (verit) A A'_BZ_A A_carrier BM P Q assoc_mult_mat mn mult_carrier_mat reduce_a_PA) qed ultimately show ?thesis by blast qed lemma reduce_abs_invertible_mat: assumes A': "A' \ carrier_mat m n" and a: "a b" and A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and a_less_b: "a < b" and mn: "m\n" and D_ge0: "D > 0" shows "\P. invertible_mat P \ P \ carrier_mat (m+n) (m+n) \ (reduce_abs a b D A) = P * A" (is ?thesis1) proof - obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(b,0))" by (metis prod_cases5) let ?A = "Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then (p*A$$(a,k) + q*A$$(b,k)) else if i = b then u * A$$(a,k) + v * A$$(b,k) else A$$(i,k) )" have D: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by auto have A: "A \ carrier_mat (m+n) n" using A_def A' by simp hence A_carrier: "?A \ carrier_mat (m+n) n" by auto let ?BM = "bezout_matrix_JNF A a b 0 euclid_ext2" have A'_BZ_A: "?A = ?BM * A" by (rule bezout_matrix_JNF_mult_eq[OF A' _ _ ab A_def D pquvd], insert a b, auto) have invertible_bezout: "invertible_mat ?BM" by (rule invertible_bezout_matrix_JNF[OF A is_bezout_ext_euclid_ext2 a_less_b _ j Aaj], insert a_less_b b, auto) have BM: "?BM \ carrier_mat (m+n) (m+n)" unfolding bezout_matrix_JNF_def using A by auto define xs where "xs = filter (\i. abs (?A $$ (a,i)) > D) [0..r D \\<^sub>m 1\<^sub>m n" proof (rule matrix_append_rows_eq_if_preserves[OF A_carrier D], rule+) fix i j assume i: "i \ {m..\<^sub>m (1\<^sub>m n))$$(i-m,j))" by (unfold A_def, rule append_rows_nth[OF A' D _ j], insert i, auto) also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, j)" using i A' by auto finally show "?A $$ (i,j) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, j)" . qed have reduce_a_eq: "?reduce_a = Matrix.mat (dim_row ?A) (dim_col ?A) (\(i, k). if i = a \ k \ set xs then if k = 0 \ D dvd ?A$$(i,k) then D else ?A $$ (i, k) gmod D else ?A $$ (i, k))" by (rule reduce_row_mod_D_abs[OF A_A'_D _ a _], insert xs_def mn D_ge0, auto) have reduce_a: "?reduce_a \ carrier_mat (m+n) n" using reduce_a_eq A by auto have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ ?reduce_a = P * ?A" by (rule reduce_row_mod_D_abs_invertible_mat[OF A_A'_D _ a], insert xs_def mn, auto) from this obtain P where P: "P \ carrier_mat (m + n) (m + n)" and inv_P: "invertible_mat P" and reduce_a_PA: "?reduce_a = P * ?A" by blast define ys where "ys = filter (\i. abs (?A $$ (b,i)) > D) [0..r D \\<^sub>m 1\<^sub>m n" proof (rule matrix_append_rows_eq_if_preserves[OF reduce_a D], rule+) fix i ja assume i: "i \ {m..a" and i_not_b: "i\b" using i a b by auto have "?reduce_a $$ (i,ja) = ?A $$ (i, ja)" unfolding reduce_a_eq using i i_not_a i_not_b ja A by auto also have "... = A $$ (i,ja)" using i i_not_a i_not_b ja A by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" - by (smt D append_rows_nth A' A_def atLeastLessThan_iff + by (smt (verit) D append_rows_nth A' A_def atLeastLessThan_iff carrier_matD(1) i ja less_irrefl_nat nat_SN.compat) finally show "?reduce_a $$ (i,ja) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" . qed have reduce_b_eq: "?reduce_b = Matrix.mat (dim_row ?reduce_a) (dim_col ?reduce_a) (\(i, k). if i = b \ k \ set ys then if k = 0 \ D dvd ?reduce_a$$(i,k) then D else ?reduce_a $$ (i, k) gmod D else ?reduce_a $$ (i, k))" by (rule reduce_row_mod_D_abs[OF reduce_a_B'_D _ b _ _ mn], unfold ys_def, insert D_ge0, auto) have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ ?reduce_b = P * ?reduce_a" by (rule reduce_row_mod_D_abs_invertible_mat[OF reduce_a_B'_D _ b _ mn], insert ys_def, auto) from this obtain Q where Q: "Q \ carrier_mat (m + n) (m + n)" and inv_Q: "invertible_mat Q" and reduce_b_Q_reduce: "?reduce_b = Q * ?reduce_a" by blast have reduce_b_eq_reduce: "?reduce_b = (reduce_abs a b D A)" proof (rule eq_matI) show dr_eq: "dim_row ?reduce_b = dim_row (reduce_abs a b D A)" and dc_eq: "dim_col ?reduce_b = dim_col (reduce_abs a b D A)" using reduce_preserves_dimensions by auto fix i ja assume i: "ia \ i\b)") case True have "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt True dr_eq dc_eq i index_mat(1) ja prod.simps(2) reduce_row_mod_D_preserves_dimensions_abs) + by (smt (verit) True dr_eq dc_eq i index_mat(1) ja prod.simps(2) reduce_row_mod_D_preserves_dimensions_abs) also have "... = ?A $$ (i,ja)" - by (smt A True carrier_matD(2) dim_col_mat(1) dim_row_mat(1) i index_mat(1) ja_n + by (smt (verit) A True carrier_matD(2) dim_col_mat(1) dim_row_mat(1) i index_mat(1) ja_n reduce_a_eq reduce_preserves_dimensions(3) split_conv) also have "... = A $$ (i,ja)" using A True im ja_n by auto also have "... = (reduce_abs a b D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using im ja_n A True by auto finally show ?thesis . next case False note a_or_b = False show ?thesis proof (cases "i=a") case True note ia = True hence i_not_b: "i\b" using ab by auto show ?thesis proof (cases "abs((p*A$$(a,ja) + q*A$$(b,ja))) > D") case True note ge_D = True have ja_in_xs: "ja \ set xs" unfolding xs_def using True ja_n im a A unfolding set_filter by auto have 1: "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) + by (smt (verit) ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) reduce_b_eq reduce_row_mod_D_preserves_dimensions_abs(2)) show ?thesis proof (cases "ja = 0 \ D dvd p*A$$(a,ja) + q*A$$(b,ja)") case True have "?reduce_a $$ (i,ja) = D" unfolding reduce_a_eq using True ab a_or_b i_not_b ja_n im a A ja_in_xs False by auto also have "... = (reduce_abs a b D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using True a_or_b i_not_b ja_n im A False ge_D by auto finally show ?thesis using 1 by simp next case False have "?reduce_a $$ (i,ja) = ?A $$ (i, ja) gmod D" unfolding reduce_a_eq using True ab a_or_b i_not_b ja_n im a A ja_in_xs False by auto also have "... = (reduce_abs a b D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using True a_or_b i_not_b ja_n im A False by auto finally show ?thesis using 1 by simp qed next case False have ja_in_xs: "ja \ set xs" unfolding xs_def using False ja_n im a A unfolding set_filter by auto have "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) + by (smt (verit) ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) reduce_b_eq reduce_row_mod_D_preserves_dimensions_abs(2)) also have "... = ?A $$ (i, ja)" unfolding reduce_a_eq using False ab a_or_b i_not_b ja_n im a A ja_in_xs by auto also have "... = (reduce_abs a b D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using False a_or_b i_not_b ja_n im A by auto finally show ?thesis . qed next case False note i_not_a = False have i_drb: "i D") case True note ge_D = True have ja_in_ys: "ja \ set ys" unfolding ys_def using True False ib ja_n im a b A unfolding set_filter by auto have "?reduce_b $$ (i,ja) = (if ja = 0 \ D dvd ?reduce_a$$(i,ja) then D else ?reduce_a $$ (i, ja) gmod D)" unfolding reduce_b_eq using i_not_a True ja ja_in_ys - by (smt i_dra ja_dra a_or_b index_mat(1) prod.simps(2)) + by (smt (verit) i_dra ja_dra a_or_b index_mat(1) prod.simps(2)) also have "... = (if ja = 0 \ D dvd ?reduce_a$$(i,ja) then D else ?A $$ (i, ja) gmod D)" unfolding reduce_a_eq using True ab a_or_b ib False ja_n im a A ja_in_ys by auto also have "... = (reduce_abs a b D A) $$ (i,ja)" proof (cases "ja = 0 \ D dvd ?reduce_a$$(i,ja)") case True have ja0: "ja=0" using True by auto have "u * A $$ (a, ja) + v * A $$ (b, ja) = 0" unfolding euclid_ext2_works[OF pquvd[symmetric]] ja0 - by (smt euclid_ext2_works[OF pquvd[symmetric]] more_arith_simps(11) mult.commute mult_minus_left) + by (smt (verit) euclid_ext2_works[OF pquvd[symmetric]] more_arith_simps(11) mult.commute mult_minus_left) hence abs_0: "abs((u*A$$(a,ja) + v * A$$(b,ja))) = 0" by auto show ?thesis using abs_0 D_ge0 ge_D by linarith next case False then show ?thesis unfolding reduce_alt_def_not0[OF Aaj pquvd] using True ge_D False a_or_b ib ja_n im A using i_not_a by auto qed finally show ?thesis . next case False have ja_in_ys: "ja \ set ys" unfolding ys_def using i_not_a False ib ja_n im a b A unfolding set_filter by auto have "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq using i_dra ja_dra ja_in_ys by auto also have "... = ?A $$ (i, ja)" unfolding reduce_a_eq using False ab a_or_b i_not_a ja_n im a A by auto also have "... = u * A $$ (a, ja) + v * A $$ (b, ja)" unfolding reduce_a_eq using False ab a_or_b i_not_a ja_n im a A ja_in_ys by auto also have "... = (reduce_abs a b D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using False a_or_b i_not_a ja_n im A by auto finally show ?thesis . qed qed qed qed have inv_QPBM: "invertible_mat (Q * P * ?BM)" by (meson BM P Q inv_P inv_Q invertible_bezout invertible_mult_JNF mult_carrier_mat) moreover have "(Q*P*?BM) \ carrier_mat (m + n) (m + n)" using BM P Q by auto moreover have "(reduce_abs a b D A) = (Q*P*?BM) * A" proof - have "?BM * A = ?A" using A'_BZ_A by auto hence "P * (?BM * A) = ?reduce_a" using reduce_a_PA by auto hence "Q * (P * (?BM * A)) = ?reduce_b" using reduce_b_Q_reduce by auto thus ?thesis using reduce_b_eq_reduce - by (smt A A'_BZ_A A_carrier BM P Q assoc_mult_mat mn mult_carrier_mat reduce_a_PA) + by (smt (verit) A A'_BZ_A A_carrier BM P Q assoc_mult_mat mn mult_carrier_mat reduce_a_PA) qed ultimately show ?thesis by blast qed lemma reduce_element_mod_D_case_m': assumes A_def: "A = A' @\<^sub>r B" and B: "B\carrier_mat n n" and A': "A' \ carrier_mat m n" and a: "a\m" and j: "j=n" and B1: "B $$ (j, j) = D" and B2: "(\j'\{0.. 0" shows "reduce_element_mod_D A a j D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k = j then if j = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" (is "_ = ?A") proof (rule eq_matI) have jm: "j carrier_mat (m+n) n" using A_def A' B mn by simp fix i ja assume i: "i < dim_row ?A" and ja: "ja < dim_col ?A" show "reduce_element_mod_D A a j D m $$ (i, ja) = ?A $$ (i, ja)" proof (cases "i=a") case False have "reduce_element_mod_D A a j D m = (if j = 0 then if D dvd A$$(a,j) then addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A else A else addrow (-((A$$(a,j) gdiv D))) a (j + m) A)" unfolding reduce_element_mod_D_def by simp also have "... $$ (i,ja) = A $$ (i, ja)" unfolding mat_addrow_def using False ja i by auto also have "... = ?A $$ (i,ja)" using False using i ja by auto finally show ?thesis . next case True note ia = True have "reduce_element_mod_D A a j D m = (if j = 0 then if D dvd A$$(a,j) then addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A else A else addrow (-((A$$(a,j) gdiv D))) a (j + m) A)" unfolding reduce_element_mod_D_def by simp also have "... $$ (i,ja) = ?A $$ (i,ja)" proof (cases "ja = j") case True note ja_j = True have "A $$ (j + m, ja) = B $$ (j,ja)" by (rule append_rows_nth2[OF A' _ A_def ], insert j ja A B mn, auto) also have "... = D" using True j mn B1 B2 B by auto finally have A_ja_jaD: "A $$ (j + m, ja) = D" . show ?thesis proof (cases "j=0 \ D dvd A$$(a,j)") case True have 1: "reduce_element_mod_D A a j D m = addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A " using True ia ja_j unfolding reduce_element_mod_D_def by auto also have "... $$(i,ja) = (- (A $$ (a, j) gdiv D) + 1) * A $$ (j + m, ja) + A $$ (i, ja)" unfolding mat_addrow_def using True ja_j ia using A i j by auto also have "... = D" proof - have "A $$ (i, ja) + D * - (A $$ (i, ja) gdiv D) = 0" using True ia ja_j using D0 by force then show ?thesis by (metis A_ja_jaD ab_semigroup_add_class.add_ac(1) add.commute add_right_imp_eq ia int_distrib(2) ja_j more_arith_simps(3) mult.commute mult_cancel_right1) qed also have "... = ?A $$ (i,ja)" using True ia A i j ja_j by auto finally show ?thesis using True 1 by auto next case False show ?thesis proof (cases "j=0") case True then show ?thesis using False i ja by auto next case False have "?A $$ (i,ja) = A $$ (i, ja) gmod D" using True ia A i j False by auto also have "... = A $$ (i, ja) - ((A $$ (i, ja) gdiv D) * D)" by (subst gmod_gdiv[OF D0], auto) also have "... = - (A $$ (a, j) gdiv D) * A $$ (j + m, ja) + A $$ (i, ja)" unfolding A_ja_jaD by (simp add: True ia) finally show ?thesis using A False True i ia j by auto qed qed next case False have "A $$ (j + m, ja) = B $$ (j,ja)" by (rule append_rows_nth2[OF A' _ A_def ], insert j mn ja A B, auto) also have "... = 0" using False using A a mn ja j B2 by force finally have A_am_ja0: "A $$ (j + m, ja) = 0" . then show ?thesis using False i ja by fastforce qed finally show ?thesis . qed next show "dim_row (reduce_element_mod_D A a j D m) = dim_row ?A" and "dim_col (reduce_element_mod_D A a j D m) = dim_col ?A" using reduce_element_mod_D_def by auto qed lemma reduce_element_mod_D_abs_case_m': assumes A_def: "A = A' @\<^sub>r B" and B: "B\carrier_mat n n" and A': "A' \ carrier_mat m n" and a: "a\m" and j: "j=n" and B1: "B $$ (j, j) = D" and B2: "(\j'\{0.. 0" shows "reduce_element_mod_D_abs A a j D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k = j then if j = 0 \ D dvd A$$(i,k) then D else A$$(i,k) gmod D else A$$(i,k))" (is "_ = ?A") proof (rule eq_matI) have jm: "j carrier_mat (m+n) n" using A_def A' B mn by simp fix i ja assume i: "i < dim_row ?A" and ja: "ja < dim_col ?A" show "reduce_element_mod_D_abs A a j D m $$ (i, ja) = ?A $$ (i, ja)" proof (cases "i=a") case False have "reduce_element_mod_D_abs A a j D m = (if j = 0 \ D dvd A$$(a,j) then addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A else addrow (-((A$$(a,j) gdiv D))) a (j + m) A)" unfolding reduce_element_mod_D_abs_def by simp also have "... $$ (i,ja) = A $$ (i, ja)" unfolding mat_addrow_def using False ja i by auto also have "... = ?A $$ (i,ja)" using False using i ja by auto finally show ?thesis . next case True note ia = True have "reduce_element_mod_D_abs A a j D m = (if j = 0 \ D dvd A$$(a,j) then addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A else addrow (-((A$$(a,j) gdiv D))) a (j + m) A)" unfolding reduce_element_mod_D_abs_def by simp also have "... $$ (i,ja) = ?A $$ (i,ja)" proof (cases "ja = j") case True note ja_j = True have "A $$ (j + m, ja) = B $$ (j,ja)" by (rule append_rows_nth2[OF A' _ A_def ], insert j ja A B mn, auto) also have "... = D" using True j mn B1 B2 B by auto finally have A_ja_jaD: "A $$ (j + m, ja) = D" . show ?thesis proof (cases "j=0 \ D dvd A$$(a,j)") case True have 1: "reduce_element_mod_D_abs A a j D m = addrow (-((A$$(a,j) gdiv D)) + 1) a (j + m) A " using True ia ja_j unfolding reduce_element_mod_D_abs_def by auto also have "... $$(i,ja) = (- (A $$ (a, j) gdiv D) + 1) * A $$ (j + m, ja) + A $$ (i, ja)" unfolding mat_addrow_def using True ja_j ia using A i j by auto also have "... = D" proof - have "A $$ (i, ja) + D * - (A $$ (i, ja) gdiv D) = 0" using True ia ja_j using D0 by force then show ?thesis by (metis A_ja_jaD ab_semigroup_add_class.add_ac(1) add.commute add_right_imp_eq ia int_distrib(2) ja_j more_arith_simps(3) mult.commute mult_cancel_right1) qed also have "... = ?A $$ (i,ja)" using True ia A i j ja_j by auto finally show ?thesis using True 1 by auto next case False have "?A $$ (i,ja) = A $$ (i, ja) gmod D" using True ia A i j False by auto also have "... = A $$ (i, ja) - ((A $$ (i, ja) gdiv D) * D)" by (subst gmod_gdiv[OF D0], auto) also have "... = - (A $$ (a, j) gdiv D) * A $$ (j + m, ja) + A $$ (i, ja)" unfolding A_ja_jaD by (simp add: True ia) finally show ?thesis using A False True i ia j by auto qed next case False have "A $$ (j + m, ja) = B $$ (j,ja)" by (rule append_rows_nth2[OF A' _ A_def ], insert j mn ja A B, auto) also have "... = 0" using False using A a mn ja j B2 by force finally have A_am_ja0: "A $$ (j + m, ja) = 0" . then show ?thesis using False i ja by fastforce qed finally show ?thesis . qed next show "dim_row (reduce_element_mod_D_abs A a j D m) = dim_row ?A" and "dim_col (reduce_element_mod_D_abs A a j D m) = dim_col ?A" using reduce_element_mod_D_abs_def by auto qed lemma reduce_row_mod_D_case_m': assumes A_def: "A = A' @\<^sub>r B" and "B \ carrier_mat n n" and A': "A' \ carrier_mat m n" and "a < m" and j: "\j\set xs. j (B $$ (j, j) = D) \ (\j'\{0..n" and D: "D > 0" shows "reduce_row_mod_D A a xs D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k \ set xs then if k = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" using assms proof (induct A a xs D m arbitrary: A' B rule: reduce_row_mod_D.induct) case (1 A a D m) then show ?case by force next case (2 A a x xs D m) note A_A'B = "2.prems"(1) note B = "2.prems"(2) note A' = "2.prems"(3) note a = "2.prems"(4) note j = "2.prems"(5) note mn = "2.prems"(7) note d = "2.prems"(6) let ?reduce_xs = "(reduce_element_mod_D A a x D m)" have reduce_xs_carrier: "?reduce_xs \ carrier_mat (m + n) n" by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) add.right_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_zero_mat(2,3) reduce_element_mod_D_preserves_dimensions) have 1: "reduce_row_mod_D A a (x # xs) D m = reduce_row_mod_D ?reduce_xs a xs D m" by simp have 2: "reduce_element_mod_D A a j D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k = j then if j = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" if "j\set (x#xs)" for j by (rule reduce_element_mod_D_case_m'[OF A_A'B B A'], insert "2.prems" that, auto) have "reduce_row_mod_D ?reduce_xs a xs D m = Matrix.mat (dim_row ?reduce_xs) (dim_col ?reduce_xs) (\(i,k). if i = a \ k \ set xs then if k = 0 then if D dvd ?reduce_xs $$ (i, k) then D else ?reduce_xs $$ (i, k) else ?reduce_xs $$ (i, k) gmod D else ?reduce_xs $$ (i, k))" proof (rule "2.hyps"[OF _ B _ a _ _ mn]) let ?A' = "mat_of_rows n [Matrix.row (reduce_element_mod_D A a x D m) i. i \ [0..r B" proof (rule matrix_append_rows_eq_if_preserves[OF reduce_xs_carrier B]) show " \i\{m..j(i,k). if i = a \ k \ set (x # xs) then if k = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" (is "?lhs = ?rhs") proof (rule eq_matI) show "dim_row ?lhs = dim_row ?rhs" and "dim_col ?lhs = dim_col ?rhs" by auto fix i j assume i: "i j \ set xs") case True note ia_jxs = True have j_not_x: "j\x" using d True by auto show ?thesis proof (cases "j=0 \ D dvd ?reduce_xs $$(i,j)") case True have "?lhs $$ (i,j) = D" using True i j ia_jxs by auto also have "... = ?rhs $$ (i,j)" using i j j_not_x - by (smt "2" calculation dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2) xn) + by (smt (verit) "2" calculation dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2) xn) finally show ?thesis . next case False show ?thesis proof (cases "j=0") case True then show ?thesis - by (smt (z3) "2" dim_col_mat(1) dim_row_mat(1) i index_mat(1) insert_iff j list.set(2) old.prod.case) + by (smt (verit) "2" dim_col_mat(1) dim_row_mat(1) i index_mat(1) insert_iff j list.set(2) old.prod.case) next case False have "?lhs $$ (i,j) = ?reduce_xs $$ (i, j) gmod D" using True False i j by auto also have "... = A $$ (i,j) gmod D" using 2[OF ] j_not_x i j by auto also have "... = ?rhs $$ (i,j)" using i j j_not_x using False True dim_col_mat(1) dim_row_mat(1) index_mat(1) list.set_intros(2) old.prod.case by auto finally show ?thesis . qed qed next case False show ?thesis using 2 i j xn - by (smt False dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2)) + by (smt (verit) False dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2)) qed qed finally show ?case using 1 by simp qed lemma reduce_row_mod_D_abs_case_m': assumes A_def: "A = A' @\<^sub>r B" and "B \ carrier_mat n n" and A': "A' \ carrier_mat m n" and "a < m" and j: "\j\set xs. j (B $$ (j, j) = D) \ (\j'\{0..n" and D: "D > 0" shows "reduce_row_mod_D_abs A a xs D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k \ set xs then if k = 0 \ D dvd A$$(i,k) then D else A$$(i,k) gmod D else A$$(i,k))" using assms proof (induct A a xs D m arbitrary: A' B rule: reduce_row_mod_D_abs.induct) case (1 A a D m) then show ?case by force next case (2 A a x xs D m) note A_A'B = "2.prems"(1) note B = "2.prems"(2) note A' = "2.prems"(3) note a = "2.prems"(4) note j = "2.prems"(5) note mn = "2.prems"(7) note d = "2.prems"(6) let ?reduce_xs = "(reduce_element_mod_D_abs A a x D m)" have reduce_xs_carrier: "?reduce_xs \ carrier_mat (m + n) n" by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) add.right_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_zero_mat(2,3) reduce_element_mod_D_preserves_dimensions) have 1: "reduce_row_mod_D_abs A a (x # xs) D m = reduce_row_mod_D_abs ?reduce_xs a xs D m" by simp have 2: "reduce_element_mod_D_abs A a j D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k = j then if j = 0 \ D dvd A$$(i,k) then D else A$$(i,k) gmod D else A$$(i,k))" if "j\set (x#xs)" for j by (rule reduce_element_mod_D_abs_case_m'[OF A_A'B B A'], insert "2.prems" that, auto) have "reduce_row_mod_D_abs ?reduce_xs a xs D m = Matrix.mat (dim_row ?reduce_xs) (dim_col ?reduce_xs) (\(i,k). if i = a \ k \ set xs then if k = 0 \ D dvd ?reduce_xs $$ (i, k) then D else ?reduce_xs $$ (i, k) gmod D else ?reduce_xs $$ (i, k))" proof (rule "2.hyps"[OF _ B _ a _ _ mn]) let ?A' = "mat_of_rows n [Matrix.row (reduce_element_mod_D_abs A a x D m) i. i \ [0..r B" proof (rule matrix_append_rows_eq_if_preserves[OF reduce_xs_carrier B]) show " \i\{m..j(i,k). if i = a \ k \ set (x # xs) then if k = 0 \ D dvd A$$(i,k) then D else A$$(i,k) gmod D else A$$(i,k))" (is "?lhs = ?rhs") proof (rule eq_matI) show "dim_row ?lhs = dim_row ?rhs" and "dim_col ?lhs = dim_col ?rhs" by auto fix i j assume i: "i j \ set xs") case True note ia_jxs = True have j_not_x: "j\x" using d True by auto show ?thesis proof (cases "j=0 \ D dvd ?reduce_xs $$(i,j)") case True have "?lhs $$ (i,j) = D" using True i j ia_jxs by auto also have "... = ?rhs $$ (i,j)" using i j j_not_x - by (smt "2" calculation dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2) xn) + by (smt (verit) "2" calculation dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2) xn) finally show ?thesis . next case False have "?lhs $$ (i,j) = ?reduce_xs $$ (i, j) gmod D" using True False i j by auto also have "... = A $$ (i,j) gmod D" using 2[OF ] j_not_x i j by auto also have "... = ?rhs $$ (i,j)" using i j j_not_x - by (smt False True \Matrix.mat (dim_row ?reduce_xs) + by (smt (verit) False True \Matrix.mat (dim_row ?reduce_xs) (dim_col ?reduce_xs) (\(i, k). if i = a \ k \ set xs then if k = 0 \ D dvd ?reduce_xs $$ (i, k) then D else ?reduce_xs $$ (i, k) gmod D else ?reduce_xs $$ (i, k)) $$ (i, j) = ?reduce_xs $$ (i, j) gmod D\ calculation dim_col_mat(1) dim_row_mat(1) dvd_imp_gmod_0[OF \D > 0\] index_mat(1) insert_iff list.set(2) gmod_0_imp_dvd prod.simps(2)) finally show ?thesis . qed next case False show ?thesis using 2 i j xn - by (smt False dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2)) + by (smt (verit) False dim_col_mat(1) dim_row_mat(1) index_mat(1) insert_iff list.set(2) prod.simps(2)) qed qed finally show ?case using 1 by simp qed lemma assumes A_def: "A = A' @\<^sub>r B" and B: "B \ carrier_mat n n" and A': "A' \ carrier_mat m n" and a: "an" shows reduce_element_mod_D_invertible_mat_case_m: "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D A a j D m = P * A" (is ?thesis1) and reduce_element_mod_D_abs_invertible_mat_case_m: "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D_abs A a j D m = P * A" (is ?thesis2) unfolding atomize_conj proof (rule conjI; cases "j = 0 \ D dvd A$$(a,j)") case True let ?P = "addrow_mat (m+n) (- (A $$ (a, j) gdiv D) + 1) a (j + m)" have A: "A \ carrier_mat (m + n) n" using A_def A' B mn by auto have "reduce_element_mod_D_abs A a j D m = addrow (- (A $$ (a, j) gdiv D) + 1) a (j + m) A" unfolding reduce_element_mod_D_abs_def using True by auto also have "... = ?P * A" by (rule addrow_mat[OF A], insert j mn, auto) finally have rw: "reduce_element_mod_D_abs A a j D m = ?P * A" . have "reduce_element_mod_D A a j D m = addrow (- (A $$ (a, j) gdiv D) + 1) a (j + m) A" unfolding reduce_element_mod_D_def using True by auto also have "... = ?P * A" by (rule addrow_mat[OF A], insert j mn, auto) finally have "reduce_element_mod_D A a j D m = ?P * A" . moreover have "?P \ carrier_mat (m+n) (m+n)" by simp moreover have "invertible_mat ?P" by (metis addrow_mat_carrier a det_addrow_mat dvd_mult_right invertible_iff_is_unit_JNF mult.right_neutral not_add_less2 semiring_gcd_class.gcd_dvd1) ultimately show ?thesis1 and ?thesis2 using rw by blast+ next case False show ?thesis1 proof (cases "j=0") case True have "reduce_element_mod_D A a j D m = A" unfolding reduce_element_mod_D_def using False True by auto then show ?thesis by (metis A_def assms(2) assms(3) carrier_append_rows invertible_mat_one left_mult_one_mat one_carrier_mat) next case False let ?P = "addrow_mat (m+n) (- (A $$ (a, j) gdiv D)) a (j + m)" have A: "A \ carrier_mat (m + n) n" using A_def B A' mn by auto have "reduce_element_mod_D A a j D m = addrow (- (A $$ (a, j) gdiv D)) a (j + m) A" unfolding reduce_element_mod_D_def using False by auto also have "... = ?P * A" by (rule addrow_mat[OF A], insert j mn, auto) finally have "reduce_element_mod_D A a j D m = ?P * A" . moreover have "?P \ carrier_mat (m+n) (m+n)" by simp moreover have "invertible_mat ?P" by (metis addrow_mat_carrier a det_addrow_mat dvd_mult_right invertible_iff_is_unit_JNF mult.right_neutral not_add_less2 semiring_gcd_class.gcd_dvd1) ultimately show ?thesis by blast qed show ?thesis2 proof - let ?P = "addrow_mat (m+n) (- (A $$ (a, j) gdiv D)) a (j + m)" have A: "A \ carrier_mat (m + n) n" using A_def B A' mn by auto have "reduce_element_mod_D_abs A a j D m = addrow (- (A $$ (a, j) gdiv D)) a (j + m) A" unfolding reduce_element_mod_D_abs_def using False by auto also have "... = ?P * A" by (rule addrow_mat[OF A], insert j mn, auto) finally have "reduce_element_mod_D_abs A a j D m = ?P * A" . moreover have "?P \ carrier_mat (m+n) (m+n)" by simp moreover have "invertible_mat ?P" by (metis addrow_mat_carrier a det_addrow_mat dvd_mult_right invertible_iff_is_unit_JNF mult.right_neutral not_add_less2 semiring_gcd_class.gcd_dvd1) ultimately show ?thesis by blast qed qed lemma reduce_row_mod_D_invertible_mat_case_m: assumes A_def: "A = A' @\<^sub>r B" and "B \ carrier_mat n n" and A': "A' \ carrier_mat m n" and a: "a < m" and j: "\j\set xs. j (B $$ (j, j) = D) \ (\j'\{0..n" shows "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_row_mod_D A a xs D m = P * A" using assms proof (induct A a xs D m arbitrary: A' B rule: reduce_row_mod_D.induct) case (1 A a D m) show ?case by (rule exI[of _ "1\<^sub>m (m+n)"], insert "1.prems", auto simp add: append_rows_def) next case (2 A a x xs D m) note A_def = "2.prems"(1) note B = "2.prems"(2) note A' = "2.prems"(3) note a = "2.prems"(4) note j = "2.prems"(5) note mn = "2.prems"(6) let ?reduce_xs = "(reduce_element_mod_D A a x D m)" have 1: "reduce_row_mod_D A a (x # xs) D m = reduce_row_mod_D ?reduce_xs a xs D m" by simp have "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D A a x D m = P * A" by (rule reduce_element_mod_D_invertible_mat_case_m, insert "2.prems", auto) from this obtain P where P: "P \ carrier_mat (m+n) (m+n)" and inv_P: "invertible_mat P" and R_P: "reduce_element_mod_D A a x D m = P * A" by auto have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ reduce_row_mod_D ?reduce_xs a xs D m = P * ?reduce_xs" proof (rule "2.hyps") let ?A' = "mat_of_rows n [Matrix.row ?reduce_xs i. i \ [0..r ?B'" - by (smt "2"(2) "2"(4) P R_P add.comm_neutral append_rows_def append_rows_split carrier_matD + by (smt (verit) "2"(2) "2"(4) P R_P add.comm_neutral append_rows_def append_rows_split carrier_matD index_mat_four_block(3) index_mult_mat(2) index_zero_mat(3) le_add1 reduce_element_mod_D_preserves_dimensions(2)) show "\j\set xs. j < n \ ?B' $$ (j, j) = D \ (\j'\{0.. set xs" have jn: "jj'\{0..{0.. ?B' $$ (j, j) = D \ (\j'\{0..m" using "2.prems" by auto qed from this obtain P2 where P2: "P2 \ carrier_mat (m + n) (m + n)" and inv_P2: "invertible_mat P2" and R_P2: "reduce_row_mod_D ?reduce_xs a xs D m = P2 * ?reduce_xs" by auto have "invertible_mat (P2 * P)" using P P2 inv_P inv_P2 invertible_mult_JNF by blast moreover have "(P2 * P) \ carrier_mat (m+n) (m+n)" using P2 P by auto moreover have "reduce_row_mod_D A a (x # xs) D m = (P2 * P) * A" - by (smt P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv + by (smt (verit) P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv index_mult_mat reduce_row_mod_D_preserves_dimensions) ultimately show ?case by blast qed lemma reduce_row_mod_D_abs_invertible_mat_case_m: assumes A_def: "A = A' @\<^sub>r B" and "B \ carrier_mat n n" and A': "A' \ carrier_mat m n" and a: "a < m" and j: "\j\set xs. j (B $$ (j, j) = D) \ (\j'\{0..n" shows "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_row_mod_D_abs A a xs D m = P * A" using assms proof (induct A a xs D m arbitrary: A' B rule: reduce_row_mod_D_abs.induct) case (1 A a D m) show ?case by (rule exI[of _ "1\<^sub>m (m+n)"], insert "1.prems", auto simp add: append_rows_def) next case (2 A a x xs D m) note A_def = "2.prems"(1) note B = "2.prems"(2) note A' = "2.prems"(3) note a = "2.prems"(4) note j = "2.prems"(5) note mn = "2.prems"(6) let ?reduce_xs = "(reduce_element_mod_D_abs A a x D m)" have 1: "reduce_row_mod_D_abs A a (x # xs) D m = reduce_row_mod_D_abs ?reduce_xs a xs D m" by simp have "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D_abs A a x D m = P * A" by (rule reduce_element_mod_D_abs_invertible_mat_case_m, insert "2.prems", auto) from this obtain P where P: "P \ carrier_mat (m+n) (m+n)" and inv_P: "invertible_mat P" and R_P: "reduce_element_mod_D_abs A a x D m = P * A" by auto have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ reduce_row_mod_D_abs ?reduce_xs a xs D m = P * ?reduce_xs" proof (rule "2.hyps") let ?A' = "mat_of_rows n [Matrix.row ?reduce_xs i. i \ [0..r ?B'" - by (smt "2"(2) "2"(4) P R_P add.comm_neutral append_rows_def append_rows_split carrier_matD + by (smt (verit) "2"(2) "2"(4) P R_P add.comm_neutral append_rows_def append_rows_split carrier_matD index_mat_four_block(3) index_mult_mat(2) index_zero_mat(3) le_add1 reduce_element_mod_D_preserves_dimensions(4)) show "\j\set xs. j < n \ ?B' $$ (j, j) = D \ (\j'\{0.. set xs" have jn: "jj'\{0..{0.. ?B' $$ (j, j) = D \ (\j'\{0..m" using "2.prems" by auto qed from this obtain P2 where P2: "P2 \ carrier_mat (m + n) (m + n)" and inv_P2: "invertible_mat P2" and R_P2: "reduce_row_mod_D_abs ?reduce_xs a xs D m = P2 * ?reduce_xs" by auto have "invertible_mat (P2 * P)" using P P2 inv_P inv_P2 invertible_mult_JNF by blast moreover have "(P2 * P) \ carrier_mat (m+n) (m+n)" using P2 P by auto moreover have "reduce_row_mod_D_abs A a (x # xs) D m = (P2 * P) * A" - by (smt P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv + by (smt (verit) P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv index_mult_mat reduce_row_mod_D_preserves_dimensions_abs) ultimately show ?case by blast qed (*Similar to thm reduce_row_mod_D_case_m' but including the case a = m. This could substitute the previous version.*) lemma reduce_row_mod_D_case_m'': assumes A_def: "A = A' @\<^sub>r B" and "B \ carrier_mat n n" and A': "A' \ carrier_mat m n" and "a \ m" and j: "\j\set xs. j (B $$ (j, j) = D) \ (\j'\{0..n" and "0 \ set xs" and "D > 0" shows "reduce_row_mod_D A a xs D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k \ set xs then if k = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" using assms proof (induct A a xs D m arbitrary: A' B rule: reduce_row_mod_D.induct) case (1 A a D m) then show ?case by force next case (2 A a x xs D m) note A_A'B = "2.prems"(1) note B = "2.prems"(2) note A' = "2.prems"(3) note a = "2.prems"(4) note j = "2.prems"(5) note mn = "2.prems"(7) note d = "2.prems"(6) note zero_not_xs = "2.prems"(8) let ?reduce_xs = "(reduce_element_mod_D A a x D m)" have reduce_xs_carrier: "?reduce_xs \ carrier_mat (m + n) n" by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) add.right_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_zero_mat(2,3) reduce_element_mod_D_preserves_dimensions) have A: "A:carrier_mat (m+n) n" using A' B A_A'B by blast have 1: "reduce_row_mod_D A a (x # xs) D m = reduce_row_mod_D ?reduce_xs a xs D m" by simp have 2: "reduce_element_mod_D A a j D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k = j then if j = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" if "j\set (x#xs)" for j by (rule reduce_element_mod_D_case_m'[OF A_A'B B A'], insert "2.prems" that, auto) have "reduce_row_mod_D ?reduce_xs a xs D m = Matrix.mat (dim_row ?reduce_xs) (dim_col ?reduce_xs) (\(i,k). if i = a \ k \ set xs then if k=0 then if D dvd ?reduce_xs $$ (i, k) then D else ?reduce_xs $$ (i, k) else ?reduce_xs $$ (i, k) gmod D else ?reduce_xs $$ (i, k))" proof (rule "2.hyps"[OF _ _ _ a _ _ mn]) let ?A' = "mat_of_rows n [Matrix.row (reduce_element_mod_D A a x D m) i. i \ [0.. [m..r B'" by (metis B'_def append_rows_split carrier_matD reduce_element_mod_D_preserves_dimensions(1) reduce_xs_carrier le_add1) show "\j\set xs. j (B' $$ (j, j) = D) \ (\j'\{0..set xs" have "B $$ (j,j') = B' $$ (j,j')" if j': "j' B' $$ (j, j) = D \ (\j'\{0..(i,k). if i = a \ k \ set (x # xs) then if k = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" (is "?lhs = ?rhs") proof (rule eq_matI) show "dim_row ?lhs = dim_row ?rhs" and "dim_col ?lhs = dim_col ?rhs" by auto fix i j assume i: "i j \ set xs") case True note ia_jxs = True have j_not_x: "j\x" using d True by auto show ?thesis proof (cases "j=0 \ D dvd ?reduce_xs $$(i,j)") case True have "?lhs $$ (i,j) = D" using True i j ia_jxs by auto also have "... = ?rhs $$ (i,j)" using i j j_not_x by (metis "2.prems"(8) True ia_jxs list.set_intros(2)) finally show ?thesis . next case False show ?thesis - by (smt (z3) "2" "2.prems"(8) dim_col_mat(1) dim_row_mat(1) i index_mat(1) insert_iff j j_not_x list.set(2) old.prod.case) + by (smt (verit) "2" "2.prems"(8) dim_col_mat(1) dim_row_mat(1) i index_mat(1) insert_iff j j_not_x list.set(2) old.prod.case) qed next case False show ?thesis using 2 i j xn - by (smt (z3) "2.prems"(8) False carrier_matD(2) dim_row_mat(1) index_mat(1) + by (smt (verit) "2.prems"(8) False carrier_matD(2) dim_row_mat(1) index_mat(1) insert_iff jn list.set(2) old.prod.case reduce_element_mod_D_preserves_dimensions(2) reduce_xs_carrier) qed qed finally show ?case using 1 by simp qed (*Similar to thm reduce_row_mod_D_abs_case_m' but including the case a = m. This could substitute the previous version.*) lemma reduce_row_mod_D_abs_case_m'': assumes A_def: "A = A' @\<^sub>r B" and "B \ carrier_mat n n" and A': "A' \ carrier_mat m n" and "a \ m" and j: "\j\set xs. j (B $$ (j, j) = D) \ (\j'\{0..n" and "0 \ set xs" and "D > 0" shows "reduce_row_mod_D_abs A a xs D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k \ set xs then if k = 0 \ D dvd A$$(i,k) then D else A$$(i,k) gmod D else A$$(i,k))" using assms proof (induct A a xs D m arbitrary: A' B rule: reduce_row_mod_D_abs.induct) case (1 A a D m) then show ?case by force next case (2 A a x xs D m) note A_A'B = "2.prems"(1) note B = "2.prems"(2) note A' = "2.prems"(3) note a = "2.prems"(4) note j = "2.prems"(5) note mn = "2.prems"(7) note d = "2.prems"(6) note zero_not_xs = "2.prems"(8) let ?reduce_xs = "(reduce_element_mod_D_abs A a x D m)" have reduce_xs_carrier: "?reduce_xs \ carrier_mat (m + n) n" by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) add.right_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_zero_mat(2,3) reduce_element_mod_D_preserves_dimensions) have A: "A:carrier_mat (m+n) n" using A' B A_A'B by blast have 1: "reduce_row_mod_D_abs A a (x # xs) D m = reduce_row_mod_D_abs ?reduce_xs a xs D m" by simp have 2: "reduce_element_mod_D_abs A a j D m = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a \ k = j then if j = 0 \ D dvd A$$(i,k) then D else A$$(i,k) gmod D else A$$(i,k))" if "j\set (x#xs)" for j by (rule reduce_element_mod_D_abs_case_m'[OF A_A'B B A'], insert "2.prems" that, auto) have "reduce_row_mod_D_abs ?reduce_xs a xs D m = Matrix.mat (dim_row ?reduce_xs) (dim_col ?reduce_xs) (\(i,k). if i = a \ k \ set xs then if k=0 \ D dvd ?reduce_xs $$ (i, k) then D else ?reduce_xs $$ (i, k) gmod D else ?reduce_xs $$ (i, k))" proof (rule "2.hyps"[OF _ _ _ a _ _ mn]) let ?A' = "mat_of_rows n [Matrix.row (reduce_element_mod_D_abs A a x D m) i. i \ [0.. [m..r B'" by (metis B'_def append_rows_split carrier_matD reduce_element_mod_D_preserves_dimensions(3) reduce_xs_carrier le_add1) show "\j\set xs. j (B' $$ (j, j) = D) \ (\j'\{0..set xs" have "B $$ (j,j') = B' $$ (j,j')" if j': "j' B' $$ (j, j) = D \ (\j'\{0..(i,k). if i = a \ k \ set (x # xs) then if k = 0 then if D dvd A$$(i,k) then D else A$$(i,k) else A$$(i,k) gmod D else A$$(i,k))" (is "?lhs = ?rhs") proof (rule eq_matI) show "dim_row ?lhs = dim_row ?rhs" and "dim_col ?lhs = dim_col ?rhs" by auto fix i j assume i: "i j \ set xs") case True note ia_jxs = True have j_not_x: "j\x" using d True by auto show ?thesis proof (cases "j=0 \ D dvd ?reduce_xs $$(i,j)") case True have "?lhs $$ (i,j) = D" using True i j ia_jxs by auto also have "... = ?rhs $$ (i,j)" using i j j_not_x by (metis "2.prems"(8) True ia_jxs list.set_intros(2)) finally show ?thesis . next case False show ?thesis - by (smt (z3) "2" "2.prems"(8) dim_col_mat(1) dim_row_mat(1) i index_mat(1) insert_iff j j_not_x list.set(2) old.prod.case) + by (smt (verit) "2" "2.prems"(8) dim_col_mat(1) dim_row_mat(1) i index_mat(1) insert_iff j j_not_x list.set(2) old.prod.case) qed next case False show ?thesis using 2 i j xn - by (smt (z3) "2.prems"(8) False carrier_matD(2) dim_row_mat(1) index_mat(1) + by (smt (verit) "2.prems"(8) False carrier_matD(2) dim_row_mat(1) index_mat(1) insert_iff jn list.set(2) old.prod.case reduce_element_mod_D_preserves_dimensions(4) reduce_xs_carrier) qed qed finally show ?case using 1 by (smt (verit, ccfv_SIG) "2.prems"(8) cong_mat split_conv) qed lemma assumes A_def: "A = A' @\<^sub>r B" and B: "B \ carrier_mat n n" and A': "A' \ carrier_mat m n" and a: "a\m" and j: "jn" and j0: "j\0" shows reduce_element_mod_D_invertible_mat_case_m': "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D A a j D m = P * A" (is ?thesis1) and reduce_element_mod_D_abs_invertible_mat_case_m': "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D_abs A a j D m = P * A" (is ?thesis2) proof - let ?P = "addrow_mat (m+n) (- (A $$ (a, j) gdiv D)) a (j + m)" have jm: "j+m \a" using j0 a by auto have A: "A \ carrier_mat (m + n) n" using A_def A' B mn by auto have rw: "reduce_element_mod_D A a j D m = reduce_element_mod_D_abs A a j D m" unfolding reduce_element_mod_D_def reduce_element_mod_D_abs_def using j0 by auto have "reduce_element_mod_D A a j D m = addrow (- (A $$ (a, j) gdiv D)) a (j + m) A" unfolding reduce_element_mod_D_def using j0 by auto also have "... = ?P * A" by (rule addrow_mat[OF A], insert j mn, auto) finally have "reduce_element_mod_D A a j D m = ?P * A" . moreover have "?P \ carrier_mat (m+n) (m+n)" by simp moreover have "invertible_mat ?P" by (metis addrow_mat_carrier det_addrow_mat dvd_mult_right jm invertible_iff_is_unit_JNF mult.right_neutral semiring_gcd_class.gcd_dvd1) ultimately show ?thesis1 and ?thesis2 using rw by metis+ qed (*Similar to reduce_row_mod_D_invertible_mat_case_m but including the case a = m, and then adding the assumption 0 not in set xs.*) lemma reduce_row_mod_D_invertible_mat_case_m': assumes A_def: "A = A' @\<^sub>r B" and "B \ carrier_mat n n" and A': "A' \ carrier_mat m n" and a: "a \ m" and j: "\j\set xs. j (B $$ (j, j) = D) \ (\j'\{0..n" and "0\ set xs" shows "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_row_mod_D A a xs D m = P * A" using assms proof (induct A a xs D m arbitrary: A' B rule: reduce_row_mod_D.induct) case (1 A a D m) show ?case by (rule exI[of _ "1\<^sub>m (m+n)"], insert "1.prems", auto simp add: append_rows_def) next case (2 A a x xs D m) note A_A'B = "2.prems"(1) note B = "2.prems"(2) note A' = "2.prems"(3) note a = "2.prems"(4) note j = "2.prems"(5) note mn = "2.prems"(7) note d = "2.prems"(6) note zero_not_xs = "2.prems"(8) let ?reduce_xs = "(reduce_element_mod_D A a x D m)" have reduce_xs_carrier: "?reduce_xs \ carrier_mat (m + n) n" by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) add.right_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_zero_mat(2,3) reduce_element_mod_D_preserves_dimensions) have A: "A:carrier_mat (m+n) n" using A' B A_A'B by blast let ?reduce_xs = "(reduce_element_mod_D A a x D m)" have 1: "reduce_row_mod_D A a (x # xs) D m = reduce_row_mod_D ?reduce_xs a xs D m" by simp have "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D A a x D m = P * A" by (rule reduce_element_mod_D_invertible_mat_case_m'[OF A_A'B B A' a _ mn], insert zero_not_xs j, auto) from this obtain P where P: "P \ carrier_mat (m+n) (m+n)" and inv_P: "invertible_mat P" and R_P: "reduce_element_mod_D A a x D m = P * A" by auto have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ reduce_row_mod_D ?reduce_xs a xs D m = P * ?reduce_xs" proof (rule "2.hyps") let ?A' = "mat_of_rows n [Matrix.row ?reduce_xs i. i \ [0.. carrier_mat n n" by auto show A'': "?A' : carrier_mat m n" by auto show reduce_split: "?reduce_xs = ?A' @\<^sub>r ?B'" - by (smt "2"(2) "2"(4) P R_P add.comm_neutral append_rows_def append_rows_split carrier_matD + by (smt (verit) "2"(2) "2"(4) P R_P add.comm_neutral append_rows_def append_rows_split carrier_matD index_mat_four_block(3) index_mult_mat(2) index_zero_mat(3) le_add1 reduce_element_mod_D_preserves_dimensions(2)) show "\j\set xs. j < n \ ?B' $$ (j, j) = D \ (\j'\{0..set xs" have "B $$ (j,j') = ?B' $$ (j,j')" if j': "j' ?B' $$ (j, j) = D \ (\j'\{0.. carrier_mat (m + n) (m + n)" and inv_P2: "invertible_mat P2" and R_P2: "reduce_row_mod_D ?reduce_xs a xs D m = P2 * ?reduce_xs" by auto have "invertible_mat (P2 * P)" using P P2 inv_P inv_P2 invertible_mult_JNF by blast moreover have "(P2 * P) \ carrier_mat (m+n) (m+n)" using P2 P by auto moreover have "reduce_row_mod_D A a (x # xs) D m = (P2 * P) * A" - by (smt P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv + by (smt (verit) P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv index_mult_mat reduce_row_mod_D_preserves_dimensions) ultimately show ?case by blast qed lemma reduce_row_mod_D_abs_invertible_mat_case_m': assumes A_def: "A = A' @\<^sub>r B" and "B \ carrier_mat n n" and A': "A' \ carrier_mat m n" and a: "a \ m" and j: "\j\set xs. j (B $$ (j, j) = D) \ (\j'\{0..n" and "0\ set xs" shows "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_row_mod_D_abs A a xs D m = P * A" using assms proof (induct A a xs D m arbitrary: A' B rule: reduce_row_mod_D_abs.induct) case (1 A a D m) show ?case by (rule exI[of _ "1\<^sub>m (m+n)"], insert "1.prems", auto simp add: append_rows_def) next case (2 A a x xs D m) note A_A'B = "2.prems"(1) note B = "2.prems"(2) note A' = "2.prems"(3) note a = "2.prems"(4) note j = "2.prems"(5) note mn = "2.prems"(7) note d = "2.prems"(6) note zero_not_xs = "2.prems"(8) let ?reduce_xs = "(reduce_element_mod_D_abs A a x D m)" have reduce_xs_carrier: "?reduce_xs \ carrier_mat (m + n) n" by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) add.right_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_zero_mat(2,3) reduce_element_mod_D_preserves_dimensions) have A: "A:carrier_mat (m+n) n" using A' B A_A'B by blast let ?reduce_xs = "(reduce_element_mod_D_abs A a x D m)" have 1: "reduce_row_mod_D_abs A a (x # xs) D m = reduce_row_mod_D_abs ?reduce_xs a xs D m" by simp have "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ reduce_element_mod_D_abs A a x D m = P * A" by (rule reduce_element_mod_D_abs_invertible_mat_case_m'[OF A_A'B B A' a _ mn], insert zero_not_xs j, auto) from this obtain P where P: "P \ carrier_mat (m+n) (m+n)" and inv_P: "invertible_mat P" and R_P: "reduce_element_mod_D_abs A a x D m = P * A" by auto have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ reduce_row_mod_D_abs ?reduce_xs a xs D m = P * ?reduce_xs" proof (rule "2.hyps") let ?A' = "mat_of_rows n [Matrix.row ?reduce_xs i. i \ [0.. carrier_mat n n" by auto show A'': "?A' : carrier_mat m n" by auto show reduce_split: "?reduce_xs = ?A' @\<^sub>r ?B'" - by (smt "2"(2) "2"(4) P R_P add.comm_neutral append_rows_def append_rows_split carrier_matD + by (smt (verit) "2"(2) "2"(4) P R_P add.comm_neutral append_rows_def append_rows_split carrier_matD index_mat_four_block(3) index_mult_mat(2) index_zero_mat(3) le_add1 reduce_element_mod_D_preserves_dimensions(4)) show "\j\set xs. j < n \ ?B' $$ (j, j) = D \ (\j'\{0..set xs" have "B $$ (j,j') = ?B' $$ (j,j')" if j': "j' ?B' $$ (j, j) = D \ (\j'\{0.. carrier_mat (m + n) (m + n)" and inv_P2: "invertible_mat P2" and R_P2: "reduce_row_mod_D_abs ?reduce_xs a xs D m = P2 * ?reduce_xs" by auto have "invertible_mat (P2 * P)" using P P2 inv_P inv_P2 invertible_mult_JNF by blast moreover have "(P2 * P) \ carrier_mat (m+n) (m+n)" using P2 P by auto moreover have "reduce_row_mod_D_abs A a (x # xs) D m = (P2 * P) * A" - by (smt P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv + by (smt (verit) P P2 R_P R_P2 1 assoc_mult_mat carrier_matD carrier_mat_triv index_mult_mat reduce_row_mod_D_preserves_dimensions_abs) ultimately show ?case by blast qed lemma reduce_invertible_mat_case_m: assumes A': "A' \ carrier_mat m n" and B: "B \ carrier_mat n n" and a: "a m" and A_def: "A = A' @\<^sub>r B" and j: "\j\set xs. j (B $$ (j, j) = D) \ (\j'\{0.. 0" and mn: "m\n" and n0: "0(i,k). if i = a then (p*A$$(a,k) + q*A$$(m,k)) else if i = m then u * A$$(a,k) + v * A$$(m,k) else A$$(i,k) )" and xs_def: "xs = [1..j\set ys. j (B $$ (j, j) = D) \ (\j'\{0.. 0" and Am0_D: "A $$ (m, 0) \ {0,D}" and Am0_D2: "A $$ (m, 0) = 0 \ A $$ (a, 0) = D" shows "\P. invertible_mat P \ P \ carrier_mat (m+n) (m+n) \ (reduce a m D A) = P * A" proof - let ?A = "Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then (p*A$$(a,k) + q*A$$(m,k)) else if i = m then u * A$$(a,k) + v * A$$(m,k) else A$$(i,k) )" have D: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" using mn by auto have A: "A \ carrier_mat (m+n) n" using A_def A' B mn by simp hence A_carrier: "?A \ carrier_mat (m+n) n" by auto let ?BM = "bezout_matrix_JNF A a m 0 euclid_ext2" have A'_BZ_A: "?A = ?BM * A" by (rule bezout_matrix_JNF_mult_eq[OF A' _ _ ab A_def B pquvd], insert a, auto) have invertible_bezout: "invertible_mat ?BM" by (rule invertible_bezout_matrix_JNF[OF A is_bezout_ext_euclid_ext2 a _ _ Aaj], insert a n0, auto) have BM: "?BM \ carrier_mat (m+n) (m+n)" unfolding bezout_matrix_JNF_def using A by auto let ?reduce_a = "reduce_row_mod_D ?A a xs D m" define A'1 where "A'1 = mat_of_rows n [Matrix.row ?A i. i \ [0.. [m..r A'2" using append_rows_split A by (metis (no_types, lifting) A'1_def A'2_def A_carrier carrier_matD le_add1) have j_A'1_A'2: "\j\set xs. j < n \ A'2 $$ (j, j) = D \ (\j'\{0..set xs" have ja_n: "ja < n" using ja unfolding xs_def by auto have ja2: "ja < dim_row A - m" using A mn ja_n by auto have ja_m: "ja < m" using ja_n mn by auto have ja_not_0: "ja \ 0" using ja unfolding xs_def by auto show "ja < n \ A'2 $$ (ja, ja) = D \ (\j'\{0.. [m..r B) $$ (m + ja, ja)" unfolding A_def .. also have "... = B $$ (ja, ja)" by (metis B Groups.add_ac(2) append_rows_nth2 assms(1) ja_n mn nat_SN.compat) also have "... = D" using j ja by blast finally have A2_D: "A'2 $$ (ja, ja) = D" . moreover have "(\j'\{0.. [m..r B) $$ (ja + m, j')" unfolding A_def by (simp add: add.commute) also have "... = B $$ (ja, j')" by (rule append_rows_nth2[OF A' B _ ja_m ja_n], insert j', auto) also have "... = 0" using mn j' ja_n j ja by auto finally show "A'2 $$ (ja, j') = 0" . qed ultimately show ?thesis using ja_n by simp qed qed have reduce_a_eq: "?reduce_a = Matrix.mat (dim_row ?A) (dim_col ?A) (\(i, k). if i = a \ k \ set xs then if k = 0 then if D dvd ?A $$ (i, k) then D else ?A $$ (i, k) else ?A $$ (i, k) gmod D else ?A $$ (i, k))" proof (rule reduce_row_mod_D_case_m'[OF A_A'_D _ _ a j_A'1_A'2 _ mn D0]) show "A'2 \ carrier_mat n n" using A A'2_def by auto show "A'1 \ carrier_mat m n" by (simp add: A'1_def mat_of_rows_def) show "distinct xs" using distinct_filter distinct_upt xs_def by blast qed have reduce_a: "?reduce_a \ carrier_mat (m+n) n" using reduce_a_eq A by auto have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ ?reduce_a = P * ?A" by (rule reduce_row_mod_D_invertible_mat_case_m[OF A_A'_D _ _ _ j_A'1_A'2 mn], insert a A A'2_def A'1_def, auto) from this obtain P where P: "P \ carrier_mat (m + n) (m + n)" and inv_P: "invertible_mat P" and reduce_a_PA: "?reduce_a = P * ?A" by blast let ?reduce_b = "reduce_row_mod_D ?reduce_a m ys D m" let ?B' = "mat_of_rows n [Matrix.row ?reduce_a i. i \ [0.. [0.. [m..r reduce_a2" by (unfold reduce_a1_def reduce_a2_def, rule append_rows_split, insert mn A, auto) have zero_notin_ys: "0 \ set ys" proof - have m: "m carrier_mat n n" unfolding reduce_a2_def using A by auto have reduce_a1: "reduce_a1 \ carrier_mat m n" unfolding reduce_a1_def using A by auto have j2: "\j\set ys. j < n \ reduce_a2 $$ (j, j) = D \ (\j'\{0.. set ys" have a_jm: "a \ j+m" using a by auto have m_not_jm: "m \ j + m" using zero_notin_ys j_in_ys by fastforce have jm: "j+m < dim_row ?A" using A_carrier j_in_ys unfolding ys_def by auto have jn: "j < dim_col ?A" using A_carrier j_in_ys unfolding ys_def by auto have jm': "j+m < dim_row A" using A_carrier j_in_ys unfolding ys_def by auto have jn': "j < dim_col A" using A_carrier j_in_ys unfolding ys_def by auto have "reduce_a2 $$ (j, j') = B $$ (j,j')" if j': "j' reduce_a2 $$ (j, j) = D \ (\j'\{0..(i, k). if i = m \ k \ set ys then if k = 0 then if D dvd ?reduce_a $$ (i, k) then D else ?reduce_a $$ (i, k) else ?reduce_a $$ (i, k) gmod D else ?reduce_a $$ (i, k))" by (rule reduce_row_mod_D_case_m''[OF reduce_a_split reduce_a2 reduce_a1 _ j2 _ mn zero_notin_ys], insert D0, auto simp add: ys_def) have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ ?reduce_b = P * ?reduce_a" by (rule reduce_row_mod_D_invertible_mat_case_m'[OF reduce_a_split reduce_a2 reduce_a1 _ j2 _ mn zero_notin_ys], auto simp add: ys_def) from this obtain Q where Q: "Q \ carrier_mat (m + n) (m + n)" and inv_Q: "invertible_mat Q" and reduce_b_Q_reduce: "?reduce_b = Q * ?reduce_a" by blast have reduce_b_eq_reduce: "?reduce_b = (reduce a m D A)" proof (rule eq_matI) show dr_eq: "dim_row ?reduce_b = dim_row (reduce a m D A)" and dc_eq: "dim_col ?reduce_b = dim_col (reduce a m D A)" using reduce_preserves_dimensions by auto fix i ja assume i: "ia \ i\m)") case True have "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt True dr_eq dc_eq i index_mat(1) ja prod.simps(2) reduce_row_mod_D_preserves_dimensions) + by (smt (verit) True dr_eq dc_eq i index_mat(1) ja prod.simps(2) reduce_row_mod_D_preserves_dimensions) also have "... = ?A $$ (i,ja)" - by (smt A True carrier_matD(2) dim_col_mat(1) dim_row_mat(1) i index_mat(1) ja_n + by (smt (verit) A True carrier_matD(2) dim_col_mat(1) dim_row_mat(1) i index_mat(1) ja_n reduce_a_eq reduce_preserves_dimensions(1) split_conv) also have "... = A $$ (i,ja)" using A True im ja_n by auto also have "... = (reduce a m D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using im ja_n A True by auto finally show ?thesis . next case False note a_or_b = False have gcd_pq: "p * A $$ (a, 0) + q * A $$ (m, 0) = gcd (A $$ (a, 0)) (A $$ (m, 0))" by (metis assms(10) euclid_ext2_works(1) euclid_ext2_works(2)) have gcd_le_D: "gcd (A $$ (a, 0)) (A $$ (m, 0)) \ D" by (metis Am0_D D0 assms(17) empty_iff gcd_le1_int gcd_le2_int insert_iff) show ?thesis proof (cases "i=a") case True note ia = True hence i_not_b: "i\m" using ab by auto have 1: "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) + by (smt (verit) ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) reduce_b_eq reduce_row_mod_D_preserves_dimensions(2)) show ?thesis proof (cases "ja=0") case True note ja0 = True hence ja_notin_xs: "ja \ set xs" unfolding xs_def by auto have "?reduce_a $$ (i,ja) = p * A $$ (a, 0) + q * A $$ (m, 0)" unfolding reduce_a_eq using True ja0 ab a_or_b i_not_b ja_n im a A False ja_notin_xs by auto also have "... = (reduce a m D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using True a_or_b i_not_b ja_n im A False using gcd_le_D gcd_pq Am0_D Am0_D2 by auto finally show ?thesis using 1 by auto next case False hence ja_in_xs: "ja \ set xs" unfolding xs_def using True ja_n im a A unfolding set_filter by auto have "?reduce_a $$ (i,ja) = ?A $$ (i, ja) gmod D" unfolding reduce_a_eq using True ab a_or_b i_not_b ja_n im a A ja_in_xs False by auto also have "... = (reduce a m D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using True a_or_b i_not_b ja_n im A False by auto finally show ?thesis using 1 by simp qed next case False note i_not_a = False have i_drb: "i set ys" unfolding ys_def using False ib ja_n im a A unfolding set_filter by auto have "?reduce_b $$ (i,ja) = (if ja = 0 then if D dvd ?reduce_a$$(i,ja) then D else ?reduce_a $$ (i, ja) else ?reduce_a $$ (i, ja) gmod D)" unfolding reduce_b_eq using i_not_a ja ja_in_ys - by (smt i_dra ja_dra a_or_b index_mat(1) prod.simps(2)) + by (smt (verit) i_dra ja_dra a_or_b index_mat(1) prod.simps(2)) also have "... = (if ja = 0 then if D dvd ?reduce_a$$(i,ja) then D else ?A $$ (i, ja) else ?A $$ (i, ja) gmod D)" unfolding reduce_a_eq using ab a_or_b ib False ja_n im a A ja_in_ys by auto also have "... = (reduce a m D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using False a_or_b ib ja_n im A using i_not_a by auto finally show ?thesis . qed qed qed qed have r: "?reduce_a = (P*?BM) * A" using A A'_BZ_A BM P reduce_a_PA by auto have "Q * P * ?BM : carrier_mat (m+n) (m+n)" using P BM Q by auto moreover have "invertible_mat (Q * P*?BM)" using inv_P invertible_bezout BM P invertible_mult_JNF inv_Q Q by (metis mult_carrier_mat) moreover have "(reduce a m D A) = (Q * P * ?BM) * A" using reduce_a_eq r reduce_b_eq_reduce - by (smt BM P Q assoc_mult_mat carrier_matD carrier_mat_triv + by (smt (verit) BM P Q assoc_mult_mat carrier_matD carrier_mat_triv dim_row_mat(1) index_mult_mat(2,3) reduce_b_Q_reduce) ultimately show ?thesis by auto qed lemma reduce_abs_invertible_mat_case_m: assumes A': "A' \ carrier_mat m n" and B: "B \ carrier_mat n n" and a: "a m" and A_def: "A = A' @\<^sub>r B" and j: "\j\set xs. j (B $$ (j, j) = D) \ (\j'\{0.. 0" and mn: "m\n" and n0: "0(i,k). if i = a then (p*A$$(a,k) + q*A$$(m,k)) else if i = m then u * A$$(a,k) + v * A$$(m,k) else A$$(i,k) )" and xs_def: "xs = filter (\i. abs (A2 $$ (a,i)) > D) [0..i. abs (A2 $$ (m,i)) > D) [0..j\set ys. j (B $$ (j, j) = D) \ (\j'\{0.. 0" shows "\P. invertible_mat P \ P \ carrier_mat (m+n) (m+n) \ (reduce_abs a m D A) = P * A" proof - let ?A = "Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then (p*A$$(a,k) + q*A$$(m,k)) else if i = m then u * A$$(a,k) + v * A$$(m,k) else A$$(i,k) )" note xs_def = xs_def[unfolded A2_def] note ys_def = ys_def[unfolded A2_def] have D: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" using mn by auto have A: "A \ carrier_mat (m+n) n" using A_def A' B mn by simp hence A_carrier: "?A \ carrier_mat (m+n) n" by auto let ?BM = "bezout_matrix_JNF A a m 0 euclid_ext2" have A'_BZ_A: "?A = ?BM * A" by (rule bezout_matrix_JNF_mult_eq[OF A' _ _ ab A_def B pquvd], insert a, auto) have invertible_bezout: "invertible_mat ?BM" by (rule invertible_bezout_matrix_JNF[OF A is_bezout_ext_euclid_ext2 a _ _ Aaj], insert a n0, auto) have BM: "?BM \ carrier_mat (m+n) (m+n)" unfolding bezout_matrix_JNF_def using A by auto let ?reduce_a = "reduce_row_mod_D_abs ?A a xs D m" define A'1 where "A'1 = mat_of_rows n [Matrix.row ?A i. i \ [0.. [m..r A'2" using append_rows_split A by (metis (no_types, lifting) A'1_def A'2_def A_carrier carrier_matD le_add1) have j_A'1_A'2: "\j\set xs. j < n \ A'2 $$ (j, j) = D \ (\j'\{0..set xs" have ja_n: "ja < n" using ja unfolding xs_def by auto have ja2: "ja < dim_row A - m" using A mn ja_n by auto have ja_m: "ja < m" using ja_n mn by auto have abs_A_a_ja_D: "\(?A $$ (a,ja))\ > D" using ja unfolding xs_def by auto have ja_not_0: "ja \ 0" proof (rule ccontr, simp) assume ja_a: "ja = 0" have A_mja_D: "A$$(m,ja) = D" proof - have "A$$(m,ja) = (A' @\<^sub>r B) $$ (m, ja)" unfolding A_def .. also have "... = B $$ (m-m,ja)" by (metis B append_rows_nth A' assms(9) carrier_matD(1) ja_a less_add_same_cancel1 less_irrefl_nat) also have "... = B $$ (0,0)" unfolding ja_a by auto also have "... = D" using mn unfolding ja_a using ja_n ja j ja_a by auto finally show ?thesis . qed have "?A $$ (a, ja) = p*A$$(a,ja) + q*A$$(m,ja)" using A_carrier ja_n a A by auto also have "... = d" using pquvd A assms(2) ja_n ja_a by (simp add: bezout_coefficients_fst_snd euclid_ext2_def) also have "... = gcd (A$$(a,ja)) (A$$(m,ja))" by (metis euclid_ext2_works(2) ja_a pquvd) also have "abs(...) \ D" using A_mja_D by (simp add: D0) finally have "abs (?A $$ (a, ja)) \ D" . thus False using abs_A_a_ja_D by auto qed show "ja < n \ A'2 $$ (ja, ja) = D \ (\j'\{0.. [m..r B) $$ (m + ja, ja)" unfolding A_def .. also have "... = B $$ (ja, ja)" by (metis B Groups.add_ac(2) append_rows_nth2 assms(1) ja_n mn nat_SN.compat) also have "... = D" using j ja by blast finally have A2_D: "A'2 $$ (ja, ja) = D" . moreover have "(\j'\{0.. [m..r B) $$ (ja + m, j')" unfolding A_def by (simp add: add.commute) also have "... = B $$ (ja, j')" by (rule append_rows_nth2[OF A' B _ ja_m ja_n], insert j', auto) also have "... = 0" using mn j' ja_n j ja by auto finally show "A'2 $$ (ja, j') = 0" . qed ultimately show ?thesis using ja_n by simp qed qed have reduce_a_eq: "?reduce_a = Matrix.mat (dim_row ?A) (dim_col ?A) (\(i, k). if i = a \ k \ set xs then if k = 0 \ D dvd ?A $$ (i, k) then D else ?A $$ (i, k) gmod D else ?A $$ (i, k))" proof (rule reduce_row_mod_D_abs_case_m'[OF A_A'_D _ _ a j_A'1_A'2 _ mn D0]) show "A'2 \ carrier_mat n n" using A A'2_def by auto show "A'1 \ carrier_mat m n" by (simp add: A'1_def mat_of_rows_def) show "distinct xs" using distinct_filter distinct_upt xs_def by blast qed have reduce_a: "?reduce_a \ carrier_mat (m+n) n" using reduce_a_eq A by auto have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ ?reduce_a = P * ?A" by (rule reduce_row_mod_D_abs_invertible_mat_case_m[OF A_A'_D _ _ _ j_A'1_A'2 mn], insert a A A'2_def A'1_def, auto) from this obtain P where P: "P \ carrier_mat (m + n) (m + n)" and inv_P: "invertible_mat P" and reduce_a_PA: "?reduce_a = P * ?A" by blast let ?reduce_b = "reduce_row_mod_D_abs ?reduce_a m ys D m" let ?B' = "mat_of_rows n [Matrix.row ?reduce_a i. i \ [0.. [0.. [m..r reduce_a2" by (unfold reduce_a1_def reduce_a2_def, rule append_rows_split, insert mn A, auto) have zero_notin_ys: "0 \ set ys" proof - have m: "m carrier_mat n n" unfolding reduce_a2_def using A by auto have reduce_a1: "reduce_a1 \ carrier_mat m n" unfolding reduce_a1_def using A by auto have j2: "\j\set ys. j < n \ reduce_a2 $$ (j, j) = D \ (\j'\{0.. set ys" have a_jm: "a \ j+m" using a by auto have m_not_jm: "m \ j + m" using zero_notin_ys j_in_ys by fastforce have jm: "j+m < dim_row ?A" using A_carrier j_in_ys unfolding ys_def by auto have jn: "j < dim_col ?A" using A_carrier j_in_ys unfolding ys_def by auto have jm': "j+m < dim_row A" using A_carrier j_in_ys unfolding ys_def by auto have jn': "j < dim_col A" using A_carrier j_in_ys unfolding ys_def by auto have "reduce_a2 $$ (j, j') = B $$ (j,j')" if j': "j' reduce_a2 $$ (j, j) = D \ (\j'\{0..(i, k). if i = m \ k \ set ys then if k = 0 \ D dvd ?reduce_a $$ (i, k) then D else ?reduce_a $$ (i, k) gmod D else ?reduce_a $$ (i, k))" by (rule reduce_row_mod_D_abs_case_m''[OF reduce_a_split reduce_a2 reduce_a1 _ j2 _ mn zero_notin_ys], insert D0, auto simp add: ys_def) have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ ?reduce_b = P * ?reduce_a" by (rule reduce_row_mod_D_abs_invertible_mat_case_m'[OF reduce_a_split reduce_a2 reduce_a1 _ j2 _ mn zero_notin_ys], auto simp add: ys_def) from this obtain Q where Q: "Q \ carrier_mat (m + n) (m + n)" and inv_Q: "invertible_mat Q" and reduce_b_Q_reduce: "?reduce_b = Q * ?reduce_a" by blast have reduce_b_eq_reduce: "?reduce_b = (reduce_abs a m D A)" proof (rule eq_matI) show dr_eq: "dim_row ?reduce_b = dim_row (reduce_abs a m D A)" and dc_eq: "dim_col ?reduce_b = dim_col (reduce_abs a m D A)" using reduce_preserves_dimensions by auto fix i ja assume i: "ia \ i\m)") case True have "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt True dr_eq dc_eq i index_mat(1) ja prod.simps(2) reduce_row_mod_D_preserves_dimensions_abs) + by (smt (verit) True dr_eq dc_eq i index_mat(1) ja prod.simps(2) reduce_row_mod_D_preserves_dimensions_abs) also have "... = ?A $$ (i,ja)" - by (smt A True carrier_matD(2) dim_col_mat(1) dim_row_mat(1) i index_mat(1) ja_n + by (smt (verit) A True carrier_matD(2) dim_col_mat(1) dim_row_mat(1) i index_mat(1) ja_n reduce_a_eq reduce_preserves_dimensions(3) split_conv) also have "... = A $$ (i,ja)" using A True im ja_n by auto also have "... = (reduce_abs a m D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using im ja_n A True by auto finally show ?thesis . next case False note a_or_b = False show ?thesis proof (cases "i=a") case True note ia = True hence i_not_b: "i\m" using ab by auto show ?thesis proof (cases "abs((p*A$$(a,ja) + q*A$$(m,ja))) > D") case True note ge_D = True have ja_in_xs: "ja \ set xs" unfolding xs_def using True ja_n im a A unfolding set_filter by auto have 1: "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) + by (smt (verit) ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) reduce_b_eq reduce_row_mod_D_preserves_dimensions_abs(2)) show ?thesis proof (cases "ja = 0 \ D dvd p*A$$(a,ja) + q*A$$(m,ja)") case True have "?reduce_a $$ (i,ja) = D" unfolding reduce_a_eq using True ab a_or_b i_not_b ja_n im a A ja_in_xs False by auto also have "... = (reduce_abs a m D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using True a_or_b i_not_b ja_n im A False ge_D by auto finally show ?thesis using 1 by simp next case False have "?reduce_a $$ (i,ja) = ?A $$ (i, ja) gmod D" unfolding reduce_a_eq using True ab a_or_b i_not_b ja_n im a A ja_in_xs False by auto also have "... = (reduce_abs a m D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using True a_or_b i_not_b ja_n im A False by auto finally show ?thesis using 1 by simp qed next case False have ja_in_xs: "ja \ set xs" unfolding xs_def using False ja_n im a A unfolding set_filter by auto have "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) + by (smt (verit) ab dc_eq dim_row_mat(1) dr_eq i ia index_mat(1) ja prod.simps(2) reduce_b_eq reduce_row_mod_D_preserves_dimensions_abs(2)) also have "... = ?A $$ (i, ja)" unfolding reduce_a_eq using False ab a_or_b i_not_b ja_n im a A ja_in_xs by auto also have "... = (reduce_abs a m D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using False a_or_b i_not_b ja_n im A by auto finally show ?thesis . qed next case False note i_not_a = False have i_drb: "i D") case True note ge_D = True have ja_in_ys: "ja \ set ys" unfolding ys_def using True False ib ja_n im a A unfolding set_filter by auto have "?reduce_b $$ (i,ja) = (if ja = 0 \ D dvd ?reduce_a$$(i,ja) then D else ?reduce_a $$ (i, ja) gmod D)" unfolding reduce_b_eq using i_not_a True ja ja_in_ys - by (smt i_dra ja_dra a_or_b index_mat(1) prod.simps(2)) + by (smt (verit) i_dra ja_dra a_or_b index_mat(1) prod.simps(2)) also have "... = (if ja = 0 \ D dvd ?reduce_a$$(i,ja) then D else ?A $$ (i, ja) gmod D)" unfolding reduce_a_eq using True ab a_or_b ib False ja_n im a A ja_in_ys by auto also have "... = (reduce_abs a m D A) $$ (i,ja)" proof (cases "ja = 0 \ D dvd ?reduce_a$$(i,ja)") case True have ja0: "ja=0" using True by auto have "u * A $$ (a, ja) + v * A $$ (m, ja) = 0" unfolding euclid_ext2_works[OF pquvd[symmetric]] ja0 - by (smt euclid_ext2_works[OF pquvd[symmetric]] more_arith_simps(11) mult.commute mult_minus_left) + by (smt (verit) euclid_ext2_works[OF pquvd[symmetric]] more_arith_simps(11) mult.commute mult_minus_left) hence abs_0: "abs((u*A$$(a,ja) + v * A$$(m,ja))) = 0" by auto show ?thesis using abs_0 D0 ge_D by linarith next case False then show ?thesis unfolding reduce_alt_def_not0[OF Aaj pquvd] using True ge_D False a_or_b ib ja_n im A using i_not_a by auto qed finally show ?thesis . next case False have ja_in_ys: "ja \ set ys" unfolding ys_def using i_not_a False ib ja_n im a A unfolding set_filter by auto have "?reduce_b $$ (i,ja) = ?reduce_a $$ (i,ja)" unfolding reduce_b_eq - by (smt False a_or_b dc_eq dim_row_mat(1) dr_eq i index_mat(1) ja ja_in_ys + by (smt (verit) False a_or_b dc_eq dim_row_mat(1) dr_eq i index_mat(1) ja ja_in_ys prod.simps(2) reduce_b_eq reduce_row_mod_D_preserves_dimensions_abs(2)) also have "... = ?A $$ (i, ja)" unfolding reduce_a_eq using False ab a_or_b i_not_a ja_n im a A ja_in_ys by auto also have "... = (reduce_abs a m D A) $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using False a_or_b i_not_a ja_n im A by auto finally show ?thesis . qed qed qed qed have r: "?reduce_a = (P*?BM) * A" using A A'_BZ_A BM P reduce_a_PA by auto have "Q * P * ?BM : carrier_mat (m+n) (m+n)" using P BM Q by auto moreover have "invertible_mat (Q * P*?BM)" using inv_P invertible_bezout BM P invertible_mult_JNF inv_Q Q by (metis mult_carrier_mat) moreover have "(reduce_abs a m D A) = (Q * P * ?BM) * A" using reduce_a_eq r reduce_b_eq_reduce - by (smt BM P Q assoc_mult_mat carrier_matD carrier_mat_triv + by (smt (verit) BM P Q assoc_mult_mat carrier_matD carrier_mat_triv dim_row_mat(1) index_mult_mat(2,3) reduce_b_Q_reduce) ultimately show ?thesis by auto qed lemma reduce_not0: assumes A: "A \ carrier_mat m n" and a: "a 0" and D0: "D \ 0" shows "reduce a b D A $$ (a, 0) \ 0" (is "?reduce $$ (a,0) \ _") and "reduce_abs a b D A $$ (a, 0) \ 0" (is "?reduce_abs $$ (a,0) \ _") proof - have "?reduce $$ (a,0) = (let r = gcd (A $$ (a, 0)) (A $$ (b, 0)) in if D dvd r then D else r)" by (rule reduce_gcd[OF A _ j Aaj], insert a, simp) also have "... \ 0" unfolding Let_def using D0 - by (smt Aaj gcd_eq_0_iff gmod_0_imp_dvd) + by (smt (verit) Aaj gcd_eq_0_iff gmod_0_imp_dvd) finally show "reduce a b D A $$ (a, 0) \ 0" . have "?reduce_abs $$ (a,0) = (let r = gcd (A $$ (a, 0)) (A $$ (b, 0)) in if D < r then if D dvd r then D else r gmod D else r)" by (rule reduce_gcd[OF A _ j Aaj], insert a, simp) also have "... \ 0" unfolding Let_def using D0 - by (smt Aaj gcd_eq_0_iff gmod_0_imp_dvd) + by (smt (verit) Aaj gcd_eq_0_iff gmod_0_imp_dvd) finally show "reduce_abs a b D A $$ (a, 0) \ 0" . qed lemma reduce_below_not0: assumes A: "A \ carrier_mat m n" and a: "a 0" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "D\ 0" shows "reduce_below a xs D A $$ (a, 0) \ 0" (is "?R $$ (a,0) \ _") using assms proof (induct a xs D A arbitrary: A rule: reduce_below.induct) case (1 a D A) then show ?case by auto next case (2 a x xs D A) note A = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note Aaj = "2.prems"(4) note d = "2.prems"(5) note D0 = "2.prems"(7) note x_less_xxs = "2.prems"(6) have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by simp obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce a x D A" have reduce_ax: "?reduce_ax \ carrier_mat m n" by (metis (no_types, lifting) A carrier_matD carrier_mat_triv reduce_preserves_dimensions) have h: "reduce_below a xs D (reduce a x D A) $$ (a,0) \ 0" proof (rule "2.hyps") show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A a _ j xm Aaj D0], insert x_less_xxs, simp) qed (insert A a j Aaj d x_less_xxs xm reduce_ax D0, auto) thus ?case by auto qed lemma reduce_below_abs_not0: assumes A: "A \ carrier_mat m n" and a: "a 0" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "D\ 0" shows "reduce_below_abs a xs D A $$ (a, 0) \ 0" (is "?R $$ (a,0) \ _") using assms proof (induct a xs D A arbitrary: A rule: reduce_below_abs.induct) case (1 a D A) then show ?case by auto next case (2 a x xs D A) note A = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note Aaj = "2.prems"(4) note d = "2.prems"(5) note D0 = "2.prems"(7) note x_less_xxs = "2.prems"(6) have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by simp obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce_abs a x D A" have reduce_ax: "?reduce_ax \ carrier_mat m n" by (metis (no_types, lifting) A carrier_matD carrier_mat_triv reduce_preserves_dimensions) have h: "reduce_below_abs a xs D (reduce_abs a x D A) $$ (a,0) \ 0" proof (rule "2.hyps") show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A a _ j xm Aaj D0], insert x_less_xxs, simp) qed (insert A a j Aaj d x_less_xxs xm reduce_ax D0, auto) thus ?case by auto qed lemma reduce_below_not0_case_m: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" and "\x \ set xs. x < m \ a < x" and "D \ 0" shows "reduce_below a (xs@[m]) D A $$ (a, 0) \ 0" (is "?R $$ (a,0) \ _") using assms proof (induct a xs D A arbitrary: A A' rule: reduce_below.induct) case (1 a D A) note A' = "1.prems"(1) note a = "1.prems"(2) note n = "1.prems"(3) note A_def = "1.prems"(4) note Aaj = "1.prems"(5) note mn = "1.prems"(6) note all_less_xxs = "1.prems"(7) note D0 = "1.prems"(8) have A: "A \ carrier_mat (m+n) n" using A' A_def by auto have "reduce_below a ([] @ [m]) D A $$ (a, 0) = reduce_below a [m] D A $$ (a, 0)" by auto also have "... = reduce a m D A $$ (a, 0)" by auto also have "... \ 0" by (rule reduce_not0[OF A _ a n _ Aaj D0], insert a n, auto) finally show ?case . next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note n = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note x_less_xxs = "2.prems"(7) note D0= "2.prems"(8) have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by simp have A: "A \ carrier_mat (m+n) n" using A' A_def by auto obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce a x D A" have reduce_ax: "?reduce_ax \ carrier_mat (m+n) n" by (metis (no_types, lifting) A carrier_matD carrier_mat_triv reduce_preserves_dimensions) have h: "reduce_below a (xs@[m]) D (reduce a x D A) $$ (a,0) \ 0" proof (rule "2.hyps") show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ _ _ _ D0], insert x_less_xxs j Aaj, auto) let ?reduce_ax' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm n Aaj]) qed (insert A a j Aaj x_less_xxs xm reduce_ax mn D0, auto) thus ?case by auto qed lemma reduce_below_abs_not0_case_m: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" and "\x \ set xs. x < m \ a < x" and "D \ 0" shows "reduce_below_abs a (xs@[m]) D A $$ (a, 0) \ 0" (is "?R $$ (a,0) \ _") using assms proof (induct a xs D A arbitrary: A A' rule: reduce_below_abs.induct) case (1 a D A) note A' = "1.prems"(1) note a = "1.prems"(2) note n = "1.prems"(3) note A_def = "1.prems"(4) note Aaj = "1.prems"(5) note mn = "1.prems"(6) note all_less_xxs = "1.prems"(7) note D0 = "1.prems"(8) have A: "A \ carrier_mat (m+n) n" using A' A_def by auto have "reduce_below_abs a ([] @ [m]) D A $$ (a, 0) = reduce_below_abs a [m] D A $$ (a, 0)" by auto also have "... = reduce_abs a m D A $$ (a, 0)" by auto also have "... \ 0" by (rule reduce_not0[OF A _ a n _ Aaj D0], insert a n, auto) finally show ?case . next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note n = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note x_less_xxs = "2.prems"(7) note D0= "2.prems"(8) have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by simp have A: "A \ carrier_mat (m+n) n" using A' A_def by auto obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce_abs a x D A" have reduce_ax: "?reduce_ax \ carrier_mat (m+n) n" by (metis (no_types, lifting) A carrier_matD carrier_mat_triv reduce_preserves_dimensions) have h: "reduce_below_abs a (xs@[m]) D (reduce_abs a x D A) $$ (a,0) \ 0" proof (rule "2.hyps") show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ _ _ _ D0], insert x_less_xxs j Aaj, auto) let ?reduce_ax' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm n Aaj]) qed (insert A a j Aaj x_less_xxs xm reduce_ax mn D0, auto) thus ?case by auto qed lemma reduce_below_invertible_mat: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "m\n" and "D>0" shows "(\P. invertible_mat P \ P \ carrier_mat (m+n) (m+n) \ reduce_below a xs D A = P * A)" using assms proof (induct a xs D A arbitrary: A' rule: reduce_below.induct) case (1 a D A) then show ?case by (metis append_rows_def carrier_matD(1) index_mat_four_block(2) reduce_below.simps(1) index_smult_mat(2) index_zero_mat(2) invertible_mat_one left_mult_one_mat' one_carrier_mat) next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note d = "2.prems"(6) note x_less_xxs = "2.prems"(7) note mn = "2.prems"(8) note D_ge0 = "2.prems"(9) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by simp obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce a x D A" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have h: "(\P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce_below a xs D (reduce a x D A) = P * reduce a x D A)" proof (rule "2.hyps"[OF _ a j _ _ ]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm j Aaj]) show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ j _ Aaj], insert "2.prems", auto) qed (insert mn d x_less_xxs D_ge0, auto) from this obtain P where inv_P: "invertible_mat P" and P: "P \ carrier_mat (m + n) (m + n)" and rb_Pr: "reduce_below a xs D (reduce a x D A) = P * reduce a x D A" by blast have *: "reduce_below a (x # xs) D A = reduce_below a xs D (reduce a x D A)" by simp have "\Q. invertible_mat Q \ Q \ carrier_mat (m+n) (m+n) \ (reduce a x D A) = Q * A" by (rule reduce_invertible_mat[OF A' a j xm _ A_def Aaj ], insert "2.prems", auto) from this obtain Q where inv_Q: "invertible_mat Q" and Q: "Q \ carrier_mat (m + n) (m + n)" and r_QA: "reduce a x D A = Q * A" by blast have "invertible_mat (P*Q)" using inv_P inv_Q P Q invertible_mult_JNF by blast moreover have "P * Q \ carrier_mat (m+n) (m+n)" using P Q by auto moreover have "reduce_below a (x # xs) D A = (P*Q) * A" - by (smt P Q * assoc_mult_mat carrier_matD(1) carrier_mat_triv index_mult_mat(2) + by (smt (verit) P Q * assoc_mult_mat carrier_matD(1) carrier_mat_triv index_mult_mat(2) r_QA rb_Pr reduce_preserves_dimensions(1)) ultimately show ?case by blast qed lemma reduce_below_abs_invertible_mat: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "m\n" and "D>0" shows "(\P. invertible_mat P \ P \ carrier_mat (m+n) (m+n) \ reduce_below_abs a xs D A = P * A)" using assms proof (induct a xs D A arbitrary: A' rule: reduce_below_abs.induct) case (1 a D A) then show ?case by (metis carrier_append_rows invertible_mat_one left_mult_one_mat one_carrier_mat reduce_below_abs.simps(1) smult_carrier_mat) next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note d = "2.prems"(6) note x_less_xxs = "2.prems"(7) note mn = "2.prems"(8) note D_ge0 = "2.prems"(9) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by simp obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce_abs a x D A" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have h: "(\P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce_below_abs a xs D (reduce_abs a x D A) = P * reduce_abs a x D A)" proof (rule "2.hyps"[OF _ a j _ _ ]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm j Aaj]) show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ j _ Aaj], insert "2.prems", auto) qed (insert mn d x_less_xxs D_ge0, auto) from this obtain P where inv_P: "invertible_mat P" and P: "P \ carrier_mat (m + n) (m + n)" and rb_Pr: "reduce_below_abs a xs D (reduce_abs a x D A) = P * reduce_abs a x D A" by blast have *: "reduce_below_abs a (x # xs) D A = reduce_below_abs a xs D (reduce_abs a x D A)" by simp have "\Q. invertible_mat Q \ Q \ carrier_mat (m+n) (m+n) \ (reduce_abs a x D A) = Q * A" by (rule reduce_abs_invertible_mat[OF A' a j xm _ A_def Aaj ], insert "2.prems", auto) from this obtain Q where inv_Q: "invertible_mat Q" and Q: "Q \ carrier_mat (m + n) (m + n)" and r_QA: "reduce_abs a x D A = Q * A" by blast have "invertible_mat (P*Q)" using inv_P inv_Q P Q invertible_mult_JNF by blast moreover have "P * Q \ carrier_mat (m+n) (m+n)" using P Q by auto moreover have "reduce_below_abs a (x # xs) D A = (P*Q) * A" - by (smt P Q * assoc_mult_mat carrier_matD(1) carrier_mat_triv index_mult_mat(2) + by (smt (verit) P Q * assoc_mult_mat carrier_matD(1) carrier_mat_triv index_mult_mat(2) r_QA rb_Pr reduce_preserves_dimensions(3)) ultimately show ?case by blast qed lemma reduce_below_preserves: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "i \ set xs" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "i\a" and "i0" shows "reduce_below a xs D A $$ (i,j) = A $$ (i,j)" using assms proof (induct a xs D A arbitrary: A' i rule: reduce_below.induct) case (1 a D A) then show ?case by auto next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note i_set_xxs = "2.prems"(7) note d = "2.prems"(8) note xxs_less_m = "2.prems"(9) note ia = "2.prems"(10) note imm = "2.prems"(11) note D_ge0 = "2.prems"(12) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "(reduce a x D A)" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) 2 add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have "reduce_below a (x # xs) D A $$ (i, j) = reduce_below a xs D (reduce a x D A) $$ (i, j)" by auto also have "... = reduce a x D A $$ (i, j)" proof (rule "2.hyps"[OF _ a j _ _ mn _ _ _ ia imm D_ge0]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm _ Aaj], insert j, auto) show "i \ set xs" using i_set_xxs by auto show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ _ _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto qed also have "... = A $$ (i,j)" by (rule reduce_preserves[OF A j Aaj], insert "2.prems", auto) finally show ?case . qed lemma reduce_below_abs_preserves: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "i \ set xs" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "i\a" and "i0" shows "reduce_below_abs a xs D A $$ (i,j) = A $$ (i,j)" using assms proof (induct a xs D A arbitrary: A' i rule: reduce_below_abs.induct) case (1 a D A) then show ?case by auto next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note i_set_xxs = "2.prems"(7) note d = "2.prems"(8) note xxs_less_m = "2.prems"(9) note ia = "2.prems"(10) note imm = "2.prems"(11) note D_ge0 = "2.prems"(12) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "(reduce_abs a x D A)" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) 2 add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have "reduce_below_abs a (x # xs) D A $$ (i, j) = reduce_below_abs a xs D (reduce_abs a x D A) $$ (i, j)" by auto also have "... = reduce_abs a x D A $$ (i, j)" proof (rule "2.hyps"[OF _ a j _ _ mn _ _ _ ia imm D_ge0]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm _ Aaj], insert j, auto) show "i \ set xs" using i_set_xxs by auto show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ _ _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto qed also have "... = A $$ (i,j)" by (rule reduce_preserves[OF A j Aaj], insert "2.prems", auto) finally show ?case . qed lemma reduce_below_0: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "i \ set xs" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "D>0" shows "reduce_below a xs D A $$ (i,0) = 0" using assms proof (induct a xs D A arbitrary: A' i rule: reduce_below.induct) case (1 a D A) then show ?case by auto next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note i_set_xxs = "2.prems"(7) note d = "2.prems"(8) note xxs_less_m = "2.prems"(9) note D_ge0 = "2.prems"(10) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce a x D A" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) show ?case proof (cases "i=x") case True have "reduce_below a (x # xs) D A $$ (i, 0) = reduce_below a xs D (reduce a x D A) $$ (i, 0)" by auto also have "... = (reduce a x D A) $$ (i, 0)" proof (rule reduce_below_preserves[OF _ a j _ _ mn ]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm j Aaj]) show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ j _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto show "i \ set xs" using True d by auto show "i \ a" using "2.prems" by blast show "i < m + n" by (simp add: True trans_less_add1 xm) qed (insert D_ge0) also have "... = 0" unfolding True by (rule reduce_0[OF A _ j _ _ Aaj], insert "2.prems", auto) finally show ?thesis . next case False note i_not_x = False have h: "reduce_below a xs D (reduce a x D A) $$ (i, 0) = 0 " proof (rule "2.hyps"[OF _ a j _ _ mn]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" proof (rule matrix_append_rows_eq_if_preserves[OF reduce_ax D1]) show "\i\{m..ja\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" proof (rule+) fix i ja assume i: "i \ {m.. a" using i a by auto have i_not_x: "i \ x" using i xm by auto have "?reduce_ax $$ (i,ja) = A $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using ja_dc i_dr i_not_a i_not_x by auto also have "... = (if i < dim_row A' then A' $$(i,ja) else (D \\<^sub>m (1\<^sub>m n))$$(i-m,ja))" by (unfold A_def, rule append_rows_nth[OF A' D1 _ ja], insert A i_dr, simp) also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" using i A' by auto finally show "?reduce_ax $$ (i,ja) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" . qed qed show "i \ set xs" using i_set_xxs i_not_x by auto show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ j _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto qed (insert D_ge0) have "reduce_below a (x # xs) D A $$ (i, 0) = reduce_below a xs D (reduce a x D A) $$ (i, 0)" by auto also have "... = 0" using h . finally show ?thesis . qed qed lemma reduce_below_abs_0: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "i \ set xs" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "D>0" shows "reduce_below_abs a xs D A $$ (i,0) = 0" using assms proof (induct a xs D A arbitrary: A' i rule: reduce_below_abs.induct) case (1 a D A) then show ?case by auto next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note i_set_xxs = "2.prems"(7) note d = "2.prems"(8) note xxs_less_m = "2.prems"(9) note D_ge0 = "2.prems"(10) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce_abs a x D A" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) show ?case proof (cases "i=x") case True have "reduce_below_abs a (x # xs) D A $$ (i, 0) = reduce_below_abs a xs D (reduce_abs a x D A) $$ (i, 0)" by auto also have "... = (reduce_abs a x D A) $$ (i, 0)" proof (rule reduce_below_abs_preserves[OF _ a j _ _ mn ]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm j Aaj]) show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ j _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto show "i \ set xs" using True d by auto show "i \ a" using "2.prems" by blast show "i < m + n" by (simp add: True trans_less_add1 xm) qed (insert D_ge0) also have "... = 0" unfolding True by (rule reduce_0[OF A _ j _ _ Aaj], insert "2.prems", auto) finally show ?thesis . next case False note i_not_x = False have h: "reduce_below_abs a xs D (reduce_abs a x D A) $$ (i, 0) = 0 " proof (rule "2.hyps"[OF _ a j _ _ mn]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" proof (rule matrix_append_rows_eq_if_preserves[OF reduce_ax D1]) show "\i\{m..ja\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" proof (rule+) fix i ja assume i: "i \ {m.. a" using i a by auto have i_not_x: "i \ x" using i xm by auto have "?reduce_ax $$ (i,ja) = A $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using ja_dc i_dr i_not_a i_not_x by auto also have "... = (if i < dim_row A' then A' $$(i,ja) else (D \\<^sub>m (1\<^sub>m n))$$(i-m,ja))" by (unfold A_def, rule append_rows_nth[OF A' D1 _ ja], insert A i_dr, simp) also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" using i A' by auto finally show "?reduce_ax $$ (i,ja) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" . qed qed show "i \ set xs" using i_set_xxs i_not_x by auto show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ j _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto qed (insert D_ge0) have "reduce_below_abs a (x # xs) D A $$ (i, 0) = reduce_below_abs a xs D (reduce_abs a x D A) $$ (i, 0)" by auto also have "... = 0" using h . finally show ?thesis . qed qed lemma reduce_below_preserves_case_m: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "i \ set xs" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "i\a" and "i m" and "D>0" shows "reduce_below a (xs @ [m]) D A $$ (i,j) = A $$ (i,j)" using assms proof (induct a xs D A arbitrary: A' i rule: reduce_below.induct) case (1 a D A) have "reduce_below a ([] @ [m]) D A $$ (i, j) = reduce_below a [m] D A $$ (i, j)" by auto also have "... = reduce a m D A $$ (i,j)" by auto also have "... = A $$ (i,j)" by (rule reduce_preserves, insert "1", auto) finally show ?case . next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note i_set_xxs = "2.prems"(7) note d = "2.prems"(8) note xxs_less_m = "2.prems"(9) note ia = "2.prems"(10) note imm = "2.prems"(11) note D_ge0 = "2.prems"(13) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "(reduce a x D A)" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) A' A_def add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have "reduce_below a ((x # xs) @ [m]) D A $$ (i, j) = reduce_below a (xs@[m]) D (reduce a x D A) $$ (i, j)" by auto also have "... = reduce a x D A $$ (i, j)" proof (rule "2.hyps"[OF _ a j _ _ mn _ _ _ ia imm _ D_ge0]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm _ Aaj], insert j, auto) show "i \ set xs" using i_set_xxs by auto show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ _ _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto show "i\m" using "2.prems" by auto qed also have "... = A $$ (i,j)" by (rule reduce_preserves[OF A j Aaj], insert "2.prems", auto) finally show ?case . qed lemma reduce_below_abs_preserves_case_m: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "i \ set xs" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "i\a" and "i m" and "D>0" shows "reduce_below_abs a (xs @ [m]) D A $$ (i,j) = A $$ (i,j)" using assms proof (induct a xs D A arbitrary: A' i rule: reduce_below_abs.induct) case (1 a D A) have "reduce_below_abs a ([] @ [m]) D A $$ (i, j) = reduce_below_abs a [m] D A $$ (i, j)" by auto also have "... = reduce_abs a m D A $$ (i,j)" by auto also have "... = A $$ (i,j)" by (rule reduce_preserves, insert "1", auto) finally show ?case . next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note i_set_xxs = "2.prems"(7) note d = "2.prems"(8) note xxs_less_m = "2.prems"(9) note ia = "2.prems"(10) note imm = "2.prems"(11) note D_ge0 = "2.prems"(13) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "(reduce_abs a x D A)" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) A' A_def add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have "reduce_below_abs a ((x # xs) @ [m]) D A $$ (i, j) = reduce_below_abs a (xs@[m]) D (reduce_abs a x D A) $$ (i, j)" by auto also have "... = reduce_abs a x D A $$ (i, j)" proof (rule "2.hyps"[OF _ a j _ _ mn _ _ _ ia imm _ D_ge0]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm _ Aaj], insert j, auto) show "i \ set xs" using i_set_xxs by auto show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ _ _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto show "i\m" using "2.prems" by auto qed also have "... = A $$ (i,j)" by (rule reduce_preserves[OF A j Aaj], insert "2.prems", auto) finally show ?case . qed lemma reduce_below_0_case_m1: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "distinct xs" and "\x \ set xs. x < m \ a < x" and "m\a" and "D>0" shows "reduce_below a (xs @ [m]) D A $$ (m,0) = 0" using assms proof (induct a xs D A arbitrary: A' rule: reduce_below.induct) case (1 a D A) have A: "A \ carrier_mat (m+n) n" using "1" by auto have " reduce_below a ([] @ [m]) D A $$ (m, 0) = reduce_below a [m] D A $$ (m, 0)" by auto also have "... = reduce a m D A $$ (m,0)" by auto also have "... = 0" by (rule reduce_0[OF A], insert "1.prems", auto) finally show ?case . next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note d = "2.prems"(7) note xxs_less_m = "2.prems"(8) note ma = "2.prems"(9) note D_ge0 = "2.prems"(10) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "(reduce a x D A)" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have "reduce_below a ((x # xs) @ [m]) D A $$ (m, 0) = reduce_below a (xs@[m]) D (reduce a x D A) $$ (m, 0)" by auto also have "... = 0" proof (rule "2.hyps"[OF ]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm j Aaj]) show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ j _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto qed (insert "2.prems", auto) finally show ?case . qed lemma reduce_below_abs_0_case_m1: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "distinct xs" and "\x \ set xs. x < m \ a < x" and "m\a" and "D>0" shows "reduce_below_abs a (xs @ [m]) D A $$ (m,0) = 0" using assms proof (induct a xs D A arbitrary: A' rule: reduce_below_abs.induct) case (1 a D A) have A: "A \ carrier_mat (m+n) n" using "1" by auto have " reduce_below_abs a ([] @ [m]) D A $$ (m, 0) = reduce_below_abs a [m] D A $$ (m, 0)" by auto also have "... = reduce_abs a m D A $$ (m,0)" by auto also have "... = 0" by (rule reduce_0[OF A], insert "1.prems", auto) finally show ?case . next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note d = "2.prems"(7) note xxs_less_m = "2.prems"(8) note ma = "2.prems"(9) note D_ge0 = "2.prems"(10) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "(reduce_abs a x D A)" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have "reduce_below_abs a ((x # xs) @ [m]) D A $$ (m, 0) = reduce_below_abs a (xs@[m]) D (reduce_abs a x D A) $$ (m, 0)" by auto also have "... = 0" proof (rule "2.hyps"[OF ]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm j Aaj]) show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ j _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto qed (insert "2.prems", auto) finally show ?case . qed lemma reduce_below_preserves_case_m2: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "i \ set xs" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "i\a" and "i0" shows "reduce_below a (xs @ [m]) D A $$ (i,0) = reduce_below a xs D A $$ (i,0)" using assms proof (induct a xs D A arbitrary: A' i rule: reduce_below.induct) case (1 a D A) then show ?case by auto next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note i_set_xxs = "2.prems"(7) note d = "2.prems"(8) note xxs_less_m = "2.prems"(9) note ia = "2.prems"(10) note imm = "2.prems"(11) note D_ge0 = "2.prems"(12) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "(reduce a x D A)" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) A_def A' add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) show ?case proof (cases "i=x") case True have "reduce_below a ((x # xs) @ [m]) D A $$ (i, 0) = reduce_below a (xs @ [m]) D (reduce a x D A) $$ (i, 0)" by auto also have "... = (reduce a x D A) $$ (i, 0)" proof (rule reduce_below_preserves_case_m[OF _ a j _ _ mn _ _ _ _ _ _ D_ge0]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" proof (rule matrix_append_rows_eq_if_preserves[OF reduce_ax D1]) show "\i\{m..ja\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" proof (rule+) fix i ja assume i: "i \ {m.. a" using i a by auto have i_not_x: "i \ x" using i xm by auto have "?reduce_ax $$ (i,ja) = A $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using ja_dc i_dr i_not_a i_not_x by auto also have "... = (if i < dim_row A' then A' $$(i,ja) else (D \\<^sub>m (1\<^sub>m n))$$(i-m,ja))" by (unfold A_def, rule append_rows_nth[OF A' D1 _ ja], insert A i_dr, simp) also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" using i A' by auto finally show "?reduce_ax $$ (i,ja) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" . qed qed show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ _ _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto show "i \ set xs" using True d by auto show "i \ a" using "2.prems" by blast show "i < m + n" by (simp add: True trans_less_add1 xm) show "i \ m" by (simp add: True less_not_refl3 xm) qed also have "... = 0" unfolding True by (rule reduce_0[OF A _ _ _ _ Aaj], insert "2.prems", auto) also have "... = reduce_below a (x # xs) D A $$ (i, 0) " unfolding True by (rule reduce_below_0[symmetric], insert "2.prems", auto) finally show ?thesis . next case False have "reduce_below a ((x # xs) @ [m]) D A $$ (i, 0) = reduce_below a (xs@[m]) D (reduce a x D A) $$ (i, 0)" by auto also have "... = reduce_below a xs D (reduce a x D A) $$ (i, 0)" proof (rule "2.hyps"[OF _ a j _ _ mn _ _ _ ia imm D_ge0]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm j Aaj]) show "i \ set xs" using i_set_xxs False by auto show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ j _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto qed also have "... = reduce_below a (x # xs) D A $$ (i, 0)" by auto finally show ?thesis . qed qed lemma reduce_below_abs_preserves_case_m2: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "i \ set xs" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "i\a" and "i0" shows "reduce_below_abs a (xs @ [m]) D A $$ (i,0) = reduce_below_abs a xs D A $$ (i,0)" using assms proof (induct a xs D A arbitrary: A' i rule: reduce_below_abs.induct) case (1 a D A) then show ?case by auto next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note i_set_xxs = "2.prems"(7) note d = "2.prems"(8) note xxs_less_m = "2.prems"(9) note ia = "2.prems"(10) note imm = "2.prems"(11) note D_ge0 = "2.prems"(12) have D0: "D\0" using D_ge0 by simp have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "(reduce_abs a x D A)" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) A_def A' add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) show ?case proof (cases "i=x") case True have "reduce_below_abs a ((x # xs) @ [m]) D A $$ (i, 0) = reduce_below_abs a (xs @ [m]) D (reduce_abs a x D A) $$ (i, 0)" by auto also have "... = (reduce_abs a x D A) $$ (i, 0)" proof (rule reduce_below_abs_preserves_case_m[OF _ a j _ _ mn _ _ _ _ _ _ D_ge0]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" proof (rule matrix_append_rows_eq_if_preserves[OF reduce_ax D1]) show "\i\{m..ja\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" proof (rule+) fix i ja assume i: "i \ {m.. a" using i a by auto have i_not_x: "i \ x" using i xm by auto have "?reduce_ax $$ (i,ja) = A $$ (i,ja)" unfolding reduce_alt_def_not0[OF Aaj pquvd] using ja_dc i_dr i_not_a i_not_x by auto also have "... = (if i < dim_row A' then A' $$(i,ja) else (D \\<^sub>m (1\<^sub>m n))$$(i-m,ja))" by (unfold A_def, rule append_rows_nth[OF A' D1 _ ja], insert A i_dr, simp) also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" using i A' by auto finally show "?reduce_ax $$ (i,ja) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, ja)" . qed qed show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ _ _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto show "i \ set xs" using True d by auto show "i \ a" using "2.prems" by blast show "i < m + n" by (simp add: True trans_less_add1 xm) show "i \ m" by (simp add: True less_not_refl3 xm) qed also have "... = 0" unfolding True by (rule reduce_0[OF A _ _ _ _ Aaj], insert "2.prems", auto) also have "... = reduce_below_abs a (x # xs) D A $$ (i, 0) " unfolding True by (rule reduce_below_abs_0[symmetric], insert "2.prems", auto) finally show ?thesis . next case False have "reduce_below_abs a ((x # xs) @ [m]) D A $$ (i, 0) = reduce_below_abs a (xs@[m]) D (reduce_abs a x D A) $$ (i, 0)" by auto also have "... = reduce_below_abs a xs D (reduce_abs a x D A) $$ (i, 0)" proof (rule "2.hyps"[OF _ a j _ _ mn _ _ _ ia imm D_ge0]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm j Aaj]) show "i \ set xs" using i_set_xxs False by auto show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ j _ Aaj], insert "2.prems", auto) show "?A' \ carrier_mat m n" by auto qed also have "... = reduce_below_abs a (x # xs) D A $$ (i, 0)" by auto finally show ?thesis . qed qed lemma reduce_below_0_case_m: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "i \ set (xs @ [m])" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "D>0" shows "reduce_below a (xs @ [m]) D A $$ (i,0) = 0" proof (cases "i=m") case True show ?thesis by (unfold True, rule reduce_below_0_case_m1, insert assms, auto) next case False have "reduce_below a (xs @ [m]) D A $$ (i,0) = reduce_below a (xs) D A $$ (i,0)" by (rule reduce_below_preserves_case_m2[OF A' a j A_def Aaj mn], insert assms False, auto) also have "... = 0" by (rule reduce_below_0, insert assms False, auto) finally show ?thesis . qed lemma reduce_below_abs_0_case_m: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" assumes "i \ set (xs @ [m])" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "D>0" shows "reduce_below_abs a (xs @ [m]) D A $$ (i,0) = 0" proof (cases "i=m") case True show ?thesis by (unfold True, rule reduce_below_abs_0_case_m1, insert assms, auto) next case False have "reduce_below_abs a (xs @ [m]) D A $$ (i,0) = reduce_below_abs a (xs) D A $$ (i,0)" by (rule reduce_below_abs_preserves_case_m2[OF A' a j A_def Aaj mn], insert assms False, auto) also have "... = 0" by (rule reduce_below_abs_0, insert assms False, auto) finally show ?thesis . qed lemma reduce_below_0_case_m_complete: assumes A': "A' \ carrier_mat m n" and a: "0r (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (0,0) \ 0" and mn: "m\n" assumes i_mn: "i < m+n" and d_xs: "distinct xs" and xs: "\x \ set xs. x < m \ 0 < x" and ia: "i\0" and xs_def: "xs = filter (\i. A $$ (i,0) \ 0) [1..0" shows "reduce_below 0 (xs @ [m]) D A $$ (i,0) = 0" proof (cases "i \ set (xs @ [m])") case True show ?thesis by (rule reduce_below_0_case_m[OF A' a j A_def Aaj mn True d_xs xs D]) next case False have A: "A \ carrier_mat (m+n) n" using A' A_def by simp have "reduce_below 0 (xs @ [m]) D A $$ (i,0) = A $$ (i,0)" by (rule reduce_below_preserves_case_m[OF A' a j A_def Aaj mn _ _ _ _ _ _ D], insert i_mn d_xs xs ia False, auto) also have "... = 0" using False ia i_mn A unfolding xs_def by auto finally show ?thesis . qed lemma reduce_below_abs_0_case_m_complete: assumes A': "A' \ carrier_mat m n" and a: "0r (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (0,0) \ 0" and mn: "m\n" assumes i_mn: "i < m+n" and d_xs: "distinct xs" and xs: "\x \ set xs. x < m \ 0 < x" and ia: "i\0" and xs_def: "xs = filter (\i. A $$ (i,0) \ 0) [1..0" shows "reduce_below_abs 0 (xs @ [m]) D A $$ (i,0) = 0" proof (cases "i \ set (xs @ [m])") case True show ?thesis by (rule reduce_below_abs_0_case_m[OF A' a j A_def Aaj mn True d_xs xs D]) next case False have A: "A \ carrier_mat (m+n) n" using A' A_def by simp have "reduce_below_abs 0 (xs @ [m]) D A $$ (i,0) = A $$ (i,0)" by (rule reduce_below_abs_preserves_case_m[OF A' a j A_def Aaj mn _ _ _ _ _ _ D], insert i_mn d_xs xs ia False, auto) also have "... = 0" using False ia i_mn A unfolding xs_def by auto finally show ?thesis . qed (*Now we take care of the mth row of A*) lemma reduce_below_invertible_mat_case_m: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" and "distinct xs" and "\x \ set xs. x < m \ a < x" and D0: "D>0" shows "(\P. invertible_mat P \ P \ carrier_mat (m+n) (m+n) \ reduce_below a (xs@[m]) D A = P * A)" using assms proof (induct a xs D A arbitrary: A' rule: reduce_below.induct) case (1 a D A) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(m,0))" by (metis prod_cases5) have D: "D \\<^sub>m (1\<^sub>m n) : carrier_mat n n" by auto note A' = "1.prems"(1) note a = "1.prems"(2) note j = "1.prems"(3) note A_def = "1.prems"(4) note Aaj = "1.prems"(5) note mn = "1.prems"(6) note D0 = "1.prems"(9) have Am0_D: "A $$ (m, 0) = D" proof - have "A $$ (m, 0) = (D \\<^sub>m (1\<^sub>m n)) $$ (m-m,0)" - by (smt (z3) "1"(1) "1"(3) "1"(4) D append_rows_nth3 diff_is_0_eq diff_self_eq_0 less_add_same_cancel1) + unfolding "1"(4) + by (meson "1"(1) "1"(3) D append_rows_nth3 less_add_same_cancel1 order.refl) also have "... = D" by (simp add: n0) finally show ?thesis . qed have "reduce_below a ([]@[m]) D A = reduce a m D A" by auto let ?A = "Matrix.mat (dim_row A) (dim_col A) (\(i, k). if i = a then p * A $$ (a, k) + q * A $$ (m, k) else if i = m then u * A $$ (a, k) + v * A $$ (m, k) else A $$ (i, k))" let ?xs = "[1..P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce a m D A = P * A" by (rule reduce_invertible_mat_case_m[OF A' D a _ A_def _ Aaj mn n0 pquvd, of ?xs _ _ ?ys], insert a D0 Am0_D, auto) then show ?case by auto next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note n0 = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note d = "2.prems"(7) note xxs_less_m = "2.prems"(8) note D0 = "2.prems"(9) have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) have Am0_D: "A $$ (m, 0) = D" proof - have "A $$ (m, 0) = (D \\<^sub>m (1\<^sub>m n)) $$ (m-m,0)" - by (smt (z3) "2"(2) "2"(4) "2"(5) D1 append_rows_nth3 - cancel_comm_monoid_add_class.diff_cancel diff_is_0_eq less_add_same_cancel1) + unfolding "2"(5) + by (meson "2"(2) "2"(4) D1 append_rows_nth3 less_add_same_cancel1 verit_comp_simplify(2)) also have "... = D" by (simp add: n0) finally show ?thesis . qed obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce a x D A" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have h: "(\P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce_below a (xs@[m]) D (reduce a x D A) = P * reduce a x D A)" proof (rule "2.hyps"[OF _ a n0 _ _ ]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm n0 Aaj]) show "reduce a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ n0 _ Aaj], insert "2.prems", auto) qed (insert d xxs_less_m mn n0 D0, auto) from this obtain P where inv_P: "invertible_mat P" and P: "P \ carrier_mat (m + n) (m + n)" and rb_Pr: "reduce_below a (xs@[m]) D (reduce a x D A) = P * reduce a x D A" by blast have *: "reduce_below a ((x # xs)@[m]) D A = reduce_below a (xs@[m]) D (reduce a x D A)" by simp have "\Q. invertible_mat Q \ Q \ carrier_mat (m+n) (m+n) \ (reduce a x D A) = Q * A" by (rule reduce_invertible_mat[OF A' a n0 xm _ A_def Aaj _ mn D0], insert xxs_less_m, auto) from this obtain Q where inv_Q: "invertible_mat Q" and Q: "Q \ carrier_mat (m + n) (m + n)" and r_QA: "reduce a x D A = Q * A" by blast have "invertible_mat (P*Q)" using inv_P inv_Q P Q invertible_mult_JNF by blast moreover have "P * Q \ carrier_mat (m+n) (m+n)" using P Q by auto moreover have "reduce_below a ((x # xs)@[m]) D A = (P*Q) * A" - by (smt P Q * assoc_mult_mat carrier_matD(1) carrier_mat_triv index_mult_mat(2) + by (smt (verit) P Q * assoc_mult_mat carrier_matD(1) carrier_mat_triv index_mult_mat(2) r_QA rb_Pr reduce_preserves_dimensions(1)) ultimately show ?case by blast qed (*Now we take care of the mth row of A*) lemma reduce_below_abs_invertible_mat_case_m: assumes A': "A' \ carrier_mat m n" and a: "ar (D \\<^sub>m (1\<^sub>m n))" and Aaj: "A $$ (a,0) \ 0" and mn: "m\n" and "distinct xs" and "\x \ set xs. x < m \ a < x" and D0: "D>0" shows "(\P. invertible_mat P \ P \ carrier_mat (m+n) (m+n) \ reduce_below_abs a (xs@[m]) D A = P * A)" using assms proof (induct a xs D A arbitrary: A' rule: reduce_below_abs.induct) case (1 a D A) obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(m,0))" by (metis prod_cases5) have D: "D \\<^sub>m (1\<^sub>m n) : carrier_mat n n" by auto note A' = "1.prems"(1) note a = "1.prems"(2) note j = "1.prems"(3) note A_def = "1.prems"(4) note Aaj = "1.prems"(5) note mn = "1.prems"(6) note D0 = "1.prems"(9) have Am0_D: "A $$ (m, 0) = D" proof - have "A $$ (m, 0) = (D \\<^sub>m (1\<^sub>m n)) $$ (m-m,0)" - by (smt (z3) "1"(1) "1"(3) "1"(4) D append_rows_nth3 diff_is_0_eq diff_self_eq_0 less_add_same_cancel1) + unfolding "1"(4) + by (meson "1"(1) "1"(3) D append_rows_nth3 le_refl less_add_same_cancel1) also have "... = D" by (simp add: n0) finally show ?thesis . qed have "reduce_below_abs a ([]@[m]) D A = reduce_abs a m D A" by auto let ?A = "Matrix.mat (dim_row A) (dim_col A) (\(i, k). if i = a then p * A $$ (a, k) + q * A $$ (m, k) else if i = m then u * A $$ (a, k) + v * A $$ (m, k) else A $$ (i, k))" let ?xs = "filter (\i. D < \?A $$ (a, i)\) [0..P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce_abs a m D A = P * A" by (rule reduce_abs_invertible_mat_case_m[OF A' D a _ A_def _ Aaj mn n0 pquvd, of ?xs _ _ ?ys], insert a D0 Am0_D, auto) then show ?case by auto next case (2 a x xs D A) note A' = "2.prems"(1) note a = "2.prems"(2) note n0 = "2.prems"(3) note A_def = "2.prems"(4) note Aaj = "2.prems"(5) note mn = "2.prems"(6) note d = "2.prems"(7) note xxs_less_m = "2.prems"(8) note D0 = "2.prems"(9) have A: "A \ carrier_mat (m+n) n" using A' mn A_def by auto have xm: "x < m" using "2.prems" by auto have D1: "D \\<^sub>m 1\<^sub>m n \ carrier_mat n n" by (simp add: mn) have Am0_D: "A $$ (m, 0) = D" proof - have "A $$ (m, 0) = (D \\<^sub>m (1\<^sub>m n)) $$ (m-m,0)" - by (smt (z3) "2"(2) "2"(4) "2"(5) D1 append_rows_nth3 - cancel_comm_monoid_add_class.diff_cancel diff_is_0_eq less_add_same_cancel1) + unfolding "2"(5) + by (meson "2"(2) "2"(4) D1 append_rows_nth3 less_add_same_cancel1 order_refl) also have "... = D" by (simp add: n0) finally show ?thesis . qed obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce_abs a x D A" have reduce_ax: "?reduce_ax \ carrier_mat (m + n) n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have h: "(\P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce_below_abs a (xs@[m]) D (reduce_abs a x D A) = P * reduce_abs a x D A)" proof (rule "2.hyps"[OF _ a n0 _ _ ]) let ?A' = "mat_of_rows n (map (Matrix.row ?reduce_ax) [0..r D \\<^sub>m 1\<^sub>m n" by (rule reduce_append_rows_eq[OF A' A_def a xm n0 Aaj]) show "reduce_abs a x D A $$ (a, 0) \ 0" by (rule reduce_not0[OF A _ _ n0 _ Aaj], insert "2.prems", auto) qed (insert d xxs_less_m mn n0 D0, auto) from this obtain P where inv_P: "invertible_mat P" and P: "P \ carrier_mat (m + n) (m + n)" and rb_Pr: "reduce_below_abs a (xs@[m]) D (reduce_abs a x D A) = P * reduce_abs a x D A" by blast have *: "reduce_below_abs a ((x # xs)@[m]) D A = reduce_below_abs a (xs@[m]) D (reduce_abs a x D A)" by simp have "\Q. invertible_mat Q \ Q \ carrier_mat (m+n) (m+n) \ (reduce_abs a x D A) = Q * A" by (rule reduce_abs_invertible_mat[OF A' a n0 xm _ A_def Aaj _ mn D0], insert xxs_less_m, auto) from this obtain Q where inv_Q: "invertible_mat Q" and Q: "Q \ carrier_mat (m + n) (m + n)" and r_QA: "reduce_abs a x D A = Q * A" by blast have "invertible_mat (P*Q)" using inv_P inv_Q P Q invertible_mult_JNF by blast moreover have "P * Q \ carrier_mat (m+n) (m+n)" using P Q by auto moreover have "reduce_below_abs a ((x # xs)@[m]) D A = (P*Q) * A" - by (smt P Q * assoc_mult_mat carrier_matD(1) carrier_mat_triv index_mult_mat(2) + by (smt (verit) P Q * assoc_mult_mat carrier_matD(1) carrier_mat_triv index_mult_mat(2) r_QA rb_Pr reduce_preserves_dimensions(3)) ultimately show ?case by blast qed end hide_const (open) C text \This lemma will be very important, since it will allow us to prove that the output matrix is in echelon form.\ lemma echelon_form_four_block_mat: assumes A: "A \ carrier_mat 1 1" and B: "B \ carrier_mat 1 (n-1)" and D: "D \ carrier_mat (m-1) (n-1)" and H_def: "H = four_block_mat A B (0\<^sub>m (m-1) 1) D" and A00: "A $$ (0,0) \ 0" and e_D: "echelon_form_JNF D" and m: "m>0" and n: "n>0" shows "echelon_form_JNF H" proof (rule echelon_form_JNF_intro) have H: "H \ carrier_mat m n" by (metis H_def Num.numeral_nat(7) A D m n carrier_matD carrier_mat_triv index_mat_four_block(2,3) linordered_semidom_class.add_diff_inverse not_less_eq) have Hij_Dij: "H $$ (i+1,j+1) = D $$ (i,j)" if i: "im (m-1) 1) $$ ((i+1) - dim_row A, (j+1)) else D $$ ((i+1) - dim_row A, (j+1) - dim_col A))" unfolding H_def by (rule index_mat_four_block, insert A D i j, auto) also have "... = D $$ ((i+1) - dim_row A, (j+1) - dim_col A)" using A D i j B m n by auto also have "... = D $$ (i,j)" using A by auto finally show ?thesis . qed have Hij_Dij': "H $$ (i,j) = D $$ (i-1,j-1)" if i: "i0" and j0: "j>0" for i j by (metis (no_types, lifting) H H_def Num.numeral_nat(7) A carrier_matD index_mat_four_block less_Suc0 less_not_refl3 i j i0 j0) have Hi0: "H$$(i,0) = 0" if i: "i\{1..m (m-1) 1) $$ (i - dim_row A, 0) else D $$ (i - dim_row A, 0 - dim_col A))" unfolding H_def by (rule index_mat_four_block, insert A D i, auto) also have "... = (0\<^sub>m (m-1) 1) $$ (i - dim_row A, 0)" using A D i m n by auto also have "... = 0" using i A n by auto finally show ?thesis . qed have A00_H00: "A $$ (0,0) = H $$ (0,0)" unfolding H_def using A by auto have "is_zero_row_JNF j H" if zero_iH: "is_zero_row_JNF i H" and ij: "i < j" and j: "j < dim_row H" for i j proof - have "\ is_zero_row_JNF 0 H" unfolding is_zero_row_JNF_def using m n H A00 A00_H00 by auto hence i_not0: "i\0" using zero_iH by meson have "is_zero_row_JNF (i-1) D" using zero_iH i_not0 Hij_Dij m n D H unfolding is_zero_row_JNF_def - by (auto, smt (z3) Suc_leI carrier_matD(1) le_add_diff_inverse2 Hij_Dij One_nat_def Suc_pred carrier_matD(1) j le_add_diff_inverse2 + by (auto, smt (verit) Suc_leI carrier_matD(1) le_add_diff_inverse2 Hij_Dij One_nat_def Suc_pred carrier_matD(1) j le_add_diff_inverse2 less_diff_conv less_imp_add_positive plus_1_eq_Suc that(2) trans_less_add1) hence "is_zero_row_JNF (j-1) D" using ij e_D D j m i_not0 unfolding echelon_form_JNF_def - by (auto, smt H Nat.lessE Suc_pred carrier_matD(1) diff_Suc_1 diff_Suc_less order.strict_trans) + by (auto, smt (verit) H Nat.lessE Suc_pred carrier_matD(1) diff_Suc_1 diff_Suc_less order.strict_trans) thus ?thesis - by (smt A H H_def Hi0 D atLeastLessThan_iff carrier_matD index_mat_four_block(1) + by (smt (verit) A H H_def Hi0 D atLeastLessThan_iff carrier_matD index_mat_four_block(1) is_zero_row_JNF_def le_add1 less_one linordered_semidom_class.add_diff_inverse not_less_eq plus_1_eq_Suc ij j zero_order(3)) qed thus "\i \ (\j \ is_zero_row_JNF j H)" by blast have "(LEAST n. H $$ (i, n) \ 0) < (LEAST n. H $$ (j, n) \ 0)" if ij: "i < j" and j: "j < dim_row H" and not_zero_iH: "\ is_zero_row_JNF i H" and not_zero_jH: "\ is_zero_row_JNF j H" for i j proof (cases "i = 0") case True have "(LEAST n. H $$ (i, n) \ 0) = 0" unfolding True using A00_H00 A00 by auto then show ?thesis by (metis (mono_tags) H Hi0 LeastI True atLeastLessThan_iff carrier_matD(1) is_zero_row_JNF_def leI less_one not_gr0 ij j not_zero_jH) next case False note i_not0 = False let ?least_H = "(LEAST n. H $$ (i, n) \ 0)" let ?least_Hj = "(LEAST n. H $$ (j, n) \ 0)" have least_not0: "(LEAST n. H $$ (i, n) \ 0) \ 0" proof - have \dim_row H = m\ using H by auto with \i < j\ \j < dim_row H\ have \i < m\ by simp then have \H $$ (i, 0) = 0\ using i_not0 by (auto simp add: Suc_le_eq intro: Hi0) moreover from is_zero_row_JNF_def [of i H] not_zero_iH obtain n where \H $$ (i, n) \ 0\ by blast ultimately show ?thesis by (metis (mono_tags, lifting) LeastI) qed have least_not0j: "(LEAST n. H $$ (j, n) \ 0) \ 0" proof - have "\n. H $$ (j, 0) = 0 \ H $$ (j, n) \ 0" by (metis (no_types) H Hi0 LeastI_ex Num.numeral_nat(7) atLeastLessThan_iff carrier_matD(1) is_zero_row_JNF_def linorder_neqE_nat not_gr0 not_less_Least not_less_eq order_trans_rules(19) ij j not_zero_jH wellorder_Least_lemma(2)) then show ?thesis by (metis (mono_tags, lifting) LeastI_ex) qed have least_n: "?least_H 0" and ln':"(\n'. (H $$ (i, n') \ 0) \ ?least_H \ n')" by (metis (mono_tags, lifting) is_zero_row_JNF_def that(3) wellorder_Least_lemma)+ have Hil_Dil: "H $$ (i,?least_H) = D $$ (i-1,?least_H - 1)" proof - have "H $$ (i,?least_H) = (if i < dim_row A then if ?least_H < dim_col A then A $$ (i, ?least_H) else B $$ (i, ?least_H - dim_col A) else if ?least_H < dim_col A then (0\<^sub>m (m-1) 1) $$ (i - dim_row A, ?least_H) else D $$ (i - dim_row A, ?least_H - dim_col A))" unfolding H_def by (rule index_mat_four_block, insert False j ij H A D n least_n, auto simp add: H_def) also have "... = D $$ (i - 1, ?least_H - 1)" using False j ij H A D n least_n B Hi0 Hil by auto finally show ?thesis . qed have not_zero_iD: "\ is_zero_row_JNF (i-1) D" by (metis (no_types, lifting) Hil Hil_Dil D carrier_matD(2) is_zero_row_JNF_def le_add1 le_add_diff_inverse2 least_n least_not0 less_diff_conv less_one linordered_semidom_class.add_diff_inverse) have not_zero_jD: "\ is_zero_row_JNF (j-1) D" - by (smt H Hij_Dij' One_nat_def Suc_pred D m carrier_matD diff_Suc_1 ij is_zero_row_JNF_def j + by (smt (verit) H Hij_Dij' One_nat_def Suc_pred D m carrier_matD diff_Suc_1 ij is_zero_row_JNF_def j least_not0j less_Suc0 less_Suc_eq_0_disj less_one neq0_conv not_less_Least not_less_eq plus_1_eq_Suc not_zero_jH zero_order(3)) have "?least_H - 1 = (LEAST n. D $$ (i-1, n) \ 0 \ n 0" using Hil Hil_Dil by auto show "(LEAST n. H $$ (i, n) \ 0) - 1 < dim_col D" using least_n least_not0 H D n by auto fix n' assume "D $$ (i - 1, n') \ 0 \ n' < dim_col D" hence Di1n'1: "D $$ (i - 1, n') \ 0" and n': "n' < dim_col D" by auto have "(LEAST n. H $$ (i, n) \ 0) \ n' + 1" proof (rule Least_le) have "H $$ (i, n'+1) = D $$ (i -1, (n'+1)-1)" by (rule Hij_Dij', insert i_not0 False H A ij j n' D, auto) thus Hin': "H $$ (i, n'+1) \ 0" using False Di1n'1 Hij_Dij' by auto qed thus "(LEAST n. H $$ (i, n) \ 0) -1 \ n'" using least_not0 by auto qed also have "... = (LEAST n. D $$ (i-1, n) \ 0)" proof (rule Least_equality) have "D $$ (i - 1, LEAST n. D $$ (i - 1, n) \ 0) \ 0" by (metis (mono_tags, lifting) Hil Hil_Dil LeastI_ex) moreover have leastD: "(LEAST n. D $$ (i - 1, n) \ 0) < dim_col D" - by (smt dual_order.strict_trans is_zero_row_JNF_def linorder_neqE_nat + by (smt (verit) dual_order.strict_trans is_zero_row_JNF_def linorder_neqE_nat not_less_Least not_zero_iD) ultimately show "D $$ (i - 1, LEAST n. D $$ (i - 1, n) \ 0) \ 0 \ (LEAST n. D $$ (i - 1, n) \ 0) < dim_col D" by simp fix y assume "D $$ (i - 1, y) \ 0 \ y < dim_col D" thus "(LEAST n. D $$ (i - 1, n) \ 0) \ y" by (meson wellorder_Least_lemma(2)) qed finally have leastHi_eq: "?least_H - 1 = (LEAST n. D $$ (i-1, n) \ 0)" . have least_nj: "?least_Hj 0" and ln':"(\n'. (H $$ (j, n') \ 0) \ ?least_Hj \ n')" by (metis (mono_tags, lifting) is_zero_row_JNF_def not_zero_jH wellorder_Least_lemma)+ have Hjl_Djl: "H $$ (j,?least_Hj) = D $$ (j-1,?least_Hj - 1)" proof - have "H $$ (j,?least_Hj) = (if j < dim_row A then if ?least_Hj < dim_col A then A $$ (j, ?least_Hj) else B $$ (j, ?least_Hj - dim_col A) else if ?least_Hj < dim_col A then (0\<^sub>m (m-1) 1) $$ (j - dim_row A, ?least_Hj) else D $$ (j - dim_row A, ?least_Hj - dim_col A))" unfolding H_def by (rule index_mat_four_block, insert False j ij H A D n least_nj, auto simp add: H_def) also have "... = D $$ (j - 1, ?least_Hj - 1)" using False j ij H A D n least_n B Hi0 Hjl by auto finally show ?thesis . qed have "(LEAST n. H $$ (j, n) \ 0) - 1 = (LEAST n. D $$ (j-1, n) \ 0 \ n 0" using Hil Hil_Dil - by (smt H Hij_Dij' LeastI_ex carrier_matD is_zero_row_JNF_def j least_not0j + by (smt (verit) H Hij_Dij' LeastI_ex carrier_matD is_zero_row_JNF_def j least_not0j linorder_neqE_nat not_gr0 not_less_Least order.strict_trans ij not_zero_jH) show "(LEAST n. H $$ (j, n) \ 0) - 1 < dim_col D" using least_nj least_not0j H D n by auto fix n' assume "D $$ (j - 1, n') \ 0 \ n' < dim_col D" hence Di1n'1: "D $$ (j - 1, n') \ 0" and n': "n' < dim_col D" by auto have "(LEAST n. H $$ (j, n) \ 0) \ n' + 1" proof (rule Least_le) have "H $$ (j, n'+1) = D $$ (j -1, (n'+1)-1)" by (rule Hij_Dij', insert i_not0 False H A ij j n' D, auto) thus Hin': "H $$ (j, n'+1) \ 0" using False Di1n'1 Hij_Dij' by auto qed thus "(LEAST n. H $$ (j, n) \ 0) -1 \ n'" using least_not0 by auto qed also have "... = (LEAST n. D $$ (j-1, n) \ 0)" proof (rule Least_equality) have "D $$ (j - 1, LEAST n. D $$ (j - 1, n) \ 0) \ 0" by (metis (mono_tags, lifting) Hjl Hjl_Djl LeastI_ex) moreover have leastD: "(LEAST n. D $$ (j - 1, n) \ 0) < dim_col D" - by (smt dual_order.strict_trans is_zero_row_JNF_def linorder_neqE_nat + by (smt (verit) dual_order.strict_trans is_zero_row_JNF_def linorder_neqE_nat not_less_Least not_zero_jD) ultimately show "D $$ (j - 1, LEAST n. D $$ (j - 1, n) \ 0) \ 0 \ (LEAST n. D $$ (j - 1, n) \ 0) < dim_col D" by simp fix y assume "D $$ (j - 1, y) \ 0 \ y < dim_col D" thus "(LEAST n. D $$ (j - 1, n) \ 0) \ y" by (meson wellorder_Least_lemma(2)) qed finally have leastHj_eq: "(LEAST n. H $$ (j, n) \ 0) - 1 = (LEAST n. D $$ (j-1, n) \ 0)" . have ij': "i-1 < j-1" using ij False by auto have "j-1 < dim_row D " using D H ij j by auto hence "(LEAST n. D $$ (i-1, n) \ 0) < (LEAST n. D $$ (j-1, n) \ 0)" using e_D echelon_form_JNF_def ij' not_zero_jD order.strict_trans by blast thus ?thesis using leastHj_eq leastHi_eq by auto qed thus "\i j. i < j \ j < dim_row H \ \ is_zero_row_JNF i H \ \ is_zero_row_JNF j H \ (LEAST n. H $$ (i, n) \ 0) < (LEAST n. H $$ (j, n) \ 0)" by blast qed context mod_operation begin lemma reduce_below: assumes "A \ carrier_mat m n" shows "reduce_below a xs D A \ carrier_mat m n" using assms by (induct a xs D A rule: reduce_below.induct, auto simp add: Let_def euclid_ext2_def) lemma reduce_below_preserves_dimensions: shows [simp]: "dim_row (reduce_below a xs D A) = dim_row A" and [simp]: "dim_col (reduce_below a xs D A) = dim_col A" using reduce_below[of A "dim_row A" "dim_col A"] by auto lemma reduce_below_abs: assumes "A \ carrier_mat m n" shows "reduce_below_abs a xs D A \ carrier_mat m n" using assms by (induct a xs D A rule: reduce_below_abs.induct, auto simp add: Let_def euclid_ext2_def) lemma reduce_below_abs_preserves_dimensions: shows [simp]: "dim_row (reduce_below_abs a xs D A) = dim_row A" and [simp]: "dim_col (reduce_below_abs a xs D A) = dim_col A" using reduce_below_abs[of A "dim_row A" "dim_col A"] by auto lemma FindPreHNF_1xn: assumes A: "A \ carrier_mat m n" and "m<2 \ n = 0" shows "FindPreHNF abs_flag D A \ carrier_mat m n" using assms by auto lemma FindPreHNF_mx1: assumes A: "A \ carrier_mat m n" and "m\2" and "n \ 0" "n<2" shows "FindPreHNF abs_flag D A \ carrier_mat m n" proof (cases "abs_flag") case True let ?nz = "(filter (\i. A $$ (i, 0) \ 0) [1..i. A $$ (i, 0) \ 0) [Suc 0.. 0 then A else let i = non_zero_positions ! 0 in swaprows 0 i A))" using assms True by auto also have "... = reduce_below_abs 0 ?nz D (if A $$ (0, 0) \ 0 then A else let i = ?nz ! 0 in swaprows 0 i A)" unfolding Let_def by auto also have "... \ carrier_mat m n" using A by auto finally show ?thesis . next case False let ?nz = "(filter (\i. A $$ (i, 0) \ 0) [1..i. A $$ (i, 0) \ 0) [Suc 0.. 0 then A else let i = non_zero_positions ! 0 in swaprows 0 i A))" using assms False by auto also have "... = reduce_below 0 ?nz D (if A $$ (0, 0) \ 0 then A else let i = ?nz ! 0 in swaprows 0 i A)" unfolding Let_def by auto also have "... \ carrier_mat m n" using A by auto finally show ?thesis . qed lemma FindPreHNF_mxn2: assumes A: "A \ carrier_mat m n" and m: "m\2" and n: "n\2" shows "FindPreHNF abs_flag D A \ carrier_mat m n" using assms proof (induct abs_flag D A arbitrary: m n rule: FindPreHNF.induct) case (1 abs_flag D A) note A = "1.prems"(1) note m = "1.prems"(2) note n = "1.prems"(3) define non_zero_positions where "non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. 0 then A else let i = non_zero_positions ! 0 in swaprows 0 i A)" define Reduce where [simp]: "Reduce = (if abs_flag then reduce_below_abs else reduce_below)" obtain A'_UL A'_UR A'_DL A'_DR where A'_split: "(A'_UL, A'_UR, A'_DL, A'_DR) = split_block (Reduce 0 non_zero_positions D (make_first_column_positive A')) 1 1" by (metis prod_cases4) define sub_PreHNF where "sub_PreHNF = FindPreHNF abs_flag D A'_DR" have A': "A' \ carrier_mat m n" unfolding A'_def using A by auto have A'_DR: "A'_DR \ carrier_mat (m -1) (n-1)" by (cases abs_flag; rule split_block(4)[OF A'_split[symmetric]], insert Reduce_def A A' m n, auto) have sub_PreHNF: "sub_PreHNF \ carrier_mat (m - 1) (n-1)" proof (cases "m-1<2") case True show ?thesis using A'_DR True unfolding sub_PreHNF_def by auto next case False note m' = False show ?thesis proof (cases "n-1<2") case True show ?thesis unfolding sub_PreHNF_def by (rule FindPreHNF_mx1[OF A'_DR _ _ True], insert n m', auto) next case False show ?thesis by (unfold sub_PreHNF_def, rule "1.hyps" [of m n, OF _ _ _ non_zero_positions_def A'_def Reduce_def _ A'_split _ _ _ A'_DR], insert A False n m' Reduce_def, auto) qed qed have A'_UL: "A'_UL \ carrier_mat 1 1" by (cases abs_flag; rule split_block(1)[OF A'_split[symmetric], of "m-1" "n-1"], insert n m A', auto) have A'_UR: "A'_UR \ carrier_mat 1 (n-1)" by (cases abs_flag; rule split_block(2)[OF A'_split[symmetric], of "m-1"], insert n m A', auto) have A'_DL: "A'_DL \ carrier_mat (m - 1) 1" by (cases abs_flag; rule split_block(3)[OF A'_split[symmetric], of _ "n-1"], insert n m A', auto) have *: "(dim_col A = 0) = False" using 1(2-) by auto have FindPreHNF_as_fbm: "FindPreHNF abs_flag D A = four_block_mat A'_UL A'_UR A'_DL sub_PreHNF" unfolding FindPreHNF.simps[of abs_flag D A] using A'_split m n A unfolding Let_def sub_PreHNF_def A'_def non_zero_positions_def * apply (cases abs_flag) - by (smt (z3) Reduce_def carrier_matD(1) carrier_matD(2) linorder_not_less prod.simps(2))+ + by (smt (verit) Reduce_def carrier_matD(1) carrier_matD(2) linorder_not_less prod.simps(2))+ also have "... \ carrier_mat m n" - by (smt m A'_UL One_nat_def add.commute carrier_matD carrier_mat_triv index_mat_four_block(2,3) + by (smt (verit) m A'_UL One_nat_def add.commute carrier_matD carrier_mat_triv index_mat_four_block(2,3) le_add_diff_inverse2 le_eq_less_or_eq lessI n nat_SN.compat numerals(2) sub_PreHNF) finally show ?case . qed lemma FindPreHNF: assumes A: "A \ carrier_mat m n" shows "FindPreHNF abs_flag D A \ carrier_mat m n" using assms FindPreHNF_mxn2[OF A] FindPreHNF_mx1[OF A] FindPreHNF_1xn[OF A] using linorder_not_less by blast end lemma make_first_column_positive_append_id: assumes A': "A' \ carrier_mat m n" and A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and D0: "D>0" and n0: "0r (D \\<^sub>m (1\<^sub>m n))" proof (rule matrix_append_rows_eq_if_preserves) have A: "A \ carrier_mat (m+n) n" using A' A_def by auto thus "make_first_column_positive A \ carrier_mat (m + n) n" by auto have "make_first_column_positive A $$ (i, j) = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, j)" if j: "j {m..\<^sub>m 1\<^sub>m n) $$ (i - m, 0)" unfolding A_def - by (smt A append_rows_def assms(1) assms(2) atLeastLessThan_iff carrier_matD + by (smt (verit) A append_rows_def assms(1) assms(2) atLeastLessThan_iff carrier_matD index_mat_four_block less_irrefl_nat nat_SN.compat j i n0) also have "... \ 0" using D0 mult_not_zero that(2) by auto finally have Ai0: "A$$(i,0)\0" . have "make_first_column_positive A $$ (i, j) = A$$(i,j)" using make_first_column_positive_works[OF A i_mn n0] j Ai0 by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i - m, j)" unfolding A_def - by (smt A append_rows_def A' A_def atLeastLessThan_iff carrier_matD + by (smt (verit) A append_rows_def A' A_def atLeastLessThan_iff carrier_matD index_mat_four_block less_irrefl_nat nat_SN.compat i j) finally show ?thesis . qed thus "\i\{m..j\<^sub>m 1\<^sub>m n) $$ (i - m, j)" by simp qed (auto) lemma A'_swaprows_invertible_mat: fixes A::"int mat" assumes A: "A\carrier_mat m n" assumes A'_def: "A' = (if A $$ (0, 0) \ 0 then A else let i = non_zero_positions ! 0 in swaprows 0 i A)" and nz_def: "non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. non_zero_positions \ []" and m0: "0P. P \ carrier_mat m m \ invertible_mat P \ A' = P * A" proof (cases "A$$(0,0) \ 0") case True then show ?thesis by (metis A A'_def invertible_mat_one left_mult_one_mat one_carrier_mat) next case False have nz_empty: "non_zero_positions \ []" using nz_empty False by simp let ?i = "non_zero_positions ! 0" let ?M = "(swaprows_mat m 0 ?i) :: int mat" have i_set_nz: "?i \ set (non_zero_positions)" using nz_empty by auto have im: "?i < m" using A nz_def i_set_nz by auto have i_not0: "?i \ 0" using A nz_def i_set_nz by auto have "A' = swaprows 0 ?i A" using False A'_def by simp also have "... = ?M * A" by (rule swaprows_mat[OF A], insert nz_def nz_empty False A m0 im, auto) finally have 1: "A' = ?M * A" . have 2: "?M \ carrier_mat m m" by auto have "Determinant.det ?M = - 1" by (rule det_swaprows_mat[OF m0 im i_not0[symmetric]]) hence 3: "invertible_mat ?M" using invertible_iff_is_unit_JNF[OF 2] by auto show ?thesis using 1 2 3 by blast qed lemma swaprows_append_id: assumes A': "A' \ carrier_mat m n" and A_def: "A = A' @\<^sub>r (D \\<^sub>m (1\<^sub>m n))" and i:"ir (D \\<^sub>m (1\<^sub>m n))" proof (rule matrix_append_rows_eq_if_preserves) have A: "A \ carrier_mat (m+n) n" using A' A_def by auto show swap: "swaprows 0 i A \ carrier_mat (m + n) n" by (simp add: A) have "swaprows 0 i A $$ (ia, j) = (D \\<^sub>m 1\<^sub>m n) $$ (ia - m, j)" if ia: "ia \ {m..\<^sub>m 1\<^sub>m n) $$ (ia - m, j)" - by (smt A append_rows_def A' A_def atLeastLessThan_iff carrier_matD + by (smt (verit) A append_rows_def A' A_def atLeastLessThan_iff carrier_matD index_mat_four_block less_irrefl_nat nat_SN.compat ia j) finally show "swaprows 0 i A $$ (ia, j) = (D \\<^sub>m 1\<^sub>m n) $$ (ia - m, j)" . qed thus "\ia\{m..j\<^sub>m 1\<^sub>m n) $$ (ia - m, j)" by simp qed (simp) lemma non_zero_positions_xs_m: fixes A::"'a::comm_ring_1 mat" assumes A_def: "A = A' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A': "A' \ carrier_mat m n" and nz_def: "non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. 0" shows "\xs. non_zero_positions = xs @ [m] \ distinct xs \ (\x\set xs. x < m \ 0 < x)" proof - have A: "A \ carrier_mat (m+n) n" using A' A_def by auto let ?xs = "filter (\i. A $$ (i,0) \ 0) [1..i. A $$ (i,0) \ 0) ([m+1..set [m + 1..\<^sub>m 1\<^sub>m n) $$ (i-m,0)" by (rule append_rows_nth3[OF A' _ A_def _ _ n0], insert i A, auto) also have "... = 0" using i A by auto finally show ?thesis . qed thus "\x\set [m + 1.. A $$ (x, 0) \ 0" by blast qed have fm: "filter (\i. A $$ (i,0) \ 0) [m] = [m]" proof - have "A $$ (m, 0) = (D \\<^sub>m 1\<^sub>m n) $$ (m-m,0)" by (rule append_rows_nth3[OF A' _ A_def _ _ n0], insert n0, auto) also have "... = D" using m0 n0 by auto finally show ?thesis using D0 by auto qed have "non_zero_positions = filter (\i. A $$ (i,0) \ 0) ([1..i. A $$ (i,0) \ 0) [1..i. A $$ (i,0) \ 0) ([m+1..i. A $$ (i,0) \ 0) [1..i. A $$ (i,0) \ 0) ([1..i. A $$ (i,0) \ 0) [1..x\set ?xs. x < m \ 0 < x)" by auto ultimately show ?thesis by blast qed lemma non_zero_positions_xs_m': fixes A::"'a::comm_ring_1 mat" assumes A_def: "A = A' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A': "A' \ carrier_mat m n" and nz_def: "non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. 0" shows "non_zero_positions = (filter (\i. A $$ (i,0) \ 0) [1.. distinct (filter (\i. A $$ (i,0) \ 0) [1.. (\x\set (filter (\i. A $$ (i,0) \ 0) [1.. 0 < x)" proof - have A: "A \ carrier_mat (m+n) n" using A' A_def by auto let ?xs = "filter (\i. A $$ (i,0) \ 0) [1..i. A $$ (i,0) \ 0) ([m+1..set [m + 1..\<^sub>m 1\<^sub>m n) $$ (i-m,0)" by (rule append_rows_nth3[OF A' _ A_def _ _ n0], insert i A, auto) also have "... = 0" using i A by auto finally show ?thesis . qed thus "\x\set [m + 1.. A $$ (x, 0) \ 0" by blast qed have fm: "filter (\i. A $$ (i,0) \ 0) [m] = [m]" proof - have "A $$ (m, 0) = (D \\<^sub>m 1\<^sub>m n) $$ (m-m,0)" by (rule append_rows_nth3[OF A' _ A_def _ _ n0], insert n0, auto) also have "... = D" using m0 n0 by auto finally show ?thesis using D0 by auto qed have "non_zero_positions = filter (\i. A $$ (i,0) \ 0) ([1..i. A $$ (i,0) \ 0) [1..i. A $$ (i,0) \ 0) ([m+1..i. A $$ (i,0) \ 0) [1..i. A $$ (i,0) \ 0) ([1..i. A $$ (i,0) \ 0) [1..x\set ?xs. x < m \ 0 < x)" by auto ultimately show ?thesis by blast qed lemma A_A'D_eq_first_n_rows: assumes A_def: "A = A' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A': "A' \ carrier_mat m n" and mn: "m\n" shows "(mat_of_rows n (map (Matrix.row A') [0..\<^sub>m 1\<^sub>m n : carrier_mat n n" by simp fix i j assume i: "ir D \\<^sub>m 1\<^sub>m n" and A': "A' \ carrier_mat m n" and nz_def: "non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. 0" and inv_A'': "invertible_mat (map_mat rat_of_int (mat_of_rows n (map (Matrix.row A') [0..n" shows "length non_zero_positions > 1" proof - have A: "A \ carrier_mat (m+n) n" using A' A_def by auto have D: "D \\<^sub>m 1\<^sub>m n : carrier_mat n n" by auto let ?RAT = "map_mat rat_of_int" let ?A'' = "(mat_of_rows n (map (Matrix.row A') [0.. carrier_mat n n" by auto have RAT_A'': "?RAT ?A'' \ carrier_mat n n" by auto let ?ys = "filter (\i. A $$ (i,0) \ 0) [1.. []" proof (rule ccontr) assume "\ ?xs \ []" hence xs0: "?xs = []" by simp have A00: "A $$ (0,0) = 0" proof - have "A $$ (0,0) = A'$$(0,0)" unfolding A_def using append_rows_nth[OF A' D] m0 n0 A' by auto thus ?thesis using A'00 by simp qed hence "(\i\set [1..iv n" proof (rule eq_vecI) show "dim_vec (col ?A'' 0) = dim_vec (0\<^sub>vn)" using A' by auto fix i assume i: "i < dim_vec (0\<^sub>v n)" have "col ?A'' 0 $v i = ?A'' $$ (i,0)" by (rule index_col, insert i A' n0, auto) also have "... = A $$ (i,0)" unfolding A_def using i A append_rows_nth[OF A' D _ n0] A' mn by (metis A'' n0 carrier_matD(1) index_zero_vec(2) le_add2 map_first_rows_index mat_of_rows_carrier(2) mat_of_rows_index nat_SN.compat) also have "... = 0" using * i by auto finally show "col ?A'' 0 $v i = 0\<^sub>v n $v i" using i by auto qed hence "col (?RAT ?A'') 0 = 0\<^sub>v n" by auto hence "\ invertible_mat (?RAT ?A'')" using invertible_mat_first_column_not0[OF RAT_A'' _ n0] by auto thus False using inv_A'' by contradiction qed have l_rw: "[1..i. A $$ (i,0) \ 0) ([m+1..set [m + 1..\<^sub>m 1\<^sub>m n) $$ (i-m,0)" by (rule append_rows_nth3[OF A' _ A_def _ _ n0], insert i A, auto) also have "... = 0" using i A by auto finally show ?thesis . qed thus "\x\set [m + 1.. A $$ (x, 0) \ 0" by blast qed have fm: "filter (\i. A $$ (i,0) \ 0) [m] = [m]" proof - have "A $$ (m, 0) = (D \\<^sub>m 1\<^sub>m n) $$ (m-m,0)" by (rule append_rows_nth3[OF A' _ A_def _ _ n0], insert n0, auto) also have "... = D" using m0 n0 by auto finally show ?thesis using D0 by auto qed have "non_zero_positions = filter (\i. A $$ (i,0) \ 0) ([1..i. A $$ (i,0) \ 0) [1..i. A $$ (i,0) \ 0) ([m+1..i. A $$ (i,0) \ 0) [1..i. A $$ (i,0) \ 0) ([1..i. A $$ (i,0) \ 0) [1.. []" using xs_not_empty mn by (metis (no_types, lifting) atLeastLessThan_iff empty_filter_conv nat_SN.compat set_upt) show ?thesis unfolding nz using ys_not_empty by auto qed corollary non_zero_positions_length_xs: assumes A_def: "A = A' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A': "A' \ carrier_mat m n" and nz_def: "non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. 0" and inv_A'': "invertible_mat (map_mat rat_of_int (mat_of_rows n (map (Matrix.row A') [0..n" and nz_xs_m: "non_zero_positions = xs @ [m]" shows "length xs > 0" proof - have "length non_zero_positions > 1" by (rule non_zero_positions_xs_m_invertible[OF A_def A' nz_def m0 n0 D0 inv_A'' A'00 mn]) thus ?thesis using nz_xs_m by auto qed lemma make_first_column_positive_nz_conv: assumes "i 0) = (A $$ (i, j) \ 0)" using assms unfolding make_first_column_positive.simps by auto lemma make_first_column_positive_00: assumes A_def: "A = A'' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A'': "A'' : carrier_mat m n" assumes nz_def: "non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. 0 then A else let i = non_zero_positions ! 0 in swaprows 0 i A)" and m0: "0 0" and mn: "m\n" shows "make_first_column_positive A' $$ (0, 0) \ 0" proof - have A: "A \ carrier_mat (m+n) n" using A_def A'' by auto hence A': "A' \ carrier_mat (m+n) n" unfolding A'_def by auto have "(make_first_column_positive A' $$ (0, 0) \ 0) = (A' $$ (0, 0) \ 0)" by (rule make_first_column_positive_nz_conv, insert m0 n0 A', auto) moreover have "A' $$ (0, 0) \ 0" proof (cases "A $$ (0, 0) \ 0") case True then show ?thesis unfolding A'_def by auto next case False have "A $$ (0, 0) = A'' $$ (0, 0)" - by (smt add_gr_0 append_rows_def A_def A'' carrier_matD index_mat_four_block(1) mn n0 nat_SN.compat) + by (smt (verit) add_gr_0 append_rows_def A_def A'' carrier_matD index_mat_four_block(1) mn n0 nat_SN.compat) hence A''00: "A''$$(0,0) = 0" using False by auto let ?i = "non_zero_positions ! 0" obtain xs where non_zero_positions_xs_m: "non_zero_positions = xs @ [m]" and d_xs: "distinct xs" and all_less_m: "\x\set xs. x < m \ 0 < x" using non_zero_positions_xs_m[OF A_def A'' nz_def m0 n0] using D0 by fast - have Ai0:"A $$ (?i,0) \ 0" - by (smt append.simps(1) append_Cons append_same_eq nz_def in_set_conv_nth length_greater_0_conv - list.simps(3) local.non_zero_positions_xs_m mem_Collect_eq set_filter) + have Ai0: "A $$ (?i,0) \ 0" + by (smt (verit, ccfv_threshold) add_gr_0 length_append less_numeral_extra(1) list.size(4) local.non_zero_positions_xs_m mem_Collect_eq nth_mem nz_def plus_1_eq_Suc set_filter) have "A' $$ (0, 0) = swaprows 0 ?i A $$ (0,0)" using False A'_def by auto also have "... \ 0" using A Ai0 n0 by auto finally show ?thesis . qed ultimately show ?thesis by blast qed context proper_mod_operation begin lemma reduce_below_0_case_m_make_first_column_positive: assumes A': "A' \ carrier_mat m n" and m0: "0r (D \\<^sub>m (1\<^sub>m n))" and mn: "m\n" assumes i_mn: "i < m+n" and d_xs: "distinct xs" and xs: "\x \ set xs. x < m \ 0 < x" and ia: "i\0" and A''_def: "A'' = (if A $$ (0, 0) \ 0 then A else let i = non_zero_positions ! 0 in swaprows 0 i A)" and D0: "D>0" and nz_def: "non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. carrier_mat (m+n) n" using A' A_def by auto define xs where "xs = filter (\i. A $$ (i,0) \ 0) [1..x\set xs. x < m \ 0 < x" using non_zero_positions_xs_m'[OF A_def A' nz_def m0 n0] using D0 A unfolding nz_def xs_def by auto have A'': "A'' \ carrier_mat (m+n) n" using A' A_def A''_def by auto have D_not0: "D\0" using D0 by auto have Ai0: "A $$ (i, 0) = 0" if im: "i>m" and imn: "i\<^sub>m (1\<^sub>m n)) \ carrier_mat n n" by simp have "A $$ (i, 0) = (D \\<^sub>m (1\<^sub>m n)) $$ (i-m, 0)" unfolding A_def using append_rows_nth[OF A' D imn n0] im A' by auto also have "... = 0" using im imn n0 by auto finally show ?thesis . qed let ?M' = "mat_of_rows n (map (Matrix.row (make_first_column_positive A'')) [0.. carrier_mat m n" using A'' by auto have mk0: "make_first_column_positive A'' $$ (0, 0) \ 0" by (rule make_first_column_positive_00[OF A_def A' nz_def A''_def m0 n0 D_not0 mn]) have M_M'D: "make_first_column_positive A'' = ?M' @\<^sub>r D \\<^sub>m 1\<^sub>m n" if xs_empty: "xs \ []" proof (cases "A$$(0,0) \ 0") case True then have *: "make_first_column_positive A'' = make_first_column_positive A" unfolding A''_def by auto show ?thesis by (unfold *, rule make_first_column_positive_append_id[OF A' A_def D0 n0]) next case False then have *: "make_first_column_positive A'' = make_first_column_positive (swaprows 0 (non_zero_positions ! 0) A)" unfolding A''_def by auto show ?thesis proof (unfold *, rule make_first_column_positive_append_id) let ?S = "mat_of_rows n (map (Matrix.row (swaprows 0 (non_zero_positions ! 0) A)) [0..r (D \\<^sub>m (1\<^sub>m n))" proof (rule swaprows_append_id[OF A' A_def]) have A'00: "A' $$ (0, 0) = 0" by (metis (no_types, lifting) A False add_pos_pos append_rows_def A' A_def carrier_matD index_mat_four_block m0 n0) have length_xs: "length xs > 0" using xs_empty by auto have "non_zero_positions ! 0 = xs ! 0" unfolding nz_xs_m by (meson length_xs nth_append) thus "non_zero_positions ! 0 < m" using all_less_m length_xs by simp qed qed (insert n0 D0, auto) qed show ?thesis proof (cases "xs = []") case True note xs_empty = True have "reduce_below 0 non_zero_positions D (make_first_column_positive A'') = reduce 0 m D (make_first_column_positive A'')" unfolding nz_xs_m True by auto also have "... $$ (i, 0) = 0" proof (cases "i=m") case True from D0 have "D \ 1" "D \ 0" by auto then show ?thesis using D0 True by (metis A add_sign_intros(2) A''_def carrier_matD(1) carrier_matD(2) carrier_matI index_mat_swaprows(2) index_mat_swaprows(3) less_add_same_cancel1 m0 make_first_column_positive_preserves_dimensions mk0 n0 neq0_conv reduce_0) next case False note i_not_m = False have nz_m: "non_zero_positions ! 0 = m" unfolding nz_xs_m True by auto let ?M = "make_first_column_positive A''" have M: "?M \ carrier_mat (m+n) n" using A'' by auto show ?thesis proof (cases "A$$(0,0) = 0") case True have "reduce 0 m D ?M $$ (i, 0) = ?M $$ (i,0)" by (rule reduce_preserves[OF M n0 mk0 False ia i_mn]) also have Mi0: "... = abs (A'' $$ (i,0))" - by (smt M carrier_matD(1) carrier_matD(2) i_mn index_mat(1) make_first_column_positive.simps + by (smt (verit) M carrier_matD(1) carrier_matD(2) i_mn index_mat(1) make_first_column_positive.simps make_first_column_positive_preserves_dimensions n0 prod.simps(2)) also have Mi02: "... = abs (A $$ (i,0)) " unfolding A''_def nz_m using True A False i_mn ia n0 by auto also have "... = 0" proof - have "filter (\n. A $$ (n, 0) \ 0) [1..n. A $$ (n, 0) = 0 \ n \ set [1.. 0" by simp have "reduce 0 m D ?M $$ (i, 0) = ?M $$ (i,0)" by (rule reduce_preserves[OF M n0 mk0 i_not_m ia i_mn]) also have Mi0: "... = abs (A'' $$ (i,0))" - by (smt M carrier_matD(1) carrier_matD(2) i_mn index_mat(1) make_first_column_positive.simps + by (smt (verit) M carrier_matD(1) carrier_matD(2) i_mn index_mat(1) make_first_column_positive.simps make_first_column_positive_preserves_dimensions n0 prod.simps(2)) also have Mi02: "... = abs (swaprows 0 m A $$ (i,0)) " unfolding A''_def nz_m using A00 A i_not_m i_mn ia n0 by auto also have "... = abs (A $$ (i,0))" using False ia A00 Mi0 A''_def calculation Mi02 by presburger also have "... = 0" proof - have "filter (\n. A $$ (n, 0) \ 0) [1..n. A $$ (n, 0) = 0 \ n \ set [1.. set (xs @ [m])") case True show ?thesis by (unfold nz_xs_m, rule reduce_below_0_case_m[OF M' m0 n0 M_M'D mk0 mn True d_xs all_less_m D0]) next case False note i_notin_xs_m = False have 1: "reduce_below 0 (xs @ [m]) D (make_first_column_positive A'') $$ (i,0) = (make_first_column_positive A'') $$ (i,0)" by (rule reduce_below_preserves_case_m[OF M' m0 n0 M_M'D mk0 mn _ d_xs all_less_m ia i_mn _ D0], insert False, auto) have "((make_first_column_positive A'') $$ (i,0) \ 0) = (A'' $$ (i,0) \ 0)" by (rule make_first_column_positive_nz_conv, insert A'' i_mn n0, auto) hence 2: "((make_first_column_positive A'') $$ (i,0) = 0) = (A'' $$ (i,0) = 0)" by auto have 3: "(A'' $$ (i,0) = 0)" proof (cases "A$$(0,0) \ 0") case True then have "A'' $$ (i, 0) = A $$ (i, 0)" unfolding A''_def by auto also have "... = 0" using False ia i_mn A nz_xs_m Ai0 unfolding nz_def xs_def by auto finally show ?thesis by auto next case False hence A00: "A $$ (0,0) = 0" by simp let ?i = "non_zero_positions ! 0" have i_noti: "i\?i" using i_notin_xs_m unfolding nz_xs_m by (metis Nil_is_append_conv length_greater_0_conv list.distinct(2) nth_mem) have "A''$$(i,0) = (swaprows 0 ?i A) $$ (i,0)" using False unfolding A''_def by auto also have "... = A $$ (i,0)" using i_notin_xs_m ia i_mn A i_noti n0 unfolding xs_def by fastforce also have "... = 0" using i_notin_xs_m ia i_mn A i_noti n0 unfolding xs_def - by (smt nz_def atLeastLessThan_iff carrier_matD(1) less_one linorder_not_less + by (smt (verit) nz_def atLeastLessThan_iff carrier_matD(1) less_one linorder_not_less mem_Collect_eq nz_xs_m set_filter set_upt xs_def) finally show ?thesis . qed show ?thesis using 1 2 3 nz_xs_m by argo qed qed qed lemma reduce_below_abs_0_case_m_make_first_column_positive: assumes A': "A' \ carrier_mat m n" and m0: "0r (D \\<^sub>m (1\<^sub>m n))" and mn: "m\n" assumes i_mn: "i < m+n" and d_xs: "distinct xs" and xs: "\x \ set xs. x < m \ 0 < x" and ia: "i\0" and A''_def: "A'' = (if A $$ (0, 0) \ 0 then A else let i = non_zero_positions ! 0 in swaprows 0 i A)" and D0: "D>0" and nz_def: "non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. carrier_mat (m+n) n" using A' A_def by auto define xs where "xs = filter (\i. A $$ (i,0) \ 0) [1..x\set xs. x < m \ 0 < x" using non_zero_positions_xs_m'[OF A_def A' nz_def m0 n0] using D0 A unfolding nz_def xs_def by auto have A'': "A'' \ carrier_mat (m+n) n" using A' A_def A''_def by auto have D_not0: "D\0" using D0 by auto have Ai0: "A $$ (i, 0) = 0" if im: "i>m" and imn: "i\<^sub>m (1\<^sub>m n)) \ carrier_mat n n" by simp have "A $$ (i, 0) = (D \\<^sub>m (1\<^sub>m n)) $$ (i-m, 0)" unfolding A_def using append_rows_nth[OF A' D imn n0] im A' by auto also have "... = 0" using im imn n0 by auto finally show ?thesis . qed let ?M' = "mat_of_rows n (map (Matrix.row (make_first_column_positive A'')) [0.. carrier_mat m n" using A'' by auto have mk0: "make_first_column_positive A'' $$ (0, 0) \ 0" by (rule make_first_column_positive_00[OF A_def A' nz_def A''_def m0 n0 D_not0 mn]) have M_M'D: "make_first_column_positive A'' = ?M' @\<^sub>r D \\<^sub>m 1\<^sub>m n" if xs_empty: "xs \ []" proof (cases "A$$(0,0) \ 0") case True then have *: "make_first_column_positive A'' = make_first_column_positive A" unfolding A''_def by auto show ?thesis by (unfold *, rule make_first_column_positive_append_id[OF A' A_def D0 n0]) next case False then have *: "make_first_column_positive A'' = make_first_column_positive (swaprows 0 (non_zero_positions ! 0) A)" unfolding A''_def by auto show ?thesis proof (unfold *, rule make_first_column_positive_append_id) let ?S = "mat_of_rows n (map (Matrix.row (swaprows 0 (non_zero_positions ! 0) A)) [0..r (D \\<^sub>m (1\<^sub>m n))" proof (rule swaprows_append_id[OF A' A_def]) have A'00: "A' $$ (0, 0) = 0" by (metis (no_types, lifting) A False add_pos_pos append_rows_def A' A_def carrier_matD index_mat_four_block m0 n0) have length_xs: "length xs > 0" using xs_empty by auto have "non_zero_positions ! 0 = xs ! 0" unfolding nz_xs_m by (meson length_xs nth_append) thus "non_zero_positions ! 0 < m" using all_less_m length_xs by simp qed qed (insert n0 D0, auto) qed show ?thesis proof (cases "xs = []") case True note xs_empty = True have "reduce_below_abs 0 non_zero_positions D (make_first_column_positive A'') = reduce_abs 0 m D (make_first_column_positive A'')" unfolding nz_xs_m True by auto also have "... $$ (i, 0) = 0" proof (cases "i=m") case True from D0 have "D \ 1" "D \ 0" by auto then show ?thesis using D0 True by (metis A add_sign_intros(2) A''_def carrier_matD(1) carrier_matD(2) carrier_matI index_mat_swaprows(2) index_mat_swaprows(3) less_add_same_cancel1 m0 make_first_column_positive_preserves_dimensions mk0 n0 neq0_conv reduce_0) next case False note i_not_m = False have nz_m: "non_zero_positions ! 0 = m" unfolding nz_xs_m True by auto let ?M = "make_first_column_positive A''" have M: "?M \ carrier_mat (m+n) n" using A'' by auto show ?thesis proof (cases "A$$(0,0) = 0") case True have "reduce_abs 0 m D ?M $$ (i, 0) = ?M $$ (i,0)" by (rule reduce_preserves[OF M n0 mk0 False ia i_mn]) also have Mi0: "... = abs (A'' $$ (i,0))" - by (smt M carrier_matD(1) carrier_matD(2) i_mn index_mat(1) make_first_column_positive.simps + by (smt (verit) M carrier_matD(1) carrier_matD(2) i_mn index_mat(1) make_first_column_positive.simps make_first_column_positive_preserves_dimensions n0 prod.simps(2)) also have Mi02: "... = abs (A $$ (i,0)) " unfolding A''_def nz_m using True A False i_mn ia n0 by auto also have "... = 0" proof - have "filter (\n. A $$ (n, 0) \ 0) [1..n. A $$ (n, 0) = 0 \ n \ set [1.. 0" by simp have "reduce_abs 0 m D ?M $$ (i, 0) = ?M $$ (i,0)" by (rule reduce_preserves[OF M n0 mk0 i_not_m ia i_mn]) also have Mi0: "... = abs (A'' $$ (i,0))" - by (smt M carrier_matD(1) carrier_matD(2) i_mn index_mat(1) make_first_column_positive.simps + by (smt (verit) M carrier_matD(1) carrier_matD(2) i_mn index_mat(1) make_first_column_positive.simps make_first_column_positive_preserves_dimensions n0 prod.simps(2)) also have Mi02: "... = abs (swaprows 0 m A $$ (i,0)) " unfolding A''_def nz_m using A00 A i_not_m i_mn ia n0 by auto also have "... = abs (A $$ (i,0))" using False ia A00 Mi0 A''_def calculation Mi02 by presburger also have "... = 0" proof - have "filter (\n. A $$ (n, 0) \ 0) [1..n. A $$ (n, 0) = 0 \ n \ set [1.. set (xs @ [m])") case True show ?thesis by (unfold nz_xs_m, rule reduce_below_abs_0_case_m[OF M' m0 n0 M_M'D mk0 mn True d_xs all_less_m D0]) next case False note i_notin_xs_m = False have 1: "reduce_below_abs 0 (xs @ [m]) D (make_first_column_positive A'') $$ (i,0) = (make_first_column_positive A'') $$ (i,0)" by (rule reduce_below_abs_preserves_case_m[OF M' m0 n0 M_M'D mk0 mn _ d_xs all_less_m ia i_mn _ D0], insert False, auto) have "((make_first_column_positive A'') $$ (i,0) \ 0) = (A'' $$ (i,0) \ 0)" by (rule make_first_column_positive_nz_conv, insert A'' i_mn n0, auto) hence 2: "((make_first_column_positive A'') $$ (i,0) = 0) = (A'' $$ (i,0) = 0)" by auto have 3: "(A'' $$ (i,0) = 0)" proof (cases "A$$(0,0) \ 0") case True then have "A'' $$ (i, 0) = A $$ (i, 0)" unfolding A''_def by auto also have "... = 0" using False ia i_mn A nz_xs_m Ai0 unfolding nz_def xs_def by auto finally show ?thesis by auto next case False hence A00: "A $$ (0,0) = 0" by simp let ?i = "non_zero_positions ! 0" have i_noti: "i\?i" using i_notin_xs_m unfolding nz_xs_m by (metis Nil_is_append_conv length_greater_0_conv list.distinct(2) nth_mem) have "A''$$(i,0) = (swaprows 0 ?i A) $$ (i,0)" using False unfolding A''_def by auto also have "... = A $$ (i,0)" using i_notin_xs_m ia i_mn A i_noti n0 unfolding xs_def by fastforce also have "... = 0" using i_notin_xs_m ia i_mn A i_noti n0 unfolding xs_def - by (smt nz_def atLeastLessThan_iff carrier_matD(1) less_one linorder_not_less + by (smt (verit) nz_def atLeastLessThan_iff carrier_matD(1) less_one linorder_not_less mem_Collect_eq nz_xs_m set_filter set_upt xs_def) finally show ?thesis . qed show ?thesis using 1 2 3 nz_xs_m by argo qed qed qed lemma FindPreHNF_invertible_mat_2xn: assumes A: "A \ carrier_mat m n" and "m<2" shows "\P. P \ carrier_mat m m \ invertible_mat P \ FindPreHNF abs_flag D A = P * A" using assms by (auto, metis invertible_mat_one left_mult_one_mat one_carrier_mat) lemma FindPreHNF_invertible_mat_mx2: assumes A_def: "A = A'' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A'': "A'' \ carrier_mat m n" and n2: "n<2" and n0: "00" and mn: "m\n" shows "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ FindPreHNF abs_flag D A = P * A" proof - have A: "A \ carrier_mat (m+n) n" using A_def A'' by auto have m0: "m>0" using mn n2 n0 by auto have D0: "D\0" using D_g0 by auto show ?thesis proof (cases "m+n<2") case True show ?thesis by (rule FindPreHNF_invertible_mat_2xn[OF A True]) next case False note mn_le_2 = False have dr_A: "dim_row A \2" using False n2 A by auto have dc_A: "dim_col A < 2" using n2 A by auto let ?non_zero_positions = "filter (\i. A $$ (i, 0) \ 0) [Suc 0..i. A $$ (i,0) \ 0) [1..x\set xs. x < m \ 0 < x" using non_zero_positions_xs_m'[OF A_def A'' _ m0 n0 D0] using D0 A unfolding xs_def by auto have *: "FindPreHNF abs_flag D A = (if abs_flag then reduce_below_abs 0 ?non_zero_positions D ?A' else reduce_below 0 ?non_zero_positions D ?A')" using dr_A dc_A by (auto simp add: Let_def) have l: "length ?non_zero_positions > 1" if "xs\[]" using that unfolding nz_xs_m by auto have inv: "\P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce_below 0 ?non_zero_positions D ?A' = P * ?A'" proof (cases "A $$ (0,0) \0") case True show ?thesis by (unfold nz_xs_m, rule reduce_below_invertible_mat_case_m [OF A'' m0 n0 _ _ mn d_xs all_less_m], insert A_def True D_g0, auto) next case False hence A00: "A $$ (0,0) = 0" by auto let ?S = "swaprows 0 (?non_zero_positions ! 0) A" have rw: "(if A $$ (0, 0) \ 0 then A else let i = ?non_zero_positions ! 0 in swaprows 0 i A) = ?S" using False by auto show ?thesis proof (cases "xs = []") case True have nz_m: "?non_zero_positions = [m]" using True nz_xs_m by simp obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (swaprows 0 m A $$ (0, 0)) (swaprows 0 m A $$ (m, 0))" by (metis prod_cases5) have Am0: "A $$ (m,0) = D" proof - have "A $$ (m,0) = (D \\<^sub>m 1\<^sub>m n) $$ (m-m, 0)" - by (smt (z3) A append_rows_def A_def A'' n0 carrier_matD diff_self_eq_0 index_mat_four_block - less_add_same_cancel1 less_diff_conv diff_add nat_less_le) + unfolding A_def + by (meson append_rows_nth3 assms(2) assms(4) less_add_same_cancel1 one_carrier_mat order_refl smult_carrier_mat) also have "... = D" by (simp add: n0) finally show ?thesis . qed have Sm0: "(swaprows 0 m A) $$ (m,0) = 0" using A False n0 by auto have S00: "(swaprows 0 m A) $$ (0,0) = D" using A Am0 n0 by auto have pquvd2: "(p,q,u,v,d) = euclid_ext2 (A $$ (m, 0)) (A $$ (0, 0))" using pquvd Sm0 S00 Am0 A00 by auto have "reduce_below 0 ?non_zero_positions D ?A' = reduce 0 m D ?A'" unfolding nz_m by auto also have "... = reduce 0 m D (swaprows 0 m A)" using True False rw nz_m by auto have " \P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce 0 m D (swaprows 0 m A) = P * (swaprows 0 m A)" proof (rule reduce_invertible_mat_case_m[OF _ _ m0 _ _ _ _ mn n0]) show "swaprows 0 m A $$ (0, 0) \ 0" using S00 D0 by auto define S' where "S' = mat_of_rows n (map (Matrix.row ?S) [0..(i, k). if i = 0 then p * A $$ (m, k) + q * A $$ (0, k) else if i = m then u * A $$ (m, k) + v * A $$ (0, k) else A $$ (i, k))" show S_S'_S'': "swaprows 0 m A = S' @\<^sub>r S''" unfolding S'_def S''_def by (metis A append_rows_split carrier_matD index_mat_swaprows(2,3) le_add1 nth_Cons_0 nz_m) show S': "S' \ carrier_mat m n" unfolding S'_def by fastforce show S'': "S'' \ carrier_mat n n" unfolding S''_def by fastforce show "0 \ m" using m0 by simp show "(p,q,u,v,d) = euclid_ext2 (swaprows 0 m A $$ (0, 0)) (swaprows 0 m A $$ (m, 0))" using pquvd by simp show "A2 = Matrix.mat (dim_row (swaprows 0 m A)) (dim_col (swaprows 0 m A)) (\(i, k). if i = 0 then p * swaprows 0 m A $$ (0, k) + q * swaprows 0 m A $$ (m, k) else if i = m then u * swaprows 0 m A $$ (0, k) + v * swaprows 0 m A $$ (m, k) else swaprows 0 m A $$ (i, k))" (is "_ = ?rhs") using A A2_def by auto define xs' where "xs' = [1.. (\j'\{0..0" for j proof - have "S'' $$ (j, i) = (D \\<^sub>m 1\<^sub>m n) $$ (j,i)" if i_n: "i\<^sub>m 1\<^sub>m n) $$ (j,i)" - by (smt A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n + by (smt (verit) A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n carrier_matD index_mat_four_block(1,2) add_diff_cancel_right' not_add_less2 jn trans_less_add1) finally show ?thesis . qed thus ?thesis using jn j0 by auto qed have "0 \ set xs'" proof - have "A2 $$ (0,0) = p * A $$ (m, 0) + q * A $$ (0, 0)" using A A2_def n0 by auto also have "... = gcd (A $$ (m, 0)) (A $$ (0, 0))" by (metis euclid_ext2_works(1) euclid_ext2_works(2) pquvd2) also have "... = D" using Am0 A00 D_g0 by auto finally have "A2 $$ (0,0) = D" . thus ?thesis unfolding xs'_def using D_g0 by auto qed thus "\j\set xs'. j (S'' $$ (j, j) = D) \ (\j'\{0.. set ys'" proof - have "A2 $$ (m,0) = u * A $$ (m, 0) + v * A $$ (0, 0)" using A A2_def n0 m0 by auto also have "... = - A $$ (0, 0) div gcd (A $$ (m, 0)) (A $$ (0, 0)) * A $$ (m, 0) + A $$ (m, 0) div gcd (A $$ (m, 0)) (A $$ (0, 0)) * A $$ (0, 0)" by (simp add: euclid_ext2_works[OF pquvd2[symmetric]]) also have "... = 0" using A00 Am0 by auto finally have "A2 $$ (m,0) = 0" . thus ?thesis unfolding ys'_def using D_g0 by auto qed thus "\j\set ys'. j (S'' $$ (j, j) = D) \ (\j'\{0.. {0, D}" using Sm0 by blast thus "swaprows 0 m A $$ (m, 0) = 0 \ swaprows 0 m A $$ (0, 0) = D" using S00 by linarith qed (insert D_g0) then show ?thesis by (simp add: False nz_m) next case False note xs_not_empty = False show ?thesis proof (unfold nz_xs_m, rule reduce_below_invertible_mat_case_m[OF _ m0 n0 _ _ mn d_xs all_less_m D_g0]) let ?S' = "mat_of_rows n (map (Matrix.row ?S) [0.. carrier_mat m n" by auto have l: "length ?non_zero_positions > 1" using l False by blast hence nz0_less_m: "?non_zero_positions ! 0 < m" by (metis One_nat_def add.commute add.left_neutral all_less_m append_Cons_nth_left length_append less_add_same_cancel1 list.size(3,4) nth_mem nz_xs_m) have "?S = ?S' @\<^sub>r D \\<^sub>m 1\<^sub>m n" by (rule swaprows_append_id[OF A'' A_def nz0_less_m]) thus "(if A $$ (0, 0) \ 0 then A else let i = (xs @ [m]) ! 0 in swaprows 0 i A)= ?S' @\<^sub>r D \\<^sub>m 1\<^sub>m n" using rw nz_xs_m by argo - have "?S $$ (0, 0) \ 0" - by (smt A l add_pos_pos carrier_matD index_mat_swaprows(1) le_eq_less_or_eq length_greater_0_conv - less_one linorder_not_less list.size(3) m0 mem_Collect_eq n0 nth_mem set_filter) + have "A $$ (filter (\i. A $$ (i, 0) \ 0) [Suc 0.. 0" + by (metis (mono_tags, lifting) Cons_eq_filterD l length_nth_simps(1) length_nth_simps(3) list.exhaust not_one_less_zero) + then have "?S $$ (0, 0) \ 0" + by (metis A add_sign_intros(2) carrier_matD(1) carrier_matD(2) index_mat_swaprows(1) m0 n0) thus "(if A $$ (0, 0) \ 0 then A else let i = (xs @ [m]) ! 0 in swaprows 0 i A) $$ (0, 0) \ 0" using rw nz_xs_m by algebra qed qed qed have inv2: "\P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce_below_abs 0 ?non_zero_positions D ?A' = P * ?A'" proof (cases "A $$ (0,0) \0") case True show ?thesis by (unfold nz_xs_m, rule reduce_below_abs_invertible_mat_case_m [OF A'' m0 n0 _ _ mn d_xs all_less_m], insert A_def True D_g0, auto) next case False hence A00: "A $$ (0,0) = 0" by auto let ?S = "swaprows 0 (?non_zero_positions ! 0) A" have rw: "(if A $$ (0, 0) \ 0 then A else let i = ?non_zero_positions ! 0 in swaprows 0 i A) = ?S" using False by auto show ?thesis proof (cases "xs = []") case True have nz_m: "?non_zero_positions = [m]" using True nz_xs_m by simp obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (swaprows 0 m A $$ (0, 0)) (swaprows 0 m A $$ (m, 0))" by (metis prod_cases5) have Am0: "A $$ (m,0) = D" proof - have "A $$ (m,0) = (D \\<^sub>m 1\<^sub>m n) $$ (m-m, 0)" - by (smt (z3) A append_rows_def A_def A'' n0 carrier_matD diff_self_eq_0 index_mat_four_block - less_add_same_cancel1 less_diff_conv diff_add nat_less_le) + unfolding A_def + by (meson append_rows_nth3 assms(2) assms(4) less_add_same_cancel1 one_carrier_mat order.refl smult_carrier_mat) also have "... = D" by (simp add: n0) finally show ?thesis . qed have Sm0: "(swaprows 0 m A) $$ (m,0) = 0" using A False n0 by auto have S00: "(swaprows 0 m A) $$ (0,0) = D" using A Am0 n0 by auto have pquvd2: "(p,q,u,v,d) = euclid_ext2 (A $$ (m, 0)) (A $$ (0, 0))" using pquvd Sm0 S00 Am0 A00 by auto have "reduce_below 0 ?non_zero_positions D ?A' = reduce 0 m D ?A'" unfolding nz_m by auto also have "... = reduce 0 m D (swaprows 0 m A)" using True False rw nz_m by auto have " \P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce_abs 0 m D (swaprows 0 m A) = P * (swaprows 0 m A)" proof (rule reduce_abs_invertible_mat_case_m[OF _ _ m0 _ _ _ _ mn n0]) show "swaprows 0 m A $$ (0, 0) \ 0" using S00 D0 by auto define S' where "S' = mat_of_rows n (map (Matrix.row ?S) [0..(i, k). if i = 0 then p * A $$ (m, k) + q * A $$ (0, k) else if i = m then u * A $$ (m, k) + v * A $$ (0, k) else A $$ (i, k))" show S_S'_S'': "swaprows 0 m A = S' @\<^sub>r S''" unfolding S'_def S''_def by (metis A append_rows_split carrier_matD index_mat_swaprows(2,3) le_add1 nth_Cons_0 nz_m) show S': "S' \ carrier_mat m n" unfolding S'_def by fastforce show S'': "S'' \ carrier_mat n n" unfolding S''_def by fastforce show "0 \ m" using m0 by simp show "(p,q,u,v,d) = euclid_ext2 (swaprows 0 m A $$ (0, 0)) (swaprows 0 m A $$ (m, 0))" using pquvd by simp show "A2 = Matrix.mat (dim_row (swaprows 0 m A)) (dim_col (swaprows 0 m A)) (\(i, k). if i = 0 then p * swaprows 0 m A $$ (0, k) + q * swaprows 0 m A $$ (m, k) else if i = m then u * swaprows 0 m A $$ (0, k) + v * swaprows 0 m A $$ (m, k) else swaprows 0 m A $$ (i, k))" (is "_ = ?rhs") using A A2_def by auto define xs' where "xs' = filter (\i. abs (A2 $$ (0,i)) > D) [0..i. abs (A2 $$ (m,i)) > D) [0..i. abs (A2 $$ (0,i)) > D) [0..i. abs (A2 $$ (m,i)) > D) [0.. (\j'\{0..0" for j proof - have "S'' $$ (j, i) = (D \\<^sub>m 1\<^sub>m n) $$ (j,i)" if i_n: "i\<^sub>m 1\<^sub>m n) $$ (j,i)" - by (smt A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n + by (smt (verit) A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n carrier_matD index_mat_four_block(1,2) add_diff_cancel_right' not_add_less2 jn trans_less_add1) finally show ?thesis . qed thus ?thesis using jn j0 by auto qed have "0 \ set xs'" proof - have "A2 $$ (0,0) = p * A $$ (m, 0) + q * A $$ (0, 0)" using A A2_def n0 by auto also have "... = gcd (A $$ (m, 0)) (A $$ (0, 0))" by (metis euclid_ext2_works(1) euclid_ext2_works(2) pquvd2) also have "... = D" using Am0 A00 D_g0 by auto finally have "A2 $$ (0,0) = D" . thus ?thesis unfolding xs'_def using D_g0 by auto qed thus "\j\set xs'. j (S'' $$ (j, j) = D) \ (\j'\{0.. set ys'" proof - have "A2 $$ (m,0) = u * A $$ (m, 0) + v * A $$ (0, 0)" using A A2_def n0 m0 by auto also have "... = - A $$ (0, 0) div gcd (A $$ (m, 0)) (A $$ (0, 0)) * A $$ (m, 0) + A $$ (m, 0) div gcd (A $$ (m, 0)) (A $$ (0, 0)) * A $$ (0, 0)" by (simp add: euclid_ext2_works[OF pquvd2[symmetric]]) also have "... = 0" using A00 Am0 by auto finally have "A2 $$ (m,0) = 0" . thus ?thesis unfolding ys'_def using D_g0 by auto qed thus "\j\set ys'. j (S'' $$ (j, j) = D) \ (\j'\{0.. carrier_mat m n" by auto have l: "length ?non_zero_positions > 1" using l False by blast hence nz0_less_m: "?non_zero_positions ! 0 < m" by (metis One_nat_def add.commute add.left_neutral all_less_m append_Cons_nth_left length_append less_add_same_cancel1 list.size(3,4) nth_mem nz_xs_m) have "?S = ?S' @\<^sub>r D \\<^sub>m 1\<^sub>m n" by (rule swaprows_append_id[OF A'' A_def nz0_less_m]) thus "(if A $$ (0, 0) \ 0 then A else let i = (xs @ [m]) ! 0 in swaprows 0 i A)= ?S' @\<^sub>r D \\<^sub>m 1\<^sub>m n" using rw nz_xs_m by argo have "?S $$ (0, 0) \ 0" - by (smt A l add_pos_pos carrier_matD index_mat_swaprows(1) le_eq_less_or_eq length_greater_0_conv + by (smt (verit) A l add_pos_pos carrier_matD index_mat_swaprows(1) le_eq_less_or_eq length_greater_0_conv less_one linorder_not_less list.size(3) m0 mem_Collect_eq n0 nth_mem set_filter) thus "(if A $$ (0, 0) \ 0 then A else let i = (xs @ [m]) ! 0 in swaprows 0 i A) $$ (0, 0) \ 0" using rw nz_xs_m by algebra qed qed qed show ?thesis proof (cases abs_flag) case False from inv obtain P where inv_P: "invertible_mat P" and P: "P \ carrier_mat (m + n) (m + n)" and r_PA': "reduce_below 0 ?non_zero_positions D ?A' = P * ?A'" by blast have Find_rw: "FindPreHNF abs_flag D A = reduce_below 0 ?non_zero_positions D ?A'" using n0 A dr_A dc_A False * by (auto simp add: Let_def) have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ ?A' = P * A" by (rule A'_swaprows_invertible_mat[OF A], insert non_zero_positions_xs_m n0 m0 l nz_xs_m, auto) from this obtain Q where Q: "Q \ carrier_mat (m + n) (m + n)" and inv_Q: "invertible_mat Q" and A'_QA: "?A' = Q * A" by blast have "reduce_below 0 ?non_zero_positions D ?A' = (P * Q) * A" using Q A'_QA P r_PA' A by auto moreover have "invertible_mat (P*Q)" using P Q inv_P inv_Q invertible_mult_JNF by blast moreover have "(P*Q) \ carrier_mat (m + n) (m + n)" using P Q by auto ultimately show ?thesis using Find_rw by metis next case True from inv2 obtain P where inv_P: "invertible_mat P" and P: "P \ carrier_mat (m + n) (m + n)" and r_PA': "reduce_below_abs 0 ?non_zero_positions D ?A' = P * ?A'" by blast have Find_rw: "FindPreHNF abs_flag D A = reduce_below_abs 0 ?non_zero_positions D ?A'" using n0 A dr_A dc_A True * by (auto simp add: Let_def) have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ ?A' = P * A" by (rule A'_swaprows_invertible_mat[OF A], insert non_zero_positions_xs_m n0 m0 l nz_xs_m, auto) from this obtain Q where Q: "Q \ carrier_mat (m + n) (m + n)" and inv_Q: "invertible_mat Q" and A'_QA: "?A' = Q * A" by blast have "reduce_below_abs 0 ?non_zero_positions D ?A' = (P * Q) * A" using Q A'_QA P r_PA' A by auto moreover have "invertible_mat (P*Q)" using P Q inv_P inv_Q invertible_mult_JNF by blast moreover have "(P*Q) \ carrier_mat (m + n) (m + n)" using P Q by auto ultimately show ?thesis using Find_rw by metis qed qed qed corollary FindPreHNF_echelon_form_mx0: assumes "A \ carrier_mat m 0" shows "echelon_form_JNF (FindPreHNF abs_flag D A)" by (rule echelon_form_mx0, rule FindPreHNF[OF assms]) lemma FindPreHNF_echelon_form_mx1: assumes A_def: "A = A'' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A'': "A'' \ carrier_mat m n" and n2: "n<2" and D_g0: "D>0" and mn: "m\n" shows "echelon_form_JNF (FindPreHNF abs_flag D A)" proof (cases "n=0") case True have A: "A \ carrier_mat m 0" using A_def A'' True by (metis add.comm_neutral append_rows_def carrier_matD carrier_matI index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3)) show ?thesis unfolding True by (rule FindPreHNF_echelon_form_mx0, insert A, auto) next case False hence n0: "0 carrier_mat (m+n) n" using A_def A'' by auto have m0: "m>0" using mn n2 n0 by auto have D0: "D\0" using D_g0 by auto show ?thesis proof (cases "m+n<2") case True show ?thesis by (rule echelon_form_JNF_1xn[OF _ True], rule FindPreHNF[OF A]) next case False note mn_le_2 = False have dr_A: "dim_row A \2" using False n2 A by auto have dc_A: "dim_col A < 2" using n2 A by auto let ?non_zero_positions = "filter (\i. A $$ (i, 0) \ 0) [Suc 0..i. A $$ (i,0) \ 0) [1..x\set xs. x < m \ 0 < x" using non_zero_positions_xs_m'[OF A_def A'' _ m0 n0 D0] using D0 A unfolding xs_def by auto have *: "FindPreHNF abs_flag D A = (if abs_flag then reduce_below_abs 0 ?non_zero_positions D ?A' else reduce_below 0 ?non_zero_positions D ?A')" using dr_A dc_A by (auto simp add: Let_def) have l: "length ?non_zero_positions > 1" if "xs\[]" using that unfolding nz_xs_m by auto have e: "echelon_form_JNF (reduce_below 0 ?non_zero_positions D ?A')" proof (cases "A $$ (0,0) \0") case True note A00 = True have 1: "reduce_below 0 ?non_zero_positions D ?A' = reduce_below 0 ?non_zero_positions D A" using True by auto have "echelon_form_JNF (reduce_below 0 ?non_zero_positions D A)" proof (rule echelon_form_JNF_mx1[OF _ n2]) show "reduce_below 0 ?non_zero_positions D A \ carrier_mat (m+n) n" using A by auto show "\i\{1.. {1..set ?non_zero_positions") case True show ?thesis unfolding nz_xs_m by (rule reduce_below_0_case_m[OF A'' m0 n0 A_def A00 mn _ d_xs all_less_m D_g0], insert nz_xs_m True, auto) next case False note i_notin_set = False have "reduce_below 0 ?non_zero_positions D A $$ (i, 0) = A $$ (i, 0)" unfolding nz_xs_m by (rule reduce_below_preserves_case_m[OF A'' m0 n0 A_def A00 mn _ d_xs all_less_m _ _ _ D_g0], insert i nz_xs_m i_notin_set, auto) also have "... = 0" using i_notin_set i A unfolding set_filter by auto finally show ?thesis . qed qed qed thus ?thesis using 1 by argo next case False hence A00: "A $$ (0,0) = 0" by simp let ?i = "((xs @ [m]) ! 0)" let ?S = "swaprows 0 ?i A" let ?S' = "mat_of_rows n (map (Matrix.row (swaprows 0 ?i A)) [0.. 0 then A else let i = ?non_zero_positions!0 in swaprows 0 i A) = ?S" using A00 nz_xs_m by auto have S: "?S \ carrier_mat (m+n) n" using A by auto have A00_eq_A'00: "A $$ (0, 0) = A'' $$ (0, 0)" by (metis A'' A_def add_gr_0 append_rows_def n0 carrier_matD index_mat_four_block(1) m0) show ?thesis proof (cases "xs=[]") case True have nz_m: "?non_zero_positions = [m]" using True nz_xs_m by simp obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (swaprows 0 m A $$ (0, 0)) (swaprows 0 m A $$ (m, 0))" by (metis prod_cases5) have Am0: "A $$ (m,0) = D" proof - have "A $$ (m,0) = (D \\<^sub>m 1\<^sub>m n) $$ (m-m, 0)" - by (smt A append_rows_def A_def A'' n0 carrier_matD diff_self_eq_0 index_mat_four_block + by (smt (verit) A append_rows_def A_def A'' n0 carrier_matD diff_self_eq_0 index_mat_four_block less_add_same_cancel1 less_diff_conv ordered_cancel_comm_monoid_diff_class.diff_add nat_less_le) also have "... = D" by (simp add: n0) finally show ?thesis . qed have Sm0: "(swaprows 0 m A) $$ (m,0) = 0" using A False n0 by auto have S00: "(swaprows 0 m A) $$ (0,0) = D" using A Am0 n0 by auto have pquvd2: "(p,q,u,v,d) = euclid_ext2 (A $$ (m, 0)) (A $$ (0, 0))" using pquvd Sm0 S00 Am0 A00 by auto have "reduce_below 0 ?non_zero_positions D ?A' = reduce 0 m D ?A'" unfolding nz_m by auto also have "... = reduce 0 m D (swaprows 0 m A)" using True False rw nz_m by auto finally have *: "reduce_below 0 ?non_zero_positions D ?A' = reduce 0 m D (swaprows 0 m A)" . have "echelon_form_JNF (reduce 0 m D (swaprows 0 m A))" proof (rule echelon_form_JNF_mx1[OF _ n2]) show "reduce 0 m D (swaprows 0 m A) \ carrier_mat (m+n) n" using A n2 reduce_carrier by (auto simp add: Let_def) show "\i\{1.. {1.. carrier_mat (m+n) n" using A by auto qed (insert m0 n0 S00 D_g0, auto) next case False have "reduce 0 m D (swaprows 0 m A) $$ (i, 0) = (swaprows 0 m A) $$ (i, 0)" proof (rule reduce_preserves[OF _ n0]) show "swaprows 0 m A \ carrier_mat (m+n) n" using A by auto qed (insert m0 n0 S00 D_g0 False i, auto) also have "... = A $$ (i, 0)" using i False A n0 by auto also have "... = 0" proof (rule ccontr) assume "A $$ (i, 0) \ 0" hence "i \ set ?non_zero_positions" using i A by auto hence "i=m" using nz_xs_m True by auto thus False using False by contradiction qed finally show ?thesis . qed qed qed then show ?thesis using * by presburger next case False have l: "length ?non_zero_positions > 1" using False nz_xs_m by auto hence l_xs: "length xs > 0" using nz_xs_m by auto hence xs_m_less_m: "(xs@[m]) ! 0 < m" by (simp add: all_less_m nth_append) - have S00: "?S $$ (0,0) \ 0" - by (smt A add_pos_pos append_Cons_nth_left n0 carrier_matD index_mat_swaprows(1) - l_xs m0 mem_Collect_eq nth_mem set_filter xs_def) + have "A $$ ((xs @ [m]) ! 0, 0) \ 0" + by (metis (mono_tags, lifting) Cons_eq_filterD List.min_list.cases append_is_Nil_conv nth_Cons_0 nz_xs_m) + then have S00: "?S $$ (0,0) \ 0" + using A n0 by auto have S': "?S' \ carrier_mat m n" using A by auto have S_S'D: "?S = ?S' @\<^sub>r D \\<^sub>m 1\<^sub>m n" by (rule swaprows_append_id[OF A'' A_def xs_m_less_m]) have 2: "reduce_below 0 ?non_zero_positions D ?A' = reduce_below 0 ?non_zero_positions D ?S" using A00 nz_xs_m by algebra have "echelon_form_JNF (reduce_below 0 ?non_zero_positions D ?S)" proof (rule echelon_form_JNF_mx1[OF _ n2]) show "reduce_below 0 ?non_zero_positions D ?S \ carrier_mat (m+n) n" using A by auto show "\i\{1.. {1..set ?non_zero_positions") case True show ?thesis unfolding nz_xs_m by (rule reduce_below_0_case_m[OF S' m0 n0 S_S'D S00 mn _ d_xs all_less_m D_g0], insert True nz_xs_m, auto) next case False note i_notin_set = False have "reduce_below 0 ?non_zero_positions D ?S $$ (i, 0) = ?S $$ (i, 0)" unfolding nz_xs_m by (rule reduce_below_preserves_case_m[OF S' m0 n0 S_S'D S00 mn _ d_xs all_less_m _ _ _ D_g0], insert i nz_xs_m i_notin_set, auto) also have "... = 0" using i_notin_set i A S00 n0 unfolding set_filter by auto finally show ?thesis . qed qed qed thus ?thesis using 2 by argo qed qed have e2: "echelon_form_JNF (reduce_below_abs 0 ?non_zero_positions D ?A')" proof (cases "A $$ (0,0) \0") case True note A00 = True have 1: "reduce_below_abs 0 ?non_zero_positions D ?A' = reduce_below_abs 0 ?non_zero_positions D A" using True by auto have "echelon_form_JNF (reduce_below_abs 0 ?non_zero_positions D A)" proof (rule echelon_form_JNF_mx1[OF _ n2]) show "reduce_below_abs 0 ?non_zero_positions D A \ carrier_mat (m+n) n" using A by auto show "\i\{1.. {1..set ?non_zero_positions") case True show ?thesis unfolding nz_xs_m by (rule reduce_below_abs_0_case_m[OF A'' m0 n0 A_def A00 mn _ d_xs all_less_m D_g0], insert nz_xs_m True, auto) next case False note i_notin_set = False have "reduce_below_abs 0 ?non_zero_positions D A $$ (i, 0) = A $$ (i, 0)" unfolding nz_xs_m by (rule reduce_below_abs_preserves_case_m[OF A'' m0 n0 A_def A00 mn _ d_xs all_less_m _ _ _ D_g0], insert i nz_xs_m i_notin_set, auto) also have "... = 0" using i_notin_set i A unfolding set_filter by auto finally show ?thesis . qed qed qed thus ?thesis using 1 by argo next case False hence A00: "A $$ (0,0) = 0" by simp let ?i = "((xs @ [m]) ! 0)" let ?S = "swaprows 0 ?i A" let ?S' = "mat_of_rows n (map (Matrix.row (swaprows 0 ?i A)) [0.. 0 then A else let i = ?non_zero_positions!0 in swaprows 0 i A) = ?S" using A00 nz_xs_m by auto have S: "?S \ carrier_mat (m+n) n" using A by auto have A00_eq_A'00: "A $$ (0, 0) = A'' $$ (0, 0)" by (metis A'' A_def add_gr_0 append_rows_def n0 carrier_matD index_mat_four_block(1) m0) show ?thesis proof (cases "xs=[]") case True have nz_m: "?non_zero_positions = [m]" using True nz_xs_m by simp obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (swaprows 0 m A $$ (0, 0)) (swaprows 0 m A $$ (m, 0))" by (metis prod_cases5) have Am0: "A $$ (m,0) = D" proof - have "A $$ (m,0) = (D \\<^sub>m 1\<^sub>m n) $$ (m-m, 0)" - by (smt A append_rows_def A_def A'' n0 carrier_matD diff_self_eq_0 index_mat_four_block + by (smt (verit) A append_rows_def A_def A'' n0 carrier_matD diff_self_eq_0 index_mat_four_block less_add_same_cancel1 less_diff_conv ordered_cancel_comm_monoid_diff_class.diff_add nat_less_le) also have "... = D" by (simp add: n0) finally show ?thesis . qed have Sm0: "(swaprows 0 m A) $$ (m,0) = 0" using A False n0 by auto have S00: "(swaprows 0 m A) $$ (0,0) = D" using A Am0 n0 by auto have pquvd2: "(p,q,u,v,d) = euclid_ext2 (A $$ (m, 0)) (A $$ (0, 0))" using pquvd Sm0 S00 Am0 A00 by auto have "reduce_below_abs 0 ?non_zero_positions D ?A' = reduce_abs 0 m D ?A'" unfolding nz_m by auto also have "... = reduce_abs 0 m D (swaprows 0 m A)" using True False rw nz_m by auto finally have *: "reduce_below_abs 0 ?non_zero_positions D ?A' = reduce_abs 0 m D (swaprows 0 m A)" . have "echelon_form_JNF (reduce_abs 0 m D (swaprows 0 m A))" proof (rule echelon_form_JNF_mx1[OF _ n2]) show "reduce_abs 0 m D (swaprows 0 m A) \ carrier_mat (m+n) n" using A n2 reduce_carrier by (auto simp add: Let_def) show "\i\{1.. {1.. carrier_mat (m+n) n" using A by auto qed (insert m0 n0 S00 D_g0, auto) next case False have "reduce_abs 0 m D (swaprows 0 m A) $$ (i, 0) = (swaprows 0 m A) $$ (i, 0)" proof (rule reduce_preserves[OF _ n0]) show "swaprows 0 m A \ carrier_mat (m+n) n" using A by auto qed (insert m0 n0 S00 D_g0 False i, auto) also have "... = A $$ (i, 0)" using i False A n0 by auto also have "... = 0" proof (rule ccontr) assume "A $$ (i, 0) \ 0" hence "i \ set ?non_zero_positions" using i A by auto hence "i=m" using nz_xs_m True by auto thus False using False by contradiction qed finally show ?thesis . qed qed qed then show ?thesis using * by presburger next case False have l: "length ?non_zero_positions > 1" using False nz_xs_m by auto hence l_xs: "length xs > 0" using nz_xs_m by auto hence xs_m_less_m: "(xs@[m]) ! 0 < m" by (simp add: all_less_m nth_append) - have S00: "?S $$ (0,0) \ 0" - by (smt A add_pos_pos append_Cons_nth_left n0 carrier_matD index_mat_swaprows(1) - l_xs m0 mem_Collect_eq nth_mem set_filter xs_def) + have "A $$ ((xs @ [m]) ! 0, 0) \ 0" + by (smt (verit) append_Cons_nth_left l_xs mem_Collect_eq nth_mem set_filter xs_def) + then have S00: "?S $$ (0,0) \ 0" + using A n0 by auto have S': "?S' \ carrier_mat m n" using A by auto have S_S'D: "?S = ?S' @\<^sub>r D \\<^sub>m 1\<^sub>m n" by (rule swaprows_append_id[OF A'' A_def xs_m_less_m]) have 2: "reduce_below_abs 0 ?non_zero_positions D ?A' = reduce_below_abs 0 ?non_zero_positions D ?S" using A00 nz_xs_m by algebra have "echelon_form_JNF (reduce_below_abs 0 ?non_zero_positions D ?S)" proof (rule echelon_form_JNF_mx1[OF _ n2]) show "reduce_below_abs 0 ?non_zero_positions D ?S \ carrier_mat (m+n) n" using A by auto show "\i\{1.. {1..set ?non_zero_positions") case True show ?thesis unfolding nz_xs_m by (rule reduce_below_abs_0_case_m[OF S' m0 n0 S_S'D S00 mn _ d_xs all_less_m D_g0], insert True nz_xs_m, auto) next case False note i_notin_set = False have "reduce_below_abs 0 ?non_zero_positions D ?S $$ (i, 0) = ?S $$ (i, 0)" unfolding nz_xs_m by (rule reduce_below_abs_preserves_case_m[OF S' m0 n0 S_S'D S00 mn _ d_xs all_less_m _ _ _ D_g0], insert i nz_xs_m i_notin_set, auto) also have "... = 0" using i_notin_set i A S00 n0 unfolding set_filter by auto finally show ?thesis . qed qed qed thus ?thesis using 2 by argo qed qed thus ?thesis using * e by presburger qed qed lemma FindPreHNF_works_n_ge2: assumes A_def: "A = A'' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A'': "A'' \ carrier_mat m n" and "n\2" and m_le_n: "m\n" and "D>0" shows "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ FindPreHNF abs_flag D A = P * A \ echelon_form_JNF (FindPreHNF abs_flag D A)" using assms proof (induct abs_flag D A arbitrary: A'' m n rule: FindPreHNF.induct) case (1 abs_flag D A) note A_def = "1.prems"(1) note A'' = "1.prems"(2) note n = "1.prems"(3) note m_le_n = "1.prems"(4) note D0 = "1.prems"(5) let ?RAT = "map_mat rat_of_int" have A: "A \ carrier_mat (m+n) n" using A_def A'' by auto have mn: "2\m+n" using n by auto have m0: "00" using D0 by auto define non_zero_positions where "non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. 0 then A else let i = non_zero_positions ! 0 in swaprows 0 i A)" let ?Reduce = "(if abs_flag then reduce_below_abs else reduce_below)" obtain A'_UL A'_UR A'_DL A'_DR where A'_split: "(A'_UL, A'_UR, A'_DL, A'_DR) = split_block (?Reduce 0 non_zero_positions D (make_first_column_positive A')) 1 1" by (metis prod_cases4) define sub_PreHNF where "sub_PreHNF = FindPreHNF abs_flag D A'_DR" obtain xs where non_zero_positions_xs_m: "non_zero_positions = xs @ [m]" and d_xs: "distinct xs" and all_less_m: "\x\set xs. x < m \ 0 < x" using non_zero_positions_xs_m[OF A_def A'' non_zero_positions_def m0 n0] using D0 by fast define M where "M = (make_first_column_positive A')" have A': "A' \ carrier_mat (m+n) n" unfolding A'_def using A by auto have mk_A'_not0:"make_first_column_positive A' $$ (0,0) \ 0" by (rule make_first_column_positive_00[OF A_def A'' non_zero_positions_def A'_def m0 n0 D_not0 m_le_n]) have M: "M \ carrier_mat (m+n) n" using A' M_def by auto let ?M' = "mat_of_rows n (map (Matrix.row (make_first_column_positive A')) [0.. carrier_mat m n" by auto have M_M'D: "make_first_column_positive A' = ?M' @\<^sub>r D \\<^sub>m 1\<^sub>m n" if xs_empty: "xs \ []" proof (cases "A$$(0,0) \ 0") case True then have *: "make_first_column_positive A' = make_first_column_positive A" unfolding A'_def by auto show ?thesis by (unfold *, rule make_first_column_positive_append_id[OF A'' A_def D0 n0]) next case False then have *: "make_first_column_positive A' = make_first_column_positive (swaprows 0 (non_zero_positions ! 0) A)" unfolding A'_def by auto show ?thesis proof (unfold *, rule make_first_column_positive_append_id) let ?S = "mat_of_rows n (map (Matrix.row (swaprows 0 (non_zero_positions ! 0) A)) [0..r (D \\<^sub>m (1\<^sub>m n))" proof (rule swaprows_append_id[OF A'' A_def]) have A''00: "A'' $$ (0, 0) = 0" by (metis (no_types, lifting) A A'' A_def False add_sign_intros(2) append_rows_def carrier_matD index_mat_four_block m0 n0) have length_xs: "length xs > 0" using xs_empty by auto have "non_zero_positions ! 0 = xs ! 0" unfolding non_zero_positions_xs_m by (meson length_xs nth_append) thus "non_zero_positions ! 0 < m" using all_less_m length_xs by simp qed qed (insert n0 D0, auto) qed have A'_DR: "A'_DR \ carrier_mat (m + (n-1)) (n-1)" by (rule split_block(4)[OF A'_split[symmetric]], insert n M M_def, auto) have sub_PreHNF: "sub_PreHNF \ carrier_mat (m + (n -1)) (n-1)" unfolding sub_PreHNF_def by (rule FindPreHNF[OF A'_DR]) hence sub_PreHNF': "sub_PreHNF \ carrier_mat (m+n - 1) (n-1)" using n by auto have A'_UL: "A'_UL \ carrier_mat 1 1" by (rule split_block(1)[OF A'_split[symmetric], of "m+n-1" "n-1"], insert n A', auto) have A'_UR: "A'_UR \ carrier_mat 1 (n-1)" by (rule split_block(2)[OF A'_split[symmetric], of "m+n-1"], insert n A', auto) have A'_DL: "A'_DL \ carrier_mat (m + (n - 1)) 1" by (rule split_block(3)[OF A'_split[symmetric], of _ "n-1"], insert n A', auto) show ?case proof (cases abs_flag) case True note abs_flag = True hence A'_split: "(A'_UL, A'_UR, A'_DL, A'_DR) = split_block (reduce_below_abs 0 non_zero_positions D (make_first_column_positive A')) 1 1" using A'_split by auto let ?R = "reduce_below_abs 0 non_zero_positions D (make_first_column_positive A')" have fbm_R: "four_block_mat A'_UL A'_UR A'_DL A'_DR = reduce_below_abs 0 non_zero_positions D (make_first_column_positive A')" by (rule split_block(5)[symmetric, OF A'_split[symmetric], of "m+n-1" "n-1"], insert A' n, auto) have A'_DL0: "A'_DL = (0\<^sub>m (m + (n - 1)) 1)" proof (rule eq_matI) show "dim_row A'_DL = dim_row (0\<^sub>m (m + (n - 1)) 1)" and "dim_col A'_DL = dim_col (0\<^sub>m (m + (n - 1)) 1)" using A'_DL by auto fix i j assume i: "i < dim_row (0\<^sub>m (m + (n - 1)) 1)" and j: "j < dim_col (0\<^sub>m (m + (n - 1)) 1)" have j0: "j=0" using j by auto have "0 = ?R $$ (i+1,j)" proof (unfold M_def non_zero_positions_xs_m j0, rule reduce_below_abs_0_case_m_make_first_column_positive[symmetric, OF A'' m0 n0 A_def m_le_n _ d_xs all_less_m _ _ D0 _ ]) show "A' = (if A $$ (0, 0) \ 0 then A else let i = (xs @ [m]) ! 0 in swaprows 0 i A)" using A'_def non_zero_positions_def non_zero_positions_xs_m by presburger show "xs @ [m] = filter (\i. A $$ (i, 0) \ 0) [1..m (m + (n - 1)) 1 $$ (i, j)" using i j by auto qed let ?A'_DR_m = "mat_of_rows (n-1) [Matrix.row A'_DR i. i \ [0.. carrier_mat m (n-1)" by auto have A'DR_A'DR_m_D: "A'_DR = ?A'_DR_m @\<^sub>r D \\<^sub>m 1\<^sub>m (n - 1)" proof (rule eq_matI) show dr: "dim_row A'_DR = dim_row (?A'_DR_m @\<^sub>r D \\<^sub>m 1\<^sub>m (n - 1))" by (metis A'_DR A'_DR_m append_rows_def carrier_matD(1) index_mat_four_block(2) index_one_mat(2) index_smult_mat(2) index_zero_mat(2)) show dc: "dim_col A'_DR = dim_col (?A'_DR_m @\<^sub>r D \\<^sub>m 1\<^sub>m (n - 1))" by (metis A'_DR A'_DR_m add.comm_neutral append_rows_def carrier_matD(2) index_mat_four_block(3) index_zero_mat(3)) fix i j assume i: "i < dim_row(?A'_DR_m @\<^sub>r D \\<^sub>m 1\<^sub>m (n - 1))" and j: "jr D \\<^sub>m 1\<^sub>m (n - 1))" have jn1: "jr D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i,j)" proof (cases "ir D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i,j)" by (metis (mono_tags, lifting) A'_DR A'_DR_m True append_rows_def carrier_matD dc i index_mat_four_block j) finally show ?thesis . next case False note i_ge_m = False let ?reduce_below = "reduce_below_abs 0 non_zero_positions D (make_first_column_positive A')" have 1: "(?A'_DR_m @\<^sub>r D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i,j) = (D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i-m,j)" - by (smt A'_DR A'_DR_m False append_rows_nth carrier_matD carrier_mat_triv dc dr i + by (smt (verit) A'_DR A'_DR_m False append_rows_nth carrier_matD carrier_mat_triv dc dr i index_one_mat(2) index_one_mat(3) index_smult_mat(2,3) j) have "?reduce_below = four_block_mat A'_UL A'_UR A'_DL A'_DR" using fbm_R .. also have "... $$ (i+1,j+1) = (if i+1 < dim_row A'_UL then if j+1 < dim_col A'_UL then A'_UL $$ (i+1, j+1) else A'_UR $$ (i+1, j+1 - dim_col A'_UL) else if j+1 < dim_col A'_UL then A'_DL $$ (i+1 - dim_row A'_UL, j+1) else A'_DR $$ (i+1 - dim_row A'_UL, j+1 - dim_col A'_UL))" by (rule index_mat_four_block, insert i j A'_UL A'_DR dr dc, auto) also have "... = A'_DR $$ (i,j)" using A'_UL by auto finally have 2: "?reduce_below $$ (i+1,j+1) = A'_DR $$ (i,j)" . show ?thesis proof (cases "xs = []") case True note xs_empty = True have i1_m: "i + 1 \ m" using False less_add_one by blast have j1n: "j+1\<^sub>m 1\<^sub>m n) $$ ((i+1)-m, j+1)" proof (cases "A $$ (0,0) = 0") case True let ?S = "(swaprows 0 m A)" have S: "?S \ carrier_mat (m+n) n" using A by auto have Si10: "?S $$ (i+1,0) = 0" proof - have "?S $$ (i+1,0) = A $$ (i+1,0)" using i1_m n0 i1_mn S by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i+1 - m,0)" - by (smt A_def A'' A i_ge_m append_rows_def carrier_matD diff_add_inverse2 i1_mn + by (smt (verit) A_def A'' A i_ge_m append_rows_def carrier_matD diff_add_inverse2 i1_mn index_mat_four_block less_imp_diff_less n0) also have "... = 0" using i_ge_m n0 i1_mn by auto finally show ?thesis . qed have "M $$ (i+1, j+1) = (make_first_column_positive ?S) $$ (i+1,j+1)" by (simp add: A'_def M_def True non_zero_positions_xs_m xs_empty) also have "... = (if ?S $$ (i+1,0) < 0 then - ?S $$ (i+1,j+1) else ?S $$ (i+1,j+1))" unfolding make_first_column_positive.simps using S i1_mn j1n by auto also have "... = ?S $$ (i+1,j+1)" using Si10 by auto also have "... = A $$ (i+1,j+1)" using i1_m n0 i1_mn S jn1 by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i+1 - m,j+1)" - by (smt A_def A'' A i_ge_m append_rows_def carrier_matD i1_mn index_mat_four_block(1,3) + by (smt (verit) A_def A'' A i_ge_m append_rows_def carrier_matD i1_mn index_mat_four_block(1,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2) j1n less_imp_diff_less add_diff_cancel_right') finally show ?thesis . next case False have Ai10: "A $$ (i+1,0) = 0" proof - have "A $$ (i+1,0) = (D \\<^sub>m 1\<^sub>m n) $$ (i+1 - m,0)" - by (smt A_def A'' A i_ge_m append_rows_def carrier_matD diff_add_inverse2 i1_mn + by (smt (verit) A_def A'' A i_ge_m append_rows_def carrier_matD diff_add_inverse2 i1_mn index_mat_four_block less_imp_diff_less n0) also have "... = 0" using i_ge_m n0 i1_mn by auto finally show ?thesis . qed have "M $$ (i+1, j+1) = (make_first_column_positive A) $$ (i+1,j+1)" by (simp add: A'_def M_def False True non_zero_positions_xs_m) also have "... = (if A $$ (i+1,0) < 0 then - A $$ (i+1,j+1) else A $$ (i+1,j+1))" unfolding make_first_column_positive.simps using A i1_mn j1n by auto also have "... = A $$ (i+1,j+1)" using Ai10 by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i+1 - m,j+1)" - by (smt A_def A'' A i_ge_m append_rows_def carrier_matD i1_mn index_mat_four_block(1,3) + by (smt (verit) A_def A'' A i_ge_m append_rows_def carrier_matD i1_mn index_mat_four_block(1,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2) j1n less_imp_diff_less add_diff_cancel_right') finally show ?thesis . qed also have "... = D * (1\<^sub>m n) $$ ((i+1)-m, j+1)" by (rule index_smult_mat, insert i jn1 A'_DR False dr, auto) also have "... = D *(1\<^sub>m (n - 1)) $$ (i-m,j)" using dc dr i j A'_DR i_ge_m - by (smt Nat.add_diff_assoc2 carrier_matD(1) index_one_mat(1) jn1 less_diff_conv + by (smt (verit) Nat.add_diff_assoc2 carrier_matD(1) index_one_mat(1) jn1 less_diff_conv linorder_not_less add_diff_cancel_right' add_diff_cancel_right' add_diff_cancel_left') also have "... = (D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i-m,j)" by (rule index_smult_mat[symmetric], insert i jn1 A'_DR False dr, auto) finally show ?thesis using 1 2 by auto next case False have "?reduce_below $$ (i+1, j+1) = M $$ (i+1, j+1)" proof (unfold non_zero_positions_xs_m M_def, rule reduce_below_abs_preserves_case_m[OF M' m0 _ M_M'D mk_A'_not0 m_le_n _ d_xs all_less_m _ _ _ D0]) show "j + 1 < n" using jn1 by auto show "i + 1 \ set xs" using all_less_m i_ge_m non_zero_positions_xs_m by auto show "i + 1 \ 0" by auto show " i + 1 < m + n" using i_ge_m i dr A'_DR by auto show " i + 1 \ m" using i_ge_m by auto qed (insert False) also have "... = (?M' @\<^sub>r D \\<^sub>m 1\<^sub>m n) $$ (i+1, j+1)" unfolding M_def using False M_M'D by argo also have "... = (D \\<^sub>m 1\<^sub>m n) $$ ((i+1)-m, j+1)" proof - have f1: "1 + j < n" by (metis Groups.add_ac(2) jn1 less_diff_conv) have f2: "\n. \ n + i < m" by (meson i_ge_m linorder_not_less nat_SN.compat not_add_less2) have "i < m + (n - 1)" by (metis (no_types) A'_DR carrier_matD(1) dr i) then have "1 + i < m + n" using f1 by linarith then show ?thesis using f2 f1 by (metis (no_types) Groups.add_ac(2) M' append_rows_def carrier_matD(1) dim_col_mat(1) index_mat_four_block(1) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) mat_of_rows_def nat_arith.rule0) qed also have "... = D * (1\<^sub>m n) $$ ((i+1)-m, j+1)" by (rule index_smult_mat, insert i jn1 A'_DR False dr, auto) also have "... = D *(1\<^sub>m (n - 1)) $$ (i-m,j)" using dc dr i j A'_DR i_ge_m - by (smt Nat.add_diff_assoc2 carrier_matD(1) index_one_mat(1) jn1 less_diff_conv + by (smt (verit) Nat.add_diff_assoc2 carrier_matD(1) index_one_mat(1) jn1 less_diff_conv linorder_not_less add_diff_cancel_right' add_diff_cancel_left') also have "... = (D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i-m,j)" by (rule index_smult_mat[symmetric], insert i jn1 A'_DR False dr, auto) finally have 3: "?reduce_below $$ (i+1,j+1) = (D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i-m,j)" . show ?thesis using 1 2 3 by presburger qed qed qed let ?A'_DR_n = "mat_of_rows (n - 1) (map (Matrix.row A'_DR) [0..P. P\carrier_mat (m + (n-1)) (m + (n-1)) \ invertible_mat P \ sub_PreHNF = P * A'_DR \ echelon_form_JNF sub_PreHNF" proof (cases "2 \ n - 1") case True show ?thesis by (unfold sub_PreHNF_def, rule "1.hyps"[OF _ _ _ non_zero_positions_def A'_def _ _ _ _ _]) (insert A n D0 m_le_n True A'DR_A'DR_m_D A A'_split abs_flag, auto) next case False have "\P. P\carrier_mat (m + (n-1)) (m + (n-1)) \ invertible_mat P \ sub_PreHNF = P * A'_DR" by (unfold sub_PreHNF_def, rule FindPreHNF_invertible_mat_mx2 [OF A'DR_A'DR_m_D A'_DR_m _ _ D0 _]) (insert False m_le_n n0 m0 "1"(4), auto) moreover have "echelon_form_JNF sub_PreHNF" unfolding sub_PreHNF_def by (rule FindPreHNF_echelon_form_mx1[OF A'DR_A'DR_m_D A'_DR_m _ D0 _], insert False n0 m_le_n, auto) ultimately show ?thesis by simp qed from this obtain P where P: "P \ carrier_mat (m + (n - 1)) (m + (n - 1))" and inv_P: "invertible_mat P" and sub_PreHNF_P_A'_DR: "sub_PreHNF = P * A'_DR" by blast define P' where "P' = (four_block_mat (1\<^sub>m 1) (0\<^sub>m 1 (m+(n-1))) (0\<^sub>m (m+(n-1)) 1) P)" have P': "P' \ carrier_mat (m+n) (m+n)" proof - have "P' \ carrier_mat (1 + (m+(n-1))) (1 + (m+(n-1))) " unfolding P'_def by (rule four_block_carrier_mat[OF _ P], simp) thus ?thesis using n by auto qed have inv_P': "invertible_mat P'" unfolding P'_def by (rule invertible_mat_four_block_mat_lower_right[OF P inv_P]) have dr_A2: "dim_row A \ 2" using A m0 n by auto have dc_A2: "dim_col A \ 2" using n A by blast have *: "(dim_col A = 0) = False" using dc_A2 by auto have FindPreHNF_as_fbm: "FindPreHNF abs_flag D A = four_block_mat A'_UL A'_UR A'_DL sub_PreHNF" unfolding FindPreHNF.simps[of abs_flag D A] using A'_split mn n A dr_A2 dc_A2 abs_flag unfolding Let_def sub_PreHNF_def M_def A'_def non_zero_positions_def * - by (smt (z3) linorder_not_less split_conv) + by (smt (verit) linorder_not_less split_conv) also have "... = P' * (reduce_below_abs 0 non_zero_positions D M)" proof - have "P' * (reduce_below_abs 0 non_zero_positions D M) = four_block_mat (1\<^sub>m 1) (0\<^sub>m 1 (m + (n - 1))) (0\<^sub>m (m + (n - 1)) 1) P * four_block_mat A'_UL A'_UR A'_DL A'_DR" unfolding P'_def fbm_R[unfolded M_def[symmetric], symmetric] .. also have "... = four_block_mat ((1\<^sub>m 1) * A'_UL + (0\<^sub>m 1 (m + (n - 1)) * A'_DL)) ((1\<^sub>m 1) * A'_UR + (0\<^sub>m 1 (m + (n - 1))) * A'_DR) ((0\<^sub>m (m + (n - 1)) 1) * A'_UL + P * A'_DL) ((0\<^sub>m (m + (n - 1)) 1) * A'_UR + P * A'_DR)" by (rule mult_four_block_mat[OF _ _ _ P A'_UL A'_UR A'_DL A'_DR], auto) also have "... = four_block_mat A'_UL A'_UR (P * A'_DL) (P * A'_DR)" by (rule cong_four_block_mat, insert A'_UL A'_UR A'_DL A'_DR P, auto) also have "... = four_block_mat A'_UL A'_UR (0\<^sub>m (m + (n - 1)) 1) sub_PreHNF" unfolding A'_DL0 sub_PreHNF_P_A'_DR using P by simp also have "... = four_block_mat A'_UL A'_UR A'_DL sub_PreHNF" unfolding A'_DL0 by simp finally show ?thesis .. qed finally have Find_P'_reduceM: "FindPreHNF abs_flag D A = P' * (reduce_below_abs 0 non_zero_positions D M)" . have "\Q. invertible_mat Q \ Q \ carrier_mat (m + n) (m + n) \ reduce_below_abs 0 (xs @ [m]) D M = Q * M" proof (cases "xs = []") case True note xs_empty = True have rw: "reduce_below_abs 0 (xs @ [m]) D M = reduce_abs 0 m D M" using True by auto obtain p q u v d where pquvd: "(p, q, u, v, d) = euclid_ext2 (M $$ (0, 0)) (M $$ (m, 0))" by (simp add: euclid_ext2_def) have "\P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce_abs 0 m D M = P * M" proof (rule reduce_abs_invertible_mat_case_m[OF _ _ m0 _ _ _ _ m_le_n n0 pquvd]) show "M $$ (0, 0) \ 0" using M_def mk_A'_not0 by blast define M' where "M' = mat_of_rows n (map (Matrix.row M) [0..(i, k). if i = 0 then p * M $$ (0, k) + q * M $$ (m, k) else if i = m then u * M $$ (0, k) + v * M $$ (m, k) else M $$ (i, k))" show M_M'_M'': "M = M' @\<^sub>r M''" unfolding M'_def M''_def by (metis M append_rows_split carrier_matD le_add1) show M': "M' \ carrier_mat m n" unfolding M'_def by fastforce show M'': "M'' \ carrier_mat n n" unfolding M''_def by fastforce show "0 \ m" using m0 by simp show "A2 = Matrix.mat (dim_row M) (dim_col M) (\(i, k). if i = 0 then p * M $$ (0, k) + q * M $$ (m, k) else if i = m then u * M $$ (0, k) + v * M $$ (m, k) else M $$ (i, k))" (is "_ = ?rhs") using A A2_def by auto define xs' where "xs' = filter (\i. abs (A2 $$ (0,i)) > D) [0..i. abs (A2 $$ (m,i)) > D) [0..i. abs (A2 $$ (0,i)) > D) [0..i. abs (A2 $$ (m,i)) > D) [0.. (\j'\{0..0" for j proof - have Ajm0: "A $$ (j+m,0) = 0" proof - have "A $$ (j+m,0) = (D \\<^sub>m 1\<^sub>m n) $$ (j+m-m,0)" - by (smt "1"(2) "1"(3) M M' M'' M_M'_M'' add.commute append_rows_def carrier_matD + by (smt (verit) "1"(2) "1"(3) M M' M'' M_M'_M'' add.commute append_rows_def carrier_matD diff_add_inverse2 index_mat_four_block index_one_mat(2) index_smult_mat(2) le_add2 less_diff_conv2 n0 not_add_less2 that(1)) also have "... = 0" using jn j0 by auto finally show ?thesis . qed have "M'' $$ (j, i) = (D \\<^sub>m 1\<^sub>m n) $$ (j,i)" if i_n: "i\<^sub>m 1\<^sub>m n) $$ (j,i)" - by (smt A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n + by (smt (verit) A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n carrier_matD index_mat_four_block(1,2) add_diff_cancel_right' not_add_less2 jn trans_less_add1) finally show ?thesis . next case False have "A' = A" unfolding A'_def non_zero_positions_xs_m using False True by auto - hence "M'' $$ (j, i) = make_first_column_positive A $$ (j+m,i)" - by (smt m_le_n M' M'' M_M'_M'' M_def append_rows_nth2 jn nat_SN.compat that) + hence "M'' $$ (j, i) = make_first_column_positive A $$ (j+m,i)" + using M' M'' M_M'_M'' unfolding M_def + by (metis (no_types, opaque_lifting) "1"(5) append_rows_nth2 jn nat_SN.compat that) also have "... = A $$ (j+m,i)" using A jn j0 i_n Ajm0 by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (j,i)" - by (smt A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n + by (smt (verit) A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n carrier_matD index_mat_four_block(1,2) add_diff_cancel_right' not_add_less2 jn trans_less_add1) finally show ?thesis . qed thus ?thesis using jn j0 by auto qed have Am0D: "A$$(m,0) = D" proof - have "A$$(m,0) = (D \\<^sub>m 1\<^sub>m n) $$ (m-m,0)" - by (smt "1"(2) "1"(3) M M' M'' M_M'_M'' append_rows_def carrier_matD + by (smt (verit) "1"(2) "1"(3) M M' M'' M_M'_M'' append_rows_def carrier_matD diff_less_mono2 diff_self_eq_0 index_mat_four_block index_one_mat(2) index_smult_mat(2) less_add_same_cancel1 n0 semiring_norm(137)) also have "... = D" using m0 n0 by auto finally show ?thesis . qed hence S00D: "(swaprows 0 m A) $$ (0,0) = D" using n0 m0 A by auto have Sm00: "(swaprows 0 m A) $$ (m,0) = A$$(0,0)" using n0 m0 A by auto have M00D: "M $$ (0, 0) = D" if A00: "A$$(0,0) = 0" proof - have "M $$ (0,0) = (make_first_column_positive (swaprows 0 m A)) $$ (0,0)" unfolding M_def A'_def using A00 by (simp add: True non_zero_positions_xs_m) also have "... = (if (swaprows 0 m A) $$ (0,0) < 0 then - (swaprows 0 m A) $$(0,0) else (swaprows 0 m A) $$(0,0))" unfolding make_first_column_positive.simps using m0 n0 A by auto also have "... = (swaprows 0 m A) $$(0,0)" using S00D D0 by auto also have "... = D" using S00D by auto finally show ?thesis . qed have Mm00: "M $$ (m, 0) = 0" if A00: "A$$(0,0) = 0" proof - have "M $$ (m,0) = (make_first_column_positive (swaprows 0 m A)) $$ (m,0)" unfolding M_def A'_def using A00 by (simp add: True non_zero_positions_xs_m) also have "... = (if (swaprows 0 m A) $$ (m,0) < 0 then - (swaprows 0 m A) $$(m,0) else (swaprows 0 m A) $$(m,0))" unfolding make_first_column_positive.simps using m0 n0 A by auto also have "... = (swaprows 0 m A) $$(m,0)" using Sm00 A00 D0 by auto also have "... = 0" using Sm00 A00 by auto finally show ?thesis . qed have M000: "M $$ (0, 0) = abs (A$$(0,0))" if A00: "A$$(0,0) \ 0" proof - have "M $$ (0,0) = (make_first_column_positive A) $$ (0,0)" unfolding M_def A'_def using A00 by (simp add: True non_zero_positions_xs_m) also have "... = (if A $$ (0,0) < 0 then - A $$(0,0) else A $$(0,0))" unfolding make_first_column_positive.simps using m0 n0 A by auto also have "... = abs (A$$(0,0))" using Sm00 A00 by auto finally show ?thesis . qed have Mm0D: "M $$ (m, 0) = D" if A00: "A $$ (0,0) \ 0" proof - have "M $$ (m,0) = (make_first_column_positive A) $$ (m,0)" unfolding M_def A'_def using A00 by (simp add: True non_zero_positions_xs_m) also have "... = (if A $$ (m,0) < 0 then - A $$(m,0) else A $$(m,0))" unfolding make_first_column_positive.simps using m0 n0 A by auto also have "... = A $$(m,0)" using S00D D0 Am0D by auto also have "... = D" using Am0D D0 by auto finally show ?thesis . qed have "0 \ set xs'" proof - have "A2 $$ (0,0) = p * M $$ (0, 0) + q * M $$ (m, 0)" using A A2_def n0 M by auto also have "... = gcd (M $$ (0, 0)) (M $$ (m, 0))" by (metis euclid_ext2_works(1,2) pquvd) also have "abs ... \ D" using M00D Mm00 M000 Mm0D using gcd_0_int D0 by fastforce finally have "abs (A2 $$ (0,0)) \ D" . thus ?thesis unfolding xs'_def using D0 by auto qed thus "\j\set xs'. j (M'' $$ (j, j) = D) \ (\j'\{0.. set ys'" proof - have "A2 $$ (m,0) = u * M $$ (0, 0) + v * M $$ (m, 0)" using A A2_def n0 m0 M by auto also have "... = - M $$ (m, 0) div gcd (M $$ (0, 0)) (M $$ (m, 0)) * M $$ (0, 0) + M $$ (0, 0) div gcd (M $$ (0, 0)) (M $$ (m, 0)) * M $$ (m, 0) " by (simp add: euclid_ext2_works[OF pquvd[symmetric]]) also have "... = 0" using M00D Mm00 M000 Mm0D - by (smt dvd_div_mult_self euclid_ext2_works(3) euclid_ext2_works(5) + by (smt (verit) dvd_div_mult_self euclid_ext2_works(3) euclid_ext2_works(5) more_arith_simps(11) mult.commute mult_minus_left pquvd semiring_gcd_class.gcd_dvd1) finally have "A2 $$ (m,0) = 0" . thus ?thesis unfolding ys'_def using D0 by auto qed thus "\j\set ys'. j (M'' $$ (j, j) = D) \ (\j'\{0.. carrier_mat (m + n) (m + n)" and reduce_QM: "reduce_below_abs 0 (xs @ [m]) D M = Q * M" by blast have "\R. invertible_mat R \ R \ carrier_mat (dim_row A') (dim_row A') \ M = R * A'" by (unfold M_def, rule make_first_column_positive_invertible) from this obtain R where inv_R: "invertible_mat R" and R: "R \ carrier_mat (dim_row A') (dim_row A')" and M_RA': "M = R * A'" by blast have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ A' = P * A" by (rule A'_swaprows_invertible_mat[OF A A'_def non_zero_positions_def], insert non_zero_positions_xs_m n m0, auto) from this obtain S where inv_S: "invertible_mat S" and S: "S \ carrier_mat (dim_row A) (dim_row A)" and A'_SA: "A' = S * A" using A by auto have "(P'*Q*R*S) \ carrier_mat (m+n) (m+n)" using P' Q R S A' A by auto moreover have "FindPreHNF abs_flag D A = (P'*Q*R*S) * A" using Find_P'_reduceM reduce_QM unfolding M_RA' A'_SA M_def - by (smt A' A'_SA P' Q R S assoc_mult_mat carrier_matD carrier_mat_triv index_mult_mat(2,3) + by (smt (verit) A' A'_SA P' Q R S assoc_mult_mat carrier_matD carrier_mat_triv index_mult_mat(2,3) non_zero_positions_xs_m) moreover have "invertible_mat (P'*Q*R*S)" using inv_P' inv_Q inv_R inv_S using P' Q R S A' A by (metis carrier_matD carrier_mat_triv index_mult_mat(2,3) invertible_mult_JNF) ultimately have exists_inv: "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ FindPreHNF abs_flag D A = P * A" by blast moreover have "echelon_form_JNF (FindPreHNF abs_flag D A)" proof (rule echelon_form_four_block_mat[OF A'_UL A'_UR sub_PreHNF' ]) show "FindPreHNF abs_flag D A = four_block_mat A'_UL A'_UR (0\<^sub>m (m + n - 1) 1) sub_PreHNF" using A'_DL0 FindPreHNF_as_fbm sub_PreHNF sub_PreHNF' by auto have "A'_UL $$ (0, 0) = ?R $$ (0,0)" by (metis (mono_tags, lifting) A A'_DR A'_UL Find_P'_reduceM M_def \FindPreHNF abs_flag D A = P' * Q * R * S * A\ add_Suc_right add_sign_intros(2) carrier_matD fbm_R index_mat_four_block(1,3) index_mult_mat(3) m0 n0 plus_1_eq_Suc zero_less_one_class.zero_less_one) also have "... \ 0" proof (cases "xs=[]") case True have "?R $$ (0,0) = reduce_abs 0 m D M $$ (0,0)" unfolding non_zero_positions_xs_m True M_def by simp also have "... \ 0" by (metis D_not0 M M_def add_pos_pos less_add_same_cancel1 m0 mk_A'_not0 n0 reduce_not0) finally show ?thesis . next case False show ?thesis by (unfold non_zero_positions_xs_m, rule reduce_below_abs_not0_case_m[OF M' m0 n0 M_M'D[OF False] mk_A'_not0 m_le_n all_less_m D_not0]) qed finally show "A'_UL $$ (0, 0) \ 0" . qed (insert mn n hyp, auto) ultimately show ?thesis by blast next case False hence A'_split: "(A'_UL, A'_UR, A'_DL, A'_DR) = split_block (reduce_below 0 non_zero_positions D (make_first_column_positive A')) 1 1" using A'_split by auto let ?R = "reduce_below 0 non_zero_positions D (make_first_column_positive A')" have fbm_R: "four_block_mat A'_UL A'_UR A'_DL A'_DR = reduce_below 0 non_zero_positions D (make_first_column_positive A')" by (rule split_block(5)[symmetric, OF A'_split[symmetric], of "m+n-1" "n-1"], insert A' n, auto) have A'_DL0: "A'_DL = (0\<^sub>m (m + (n - 1)) 1)" proof (rule eq_matI) show "dim_row A'_DL = dim_row (0\<^sub>m (m + (n - 1)) 1)" and "dim_col A'_DL = dim_col (0\<^sub>m (m + (n - 1)) 1)" using A'_DL by auto fix i j assume i: "i < dim_row (0\<^sub>m (m + (n - 1)) 1)" and j: "j < dim_col (0\<^sub>m (m + (n - 1)) 1)" have j0: "j=0" using j by auto have "0 = ?R $$ (i+1,j)" proof (unfold M_def non_zero_positions_xs_m j0, rule reduce_below_0_case_m_make_first_column_positive[symmetric, OF A'' m0 n0 A_def m_le_n _ d_xs all_less_m _ _ D0 _ ]) show "A' = (if A $$ (0, 0) \ 0 then A else let i = (xs @ [m]) ! 0 in swaprows 0 i A)" using A'_def non_zero_positions_def non_zero_positions_xs_m by presburger show "xs @ [m] = filter (\i. A $$ (i, 0) \ 0) [1..m (m + (n - 1)) 1 $$ (i, j)" using i j by auto qed let ?A'_DR_m = "mat_of_rows (n-1) [Matrix.row A'_DR i. i \ [0.. carrier_mat m (n-1)" by auto have A'DR_A'DR_m_D: "A'_DR = ?A'_DR_m @\<^sub>r D \\<^sub>m 1\<^sub>m (n - 1)" proof (rule eq_matI) show dr: "dim_row A'_DR = dim_row (?A'_DR_m @\<^sub>r D \\<^sub>m 1\<^sub>m (n - 1))" by (metis A'_DR A'_DR_m append_rows_def carrier_matD(1) index_mat_four_block(2) index_one_mat(2) index_smult_mat(2) index_zero_mat(2)) show dc: "dim_col A'_DR = dim_col (?A'_DR_m @\<^sub>r D \\<^sub>m 1\<^sub>m (n - 1))" by (metis A'_DR A'_DR_m add.comm_neutral append_rows_def carrier_matD(2) index_mat_four_block(3) index_zero_mat(3)) fix i j assume i: "i < dim_row(?A'_DR_m @\<^sub>r D \\<^sub>m 1\<^sub>m (n - 1))" and j: "jr D \\<^sub>m 1\<^sub>m (n - 1))" have jn1: "jr D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i,j)" proof (cases "ir D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i,j)" by (metis (mono_tags, lifting) A'_DR A'_DR_m True append_rows_def carrier_matD dc i index_mat_four_block j) finally show ?thesis . next case False note i_ge_m = False let ?reduce_below = "reduce_below 0 non_zero_positions D (make_first_column_positive A')" have 1: "(?A'_DR_m @\<^sub>r D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i,j) = (D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i-m,j)" - by (smt A'_DR A'_DR_m False append_rows_nth carrier_matD carrier_mat_triv dc dr i + by (smt (verit) A'_DR A'_DR_m False append_rows_nth carrier_matD carrier_mat_triv dc dr i index_one_mat(2) index_one_mat(3) index_smult_mat(2,3) j) have "?reduce_below = four_block_mat A'_UL A'_UR A'_DL A'_DR" using fbm_R .. also have "... $$ (i+1,j+1) = (if i+1 < dim_row A'_UL then if j+1 < dim_col A'_UL then A'_UL $$ (i+1, j+1) else A'_UR $$ (i+1, j+1 - dim_col A'_UL) else if j+1 < dim_col A'_UL then A'_DL $$ (i+1 - dim_row A'_UL, j+1) else A'_DR $$ (i+1 - dim_row A'_UL, j+1 - dim_col A'_UL))" by (rule index_mat_four_block, insert i j A'_UL A'_DR dr dc, auto) also have "... = A'_DR $$ (i,j)" using A'_UL by auto finally have 2: "?reduce_below $$ (i+1,j+1) = A'_DR $$ (i,j)" . show ?thesis proof (cases "xs = []") case True note xs_empty = True have i1_m: "i + 1 \ m" using False less_add_one by blast have j1n: "j+1\<^sub>m 1\<^sub>m n) $$ ((i+1)-m, j+1)" proof (cases "A $$ (0,0) = 0") case True let ?S = "(swaprows 0 m A)" have S: "?S \ carrier_mat (m+n) n" using A by auto have Si10: "?S $$ (i+1,0) = 0" proof - have "?S $$ (i+1,0) = A $$ (i+1,0)" using i1_m n0 i1_mn S by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i+1 - m,0)" - by (smt A_def A'' A i_ge_m append_rows_def carrier_matD diff_add_inverse2 i1_mn + by (smt (verit) A_def A'' A i_ge_m append_rows_def carrier_matD diff_add_inverse2 i1_mn index_mat_four_block less_imp_diff_less n0) also have "... = 0" using i_ge_m n0 i1_mn by auto finally show ?thesis . qed have "M $$ (i+1, j+1) = (make_first_column_positive ?S) $$ (i+1,j+1)" by (simp add: A'_def M_def True non_zero_positions_xs_m xs_empty) also have "... = (if ?S $$ (i+1,0) < 0 then - ?S $$ (i+1,j+1) else ?S $$ (i+1,j+1))" unfolding make_first_column_positive.simps using S i1_mn j1n by auto also have "... = ?S $$ (i+1,j+1)" using Si10 by auto also have "... = A $$ (i+1,j+1)" using i1_m n0 i1_mn S jn1 by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i+1 - m,j+1)" - by (smt A_def A'' A i_ge_m append_rows_def carrier_matD i1_mn index_mat_four_block(1,3) + by (smt (verit) A_def A'' A i_ge_m append_rows_def carrier_matD i1_mn index_mat_four_block(1,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2) j1n less_imp_diff_less add_diff_cancel_right') finally show ?thesis . next case False have Ai10: "A $$ (i+1,0) = 0" proof - have "A $$ (i+1,0) = (D \\<^sub>m 1\<^sub>m n) $$ (i+1 - m,0)" - by (smt A_def A'' A i_ge_m append_rows_def carrier_matD diff_add_inverse2 i1_mn + by (smt (verit) A_def A'' A i_ge_m append_rows_def carrier_matD diff_add_inverse2 i1_mn index_mat_four_block less_imp_diff_less n0) also have "... = 0" using i_ge_m n0 i1_mn by auto finally show ?thesis . qed have "M $$ (i+1, j+1) = (make_first_column_positive A) $$ (i+1,j+1)" by (simp add: A'_def M_def False True non_zero_positions_xs_m) also have "... = (if A $$ (i+1,0) < 0 then - A $$ (i+1,j+1) else A $$ (i+1,j+1))" unfolding make_first_column_positive.simps using A i1_mn j1n by auto also have "... = A $$ (i+1,j+1)" using Ai10 by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (i+1 - m,j+1)" - by (smt A_def A'' A i_ge_m append_rows_def carrier_matD i1_mn index_mat_four_block(1,3) + by (smt (verit) A_def A'' A i_ge_m append_rows_def carrier_matD i1_mn index_mat_four_block(1,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2) j1n less_imp_diff_less add_diff_cancel_right') finally show ?thesis . qed also have "... = D * (1\<^sub>m n) $$ ((i+1)-m, j+1)" by (rule index_smult_mat, insert i jn1 A'_DR False dr, auto) also have "... = D *(1\<^sub>m (n - 1)) $$ (i-m,j)" using dc dr i j A'_DR i_ge_m - by (smt Nat.add_diff_assoc2 carrier_matD(1) index_one_mat(1) jn1 less_diff_conv + by (smt (verit) Nat.add_diff_assoc2 carrier_matD(1) index_one_mat(1) jn1 less_diff_conv linorder_not_less add_diff_cancel_right' add_diff_cancel_right' add_diff_cancel_left') also have "... = (D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i-m,j)" by (rule index_smult_mat[symmetric], insert i jn1 A'_DR False dr, auto) finally show ?thesis using 1 2 by auto next case False have "?reduce_below $$ (i+1, j+1) = M $$ (i+1, j+1)" proof (unfold non_zero_positions_xs_m M_def, rule reduce_below_preserves_case_m[OF M' m0 _ M_M'D mk_A'_not0 m_le_n _ d_xs all_less_m _ _ _ D0]) show "j + 1 < n" using jn1 by auto show "i + 1 \ set xs" using all_less_m i_ge_m non_zero_positions_xs_m by auto show "i + 1 \ 0" by auto show " i + 1 < m + n" using i_ge_m i dr A'_DR by auto show " i + 1 \ m" using i_ge_m by auto qed (insert False) also have "... = (?M' @\<^sub>r D \\<^sub>m 1\<^sub>m n) $$ (i+1, j+1)" unfolding M_def using False M_M'D by argo also have "... = (D \\<^sub>m 1\<^sub>m n) $$ ((i+1)-m, j+1)" proof - have f1: "1 + j < n" by (metis Groups.add_ac(2) jn1 less_diff_conv) have f2: "\n. \ n + i < m" by (meson i_ge_m linorder_not_less nat_SN.compat not_add_less2) have "i < m + (n - 1)" by (metis (no_types) A'_DR carrier_matD(1) dr i) then have "1 + i < m + n" using f1 by linarith then show ?thesis using f2 f1 by (metis (no_types) Groups.add_ac(2) M' append_rows_def carrier_matD(1) dim_col_mat(1) index_mat_four_block(1) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) mat_of_rows_def nat_arith.rule0) qed also have "... = D * (1\<^sub>m n) $$ ((i+1)-m, j+1)" by (rule index_smult_mat, insert i jn1 A'_DR False dr, auto) also have "... = D *(1\<^sub>m (n - 1)) $$ (i-m,j)" using dc dr i j A'_DR i_ge_m - by (smt Nat.add_diff_assoc2 carrier_matD(1) index_one_mat(1) jn1 less_diff_conv + by (smt (verit) Nat.add_diff_assoc2 carrier_matD(1) index_one_mat(1) jn1 less_diff_conv linorder_not_less add_diff_cancel_right' add_diff_cancel_left') also have "... = (D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i-m,j)" by (rule index_smult_mat[symmetric], insert i jn1 A'_DR False dr, auto) finally have 3: "?reduce_below $$ (i+1,j+1) = (D \\<^sub>m 1\<^sub>m (n - 1)) $$ (i-m,j)" . show ?thesis using 1 2 3 by presburger qed qed qed let ?A'_DR_n = "mat_of_rows (n - 1) (map (Matrix.row A'_DR) [0..P. P\carrier_mat (m + (n-1)) (m + (n-1)) \ invertible_mat P \ sub_PreHNF = P * A'_DR \ echelon_form_JNF sub_PreHNF" proof (cases "2 \ n - 1") case True show ?thesis by (unfold sub_PreHNF_def, rule "1.hyps"[OF _ _ _ non_zero_positions_def A'_def _ _ _ _ _]) (insert A n D0 m_le_n True A'DR_A'DR_m_D A A'_split False, auto) next case False have "\P. P\carrier_mat (m + (n-1)) (m + (n-1)) \ invertible_mat P \ sub_PreHNF = P * A'_DR" by (unfold sub_PreHNF_def, rule FindPreHNF_invertible_mat_mx2 [OF A'DR_A'DR_m_D A'_DR_m _ _ D0 _]) (insert False m_le_n n0 m0 "1"(4), auto) moreover have "echelon_form_JNF sub_PreHNF" unfolding sub_PreHNF_def by (rule FindPreHNF_echelon_form_mx1[OF A'DR_A'DR_m_D A'_DR_m _ D0 _], insert False n0 m_le_n, auto) ultimately show ?thesis by simp qed from this obtain P where P: "P \ carrier_mat (m + (n - 1)) (m + (n - 1))" and inv_P: "invertible_mat P" and sub_PreHNF_P_A'_DR: "sub_PreHNF = P * A'_DR" by blast define P' where "P' = (four_block_mat (1\<^sub>m 1) (0\<^sub>m 1 (m+(n-1))) (0\<^sub>m (m+(n-1)) 1) P)" have P': "P' \ carrier_mat (m+n) (m+n)" proof - have "P' \ carrier_mat (1 + (m+(n-1))) (1 + (m+(n-1))) " unfolding P'_def by (rule four_block_carrier_mat[OF _ P], simp) thus ?thesis using n by auto qed have inv_P': "invertible_mat P'" unfolding P'_def by (rule invertible_mat_four_block_mat_lower_right[OF P inv_P]) have dr_A2: "dim_row A \ 2" using A m0 n by auto have dc_A2: "dim_col A \ 2" using n A by blast have *: "(dim_col A = 0) = False" using dc_A2 by auto have FindPreHNF_as_fbm: "FindPreHNF abs_flag D A = four_block_mat A'_UL A'_UR A'_DL sub_PreHNF" unfolding FindPreHNF.simps[of abs_flag D A] using A'_split mn n A dr_A2 dc_A2 False unfolding Let_def sub_PreHNF_def M_def A'_def non_zero_positions_def * - by (smt (z3) linorder_not_less split_conv) + by (smt (verit) linorder_not_less split_conv) also have "... = P' * (reduce_below 0 non_zero_positions D M)" proof - have "P' * (reduce_below 0 non_zero_positions D M) = four_block_mat (1\<^sub>m 1) (0\<^sub>m 1 (m + (n - 1))) (0\<^sub>m (m + (n - 1)) 1) P * four_block_mat A'_UL A'_UR A'_DL A'_DR" unfolding P'_def fbm_R[unfolded M_def[symmetric], symmetric] .. also have "... = four_block_mat ((1\<^sub>m 1) * A'_UL + (0\<^sub>m 1 (m + (n - 1)) * A'_DL)) ((1\<^sub>m 1) * A'_UR + (0\<^sub>m 1 (m + (n - 1))) * A'_DR) ((0\<^sub>m (m + (n - 1)) 1) * A'_UL + P * A'_DL) ((0\<^sub>m (m + (n - 1)) 1) * A'_UR + P * A'_DR)" by (rule mult_four_block_mat[OF _ _ _ P A'_UL A'_UR A'_DL A'_DR], auto) also have "... = four_block_mat A'_UL A'_UR (P * A'_DL) (P * A'_DR)" by (rule cong_four_block_mat, insert A'_UL A'_UR A'_DL A'_DR P, auto) also have "... = four_block_mat A'_UL A'_UR (0\<^sub>m (m + (n - 1)) 1) sub_PreHNF" unfolding A'_DL0 sub_PreHNF_P_A'_DR using P by simp also have "... = four_block_mat A'_UL A'_UR A'_DL sub_PreHNF" unfolding A'_DL0 by simp finally show ?thesis .. qed finally have Find_P'_reduceM: "FindPreHNF abs_flag D A = P' * (reduce_below 0 non_zero_positions D M)" . have "\Q. invertible_mat Q \ Q \ carrier_mat (m + n) (m + n) \ reduce_below 0 (xs @ [m]) D M = Q * M" proof (cases "xs = []") case True note xs_empty = True have rw: "reduce_below 0 (xs @ [m]) D M = reduce 0 m D M" using True by auto obtain p q u v d where pquvd: "(p, q, u, v, d) = euclid_ext2 (M $$ (0, 0)) (M $$ (m, 0))" by (simp add: euclid_ext2_def) have "\P. invertible_mat P \ P \ carrier_mat (m + n) (m + n) \ reduce 0 m D M = P * M" proof (rule reduce_invertible_mat_case_m[OF _ _ m0 _ _ _ _ m_le_n n0 pquvd]) show "M $$ (0, 0) \ 0" using M_def mk_A'_not0 by blast define M' where "M' = mat_of_rows n (map (Matrix.row M) [0..(i, k). if i = 0 then p * M $$ (0, k) + q * M $$ (m, k) else if i = m then u * M $$ (0, k) + v * M $$ (m, k) else M $$ (i, k))" show M_M'_M'': "M = M' @\<^sub>r M''" unfolding M'_def M''_def by (metis M append_rows_split carrier_matD le_add1) show M': "M' \ carrier_mat m n" unfolding M'_def by fastforce show M'': "M'' \ carrier_mat n n" unfolding M''_def by fastforce show "0 \ m" using m0 by simp show "A2 = Matrix.mat (dim_row M) (dim_col M) (\(i, k). if i = 0 then p * M $$ (0, k) + q * M $$ (m, k) else if i = m then u * M $$ (0, k) + v * M $$ (m, k) else M $$ (i, k))" (is "_ = ?rhs") using A A2_def by auto define xs' where "xs' = [1.. (\j'\{0..0" for j proof - have Ajm0: "A $$ (j+m,0) = 0" proof - have "A $$ (j+m,0) = (D \\<^sub>m 1\<^sub>m n) $$ (j+m-m,0)" - by (smt "1"(2) "1"(3) M M' M'' M_M'_M'' add.commute append_rows_def carrier_matD + by (smt (verit) "1"(2) "1"(3) M M' M'' M_M'_M'' add.commute append_rows_def carrier_matD diff_add_inverse2 index_mat_four_block index_one_mat(2) index_smult_mat(2) le_add2 less_diff_conv2 n0 not_add_less2 that(1)) also have "... = 0" using jn j0 by auto finally show ?thesis . qed have "M'' $$ (j, i) = (D \\<^sub>m 1\<^sub>m n) $$ (j,i)" if i_n: "i\<^sub>m 1\<^sub>m n) $$ (j,i)" - by (smt A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n + by (smt (verit) A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n carrier_matD index_mat_four_block(1,2) add_diff_cancel_right' not_add_less2 jn trans_less_add1) finally show ?thesis . next case False have "A' = A" unfolding A'_def non_zero_positions_xs_m using False True by auto hence "M'' $$ (j, i) = make_first_column_positive A $$ (j+m,i)" - by (smt m_le_n M' M'' M_M'_M'' M_def append_rows_nth2 jn nat_SN.compat that) + using M' M'' M_M'_M'' unfolding M_def + by (metis (no_types, opaque_lifting) "1"(5) append_rows_nth2 jn nat_SN.compat that) also have "... = A $$ (j+m,i)" using A jn j0 i_n Ajm0 by auto also have "... = (D \\<^sub>m 1\<^sub>m n) $$ (j,i)" - by (smt A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n + by (smt (verit) A Groups.add_ac(2) add_mono_thms_linordered_field(1) append_rows_def A_def A'' i_n carrier_matD index_mat_four_block(1,2) add_diff_cancel_right' not_add_less2 jn trans_less_add1) finally show ?thesis . qed thus ?thesis using jn j0 by auto qed have Am0D: "A$$(m,0) = D" proof - have "A$$(m,0) = (D \\<^sub>m 1\<^sub>m n) $$ (m-m,0)" - by (smt "1"(2) "1"(3) M M' M'' M_M'_M'' append_rows_def carrier_matD + by (smt (verit) "1"(2) "1"(3) M M' M'' M_M'_M'' append_rows_def carrier_matD diff_less_mono2 diff_self_eq_0 index_mat_four_block index_one_mat(2) index_smult_mat(2) less_add_same_cancel1 n0 semiring_norm(137)) also have "... = D" using m0 n0 by auto finally show ?thesis . qed hence S00D: "(swaprows 0 m A) $$ (0,0) = D" using n0 m0 A by auto have Sm00: "(swaprows 0 m A) $$ (m,0) = A$$(0,0)" using n0 m0 A by auto have M00D: "M $$ (0, 0) = D" if A00: "A$$(0,0) = 0" proof - have "M $$ (0,0) = (make_first_column_positive (swaprows 0 m A)) $$ (0,0)" unfolding M_def A'_def using A00 by (simp add: True non_zero_positions_xs_m) also have "... = (if (swaprows 0 m A) $$ (0,0) < 0 then - (swaprows 0 m A) $$(0,0) else (swaprows 0 m A) $$(0,0))" unfolding make_first_column_positive.simps using m0 n0 A by auto also have "... = (swaprows 0 m A) $$(0,0)" using S00D D0 by auto also have "... = D" using S00D by auto finally show ?thesis . qed have Mm00: "M $$ (m, 0) = 0" if A00: "A$$(0,0) = 0" proof - have "M $$ (m,0) = (make_first_column_positive (swaprows 0 m A)) $$ (m,0)" unfolding M_def A'_def using A00 by (simp add: True non_zero_positions_xs_m) also have "... = (if (swaprows 0 m A) $$ (m,0) < 0 then - (swaprows 0 m A) $$(m,0) else (swaprows 0 m A) $$(m,0))" unfolding make_first_column_positive.simps using m0 n0 A by auto also have "... = (swaprows 0 m A) $$(m,0)" using Sm00 A00 D0 by auto also have "... = 0" using Sm00 A00 by auto finally show ?thesis . qed have M000: "M $$ (0, 0) = abs (A$$(0,0))" if A00: "A$$(0,0) \ 0" proof - have "M $$ (0,0) = (make_first_column_positive A) $$ (0,0)" unfolding M_def A'_def using A00 by (simp add: True non_zero_positions_xs_m) also have "... = (if A $$ (0,0) < 0 then - A $$(0,0) else A $$(0,0))" unfolding make_first_column_positive.simps using m0 n0 A by auto also have "... = abs (A$$(0,0))" using Sm00 A00 by auto finally show ?thesis . qed have Mm0D: "M $$ (m, 0) = D" if A00: "A $$ (0,0) \ 0" proof - have "M $$ (m,0) = (make_first_column_positive A) $$ (m,0)" unfolding M_def A'_def using A00 by (simp add: True non_zero_positions_xs_m) also have "... = (if A $$ (m,0) < 0 then - A $$(m,0) else A $$(m,0))" unfolding make_first_column_positive.simps using m0 n0 A by auto also have "... = A $$(m,0)" using S00D D0 Am0D by auto also have "... = D" using Am0D D0 by auto finally show ?thesis . qed have "0 \ set xs'" proof - have "A2 $$ (0,0) = p * M $$ (0, 0) + q * M $$ (m, 0)" using A A2_def n0 M by auto also have "... = gcd (M $$ (0, 0)) (M $$ (m, 0))" by (metis euclid_ext2_works(1,2) pquvd) also have "abs ... \ D" using M00D Mm00 M000 Mm0D using gcd_0_int D0 by fastforce finally have "abs (A2 $$ (0,0)) \ D" . thus ?thesis unfolding xs'_def using D0 by auto qed thus "\j\set xs'. j (M'' $$ (j, j) = D) \ (\j'\{0.. set ys'" proof - have "A2 $$ (m,0) = u * M $$ (0, 0) + v * M $$ (m, 0)" using A A2_def n0 m0 M by auto also have "... = - M $$ (m, 0) div gcd (M $$ (0, 0)) (M $$ (m, 0)) * M $$ (0, 0) + M $$ (0, 0) div gcd (M $$ (0, 0)) (M $$ (m, 0)) * M $$ (m, 0) " by (simp add: euclid_ext2_works[OF pquvd[symmetric]]) also have "... = 0" using M00D Mm00 M000 Mm0D - by (smt dvd_div_mult_self euclid_ext2_works(3) euclid_ext2_works(5) + by (smt (verit) dvd_div_mult_self euclid_ext2_works(3) euclid_ext2_works(5) more_arith_simps(11) mult.commute mult_minus_left pquvd semiring_gcd_class.gcd_dvd1) finally have "A2 $$ (m,0) = 0" . thus ?thesis unfolding ys'_def using D0 by auto qed thus "\j\set ys'. j (M'' $$ (j, j) = D) \ (\j'\{0.. {0,D}" using Mm00 Mm0D by blast show " M $$ (m, 0) = 0 \ M $$ (0, 0) = D" using Mm00 Mm0D D_not0 M00D by blast qed (insert D0) then show ?thesis using rw by auto next case False show ?thesis by (unfold M_def, rule reduce_below_invertible_mat_case_m[OF M' m0 n0 M_M'D[OF False] mk_A'_not0 m_le_n d_xs all_less_m D0]) qed from this obtain Q where inv_Q: "invertible_mat Q" and Q: "Q \ carrier_mat (m + n) (m + n)" and reduce_QM: "reduce_below 0 (xs @ [m]) D M = Q * M" by blast have "\R. invertible_mat R \ R \ carrier_mat (dim_row A') (dim_row A') \ M = R * A'" by (unfold M_def, rule make_first_column_positive_invertible) from this obtain R where inv_R: "invertible_mat R" and R: "R \ carrier_mat (dim_row A') (dim_row A')" and M_RA': "M = R * A'" by blast have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ A' = P * A" by (rule A'_swaprows_invertible_mat[OF A A'_def non_zero_positions_def], insert non_zero_positions_xs_m n m0, auto) from this obtain S where inv_S: "invertible_mat S" and S: "S \ carrier_mat (dim_row A) (dim_row A)" and A'_SA: "A' = S * A" using A by auto have "(P'*Q*R*S) \ carrier_mat (m+n) (m+n)" using P' Q R S A' A by auto moreover have "FindPreHNF abs_flag D A = (P'*Q*R*S) * A" using Find_P'_reduceM reduce_QM unfolding M_RA' A'_SA M_def - by (smt A' A'_SA P' Q R S assoc_mult_mat carrier_matD carrier_mat_triv index_mult_mat(2,3) + by (smt (verit) A' A'_SA P' Q R S assoc_mult_mat carrier_matD carrier_mat_triv index_mult_mat(2,3) non_zero_positions_xs_m) moreover have "invertible_mat (P'*Q*R*S)" using inv_P' inv_Q inv_R inv_S using P' Q R S A' A by (metis carrier_matD carrier_mat_triv index_mult_mat(2,3) invertible_mult_JNF) ultimately have exists_inv: "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ FindPreHNF abs_flag D A = P * A" by blast moreover have "echelon_form_JNF (FindPreHNF abs_flag D A)" proof (rule echelon_form_four_block_mat[OF A'_UL A'_UR sub_PreHNF' ]) show "FindPreHNF abs_flag D A = four_block_mat A'_UL A'_UR (0\<^sub>m (m + n - 1) 1) sub_PreHNF" using A'_DL0 FindPreHNF_as_fbm sub_PreHNF sub_PreHNF' by auto have "A'_UL $$ (0, 0) = ?R $$ (0,0)" by (metis (mono_tags, lifting) A A'_DR A'_UL Find_P'_reduceM M_def \FindPreHNF abs_flag D A = P' * Q * R * S * A\ add_Suc_right add_sign_intros(2) carrier_matD fbm_R index_mat_four_block(1,3) index_mult_mat(3) m0 n0 plus_1_eq_Suc zero_less_one_class.zero_less_one) also have "... \ 0" proof (cases "xs=[]") case True have "?R $$ (0,0) = reduce 0 m D M $$ (0,0)" unfolding non_zero_positions_xs_m True M_def by simp also have "... \ 0" by (metis D_not0 M M_def add_pos_pos less_add_same_cancel1 m0 mk_A'_not0 n0 reduce_not0) finally show ?thesis . next case False show ?thesis by (unfold non_zero_positions_xs_m, rule reduce_below_not0_case_m[OF M' m0 n0 M_M'D[OF False] mk_A'_not0 m_le_n all_less_m D_not0]) qed finally show "A'_UL $$ (0, 0) \ 0" . qed (insert mn n hyp, auto) ultimately show ?thesis by blast qed qed lemma assumes A_def: "A = A'' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A'': "A'' \ carrier_mat m n" and "n\2" and m_le_n: "m\n" and "D>0" shows FindPreHNF_invertible_mat_n_ge2: "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ FindPreHNF abs_flag D A = P * A" and FindPreHNF_echelon_form_n_ge2: "echelon_form_JNF (FindPreHNF abs_flag D A)" using FindPreHNF_works_n_ge2[OF assms] by blast+ lemma FindPreHNF_invertible_mat: assumes A_def: "A = A'' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A'': "A'' \ carrier_mat m n" and n0: "0n" and D: "D>0" shows "\P. P \ carrier_mat (m+n) (m+n) \ invertible_mat P \ FindPreHNF abs_flag D A = P * A" proof - have A: "A \ carrier_mat (m+n) n" using A_def A'' by auto show ?thesis proof (cases "m+n<2") case True show ?thesis by (rule FindPreHNF_invertible_mat_2xn[OF A True]) next case False note m_ge2 = False show ?thesis proof (cases "n<2") case True show ?thesis by (rule FindPreHNF_invertible_mat_mx2[OF A_def A'' True n0 D mn]) next case False show ?thesis by (rule FindPreHNF_invertible_mat_n_ge2[OF A_def A'' _ mn D], insert False, auto) qed qed qed lemma FindPreHNF_echelon_form: assumes A_def: "A = A'' @\<^sub>r D \\<^sub>m 1\<^sub>m n" and A'': "A'' \ carrier_mat m n" and mn: "m\n" and D: "D>0" shows "echelon_form_JNF (FindPreHNF abs_flag D A)" proof - have A: "A \ carrier_mat (m+n) n" using A_def A'' by auto have FindPreHNF: "(FindPreHNF abs_flag D A) \ carrier_mat (m+n) n" by (rule FindPreHNF[OF A]) show ?thesis proof (cases "m+n<2") case True show ?thesis by (rule echelon_form_JNF_1xn[OF FindPreHNF True]) next case False note m_ge2 = False show ?thesis proof (cases "n<2") case True show ?thesis by (rule FindPreHNF_echelon_form_mx1[OF A_def A'' True D mn]) next case False show ?thesis by (rule FindPreHNF_echelon_form_n_ge2[OF A_def A'' _ mn D], insert False, auto) qed qed qed end text \We connect the algorithm developed in the Hermite AFP entry with ours. This would permit to reuse many existing results and prove easily the soundness.\ (*In HOL Analysis*) thm Hermite.Hermite_reduce_above.simps thm Hermite.Hermite_of_row_i_def thm Hermite.Hermite_of_upt_row_i_def thm Hermite.Hermite_of_def (*In JNF*) thm Hermite_reduce_above.simps thm Hermite_of_row_i_def thm Hermite_of_list_of_rows.simps thm mod_operation.Hermite_mod_det_def (*Connecting Hermite.Hermite_reduce_above and Hermite_reduce_above*) thm Hermite.Hermite_reduce_above.simps Hermite_reduce_above.simps context includes lifting_syntax begin definition "res_int = (\b n::int. n mod b)" lemma res_function_res_int: "res_function res_int" using res_function_euclidean2 unfolding res_int_def by auto lemma HMA_Hermite_reduce_above[transfer_rule]: assumes "n int ^ 'n :: mod_type ^ 'm :: mod_type \ _) ===> (Mod_Type_Connect.HMA_I) ===> (Mod_Type_Connect.HMA_I) ===> (Mod_Type_Connect.HMA_M)) (\A i j. Hermite_reduce_above A n i j) (\A i j. Hermite.Hermite_reduce_above A n i j res_int)" proof (intro rel_funI, goal_cases) case (1 A A' i i' j j') then show ?case using assms proof (induct n arbitrary: A A') case 0 then show ?case by auto next case (Suc n) note AA'[transfer_rule] = "Suc.prems"(1) note ii'[transfer_rule] = "Suc.prems"(2) note jj'[transfer_rule] = "Suc.prems"(3) note Suc_n_less_m = "Suc.prems"(4) let ?H_JNF = "HNF_Mod_Det_Algorithm.Hermite_reduce_above" let ?H_HMA = "Hermite.Hermite_reduce_above" let ?from_nat_rows = "mod_type_class.from_nat :: _ \ 'm" have nn[transfer_rule]: "Mod_Type_Connect.HMA_I n (?from_nat_rows n)" unfolding Mod_Type_Connect.HMA_I_def by (simp add: Suc_lessD Suc_n_less_m mod_type_class.from_nat_to_nat) have Anj: "A' $h (?from_nat_rows n) $h j' = A $$ (n,j)" by (unfold index_hma_def[symmetric], transfer, simp) have Aij: "A' $h i' $h j' = A $$ (i,j)" by (unfold index_hma_def[symmetric], transfer, simp) let ?s = "(- (A $$ (n, j) div A $$ (i, j)))" let ?s' = "((res_int (A' $h i' $h j') (A' $h ?from_nat_rows n $h j') - A' $h ?from_nat_rows n $h j') div A' $h i' $h j')" have ss'[transfer_rule]: "?s = ?s'" unfolding res_int_def Anj Aij by (metis (no_types, opaque_lifting) Groups.add_ac(2) add_diff_cancel_left' div_by_0 minus_div_mult_eq_mod more_arith_simps(7) nat_arith.rule0 nonzero_mult_div_cancel_right uminus_add_conv_diff) have H_JNF_eq: "?H_JNF A (Suc n) i j = ?H_JNF (addrow (- (A $$ (n, j) div A $$ (i, j))) n i A) n i j" by auto have H_HMA_eq: "?H_HMA A' (Suc n) i' j' res_int = ?H_HMA (row_add A' (?from_nat_rows n) i' ?s') n i' j' res_int" by (auto simp add: Let_def) have "Mod_Type_Connect.HMA_M (?H_JNF (addrow ?s n i A) n i j) (?H_HMA (row_add A' (?from_nat_rows n) i' ?s') n i' j' res_int)" by (rule "Suc.hyps"[OF _ ii' jj'], transfer_prover, insert Suc_n_less_m, simp) thus ?case using H_JNF_eq H_HMA_eq by auto qed qed corollary HMA_Hermite_reduce_above': assumes "n is_zero_row_JNF i A" using False by transfer hence "find_fst_non0_in_row i A \ None" using find_fst_non0_in_row_None[OF _ upt_A i] by auto from this obtain j where j: "find_fst_non0_in_row i A = Some j" by blast have j_eq: "j = (LEAST n. A $$ (i,n) \ 0)" by (rule find_fst_non0_in_row_LEAST[OF _ upt_A j i], auto) have H_JNF_rw: "(Hermite_of_row_i A i) = (if A $$ (i, j) < 0 then Hermite_reduce_above (multrow i (- 1) A) i i j else Hermite_reduce_above A i i j)" unfolding Hermite_of_row_i_def using j by auto let ?H_HMA = "Hermite.Hermite_of_row_i" let ?j' = "(LEAST n. A' $h i' $h n \ 0)" have ii'2: "(mod_type_class.to_nat i') = i" using ii' by (simp add: Mod_Type_Connect.HMA_I_def) have jj'[transfer_rule]: "Mod_Type_Connect.HMA_I j ?j'" unfolding j_eq index_hma_def[symmetric] by (rule HMA_LEAST[OF AA' ii' nz_iA]) have Aij: "A $$ (i, j) = A' $h i' $h (LEAST n. A' $h i' $h n \ 0)" by (subst index_hma_def[symmetric], transfer', simp) have H_HMA_rw: "?H_HMA ass_function_euclidean res_int A' i' = Hermite.Hermite_reduce_above (mult_row A' i' (\A' $h i' $h ?j'\ div A' $h i' $h ?j')) (mod_type_class.to_nat i') i' ?j' res_int" unfolding Hermite.Hermite_of_row_i_def Let_def ass_function_euclidean_def by (auto simp add: False) have im: "i < CARD('m)" using ii' unfolding Mod_Type_Connect.HMA_I_def using mod_type_class.to_nat_less_card by blast show ?thesis proof (cases "A $$ (i, j) < 0") case True have A'i'j'_le_0: "A' $h i' $h ?j' < 0" using Aij True by auto hence 1: "(\A' $h i' $h ?j'\ div A' $h i' $h ?j') = -1" using div_pos_neg_trivial by auto have [transfer_rule]: "Mod_Type_Connect.HMA_M (multrow i (- 1) A) (mult_row A' i' (\A' $h i' $h ?j'\ div A' $h i' $h ?j'))" unfolding 1 by transfer_prover have H_HMA_rw2: "Hermite_of_row_i A i = Hermite_reduce_above (multrow i (- 1) A) i i j" using True H_JNF_rw by auto have *: "Mod_Type_Connect.HMA_M (Hermite_reduce_above (multrow i (- 1) A) i i j) (Hermite.Hermite_reduce_above (mult_row A' i' (\A' $h i' $h ?j'\ div A' $h i' $h ?j')) (mod_type_class.to_nat i') i' ?j' res_int) " unfolding 1 ii'2 by (rule HMA_Hermite_reduce_above'[OF im _ ii' jj'], transfer_prover) show ?thesis unfolding H_JNF_rw H_HMA_rw unfolding H_HMA_rw2 using True * by auto next case False have Aij_not0: "A $$ (i, j) \ 0" using j_eq nz_iA by (metis (mono_tags) LeastI is_zero_row_JNF_def) have A'i'j'_le_0: "A' $h i' $h ?j' > 0" using False Aij_not0 Aij by auto hence 1: "(\A' $h i' $h ?j'\ div A' $h i' $h ?j') = 1" by auto have H_HMA_rw2: "Hermite_of_row_i A i = Hermite_reduce_above A i i j" using False H_JNF_rw by auto have *: "?H_HMA ass_function_euclidean res_int A' i' = (Hermite.Hermite_reduce_above A' (mod_type_class.to_nat i') i' ?j' res_int)" using H_HMA_rw unfolding 1 unfolding mult_row_1_id by simp have "Mod_Type_Connect.HMA_M (Hermite_reduce_above A i i j) (Hermite.Hermite_reduce_above A' (mod_type_class.to_nat i') i' ?j' res_int)" unfolding 1 ii'2 by (rule HMA_Hermite_reduce_above'[OF im AA' ii' jj']) then show ?thesis using H_HMA_rw * H_HMA_rw2 by presburger qed qed qed lemma Hermite_of_list_of_rows_append: "Hermite_of_list_of_rows A (xs @ [x]) = Hermite_of_row_i (Hermite_of_list_of_rows A xs) x" by (induct xs arbitrary: A, auto) lemma Hermite_reduce_above[simp]: "Hermite_reduce_above A n i j \ carrier_mat (dim_row A) (dim_col A)" proof (induct n arbitrary: A) case 0 then show ?case by auto next case (Suc n) let ?A = "(addrow (- (A $$ (n, j) div A $$ (i, j))) n i A)" have "Hermite_reduce_above A (Suc n) i j = Hermite_reduce_above ?A n i j" by (auto simp add: Let_def) also have "... \ carrier_mat (dim_row ?A) (dim_col ?A)" by(rule Suc.hyps) finally show ?case by auto qed lemma Hermite_of_row_i: "Hermite_of_row_i A i \ carrier_mat (dim_row A) (dim_col A)" proof - have "Hermite_reduce_above (multrow i (- 1) A) i i a \ carrier_mat (dim_row (multrow i (- 1) A)) (dim_col (multrow i (- 1) A))" for a by (rule Hermite_reduce_above) thus ?thesis unfolding Hermite_of_row_i_def using Hermite_reduce_above by (cases "find_fst_non0_in_row i A", auto) qed end text \We now move more lemmas from HOL Analysis (with mod-type restrictions) to the JNF matrix representation.\ (*thm echelon_form_Hermite_of_row will be transferred from HOL Analysis to JNF*) context begin private lemma echelon_form_Hermite_of_row_mod_type: fixes A::"int mat" assumes "A \ carrier_mat CARD('m::mod_type) CARD('n::mod_type)" assumes eA: "echelon_form_JNF A" and i: "im A :: int ^'n :: mod_type ^'m :: mod_type)" define i' where "i' = (Mod_Type.from_nat i :: 'm)" have AA'[transfer_rule]: "Mod_Type_Connect.HMA_M A A'" unfolding Mod_Type_Connect.HMA_M_def using assms A'_def by auto have ii'[transfer_rule]: "Mod_Type_Connect.HMA_I i i'" unfolding Mod_Type_Connect.HMA_I_def i'_def using assms using from_nat_not_eq order.strict_trans by blast have eA'[transfer_rule]: "echelon_form A'" using eA by transfer have [transfer_rule]: "Mod_Type_Connect.HMA_M (HNF_Mod_Det_Algorithm.Hermite_of_row_i A i) (Hermite.Hermite_of_row_i ass_function_euclidean res_int A' i')" by (rule HMA_Hermite_of_row_i[OF uA AA' ii']) have "echelon_form (Hermite.Hermite_of_row_i ass_function_euclidean res_int A' i')" by (rule echelon_form_Hermite_of_row[OF ass_function_euclidean res_function_res_int eA']) thus ?thesis by (transfer, simp) qed private lemma echelon_form_Hermite_of_row_nontriv_mod_ring: fixes A::"int mat" assumes "A \ carrier_mat CARD('m::nontriv mod_ring) CARD('n::nontriv mod_ring)" assumes eA: "echelon_form_JNF A" and "i(Rep :: ('b \ int)) Abs. type_definition Rep Abs {0..(Rep :: ('c \ int)) Abs. type_definition Rep Abs {0..1" and n: "n>1" begin lemma echelon_form_Hermite_of_row_nontriv_mod_ring_aux: fixes A::"int mat" assumes "A \ carrier_mat m n" assumes eA: "echelon_form_JNF A" and "iRep Abs. type_definition Rep Abs {0.. 1 < m \ 1 < n \ A \ carrier_mat m n \ echelon_form_JNF A \ i < m \ echelon_form_JNF (HNF_Mod_Det_Algorithm.Hermite_of_row_i A i)" using echelon_form_Hermite_of_row_nontriv_mod_ring_aux[cancel_type_definition, of m n A i] by auto (*Canceling the second*) private lemma echelon_form_Hermite_of_row_i_cancelled_both: "1 < m \ 1 < n \ A \ carrier_mat m n \ echelon_form_JNF A \ i < m \ echelon_form_JNF (HNF_Mod_Det_Algorithm.Hermite_of_row_i A i)" using echelon_form_Hermite_of_row_i_cancelled_first[cancel_type_definition, of n m A i] by simp (*The final results in JNF*) lemma echelon_form_JNF_Hermite_of_row_i': fixes A::"int mat" assumes "A \ carrier_mat m n" assumes eA: "echelon_form_JNF A" and "i {0,1}" by auto show ?thesis proof (cases "dim_col A = 0") case True have H: "Hermite_of_row_i A i \ carrier_mat (dim_row A) (dim_col A)" using Hermite_of_row_i by blast show ?thesis by (rule echelon_form_mx0, insert True H, auto) next case False hence dc_1: "dim_col A = 1" using dc_01 by simp then show ?thesis proof (cases "i=0") case True have eA': "echelon_form_JNF (multrow 0 (- 1) A)" by (rule echelon_form_JNF_multrow[OF _ _ eA], insert m_ge2, auto) show ?thesis using True unfolding Hermite_of_row_i_def by (cases "find_fst_non0_in_row 0 A", insert eA eA', auto) next case False have all_zero: "(\j\{i.. carrier_mat (dim_row A) (dim_col A)" proof (induct xs arbitrary: A rule: rev_induct) case Nil then show ?case by auto next case (snoc x xs) let ?A = "(Hermite_of_list_of_rows A xs)" have hyp: "(Hermite_of_list_of_rows A xs) \ carrier_mat (dim_row A) (dim_col A)" by (rule snoc.hyps) have "Hermite_of_list_of_rows A (xs @ [x]) = Hermite_of_row_i ?A x" using Hermite_of_list_of_rows_append by auto also have "... \ carrier_mat (dim_row ?A) (dim_col ?A)" using Hermite_of_row_i by auto finally show ?case using hyp by auto qed lemma echelon_form_JNF_Hermite_of_list_of_rows: assumes "A\carrier_mat m n" and "\x\set xs. x < m" and "echelon_form_JNF A" shows "echelon_form_JNF (Hermite_of_list_of_rows A xs)" using assms proof (induct xs arbitrary: A rule: rev_induct) case Nil then show ?case by auto next case (snoc x xs) have hyp: "echelon_form_JNF (Hermite_of_list_of_rows A xs)" by (rule snoc.hyps, insert snoc.prems, auto) have H_Axs: "(Hermite_of_list_of_rows A xs) \ carrier_mat (dim_row A) (dim_col A)" by (rule Hermite_of_list_of_rows) have "(Hermite_of_list_of_rows A (xs @ [x])) = Hermite_of_row_i (Hermite_of_list_of_rows A xs) x" using Hermite_of_list_of_rows_append by simp also have "echelon_form_JNF ..." proof (rule echelon_form_JNF_Hermite_of_row_i[OF hyp]) show "x < dim_row (Hermite_of_list_of_rows A xs)" using snoc.prems H_Axs by auto qed finally show ?case . qed lemma HMA_Hermite_of_upt_row_i[transfer_rule]: assumes "xs = [0..x\set xs. x < CARD('m)" assumes "Mod_Type_Connect.HMA_M A (A':: int ^ 'n :: mod_type ^ 'm :: mod_type)" and "echelon_form_JNF A" shows "Mod_Type_Connect.HMA_M (Hermite_of_list_of_rows A xs) (Hermite.Hermite_of_upt_row_i A' i ass_function_euclidean res_int)" using assms proof (induct xs arbitrary: A A' i rule: rev_induct) case Nil have "i=0" using Nil by (metis le_0_eq upt_eq_Nil_conv) then show ?case using Nil unfolding Hermite_of_upt_row_i_def by auto next case (snoc x xs) note xs_x_eq = snoc.prems(1) note all_xm = snoc.prems(2) note AA' = snoc.prems(3) note upt_A = snoc.prems(4) let ?x' = "(mod_type_class.from_nat x::'m)" have xm: "x < CARD('m)" using all_xm by auto have xx'[transfer_rule]: "Mod_Type_Connect.HMA_I x ?x'" unfolding Mod_Type_Connect.HMA_I_def using from_nat_not_eq xm by blast have last_i1: "last [0..carrier_mat (CARD('m)) (CARD('n))" using Mod_Type_Connect.dim_col_transfer_rule Mod_Type_Connect.dim_row_transfer_rule snoc(4) by blast show "\x\set xs. x < CARD('m)" using all_xm by auto qed show ?case unfolding 1 2 by (rule HMA_Hermite_of_row_i[OF upt_H_Axs hyp xx']) qed (*This is the lemma that I will transfer to JNF to get the soundness*) lemma Hermite_Hermite_of_upt_row_i: assumes a: "ass_function ass" and r: "res_function res" and eA: "echelon_form A" shows "Hermite (range ass) (\c. range (res c)) (Hermite_of_upt_row_i A (nrows A) ass res)" proof - let ?H = "(Hermite_of_upt_row_i A (nrows A) ass res)" show ?thesis proof (rule Hermite_intro, auto) show "Complete_set_non_associates (range ass)" by (simp add: ass_function_Complete_set_non_associates a) show "Complete_set_residues (\c. range (res c))" by (simp add: r res_function_Complete_set_residues) show "echelon_form ?H" by (rule echelon_form_Hermite_of_upt_row_i[OF eA a r]) fix i assume i: "\ is_zero_row i ?H" show "?H $ i $ (LEAST n. ?H $ i $ n \ 0) \ range ass" proof - have non_zero_i_eA: "\ is_zero_row i A" using Hermite_of_upt_row_preserves_zero_rows[OF _ _ a r] i eA by blast have least: "(LEAST n. ?H $h i $h n \ 0) = (LEAST n. A $h i $h n \ 0)" by (rule Hermite_of_upt_row_i_Least[OF non_zero_i_eA eA a r], simp) have "?H $ i $ (LEAST n. A $ i $ n \ 0) \ range ass" by (rule Hermite_of_upt_row_i_in_range[OF non_zero_i_eA eA a r], auto) thus ?thesis unfolding least by auto qed next fix i j assume i: "\ is_zero_row i ?H" and j: "j < i" show "?H $ j $ (LEAST n. ?H $ i $ n \ 0) \ range (res (?H $ i $ (LEAST n. ?H $ i $ n \ 0)))" proof - have non_zero_i_eA: "\ is_zero_row i A" using Hermite_of_upt_row_preserves_zero_rows[OF _ _ a r] i eA by blast have least: "(LEAST n. ?H $h i $h n \ 0) = (LEAST n. A $h i $h n \ 0)" by (rule Hermite_of_upt_row_i_Least[OF non_zero_i_eA eA a r], simp) have "?H $ j $ (LEAST n. A $ i $ n \ 0) \ range (res (?H $ i $ (LEAST n. A $ i $ n \ 0)))" by (rule Hermite_of_upt_row_i_in_range_res[OF non_zero_i_eA eA a r _ _ j], auto) thus ?thesis unfolding least by auto qed qed qed lemma Hermite_of_row_i_0: "Hermite_of_row_i A 0 = A \ Hermite_of_row_i A 0 = multrow 0 (- 1) A" by (cases "find_fst_non0_in_row 0 A", unfold Hermite_of_row_i_def, auto) lemma Hermite_JNF_intro: assumes "Complete_set_non_associates associates" "(Complete_set_residues res)" "echelon_form_JNF A" "(\i is_zero_row_JNF i A \ A $$ (i, LEAST n. A $$ (i, n) \ 0) \ associates)" "(\i is_zero_row_JNF i A \ (\j. j A $$ (j, (LEAST n. A $$ (i, n) \ 0)) \ res (A $$ (i,(LEAST n. A $$ (i,n) \ 0)))))" shows "Hermite_JNF associates res A" using assms unfolding Hermite_JNF_def by auto lemma least_multrow: assumes "A \ carrier_mat m n" and "i is_zero_row_JNF ia (multrow i (- 1) A)" shows "(LEAST n. multrow i (- 1) A $$ (ia, n) \ 0) = (LEAST n. A $$ (ia, n) \ 0)" proof (rule Least_equality) have nz_ia_A: "\ is_zero_row_JNF ia A" using nz_ia_mrA ia by auto have Least_Aian_n: "(LEAST n. A $$ (ia, n) \ 0) < dim_col A" - by (smt dual_order.strict_trans is_zero_row_JNF_def not_less_Least not_less_iff_gr_or_eq nz_ia_A) + by (smt (verit) dual_order.strict_trans is_zero_row_JNF_def not_less_Least not_less_iff_gr_or_eq nz_ia_A) show "multrow i (- 1) A $$ (ia, LEAST n. A $$ (ia, n) \ 0) \ 0" - by (smt LeastI Least_Aian_n class_cring.cring_simprules(22) equation_minus_iff ia + by (smt (verit) LeastI Least_Aian_n class_cring.cring_simprules(22) equation_minus_iff ia index_mat_multrow(1) is_zero_row_JNF_def mult_minus1 nz_ia_A) show " \y. multrow i (- 1) A $$ (ia, y) \ 0 \ (LEAST n. A $$ (ia, n) \ 0) \ y" by (metis (mono_tags, lifting) Least_Aian_n class_cring.cring_simprules(22) ia index_mat_multrow(1) leI mult_minus1 order.strict_trans wellorder_Least_lemma(2)) qed lemma Hermite_Hermite_of_row_i: assumes A: "A \ carrier_mat 1 n" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_row_i A 0)" proof (rule Hermite_JNF_intro) show "Complete_set_non_associates (range ass_function_euclidean)" using ass_function_Complete_set_non_associates ass_function_euclidean by blast show "Complete_set_residues (\c. range (res_int c))" using res_function_Complete_set_residues res_function_res_int by blast show "echelon_form_JNF (HNF_Mod_Det_Algorithm.Hermite_of_row_i A 0)" by (metis (full_types) assms carrier_matD(1) echelon_form_JNF_Hermite_of_row_i echelon_form_JNF_def less_one not_less_zero) let ?H = "Hermite_of_row_i A 0" show "\i is_zero_row_JNF i ?H \ ?H $$ (i, LEAST n. ?H $$ (i, n) \ 0) \ range ass_function_euclidean" proof (auto) fix i assume i: "i is_zero_row_JNF i ?H" have nz_iA: "\ is_zero_row_JNF i A" by (metis (full_types) Hermite_of_row_i Hermite_of_row_i_0 carrier_matD(1) i is_zero_row_JNF_multrow nz_iH) have "?H $$ (i, LEAST n. ?H $$ (i, n) \ 0) \ 0" proof (cases "find_fst_non0_in_row 0 A") case None then show ?thesis using nz_iH unfolding Hermite_of_row_i_def - by (smt HNF_Mod_Det_Algorithm.Hermite_of_row_i_def upper_triangular'_def assms + by (smt (verit) HNF_Mod_Det_Algorithm.Hermite_of_row_i_def upper_triangular'_def assms carrier_matD(1) find_fst_non0_in_row_None i less_one not_less_zero option.simps(4)) next case (Some a) have upA: "upper_triangular' A" using A unfolding upper_triangular'_def by auto have eA: "echelon_form_JNF A" by (metis A Suc_1 echelon_form_JNF_1xn lessI) have i0: "i=0" using Hermite_of_row_i[of A 0] A i by auto have Aia: "A $$ (i,a) \ 0" and a0: "0 \ a" and an: "a 0) = (LEAST n. multrow 0 (- 1) A $$ (i, n) \ 0)" by (rule least_multrow[symmetric, OF A _ eA _], insert nz_iA i A i0, auto) have a1: "a = (LEAST n. A $$ (i, n) \ 0)" by (rule find_fst_non0_in_row_LEAST[OF A upA], insert Some i0, auto) hence a2: "a = (LEAST n. multrow 0 (- 1) A $$ (i, n) \ 0)" unfolding l by simp have m1: "multrow 0 (- 1) A $$ (i, LEAST n. multrow 0 (- 1) A $$ (i, n) \ 0) = (- 1) * A $$ (i, LEAST n. A $$ (i, n) \ 0)" by (metis Hermite_of_row_i_0 a1 a2 an assms carrier_matD(2) i i0 index_mat_multrow(1,4)) then show ?thesis using nz_iH Some a1 Aia a2 i0 unfolding Hermite_of_row_i_def by auto qed thus "?H $$ (i, LEAST n. ?H $$ (i, n) \ 0) \ range ass_function_euclidean" using ass_function_int ass_function_int_UNIV by auto qed show "\i is_zero_row_JNF i ?H \ (\j 0) \ range (res_int (?H $$ (i, LEAST n. ?H $$ (i, n) \ 0))))" using Hermite_of_row_i[of A 0] A by auto qed lemma Hermite_of_row_i_0_eq_0: assumes A: "A\carrier_mat m n" and i: "i>0" and eA: "echelon_form_JNF A" and im: "i 0" and a0: "0 \ a" and an: "a carrier_mat m 1" and eA: "echelon_form_JNF A" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_row_i A 0)" proof (rule Hermite_JNF_intro) show "Complete_set_non_associates (range ass_function_euclidean)" using ass_function_Complete_set_non_associates ass_function_euclidean by blast show "Complete_set_residues (\c. range (res_int c))" using res_function_Complete_set_residues res_function_res_int by blast have H: "Hermite_of_row_i A 0 : carrier_mat m 1" using A Hermite_of_row_i[of A] by auto have upA: "upper_triangular' A" by (simp add: eA echelon_form_JNF_imp_upper_triangular) show eH: "echelon_form_JNF (Hermite_of_row_i A 0)" proof (rule echelon_form_JNF_mx1[OF H]) show "\i\{1..i is_zero_row_JNF i ?H \ ?H $$ (i, LEAST n. ?H $$ (i, n) \ 0) \ range ass_function_euclidean" proof (auto) fix i assume i: "i is_zero_row_JNF i ?H" have nz_iA: "\ is_zero_row_JNF i A" by (metis (full_types) Hermite_of_row_i Hermite_of_row_i_0 carrier_matD(1) i is_zero_row_JNF_multrow nz_iH) have "?H $$ (i, LEAST n. ?H $$ (i, n) \ 0) \ 0" proof (cases "find_fst_non0_in_row 0 A") case None have "is_zero_row_JNF i A" by (metis H upper_triangular'_def None assms(1) carrier_matD find_fst_non0_in_row_None i is_zero_row_JNF_def less_one linorder_neqE_nat not_less0 upA) then show ?thesis using nz_iH None unfolding Hermite_of_row_i_def by auto next case (Some a) have Aia: "A $$ (0,a) \ 0" and a0: "0 \ a" and an: "a<1" using find_fst_non0_in_row[OF A Some] A by auto have nz_j_mA: "is_zero_row_JNF j (multrow 0 (- 1) A)" if j0: "j>0" and jm: "j 0) \ range ass_function_euclidean" using ass_function_int ass_function_int_UNIV by auto qed show "\i is_zero_row_JNF i ?H \ (\j 0) \ range (res_int (?H $$ (i, LEAST n. ?H $$ (i, n) \ 0))))" proof auto fix i j assume i: "i is_zero_row_JNF i ?H" and ji: "j 0) \ range (res_int (?H $$ (i, LEAST n. ?H $$ (i, n) \ 0)))" using ji by auto qed qed lemma Hermite_of_list_of_rows_1xn: assumes A: "A \ carrier_mat 1 n" and eA: "echelon_form_JNF A" and x: "\x \ set xs. x < 1" and xs: "xs\[]" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A xs)" using x xs proof (induct xs rule: rev_induct) case Nil then show ?case by auto next case (snoc x xs) have x0: "x=0" using snoc.prems by auto show ?case proof (cases "xs = []") case True have "Hermite_of_list_of_rows A (xs @ [x]) = Hermite_of_row_i A 0" unfolding Hermite_of_list_of_rows_append x0 using True by auto then show ?thesis using Hermite_Hermite_of_row_i[OF A] by auto next case False have x0: "x=0" using snoc.prems by auto have hyp: "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A xs)" by (rule snoc.hyps, insert snoc.prems False, auto) have "Hermite_of_list_of_rows A (xs @ [x]) = Hermite_of_row_i (Hermite_of_list_of_rows A xs) 0" unfolding Hermite_of_list_of_rows_append hyp x0 .. thus ?thesis by (metis A Hermite_Hermite_of_row_i Hermite_of_list_of_rows carrier_matD(1)) qed qed lemma Hermite_of_row_i_id_mx1: assumes H': "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) A" and x: "xcarrier_mat m 1" shows "Hermite_of_row_i A x = A" proof (cases "find_fst_non0_in_row x A") case None then show ?thesis unfolding Hermite_of_row_i_def by auto next case (Some a) have eH: "echelon_form_JNF A" using H' unfolding Hermite_JNF_def by simp have ut_A: "upper_triangular' A" by (simp add: eH echelon_form_JNF_imp_upper_triangular) have a_least: "a = (LEAST n. A $$ (x,n) \ 0)" by (rule find_fst_non0_in_row_LEAST[OF _ ut_A Some], insert x, auto) have Axa: "A $$ (x, a) \ 0" and xa: "x\a" and a: "a is_zero_row_JNF x A" using Axa xa x a unfolding is_zero_row_JNF_def by blast have a0: "a = 0" using a A by auto have x0: "x=0" using echelon_form_JNF_first_column_0[OF eH A] Axa a0 xa by blast have "A $$ (x, a) \ (range ass_function_euclidean)" using nz_xA H' x unfolding a_least unfolding Hermite_JNF_def by auto hence "A $$ (x, a) > 0" using Axa unfolding image_def ass_function_euclidean_def by auto then show ?thesis unfolding Hermite_of_row_i_def using Some x0 by auto qed lemma Hermite_of_row_i_id_mx1': assumes eA: "echelon_form_JNF A" and x: "xcarrier_mat m 1" shows "Hermite_of_row_i A x = A \ Hermite_of_row_i A x = multrow 0 (- 1) A" proof (cases "find_fst_non0_in_row x A") case None then show ?thesis unfolding Hermite_of_row_i_def by auto next case (Some a) have ut_A: "upper_triangular' A" by (simp add: eA echelon_form_JNF_imp_upper_triangular) have a_least: "a = (LEAST n. A $$ (x,n) \ 0)" by (rule find_fst_non0_in_row_LEAST[OF _ ut_A Some], insert x, auto) have Axa: "A $$ (x, a) \ 0" and xa: "x\a" and a: "a is_zero_row_JNF x A" using Axa xa x a unfolding is_zero_row_JNF_def by blast have a0: "a = 0" using a A by auto have x0: "x=0" using echelon_form_JNF_first_column_0[OF eA A] Axa a0 xa by blast show ?thesis by (cases "A $$(x,a)>0", unfold Hermite_of_row_i_def, insert Some x0, auto) qed lemma Hermite_of_list_of_rows_mx1: assumes A: "A \ carrier_mat m 1" and eA: "echelon_form_JNF A" and x: "\x \ set xs. x < m" and xs: "xs=[0..0" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A xs)" using x xs i proof (induct xs arbitrary: i rule: rev_induct) case Nil then show ?case by (metis neq0_conv not_less upt_eq_Nil_conv) next case (snoc x xs) note all_n_xs_x = snoc.prems(1) note xs_x = snoc.prems(2) note i0 = snoc.prems(3) have i_list_rw:"[0.. carrier_mat m 1" using A Hermite_of_list_of_rows[of A xs] by auto show ?case proof (cases "i-1=0") case True hence xs_empty: "xs = []" using xs by auto have *: "Hermite_of_list_of_rows A (xs @ [x]) = Hermite_of_row_i A 0" unfolding Hermite_of_list_of_rows_append xs_empty x True by simp show ?thesis unfolding * by (rule Hermite_Hermite_of_row_i_mx1[OF A eA]) next case False have hyp: "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A xs)" by (rule snoc.hyps[OF _ xs], insert False all_n_xs_x, auto) have "Hermite_of_list_of_rows A (xs @ [x]) = Hermite_of_row_i (Hermite_of_list_of_rows A xs) x" unfolding Hermite_of_list_of_rows_append .. also have "... = (Hermite_of_list_of_rows A xs)" by (rule Hermite_of_row_i_id_mx1[OF hyp _ H], insert snoc.prems H x, auto) finally show ?thesis using hyp by auto qed qed lemma invertible_Hermite_of_list_of_rows_1xn: assumes "A \ carrier_mat 1 n" shows "\P. P \ carrier_mat 1 1 \ invertible_mat P \ Hermite_of_list_of_rows A [0..<1] = P * A" proof - let ?H = "Hermite_of_list_of_rows A [0..<1]" have "?H = Hermite_of_row_i A 0" by auto hence H_or: "?H = A \ ?H = multrow 0 (- 1) A" using Hermite_of_row_i_0 by simp show ?thesis proof (cases "?H = A") case True then show ?thesis by (metis assms invertible_mat_one left_mult_one_mat one_carrier_mat) next case False hence H_mr: "?H = multrow 0 (- 1) A" using H_or by simp let ?M = "multrow_mat 1 0 (-1)::int mat" show ?thesis proof (rule exI[of _ "?M"]) have "?M \ carrier_mat 1 1" by auto moreover have "invertible_mat ?M" by (metis calculation det_multrow_mat det_one dvd_mult_right invertible_iff_is_unit_JNF invertible_mat_one one_carrier_mat square_eq_1_iff zero_less_one_class.zero_less_one) moreover have "?H= ?M * A" by (metis H_mr assms multrow_mat) ultimately show "?M \ carrier_mat 1 1 \ invertible_mat (?M) \ Hermite_of_list_of_rows A [0..<1] = ?M * A" by blast qed qed qed lemma invertible_Hermite_of_list_of_rows_mx1': assumes A: "A \ carrier_mat m 1" and eA: "echelon_form_JNF A" and xs_i: "xs = [0..x\set xs. x < m" and i: "i>0" shows "\P. P \ carrier_mat m m \ invertible_mat P \ Hermite_of_list_of_rows A xs = P * A" using xs_i xs_m i proof (induct xs arbitrary: i rule: rev_induct) case Nil then show ?case by (metis diff_zero length_upt list.size(3) zero_order(3)) next case (snoc x xs) note all_n_xs_x = snoc.prems(2) note xs_x = snoc.prems(1) note i0 = snoc.prems(3) have i_list_rw:"[0.. carrier_mat m 1" using A Hermite_of_list_of_rows[of A xs] by auto show ?case proof (cases "i-1=0") case True hence xs_empty: "xs = []" using xs by auto let ?H = "Hermite_of_list_of_rows A (xs @ [x])" have *: "Hermite_of_list_of_rows A (xs @ [x]) = Hermite_of_row_i A 0" unfolding Hermite_of_list_of_rows_append xs_empty x True by simp hence H_or: "?H = A \ ?H = multrow 0 (- 1) A" using Hermite_of_row_i_0 by simp thus ?thesis proof (cases "?H=A") case True then show ?thesis unfolding * by (metis A invertible_mat_one left_mult_one_mat one_carrier_mat) next case False hence H_mr: "?H = multrow 0 (- 1) A" using H_or by simp let ?M = "multrow_mat m 0 (-1)::int mat" show ?thesis proof (rule exI[of _ "?M"]) have "?M \ carrier_mat m m" by auto moreover have "invertible_mat ?M" by (metis (full_types) det_multrow_mat dvd_mult_right invertible_iff_is_unit_JNF invertible_mat_zero more_arith_simps(10) mult_minus1_right multrow_mat_carrier neq0_conv) moreover have "?H = ?M * A" unfolding H_mr using A multrow_mat by blast ultimately show "?M \ carrier_mat m m \ invertible_mat ?M \ ?H = ?M * A" by blast qed qed next case False let ?A = "(Hermite_of_list_of_rows A xs)" have A': "?A \ carrier_mat m 1" using A Hermite_of_list_of_rows[of A xs] by simp have hyp: "\P. P \ carrier_mat m m \ invertible_mat P \ Hermite_of_list_of_rows A xs = P * A" by (rule snoc.hyps[OF xs], insert False all_n_xs_x, auto) have rw: "Hermite_of_list_of_rows A (xs @ [x]) = Hermite_of_row_i (Hermite_of_list_of_rows A xs) x" unfolding Hermite_of_list_of_rows_append .. have *: "Hermite_of_row_i ?A x = ?A \ Hermite_of_row_i ?A x = multrow 0 (- 1) ?A" proof (rule Hermite_of_row_i_id_mx1'[OF _ _ A']) show "echelon_form_JNF ?A" using A eA echelon_form_JNF_Hermite_of_list_of_rows snoc(3) by auto show "x < dim_row ?A" using A' x i A by (simp add: snoc(3)) qed show ?thesis proof (cases "Hermite_of_row_i ?A x = ?A") case True then show ?thesis by (simp add: hyp rw) next case False let ?M = "multrow_mat m 0 (-1)::int mat" obtain P where P: "P \ carrier_mat m m" and inv_P: "invertible_mat P" and H_PA: "Hermite_of_list_of_rows A xs = P * A" using hyp by auto have M: "?M \ carrier_mat m m" by auto have inv_M: "invertible_mat ?M" by (metis (full_types) det_multrow_mat dvd_mult_right invertible_iff_is_unit_JNF invertible_mat_zero more_arith_simps(10) mult_minus1_right multrow_mat_carrier neq0_conv) have H_MA': "Hermite_of_row_i ?A x = ?M * ?A" using False * H multrow_mat by metis have inv_MP: "invertible_mat (?M*P)" using M inv_M P inv_P invertible_mult_JNF by blast moreover have MP: "(?M*P) \ carrier_mat m m" using M P by fastforce moreover have "Hermite_of_list_of_rows A (xs @ [x]) = (?M*P) * A" by (metis A H_MA' H_PA M P assoc_mult_mat rw) ultimately show ?thesis by blast qed qed qed corollary invertible_Hermite_of_list_of_rows_mx1: assumes "A \ carrier_mat m 1" and eA: "echelon_form_JNF A" shows "\P. P \ carrier_mat m m \ invertible_mat P \ Hermite_of_list_of_rows A [0.. carrier_mat m 0" and xs: "xs = [0..x\ set xs. x < m" shows "Hermite_of_list_of_rows A xs = A" using xs x proof (induct xs arbitrary: i rule: rev_induct) case Nil then show ?case by auto next case (snoc x xs) note all_n_xs_x = snoc.prems(2) note xs_x = snoc.prems(1) have i0: "i>0" using neq0_conv snoc(2) by fastforce have i_list_rw:"[0.. carrier_mat m 0" using A Hermite_of_list_of_rows[of A xs] by auto define A' where "A' = (Hermite_of_list_of_rows A xs)" have A'A: "A' = A" by (unfold A'_def, rule snoc.hyps, insert snoc.prems xs, auto) have "Hermite_of_list_of_rows A (xs @ [x]) = Hermite_of_row_i A' x" using Hermite_of_list_of_rows_append A'_def by auto also have "... = A" proof (cases "find_fst_non0_in_row x A'") case None then show ?thesis unfolding Hermite_of_row_i_def using A'A by auto next case (Some a) then show ?thesis by (metis (full_types) A'A A carrier_matD(2) find_fst_non0_in_row(3) zero_order(3)) qed finally show ?case . qed text \Again, we move more lemmas from HOL Analysis (with mod-type restrictions) to the JNF matrix representation.\ (* The following lemmas will be transferred from HOL Analysis to JNF: thm Hermite_Hermite_of_upt_row_i thm invertible_Hermite_of_upt_row_i *) context begin private lemma Hermite_Hermite_of_list_of_rows_mod_type: fixes A::"int mat" assumes "A \ carrier_mat CARD('m::mod_type) CARD('n::mod_type)" assumes eA: "echelon_form_JNF A" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A [0..m A :: int ^'n :: mod_type ^'m :: mod_type)" have AA'[transfer_rule]: "Mod_Type_Connect.HMA_M A A'" unfolding Mod_Type_Connect.HMA_M_def using assms A'_def by auto have eA'[transfer_rule]: "echelon_form A'" using eA by transfer have [transfer_rule]: "Mod_Type_Connect.HMA_M (Hermite_of_list_of_rows A [0..c. range (res_int c)) = (\c. range (res_int c))" .. have n: "CARD('m) = nrows A'" using AA' unfolding nrows_def by auto have "Hermite (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_upt_row_i A' (CARD('m)) ass_function_euclidean res_int)" by (unfold n, rule Hermite_Hermite_of_upt_row_i[OF ass_function_euclidean res_function_res_int eA']) thus ?thesis by transfer qed private lemma invertible_Hermite_of_list_of_rows_mod_type: fixes A::"int mat" assumes "A \ carrier_mat CARD('m::mod_type) CARD('n::mod_type)" assumes eA: "echelon_form_JNF A" shows "\P. P \ carrier_mat CARD('m) CARD('m) \ invertible_mat P \ Hermite_of_list_of_rows A [0..m A :: int ^'n :: mod_type ^'m :: mod_type)" have AA'[transfer_rule]: "Mod_Type_Connect.HMA_M A A'" unfolding Mod_Type_Connect.HMA_M_def using assms A'_def by auto have eA'[transfer_rule]: "echelon_form A'" using eA by transfer have [transfer_rule]: "Mod_Type_Connect.HMA_M (Hermite_of_list_of_rows A [0..c. range (res_int c)) = (\c. range (res_int c))" .. have n: "CARD('m) = nrows A'" using AA' unfolding nrows_def by auto have "\P. invertible P \ Hermite_of_upt_row_i A' (CARD('m)) ass_function_euclidean res_int = P ** A'" by (rule invertible_Hermite_of_upt_row_i[OF ass_function_euclidean]) thus ?thesis by (transfer, auto) qed private lemma Hermite_Hermite_of_list_of_rows_nontriv_mod_ring: fixes A::"int mat" assumes "A \ carrier_mat CARD('m::nontriv mod_ring) CARD('n::nontriv mod_ring)" assumes eA: "echelon_form_JNF A" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A [0.. carrier_mat CARD('m::nontriv mod_ring) CARD('n::nontriv mod_ring)" assumes eA: "echelon_form_JNF A" shows "\P. P \ carrier_mat CARD('m) CARD('m) \ invertible_mat P \ Hermite_of_list_of_rows A [0..(Rep :: ('b \ int)) Abs. type_definition Rep Abs {0..(Rep :: ('c \ int)) Abs. type_definition Rep Abs {0..1" and n: "n>1" begin lemma Hermite_Hermite_of_list_of_rows_nontriv_mod_ring_aux: fixes A::"int mat" assumes "A \ carrier_mat m n" assumes eA: "echelon_form_JNF A" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A [0.. carrier_mat m n" assumes eA: "echelon_form_JNF A" shows "\P. P \ carrier_mat m m \ invertible_mat P \ Hermite_of_list_of_rows A [0..Rep Abs. type_definition Rep Abs {0.. 1 < m \ 1 < n \ A \ carrier_mat m n \ echelon_form_JNF A \ \P. P \ carrier_mat m m \ invertible_mat P \ Hermite_of_list_of_rows A [0.. 1 < n \ A \ carrier_mat m n \ echelon_form_JNF A \ \P. P \ carrier_mat m m \ invertible_mat P \ Hermite_of_list_of_rows A [0..Rep Abs. type_definition Rep Abs {0.. 1 < m \ 1 < n \ A \ carrier_mat m n \ echelon_form_JNF A \ Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A [0.. 1 < n \ A \ carrier_mat m n \ echelon_form_JNF A \ Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A [0.. carrier_mat m n" and "echelon_form_JNF A" and "1 < m" and "1 < n" (*Required from the mod_type restrictions*) shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A [0.. carrier_mat m n" and eA: "echelon_form_JNF A" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_of_list_of_rows A [0.. n=0") case True then show ?thesis by (auto, metis Hermite_Hermite_of_row_i Hermite_JNF_def A eA carrier_matD(1) one_carrier_mat zero_order(3)) (metis Hermite_Hermite_of_row_i Hermite_JNF_def Hermite_of_list_of_rows A carrier_matD(2) echelon_form_mx0 is_zero_row_JNF_def mat_carrier zero_order(3)) next case False note not_m0_or_n0 = False show ?thesis proof (cases "m=1 \ n=1") case True then show ?thesis by (metis False Hermite_of_list_of_rows_1xn Hermite_of_list_of_rows_mx1 A eA atLeastLessThan_iff linorder_not_less neq0_conv set_upt upt_eq_Nil_conv) next case False show ?thesis by (rule Hermite_Hermite_of_list_of_rows'[OF A eA], insert not_m0_or_n0 False, auto) qed qed lemma invertible_Hermite_of_list_of_rows: assumes A: "A \ carrier_mat m n" and eA: "echelon_form_JNF A" shows "\P. P \ carrier_mat m m \ invertible_mat P \ Hermite_of_list_of_rows A [0.. n=0") case True have *: "Hermite_of_list_of_rows A [0.. n=1") case True then show ?thesis using A eA invertible_Hermite_of_list_of_rows_1xn invertible_Hermite_of_list_of_rows_mx1 by blast next case False then show ?thesis using invertible_Hermite_of_list_of_rows_cancelled_both[OF _ _ A eA] False mn by auto qed qed end end end end text \Now we have all the required stuff to prove the soundness of the algorithm.\ context proper_mod_operation begin (* thm invertible_Hermite_of_list_of_rows thm Hermite_Hermite_of_list_of_rows thm LLL_with_assms.Hermite_append_det_id thm FindPreHNF_invertible_mat thm FindPreHNF_echelon_form *) lemma Hermite_mod_det_mx0: assumes "A \ carrier_mat m 0" shows "Hermite_mod_det abs_flag A = A" unfolding Hermite_mod_det_def Let_def using assms by auto lemma Hermite_JNF_mx0: assumes A: "A \ carrier_mat m 0" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) A" unfolding Hermite_JNF_def using A echelon_form_mx0 unfolding is_zero_row_JNF_def using ass_function_Complete_set_non_associates[OF ass_function_euclidean] using res_function_Complete_set_residues[OF res_function_res_int] by auto lemma Hermite_mod_det_soundness_mx0: assumes A: "A \ carrier_mat m n" and n0: "n=0" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_mod_det abs_flag A)" and "(\P. invertible_mat P \ P \ carrier_mat m m \ (Hermite_mod_det abs_flag A) = P * A)" proof - have A: "A \ carrier_mat m 0" using A n0 by blast then show "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_mod_det abs_flag A)" using Hermite_JNF_mx0[OF A] Hermite_mod_det_mx0[OF A] by auto show "(\P. invertible_mat P \ P \ carrier_mat m m \ (Hermite_mod_det abs_flag A) = P * A)" by (metis A Hermite_mod_det_mx0 invertible_mat_one left_mult_one_mat one_carrier_mat) qed lemma Hermite_mod_det_soundness_mxn: assumes mn: "m = n" and A: "A \ carrier_mat m n" and n0: "0c. range (res_int c)) (Hermite_mod_det abs_flag A)" and "(\P. invertible_mat P \ P \ carrier_mat m m \ (Hermite_mod_det abs_flag A) = P * A)" proof - define D A' E H H' where D_def: "D = \Determinant.det A\" and A'_def: "A' = A @\<^sub>r D \\<^sub>m 1\<^sub>m n" and E_def: "E = FindPreHNF abs_flag D A'" and H_def: "H = Hermite_of_list_of_rows E [0.. carrier_mat (m+n) n" using A A A'_def by auto let ?RAT = "of_int_hom.mat_hom :: int mat \ rat mat" have RAT_A: "?RAT A \ carrier_mat n n" using A map_carrier_mat mat_of_rows_carrier(1) mn by auto have det_RAT_fs_init: "det (?RAT A) \ 0" using inv_RAT_A unfolding invertible_iff_is_unit_JNF[OF RAT_A] by auto moreover have "mat_of_rows n (map (Matrix.row A') [0..\<^sub>m 1\<^sub>m n \ carrier_mat n n" using mn by auto have "?A' $$ (i,j) = (map (Matrix.row A') [0.. carrier_mat (m+n) n" unfolding E_def by (rule FindPreHNF[OF A']) have "\P. P \ carrier_mat (m + n) (m + n) \ invertible_mat P \ E = P * A'" by (unfold E_def, rule FindPreHNF_invertible_mat[OF A'_def A n0 _ _], insert mn D_def det_RAT_fs_init, auto) from this obtain P where P: "P \ carrier_mat (m + n) (m + n)" and inv_P: "invertible_mat P" and E_PA': "E = P * A'" by blast have "\Q. Q \ carrier_mat (m+n) (m+n) \ invertible_mat Q \ H = Q * E" by (unfold H_def, rule invertible_Hermite_of_list_of_rows[OF E eE]) from this obtain Q where Q: "Q \ carrier_mat (m+n) (m+n)" and inv_Q: "invertible_mat Q" and H_QE: "H = Q * E" by blast let ?ass ="(range ass_function_euclidean)" let ?res = "(\c. range (res_int c))" have Hermite_H: "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) H" by (unfold H_def, rule Hermite_Hermite_of_list_of_rows[OF E eE]) hence eH: "echelon_form_JNF H" unfolding Hermite_JNF_def by auto have H': "H' \ carrier_mat m n" using H'_def by auto have H_H'0: "H = H' @\<^sub>r 0\<^sub>m m n" proof (unfold H'_def, rule upper_triangular_append_zero) show "upper_triangular' H" using eH by (rule echelon_form_JNF_imp_upper_triangular) show "H \ carrier_mat (m + m) n" unfolding H_def using Hermite_of_list_of_rows[of E] E mn by auto qed (insert mn, simp) obtain P' where PP': "inverts_mat P P'" and P'P: "inverts_mat P' P" and P': "P' \ carrier_mat (m+n) (m+n)" using P inv_P obtain_inverse_matrix by blast obtain Q' where QQ': "inverts_mat Q Q'" and Q'Q: "inverts_mat Q' Q" and Q': "Q' \ carrier_mat (m+n) (m+n)" using Q inv_Q obtain_inverse_matrix by blast have P'Q': "(P'*Q') \ carrier_mat (m + m) (m + m)" using P' Q' mn by simp have A'_P'Q'H: "A' = P' * Q' * H" proof - have QP: "Q * P \ carrier_mat (m + m) (m + m)" using Q P mn by auto have "H = Q * (P * A')" using H_QE E_PA' by auto also have "... = (Q * P) * A'" using A' P Q by auto also have "(P' * Q') * ... = ((P' * Q') * (Q * P)) * A'" using A' P'Q' QP mn by auto also have "... = (P' * (Q' * Q) * P) * A'" - by (smt P P' P'Q' Q Q' assms(1) assoc_mult_mat) + by (smt (verit) P P' P'Q' Q Q' assms(1) assoc_mult_mat) also have "... = (P'*P) * A'" by (metis P' Q' Q'Q carrier_matD(1) inverts_mat_def right_mult_one_mat) also have "... = A'" by (metis A' P' P'P carrier_matD(1) inverts_mat_def left_mult_one_mat) finally show "A' = P' * Q' * H" .. qed have inv_P'Q': "invertible_mat (P' * Q')" by (metis P' P'P PP' Q' Q'Q QQ' carrier_matD(1) carrier_matD(2) invertible_mat_def invertible_mult_JNF square_mat.simps) interpret vec_module "TYPE(int)" . interpret B: cof_vec_space n "TYPE(rat)" . interpret A: LLL_with_assms n m "(Matrix.rows A)" "4/3" proof show "length (rows A) = m " using A unfolding Matrix.rows_def by simp have s: "set (map of_int_hom.vec_hom (rows A)) \ carrier_vec n" using A unfolding Matrix.rows_def by auto have rw: "(map of_int_hom.vec_hom (rows A)) = (rows (?RAT A))" by (metis A s carrier_matD(2) mat_of_rows_map mat_of_rows_rows rows_mat_of_rows set_rows_carrier subsetI) have "B.lin_indpt (set (map of_int_hom.vec_hom (rows A)))" unfolding rw by (rule B.det_not_0_imp_lin_indpt_rows[OF RAT_A det_RAT_fs_init]) moreover have "distinct (map of_int_hom.vec_hom (rows A)::rat Matrix.vec list)" proof (rule ccontr) assume " \ distinct (map of_int_hom.vec_hom (rows A)::rat Matrix.vec list)" from this obtain i j where "row (?RAT A) i = row (?RAT A) j" and "i \ j" and "i < n" and "j < n" unfolding rw by (metis Determinant.det_transpose RAT_A add_0 cols_transpose det_RAT_fs_init not_add_less2 transpose_carrier_mat vec_space.det_rank_iff vec_space.non_distinct_low_rank) thus False using Determinant.det_identical_rows[OF RAT_A] using det_RAT_fs_init RAT_A by auto qed ultimately show "B.lin_indpt_list (map of_int_hom.vec_hom (rows A))" using s unfolding B.lin_indpt_list_def by auto qed (simp) have A_eq: "mat_of_rows n (Matrix.rows A) = A" using A mat_of_rows_rows by blast have D_A: "D = \det (mat_of_rows n (rows A))\" using D_def A_eq by auto have Hermite_H': "Hermite_JNF ?ass ?res H'" by (rule A.Hermite_append_det_id(1)[OF _ mn _ H' H_H'0 P'Q' inv_P'Q' A'_P'Q'H Hermite_H], insert D_def A'_def mn A inv_RAT_A D_A A_eq, auto) have dc: "dim_row A = m" and dr: "dim_col A = n" using A by auto have Hermite_mod_det_H': "Hermite_mod_det abs_flag A = H'" unfolding Hermite_mod_det_def Let_def H'_def H_def E_def A'_def D_def dc dr det_int by blast show "Hermite_JNF ?ass ?res (Hermite_mod_det abs_flag A)" using Hermite_mod_det_H' Hermite_H' by simp have "\R. invertible_mat R \ R \ carrier_mat m m \ A = R * H'" by (subst A_eq[symmetric], rule A.Hermite_append_det_id(2)[OF _ mn _ H' H_H'0 P'Q' inv_P'Q' A'_P'Q'H Hermite_H], insert D_def A'_def mn A inv_RAT_A D_A A_eq, auto) from this obtain R where inv_R: "invertible_mat R" and R: "R \ carrier_mat m m" and A_RH': "A = R * H'" by blast obtain R' where inverts_R: "inverts_mat R R'" and R': "R' \ carrier_mat m m" by (meson R inv_R obtain_inverse_matrix) have inv_R': "invertible_mat R'" using inverts_R unfolding invertible_mat_def inverts_mat_def using R R' mat_mult_left_right_inverse by auto moreover have "H' = R' * A" proof - have "R' * A = R' * (R * H')" using A_RH' by auto also have "... = (R'*R) * H'" using H' R R' by auto also have "... = H'" by (metis H' R R' mat_mult_left_right_inverse carrier_matD(1) inverts_R inverts_mat_def left_mult_one_mat) finally show ?thesis .. qed ultimately show "\S. invertible_mat S \ S \ carrier_mat m m \ Hermite_mod_det abs_flag A = S * A" using R' Hermite_mod_det_H' by blast qed lemma Hermite_mod_det_soundness: assumes mn: "m = n" and A_def: "A \ carrier_mat m n" and i: "invertible_mat (map_mat rat_of_int A)" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (Hermite_mod_det abs_flag A)" and "(\P. invertible_mat P \ P \ carrier_mat m m \ (Hermite_mod_det abs_flag A) = P * A)" using A_def Hermite_mod_det_soundness_mx0(1) Hermite_mod_det_soundness_mxn(1) mn i by blast (insert Hermite_mod_det_soundness_mx0(2) Hermite_mod_det_soundness_mxn(2) assms, blast) text \We can even move the whole echelon form algorithm @{text "echelon_form_of"} from HOL Analysis to JNF and then we can combine it with @{text "Hermite_of_list_of_rows"} to have another HNF algorithm which is not efficient, but valid for arbitrary matrices.\ lemma reduce_D0: "reduce a b 0 A = (let Aaj = A$$(a,0); Abj = A $$ (b,0) in if Aaj = 0 then A else case euclid_ext2 Aaj Abj of (p,q,u,v,d) \ Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then (p*A$$(a,k) + q*A$$(b,k)) else if i = b then u * A$$(a,k) + v * A$$(b,k) else A$$(i,k) ) )" (is "?lhs = ?rhs") proof obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A $$ (a, 0)) (A $$ (b, 0))" by (simp add: euclid_ext2_def) have *:" Matrix.mat (dim_row A) (dim_col A) (\(i, k). if i = a then let r = p * A $$ (a, k) + q * A $$ (b, k) in if 0 < \r\ then if k = 0 \ 0 dvd r then 0 else r mod 0 else r else if i = b then let r = u * A $$ (a, k) + v * A $$ (b, k) in if 0 < \r\ then r mod 0 else r else A $$ (i, k)) = Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then (p*A$$(a,k) + q*A$$(b,k)) else if i = b then u * A$$(a,k) + v * A$$(b,k) else A$$(i,k) )" by (rule eq_matI, auto simp add: Let_def) show "dim_row ?lhs = dim_row ?rhs" - unfolding reduce.simps Let_def by (smt dim_row_mat(1) pquvd prod.simps(2)) + unfolding reduce.simps Let_def by (smt (verit) dim_row_mat(1) pquvd prod.simps(2)) show "dim_col ?lhs = dim_col ?rhs" - unfolding reduce.simps Let_def by (smt dim_col_mat(1) pquvd prod.simps(2)) + unfolding reduce.simps Let_def by (smt (verit) dim_col_mat(1) pquvd prod.simps(2)) fix i j assume i: "i carrier_mat m n" and a: "a b" and A_def: "A = A' @\<^sub>r B" and B: "B \ carrier_mat t n" assumes pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,j)) (A$$(b,j))" shows "Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then (p*A$$(a,k) + q*A$$(b,k)) else if i = b then u * A$$(a,k) + v * A$$(b,k) else A$$(i,k) ) = (bezout_matrix_JNF A a b j euclid_ext2) * A" (is "?A = ?BM * A") proof (rule eq_matI) have A: "A \ carrier_mat (m+t) n" using A_def A' B by simp hence A_carrier: "?A \ carrier_mat (m+t) n" by auto show dr: "dim_row ?A = dim_row (?BM * A)" and dc: "dim_col ?A = dim_col (?BM * A)" unfolding bezout_matrix_JNF_def by auto fix i ja assume i: "i < dim_row (?BM * A)" and ja: "ja < dim_col (?BM * A)" let ?f = "\ia. (bezout_matrix_JNF A a b j euclid_ext2) $$ (i,ia) * A $$ (ia,ja)" have dv: "dim_vec (col A ja) = m+t" using A by auto have i_dr: "i col A ja" by (rule index_mult_mat, insert i ja, auto) also have "... = (\ia = 0..ia = 0..ia \ ({a,b} \ ({0.. {0.. i" using True x by blast have x_dr: "x < dim_row A" using x A by auto have "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) = 0" unfolding bezout_matrix_JNF_def unfolding index_mat(1)[OF i_dr x_dr] using x_not_i x by auto thus "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) * A $$ (x, ja) = 0" by auto qed have fa: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, a) = p" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr a_dr] using True pquvd by (auto, metis split_conv) have fb: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, b) = q" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr b_dr] using True pquvd ab by (auto, metis split_conv) have "sum ?f {a,b} + sum ?f ({0.. {0.. i" using True x by blast have x_dr: "x < dim_row A" using x A by auto have "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) = 0" unfolding bezout_matrix_JNF_def unfolding index_mat(1)[OF i_dr x_dr] using x_not_i x by auto thus "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) * A $$ (x, ja) = 0" by auto qed have fa: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, a) = u" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr a_dr] using True i_not_a pquvd by (auto, metis split_conv) have fb: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, b) = v" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr b_dr] using True i_not_a pquvd ab by (auto, metis split_conv) have "sum ?f {a,b} + sum ?f ({0.. {0.. i" using x by blast have x_dr: "x < dim_row A" using x A by auto have "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) = 0" unfolding bezout_matrix_JNF_def unfolding index_mat(1)[OF i_dr x_dr] using x_not_i x by auto thus "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, x) * A $$ (x, ja) = 0" by auto qed have fa: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, a) = 0" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr a_dr] using False i_not_a pquvd by auto have fb: "bezout_matrix_JNF A a b j euclid_ext2 $$ (i, b) = 0" unfolding bezout_matrix_JNF_def index_mat(1)[OF i_dr b_dr] using False i_not_a pquvd by auto have "sum ?f ({0.. carrier_mat m n" and a: "a b" assumes pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,j)) (A$$(b,j))" shows "Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then (p*A$$(a,k) + q*A$$(b,k)) else if i = b then u * A$$(a,k) + v * A$$(b,k) else A$$(i,k) ) = (bezout_matrix_JNF A a b j euclid_ext2) * A" (is "?A = ?BM * A") proof (rule bezout_matrix_JNF_mult_eq'[OF A a b ab _ _ pquvd]) show "A = A @\<^sub>r (0\<^sub>m 0 n)" by (rule eq_matI, unfold append_rows_def, auto) show "(0\<^sub>m 0 n) \ carrier_mat 0 n" by auto qed lemma reduce_invertible_mat_D0_BM: assumes A: "A \ carrier_mat m n" and a: "a < m" and b: "b < m" and ab: "a \ b" and Aa0: "A$$(a,0) \ 0" shows "reduce a b 0 A = (bezout_matrix_JNF A a b 0 euclid_ext2) * A" proof - obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(b,0))" by (simp add: euclid_ext2_def) let ?BM = "bezout_matrix_JNF A a b 0 euclid_ext2" let ?A = "Matrix.mat (dim_row A) (dim_col A) (\(i,k). if i = a then (p*A$$(a,k) + q*A$$(b,k)) else if i = b then u * A$$(a,k) + v * A$$(b,k) else A$$(i,k))" have A'_BZ_A: "?A = ?BM * A" by (rule bezout_matrix_JNF_mult_eq2[OF A _ _ ab pquvd], insert a b, auto) moreover have "?A = reduce a b 0 A" using pquvd Aa0 unfolding reduce_D0 Let_def by (metis (no_types, lifting) split_conv) ultimately show ?thesis by simp qed lemma reduce_invertible_mat_D0: assumes A: "A \ carrier_mat m n" and a: "a < m" and b: "b < m" and n0: "0 b" and a_less_b: "aP. invertible_mat P \ P \ carrier_mat m m \ reduce a b 0 A = P * A" proof (cases "A$$(a,0) = 0") case True then show ?thesis - by (smt A invertible_mat_one left_mult_one_mat one_carrier_mat reduce.simps) + by (smt (verit) A invertible_mat_one left_mult_one_mat one_carrier_mat reduce.simps) next case False obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(b,0))" by (simp add: euclid_ext2_def) let ?BM = "bezout_matrix_JNF A a b 0 euclid_ext2" have "reduce a b 0 A = ?BM * A" by (rule reduce_invertible_mat_D0_BM[OF A a b ab False]) moreover have invertible_bezout: "invertible_mat ?BM" by (rule invertible_bezout_matrix_JNF[OF A is_bezout_ext_euclid_ext2 a_less_b _ n0 False], insert a_less_b b, auto) moreover have BM: "?BM \ carrier_mat m m" unfolding bezout_matrix_JNF_def using A by auto ultimately show ?thesis by blast qed lemma reduce_below_invertible_mat_D0: assumes A': "A \ carrier_mat m n" and a: "ax \ set xs. x < m \ a < x" and "D=0" shows "(\P. invertible_mat P \ P \ carrier_mat m m \ reduce_below a xs D A = P * A)" using assms proof (induct a xs D A arbitrary: A rule: reduce_below.induct) case (1 a D A) then show ?case by (auto, metis invertible_mat_one left_mult_one_mat one_carrier_mat) next case (2 a x xs D A) note A = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note d = "2.prems"(4) note x_xs = "2.prems"(5) note D0 = "2.prems"(6) have xm: "x < m" using "2.prems" by auto obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce a x D A" have reduce_ax: "?reduce_ax \ carrier_mat m n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have h: "(\P. invertible_mat P \ P \ carrier_mat m m \ reduce_below a xs D (reduce a x D A) = P * reduce a x D A)" by (rule "2.hyps"[OF _ a j _ _ ],insert d x_xs D0 reduce_ax, auto) from this obtain P where inv_P: "invertible_mat P" and P: "P \ carrier_mat m m" and rb_Pr: "reduce_below a xs D (reduce a x D A) = P * reduce a x D A" by blast have *: "reduce_below a (x # xs) D A = reduce_below a xs D (reduce a x D A)" by simp have "\Q. invertible_mat Q \ Q \ carrier_mat m m \ (reduce a x D A) = Q * A" by (unfold D0, rule reduce_invertible_mat_D0[OF A a xm j], insert "2.prems", auto) from this obtain Q where inv_Q: "invertible_mat Q" and Q: "Q \ carrier_mat m m" and r_QA: "reduce a x D A = Q * A" by blast have "invertible_mat (P*Q)" using inv_P inv_Q P Q invertible_mult_JNF by blast moreover have "P * Q \ carrier_mat m m" using P Q by auto moreover have "reduce_below a (x # xs) D A = (P*Q) * A" - by (smt P Q * assoc_mult_mat carrier_matD(1) carrier_mat_triv index_mult_mat(2) + by (smt (verit) P Q * assoc_mult_mat carrier_matD(1) carrier_mat_triv index_mult_mat(2) r_QA rb_Pr reduce_preserves_dimensions(1)) ultimately show ?case by blast qed (*This lemma permits to get rid of one assumption in reduce_not0*) lemma reduce_not0': assumes A: "A \ carrier_mat m n" and a: "a 0" shows "reduce a b 0 A $$ (a, 0) \ 0" (is "?reduce_ab $$ (a,0) \ _") proof - have "?reduce_ab $$ (a,0) = (let r = gcd (A $$ (a, 0)) (A $$ (b, 0)) in if 0 dvd r then 0 else r)" by (rule reduce_gcd[OF A _ j Aaj], insert a, simp) also have "... \ 0" unfolding Let_def by (simp add: assms(6)) finally show ?thesis . qed lemma reduce_below_preserves_D0: assumes A': "A \ carrier_mat m n" and a: "a 0" assumes "i \ set xs" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "i\a" and "i carrier_mat m n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) have "reduce_below a (x # xs) D A $$ (i, j) = reduce_below a xs D (reduce a x D A) $$ (i, j)" by auto also have "... = reduce a x D A $$ (i, j)" proof (rule "2.hyps"[OF _ a j _ _ ]) show "i \ set xs" using i_set_xxs by auto show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce a x D A $$ (a, 0) \ 0" by (unfold D0, rule reduce_not0'[OF A _ _ _ _ Aaj], insert "2.prems", auto) show "reduce a x D A \ carrier_mat m n" using reduce_ax by linarith qed (insert "2.prems", auto) also have "... = A $$ (i,j)" by (rule reduce_preserves[OF A j Aaj], insert "2.prems", auto) finally show ?case . qed lemma reduce_below_0_D0: assumes A: "A \ carrier_mat m n" and a: "a 0" assumes "i \ set xs" and "distinct xs" and "\x \ set xs. x < m \ a < x" and "D=0" shows "reduce_below a xs D A $$ (i,0) = 0" using assms proof (induct a xs D A arbitrary: A i rule: reduce_below.induct) case (1 a D A) then show ?case by auto next case (2 a x xs D A) note A = "2.prems"(1) note a = "2.prems"(2) note j = "2.prems"(3) note Aaj = "2.prems"(4) note i_set_xxs = "2.prems"(5) note d = "2.prems"(6) note xxs_less_m = "2.prems"(7) note D0 = "2.prems"(8) have xm: "x < m" using "2.prems" by auto obtain p q u v d where pquvd: "(p,q,u,v,d) = euclid_ext2 (A$$(a,0)) (A$$(x,0))" by (metis prod_cases5) let ?reduce_ax = "reduce a x D A" have reduce_ax: "?reduce_ax \ carrier_mat m n" by (metis (no_types, lifting) "2" add.comm_neutral append_rows_def carrier_matD carrier_mat_triv index_mat_four_block(2,3) index_one_mat(2) index_smult_mat(2) index_zero_mat(2,3) reduce_preserves_dimensions) show ?case proof (cases "i=x") case True have "reduce_below a (x # xs) D A $$ (i, 0) = reduce_below a xs D (reduce a x D A) $$ (i, 0)" by auto also have "... = (reduce a x D A) $$ (i, 0)" proof (rule reduce_below_preserves_D0[OF _ a j _ _ ]) show "reduce a x D A \ carrier_mat m n" using reduce_ax by linarith show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce a x D A $$ (a, 0) \ 0" by (unfold D0, rule reduce_not0'[OF A _ _ j _ Aaj], insert "2.prems", auto) show "i \ set xs" using True d by auto show "i \ a" using "2.prems" by blast show "i < m" by (simp add: True trans_less_add1 xm) qed (insert D0) also have "... = 0" unfolding True by (rule reduce_0[OF A _ j _ _ Aaj], insert "2.prems", auto) finally show ?thesis . next case False note i_not_x = False have h: "reduce_below a xs D (reduce a x D A) $$ (i, 0) = 0 " proof (rule "2.hyps"[OF _ a j _ _ ]) show "reduce a x D A \ carrier_mat m n" using reduce_ax by linarith show "i \ set xs" using i_set_xxs i_not_x by auto show "distinct xs" using d by auto show "\x\set xs. x < m \ a < x" using xxs_less_m by auto show "reduce a x D A $$ (a, 0) \ 0" by (unfold D0, rule reduce_not0'[OF A _ _ j _ Aaj], insert "2.prems", auto) qed (insert D0) have "reduce_below a (x # xs) D A $$ (i, 0) = reduce_below a xs D (reduce a x D A) $$ (i, 0)" by auto also have "... = 0" using h . finally show ?thesis . qed qed end text \Definition of the echelon form algorithm in JNF\ primrec bezout_iterate_JNF where "bezout_iterate_JNF A 0 i j bezout = A" | "bezout_iterate_JNF A (Suc n) i j bezout = (if (Suc n) \ i then A else bezout_iterate_JNF (bezout_matrix_JNF A i ((Suc n)) j bezout * A) n i j bezout)" definition "echelon_form_of_column_k_JNF bezout A' k = (let (A, i) = A' in if (i = dim_row A) \ (\m \ {i..m\{i+1.. 0 \ i \ n); interchange_A = swaprows i n A in (bezout_iterate_JNF (interchange_A) (dim_row A - 1) i k bezout, i + 1) )" definition "echelon_form_of_upt_k_JNF A k bezout = (fst (foldl (echelon_form_of_column_k_JNF bezout) (A,0) [0.. int ^ 'n :: mod_type ^ 'm :: mod_type \ _) ===> (Mod_Type_Connect.HMA_I) ===> (Mod_Type_Connect.HMA_I) ===> (=) ===> (Mod_Type_Connect.HMA_M)) (\A i j bezout. bezout_iterate_JNF A n i j bezout) (\A i j bezout. bezout_iterate A n i j bezout) " proof (intro rel_funI, goal_cases) case (1 A A' i i' j j' bezout bezout') then show ?case using assms proof (induct n arbitrary: A A') case 0 then show ?case by auto next case (Suc n) note AA'[transfer_rule] = "Suc.prems"(1) note ii'[transfer_rule] = "Suc.prems"(2) note jj'[transfer_rule] = "Suc.prems"(3) note bb'[transfer_rule] = "Suc.prems"(4) note Suc_n_less_m = "Suc.prems"(5) let ?BI_JNF = "bezout_iterate_JNF" let ?BI_HMA = "bezout_iterate" let ?from_nat_rows = "mod_type_class.from_nat :: _ \ 'm" have Sucn[transfer_rule]: "Mod_Type_Connect.HMA_I (Suc n) (?from_nat_rows (Suc n))" unfolding Mod_Type_Connect.HMA_I_def by (simp add: Suc_lessD Suc_n_less_m mod_type_class.from_nat_to_nat) have n: " n < CARD('m)" using Suc_n_less_m by simp have [transfer_rule]: "Mod_Type_Connect.HMA_M (?BI_JNF (bezout_matrix_JNF A i (Suc n) j bezout * A) n i j bezout) (?BI_HMA (bezout_matrix A' i' (?from_nat_rows (Suc n)) j' bezout' ** A') n i' j' bezout')" by (rule Suc.hyps[OF _ ii' jj' bb' n], transfer_prover) moreover have "Suc n \ i \ Suc n \ mod_type_class.to_nat i'" and "Suc n > i \ Suc n > mod_type_class.to_nat i'" by (metis "1"(2) Mod_Type_Connect.HMA_I_def)+ ultimately show ?case using AA' by auto qed qed corollary HMA_bezout_iterate'[transfer_rule]: fixes A'::"int ^ 'n :: mod_type ^ 'm :: mod_type" assumes n: "n dim_row A" using assms unfolding echelon_form_of_column_k_JNF_def by auto lemma HMA_echelon_form_of_column_k[transfer_rule]: assumes k: "k rel_prod (Mod_Type_Connect.HMA_M :: _ \ int ^ 'n :: mod_type ^ 'm :: mod_type \ _) (\a b. a=b \ a\CARD('m)) ===> (rel_prod (Mod_Type_Connect.HMA_M) (\a b. a=b \ a\CARD('m)))) (\bezout A. echelon_form_of_column_k_JNF bezout A k) (\bezout A. echelon_form_of_column_k bezout A k) " proof (intro rel_funI, goal_cases) case (1 bezout bezout' xa ya ) obtain A i where xa: "xa = (A,i)" using surjective_pairing by blast obtain A' i' where ya: "ya = (A',i')" using surjective_pairing by blast have ii'[transfer_rule]: "i=i'" using "1"(2) xa ya by auto have i_le_m: "i\CARD('m)" using "1"(2) xa ya by auto have AA'[transfer_rule]: "Mod_Type_Connect.HMA_M A A'" using "1"(2) xa ya by auto have bb'[transfer_rule]: "bezout=bezout'" using "1" by auto let ?from_nat_rows = "mod_type_class.from_nat :: _ \ 'm" let ?from_nat_cols = "mod_type_class.from_nat :: _ \ 'n" have kk'[transfer_rule]: "Mod_Type_Connect.HMA_I k (?from_nat_cols k)" by (simp add: Mod_Type_Connect.HMA_I_def assms mod_type_class.to_nat_from_nat_id) have c1_eq: "(i = dim_row A) = (i = nrows A')" by (metis AA' Mod_Type_Connect.dim_row_transfer_rule nrows_def) have c2_eq: "(\m \ {i..m\?from_nat_rows i. A' $ m $ ?from_nat_cols k = 0)" (is "?lhs = ?rhs") if i_not: "i\dim_row A" proof assume lhs: "?lhs" show "?rhs" proof (rule+) fix m assume im: "?from_nat_rows i \ m" have im': "i ?m'" by (simp add: to_nat_mono') hence "?m' >= i" using im im' by (simp add: mod_type_class.to_nat_from_nat_id) hence "?m' \ {i.. {i..?from_nat_rows i" using AA' Mod_Type_Connect.dim_row_transfer_rule from_nat_mono' m by fastforce hence "A' $h ?m $h ?from_nat_cols k = 0" using rhs by auto moreover have "A $$ (m, k) = A' $h ?m $h ?from_nat_cols k" unfolding index_hma_def[symmetric] by transfer_prover ultimately show "A $$ (m, k) = 0" by simp qed qed show ?case proof (cases "(i = dim_row A) \ (\m \ {i..m\?from_nat_rows i. A' $ m $ ?from_nat_cols k = 0) \ (i = nrows A')" using c1_eq c2_eq by auto have "echelon_form_of_column_k_JNF bezout xa k = (A,i)" unfolding echelon_form_of_column_k_JNF_def using True xa by auto moreover have "echelon_form_of_column_k bezout ya k = (A',i')" unfolding echelon_form_of_column_k_def Let_def using * ya ii' by simp ultimately show ?thesis unfolding xa ya rel_prod.simps using AA' ii' bb' i_le_m by blast next case False note not_c1 = False hence im': "im\{i+1..m>?from_nat_rows i. A' $ m $ ?from_nat_cols k = 0)" (is "?lhs = ?rhs") proof assume lhs: "?lhs" show "?rhs" proof (rule+) fix m assume im: "?from_nat_rows i < m" let ?m' = "mod_type_class.to_nat m" have mm'[transfer_rule]: "Mod_Type_Connect.HMA_I ?m' m" by (simp add: Mod_Type_Connect.HMA_I_def) from im have "mod_type_class.to_nat (?from_nat_rows i) < ?m'" by (simp add: to_nat_mono) hence "?m' > i" using im im' by (simp add: mod_type_class.to_nat_from_nat_id) hence "?m' \ {i+1.. {i+1..?from_nat_rows i" by (metis Mod_Type_Connect.HMA_I_def One_nat_def add_Suc_right atLeastLessThan_iff from_nat_mono le_simps(3) m mm' mod_type_class.to_nat_less_card nat_arith.rule0) hence "A' $h ?m $h ?from_nat_cols k = 0" using rhs by auto moreover have "A $$ (m, k) = A' $h ?m $h ?from_nat_cols k" unfolding index_hma_def[symmetric] by transfer_prover ultimately show "A $$ (m, k) = 0" by simp qed qed show ?thesis proof (cases "(\m\{i+1.. (\m>?from_nat_rows i. A' $ m $ ?from_nat_cols k = 0)" using * by auto have **: "\ ((\m\?from_nat_rows i. A' $h m $h ?from_nat_cols k = 0) \ i = nrows A')" using c1_eq c2_eq not_c1 by auto define n where "n=(LEAST n. A $$ (n,k) \ 0 \ i \ n)" define n' where "n'=(LEAST n. A' $ n $ ?from_nat_cols k \ 0 \ ?from_nat_rows i \ n)" let ?interchange_A = "swaprows i n A" let ?interchange_A' = "interchange_rows A' (?from_nat_rows i') n'" have nn'[transfer_rule]: "Mod_Type_Connect.HMA_I n n'" proof - let ?n' = "mod_type_class.to_nat n'" have exist: "\n. A' $ n $ ?from_nat_cols k \ 0 \ ?from_nat_rows i \ n" using * by auto from this obtain a where c: "A' $ a $ ?from_nat_cols k \ 0 \ ?from_nat_rows i \ a" by blast have "n = ?n'" proof (unfold n_def, rule Least_equality) have n'n'[transfer_rule]: "Mod_Type_Connect.HMA_I ?n' n'" by (simp add: Mod_Type_Connect.HMA_I_def) have e: "(A' $ n' $ ?from_nat_cols k \ 0 \ ?from_nat_rows i \ n')" by (metis (mono_tags, lifting) LeastI c2_eq n'_def not_c1) hence "i \ mod_type_class.to_nat n'" using im' mod_type_class.from_nat_to_nat to_nat_mono' by fastforce moreover have "A' $ n' $ ?from_nat_cols k = A $$ (?n', k)" unfolding index_hma_def[symmetric] by (transfer', auto) ultimately show "A $$ (?n', k) \ 0 \ i \ ?n'" using e by auto show " \y. A $$ (y, k) \ 0 \ i \ y \ mod_type_class.to_nat n' \ y" - by (smt AA' Mod_Type_Connect.HMA_M_def Mod_Type_Connect.from_hma\<^sub>m_def assms from_nat_mono - from_nat_mono' index_mat(1) linorder_not_less mod_type_class.from_nat_to_nat_id - mod_type_class.to_nat_less_card n'_def order.strict_trans prod.simps(2) wellorder_Least_lemma(2)) + unfolding n'_def + by (smt (verit, del_insts) AA' Mod_Type_Connect.HMA_M_def Mod_Type_Connect.from_hma\<^sub>m_def assms from_nat_mono + from_nat_mono' index_mat(1) less_trans mod_type_class.from_nat_to_nat_id mod_type_class.to_nat_less_card + not_le prod.simps(2) wellorder_Least_lemma(2)) qed thus ?thesis unfolding Mod_Type_Connect.HMA_I_def by auto qed have dr1[transfer_rule]: "(nrows A' - 1) = (dim_row A - 1)" unfolding nrows_def using AA' Mod_Type_Connect.dim_row_transfer_rule by force have ii'2[transfer_rule]: "Mod_Type_Connect.HMA_I i (?from_nat_rows i')" by (metis "**" Mod_Type_Connect.HMA_I_def i_le_m ii' le_neq_implies_less mod_type_class.to_nat_from_nat_id nrows_def) have ii'3[transfer_rule]: "Mod_Type_Connect.HMA_I i' (?from_nat_rows i')" using ii' ii'2 by blast let ?BI_JNF = "(bezout_iterate_JNF (?interchange_A) (dim_row A - 1) i k bezout)" let ?BI_HA = "(bezout_iterate (?interchange_A') (nrows A' - 1) (?from_nat_rows i) (?from_nat_cols k) bezout)" have e_rw: "echelon_form_of_column_k_JNF bezout xa k = (?BI_JNF,i+1)" unfolding echelon_form_of_column_k_JNF_def n_def using False xa not_c1 by auto have e_rw2: "echelon_form_of_column_k bezout ya k = (?BI_HA,i+1)" unfolding echelon_form_of_column_k_def Let_def n'_def using * ya ** ii' by auto have s[transfer_rule]: "Mod_Type_Connect.HMA_M (swaprows i' n A) (interchange_rows A' (?from_nat_rows i') n')" by transfer_prover have n_CARD: "(nrows A' - 1) < CARD('m)" unfolding nrows_def by auto note a[transfer_rule] = HMA_bezout_iterate[OF n_CARD] have BI[transfer_rule]:"Mod_Type_Connect.HMA_M ?BI_JNF ?BI_HA" unfolding ii' dr1 by (rule HMA_bezout_iterate'[OF _ s ii'3 kk'], insert n_CARD, transfer', simp) thus ?thesis using e_rw e_rw2 bb' by (metis (mono_tags, lifting) AA' False Mod_Type_Connect.dim_row_transfer_rule atLeastLessThan_iff dual_order.trans order_less_imp_le rel_prod_inject) qed qed qed corollary HMA_echelon_form_of_column_k'[transfer_rule]: assumes k: "kCARD('m)" and "(Mod_Type_Connect.HMA_M :: _ \ int ^ 'n :: mod_type ^ 'm :: mod_type \ _) A A'" shows "(rel_prod (Mod_Type_Connect.HMA_M) (\a b. a=b \ a\CARD('m))) (echelon_form_of_column_k_JNF bezout (A,i) k) (echelon_form_of_column_k bezout (A',i) k)" using assms HMA_echelon_form_of_column_k[OF k] unfolding rel_fun_def by force lemma HMA_foldl_echelon_form_of_column_k: assumes k: "k\CARD('n)" shows "((Mod_Type_Connect.HMA_M :: _ \ int ^ 'n :: mod_type ^ 'm :: mod_type \ _) ===> (=) ===> (rel_prod (Mod_Type_Connect.HMA_M) (\a b. a=b \ a\CARD('m)))) (\A bezout. (foldl (echelon_form_of_column_k_JNF bezout) (A,0) [0..A bezout. (foldl (echelon_form_of_column_k bezout) (A,0) [0..a b. a=b \ a\CARD('m)) (?foldl_JNF [0.. int ^ 'n :: mod_type ^ 'm :: mod_type \ _) ===> (=) ===> (Mod_Type_Connect.HMA_M)) (\A bezout. echelon_form_of_upt_k_JNF A k bezout) (\A bezout. echelon_form_of_upt_k A k bezout) " proof (intro rel_funI, goal_cases) case (1 A A' bezout bezout') have k': "Suc k \ CARD('n)" using k by auto have rel_foldl: "(rel_prod (Mod_Type_Connect.HMA_M) (\a b. a=b \ a\CARD('m))) (foldl (echelon_form_of_column_k_JNF bezout) (A,0) [0.. int ^ 'n :: mod_type ^ 'm :: mod_type \ _) ===> (=) ===> (Mod_Type_Connect.HMA_M)) (\A bezout. echelon_form_of_JNF A bezout) (\A bezout. echelon_form_of A bezout) " proof (intro rel_funI, goal_cases) case (1 A A' bezout bezout') note AA'[transfer_rule] = 1(1) note bb'[transfer_rule] = 1(2) have *: "(dim_col A - 1) < CARD('n)" using 1 using Mod_Type_Connect.dim_col_transfer_rule by force note **[transfer_rule] = HMA_echelon_form_of_upt_k[OF *] have [transfer_rule]: "(ncols A' - 1) = (dim_col A - 1)" by (metis "1"(1) Mod_Type_Connect.dim_col_transfer_rule ncols_def) have [transfer_rule]: "(dim_col A - 1) = (dim_col A - 1)" .. show ?case unfolding echelon_form_of_def echelon_form_of_JNF_def bb' by (metis (mono_tags) "**" "1"(1) \ncols A' - 1 = dim_col A - 1\ rel_fun_def) qed end context begin private lemma echelon_form_of_euclidean_invertible_mod_type: fixes A::"int mat" assumes "A \ carrier_mat CARD('m::mod_type) CARD('n::mod_type)" shows "\P. invertible_mat P \ P \ carrier_mat (CARD('m::mod_type)) (CARD('m::mod_type)) \ P * A = echelon_form_of_JNF A euclid_ext2 \ echelon_form_JNF (echelon_form_of_JNF A euclid_ext2)" proof - define A' where "A' = (Mod_Type_Connect.to_hma\<^sub>m A :: int ^'n :: mod_type ^'m :: mod_type)" have AA'[transfer_rule]: "Mod_Type_Connect.HMA_M A A'" unfolding Mod_Type_Connect.HMA_M_def using assms A'_def by auto have [transfer_rule]: "Mod_Type_Connect.HMA_M (echelon_form_of_JNF A euclid_ext2) (echelon_form_of A' euclid_ext2)" by transfer_prover have "\P. invertible P \ P**A' = (echelon_form_of A' euclid_ext2) \ echelon_form (echelon_form_of A' euclid_ext2)" by (rule echelon_form_of_euclidean_invertible) thus ?thesis by (transfer, auto) qed private lemma echelon_form_of_euclidean_invertible_nontriv_mod_ring: fixes A::"int mat" assumes "A \ carrier_mat CARD('m::nontriv mod_ring) CARD('n::nontriv mod_ring)" shows "\P. invertible_mat P \ P \ carrier_mat (CARD('m)) (CARD('m)) \ P * A = echelon_form_of_JNF A euclid_ext2 \ echelon_form_JNF (echelon_form_of_JNF A euclid_ext2)" - using assms echelon_form_of_euclidean_invertible_mod_type by (smt CARD_mod_ring) + using assms echelon_form_of_euclidean_invertible_mod_type by (smt (verit) CARD_mod_ring) (*We internalize both sort constraints in one step*) lemmas echelon_form_of_euclidean_invertible_nontriv_mod_ring_internalized = echelon_form_of_euclidean_invertible_nontriv_mod_ring[unfolded CARD_mod_ring, internalize_sort "'m::nontriv", internalize_sort "'b::nontriv"] context fixes m::nat and n::nat assumes local_typedef1: "\(Rep :: ('b \ int)) Abs. type_definition Rep Abs {0..(Rep :: ('c \ int)) Abs. type_definition Rep Abs {0..1" and n: "n>1" begin lemma echelon_form_of_euclidean_invertible_nontriv_mod_ring_aux: fixes A::"int mat" assumes "A \ carrier_mat m n" shows "\P. invertible_mat P \ P \ carrier_mat m m \ P * A = echelon_form_of_JNF A euclid_ext2 \ echelon_form_JNF (echelon_form_of_JNF A euclid_ext2)" using echelon_form_of_euclidean_invertible_nontriv_mod_ring_internalized [OF type_to_set2(1)[OF local_typedef1 local_typedef2] type_to_set1(1)[OF local_typedef1 local_typedef2]] using assms using type_to_set1(2) local_typedef1 local_typedef2 n m by metis end (*Canceling the first local type definitions*) context begin (*Canceling the first*) private lemma echelon_form_of_euclidean_invertible_cancelled_first: "\Rep Abs. type_definition Rep Abs {0.. 1 < m \ 1 < n \ A \ carrier_mat m n \ \P. invertible_mat P \ P \ carrier_mat m m \ P * (A::int mat) = echelon_form_of_JNF A euclid_ext2 \ echelon_form_JNF (echelon_form_of_JNF A euclid_ext2)" using echelon_form_of_euclidean_invertible_nontriv_mod_ring_aux[cancel_type_definition, of m n A] by force (*Canceling the second*) private lemma echelon_form_of_euclidean_invertible_cancelled_both: "1 < m \ 1 < n \ A \ carrier_mat m n \ \P. invertible_mat P \ P \ carrier_mat m m \ P * (A::int mat) = echelon_form_of_JNF A euclid_ext2 \ echelon_form_JNF (echelon_form_of_JNF A euclid_ext2)" using echelon_form_of_euclidean_invertible_cancelled_first[cancel_type_definition, of n m A] by force (*The final result in JNF*) lemma echelon_form_of_euclidean_invertible': fixes A::"int mat" assumes "A \ carrier_mat m n" and "1 < m" and "1 < n" (*Required from the mod_type restrictions*) shows "\P. invertible_mat P \ P \ carrier_mat m m \ P * A = echelon_form_of_JNF A euclid_ext2 \ echelon_form_JNF (echelon_form_of_JNF A euclid_ext2)" using echelon_form_of_euclidean_invertible_cancelled_both assms by auto end end context mod_operation begin definition "FindPreHNF_rectangular A = (let m = dim_row A; n = dim_col A in if m < 2 \ n = 0 then A else \ \ No operations are carried out if m = 1 \ if n = 1 then let non_zero_positions = filter (\i. A $$ (i,0) \ 0) [1.. 0 then A else let i = non_zero_positions ! 0 in swaprows 0 i A) in reduce_below_impl 0 non_zero_positions 0 A' else (echelon_form_of_JNF A euclid_ext2))" text \This is the (non-efficient) HNF algorithm obtained from the echelon form and Hermite normal form AFP entries\ definition "HNF_algorithm_from_HA A = Hermite_of_list_of_rows (FindPreHNF_rectangular A) [0..<(dim_row A)]" (* Now we can combine FindPreHNF_rectangular, FindPreHNF and Hermite_of_list_of_rows to get an algorithm to compute the HNF of any matrix (if it is square and invertible, then the HNF is computed reducing entries modulo D) *) text \Now we can combine @{text"FindPreHNF_rectangular"}, @{text"FindPreHNF"} and @{text"Hermite_of_list_of_rows"} to get an algorithm to compute the HNF of any matrix (if it is square and invertible, then the HNF is computed reducing entries modulo D)\ definition "HNF_algorithm abs_flag A = (let m = dim_row A; n = dim_col A in if m \ n then Hermite_of_list_of_rows (FindPreHNF_rectangular A) [0..r D \\<^sub>m 1\<^sub>m n; E = FindPreHNF abs_flag D A'; H = Hermite_of_list_of_rows E [0.. carrier_mat m n" shows "\P. invertible_mat P \ P \ carrier_mat m m \ P * A = FindPreHNF_rectangular A \ echelon_form_JNF (FindPreHNF_rectangular A)" proof (cases "m < 2 \ n = 0") case True then show ?thesis - by (smt A FindPreHNF_rectangular_def carrier_matD echelon_form_JNF_1xn echelon_form_mx0 + by (smt (verit) A FindPreHNF_rectangular_def carrier_matD echelon_form_JNF_1xn echelon_form_mx0 invertible_mat_one left_mult_one_mat one_carrier_mat) next case False have m1: "m>1" using False by auto have n0: "n>0" using False by auto show ?thesis proof (cases "n=1") case True note n1 = True let ?nz = "filter (\i. A $$ (i,0) \ 0) [1.. carrier_mat m n" using A by auto have A'00: "?A' $$ (0,0) \ 0" if "?nz \ []" - by (smt True assms carrier_matD index_mat_swaprows(1) length_greater_0_conv m1 + by (smt (verit) True assms carrier_matD index_mat_swaprows(1) length_greater_0_conv m1 mem_Collect_eq nat_SN.gt_trans nth_mem set_filter that zero_less_one_class.zero_less_one) have e_r: "echelon_form_JNF (reduce_below 0 ?nz 0 ?A')" if nz_not_empty: "?nz \ []" proof (rule echelon_form_JNF_mx1) show "(reduce_below 0 ?nz 0 ?A') \ carrier_mat m n" using A reduce_below by auto have "(reduce_below 0 ?nz 0 ?A') $$ (i,0) = 0" if i: "i \ {1.. set ?nz") case True show ?thesis by (rule reduce_below_0_D0[OF A' _ _ A'00 True], insert m1 n0 True A nz_not_empty, auto) next case False have "(reduce_below 0 ?nz 0 ?A') $$ (i,0) = ?A' $$ (i,0)" by (rule reduce_below_preserves_D0[OF A' _ _ A'00 False], insert m1 n0 True A i nz_not_empty, auto) also have "... = 0" using False n1 assms that by auto finally show ?thesis . qed thus "\i \ {1..P. invertible_mat P \ P \ carrier_mat m m \ reduce_below 0 ?nz 0 ?A' = P * ?A'" by (rule reduce_below_invertible_mat_D0[OF A'], insert m1 n0 True A, auto) moreover have "\P. invertible_mat P \ P \ carrier_mat m m \ ?A' = P * A" if "?nz \ []" using A A'_swaprows_invertible_mat m1 that by blast ultimately have e_inv: "\P. invertible_mat P \ P \ carrier_mat m m \ reduce_below 0 ?nz 0 ?A' = P * A" if "?nz \ []" - by (smt that A assoc_mult_mat invertible_mult_JNF mult_carrier_mat) + by (smt (verit) that A assoc_mult_mat invertible_mult_JNF mult_carrier_mat) have e_r1: "echelon_form_JNF A" if nz_empty: "?nz = []" proof (rule echelon_form_JNF_mx1[OF A]) show "\i\{1..P. invertible_mat P \ P \ carrier_mat m m \ A = P * A" by (metis A invertible_mat_one left_mult_one_mat one_carrier_mat) have "FindPreHNF_rectangular A = (if ?nz = [] then A else reduce_below_impl 0 ?nz 0 ?A')" unfolding FindPreHNF_rectangular_def Let_def using m1 n1 A True by auto also have "reduce_below_impl 0 ?nz 0 ?A' = reduce_below 0 ?nz 0 ?A'" by (rule reduce_below_impl[OF _ _ _ _ A'], insert m1 n0 A, auto) finally show ?thesis using e_inv e_r e_r1 e_inv1 by metis next case False have f_rw: "FindPreHNF_rectangular A = echelon_form_of_JNF A euclid_ext2" unfolding FindPreHNF_rectangular_def Let_def using m1 n0 A False by auto show ?thesis unfolding f_rw by (rule echelon_form_of_euclidean_invertible'[OF A], insert False n0 m1, auto) qed qed lemma HNF_algorithm_from_HA_soundness: assumes A: "A \ carrier_mat m n" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (HNF_algorithm_from_HA A) \ (\P. P \ carrier_mat m m \ invertible_mat P \ (HNF_algorithm_from_HA A) = P * A)" proof - have m: "dim_row A = m" using A by auto have "(\P. P \ carrier_mat m m \ invertible_mat P \ (HNF_algorithm_from_HA A) = P * (FindPreHNF_rectangular A))" unfolding HNF_algorithm_from_HA_def m proof (rule invertible_Hermite_of_list_of_rows) show "FindPreHNF_rectangular A \ carrier_mat m n" - by (smt A FindPreHNF_rectangular_soundness mult_carrier_mat) + by (smt (verit) A FindPreHNF_rectangular_soundness mult_carrier_mat) show "echelon_form_JNF (FindPreHNF_rectangular A)" using FindPreHNF_rectangular_soundness by blast qed moreover have "(\P. P \ carrier_mat m m \ invertible_mat P \ (FindPreHNF_rectangular A) = P * A)" by (metis A FindPreHNF_rectangular_soundness) ultimately have "(\P. P \ carrier_mat m m \ invertible_mat P \ (HNF_algorithm_from_HA A) = P * A)" - by (smt assms assoc_mult_mat invertible_mult_JNF mult_carrier_mat) + by (smt (verit) assms assoc_mult_mat invertible_mult_JNF mult_carrier_mat) moreover have "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (HNF_algorithm_from_HA A)" by (metis A FindPreHNF_rectangular_soundness HNF_algorithm_from_HA_def m Hermite_Hermite_of_list_of_rows mult_carrier_mat) ultimately show ?thesis by simp qed text \Soundness theorem for any matrix\ lemma HNF_algorithm_soundness: assumes A: "A \ carrier_mat m n" shows "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (HNF_algorithm abs_flag A) \ (\P. P \ carrier_mat m m \ invertible_mat P \ (HNF_algorithm abs_flag A) = P * A)" proof (cases "m\n \ Determinant.det A = 0") case True have H_rw: "HNF_algorithm abs_flag A = Hermite_of_list_of_rows (FindPreHNF_rectangular A) [0..P. P \ carrier_mat m m \ invertible_mat P \ (HNF_algorithm abs_flag A) = P * (FindPreHNF_rectangular A))" unfolding H_rw proof (rule invertible_Hermite_of_list_of_rows) show "FindPreHNF_rectangular A \ carrier_mat m n" - by (smt A FindPreHNF_rectangular_soundness mult_carrier_mat) + by (smt (verit) A FindPreHNF_rectangular_soundness mult_carrier_mat) show "echelon_form_JNF (FindPreHNF_rectangular A)" using FindPreHNF_rectangular_soundness by blast qed moreover have "(\P. P \ carrier_mat m m \ invertible_mat P \ (FindPreHNF_rectangular A) = P * A)" by (metis A FindPreHNF_rectangular_soundness) ultimately have "(\P. P \ carrier_mat m m \ invertible_mat P \ (HNF_algorithm abs_flag A) = P * A)" - by (smt assms assoc_mult_mat invertible_mult_JNF mult_carrier_mat) + by (smt (verit) assms assoc_mult_mat invertible_mult_JNF mult_carrier_mat) moreover have "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (HNF_algorithm abs_flag A)" by (metis A FindPreHNF_rectangular_soundness H_rw Hermite_Hermite_of_list_of_rows mult_carrier_mat) ultimately show ?thesis by simp next case False hence mn: "m=n" and det_A_not0:"(Determinant.det A) \ 0" by auto have inv_RAT_A: "invertible_mat (map_mat rat_of_int A)" proof - have "det (map_mat rat_of_int A) \ 0" using det_A_not0 by auto thus ?thesis by (metis False assms dvd_field_iff invertible_iff_is_unit_JNF map_carrier_mat) qed have "HNF_algorithm abs_flag A = Hermite_mod_det abs_flag A" unfolding HNF_algorithm_def Hermite_mod_det_def Let_def using False A by simp then show ?thesis using Hermite_mod_det_soundness[OF mn A inv_RAT_A] by auto qed end text \New predicate of soundness of a HNF algorithm, without providing explicitly the transformation matrix.\ definition "is_sound_HNF' algorithm associates res = (\A. let H = algorithm A; m = dim_row A; n = dim_col A in Hermite_JNF associates res H \ H \ carrier_mat m n \ (\P. P \ carrier_mat m m \ invertible_mat P \ A = P * H))" lemma is_sound_HNF_conv: assumes s: "is_sound_HNF' algorithm associates res" shows "is_sound_HNF (\A. let H = algorithm A in (SOME P. P \ carrier_mat (dim_row A) (dim_row A) \ invertible_mat P \ A = P * H, H)) associates res" proof (unfold is_sound_HNF_def Let_def prod.case, rule allI) fix A::"'a mat" define m where "m = dim_row A" obtain P where P: "P \ carrier_mat m m \ invertible_mat P \ A = P * (algorithm A)" using s unfolding is_sound_HNF'_def Let_def m_def by auto let ?some_P = "(SOME P. P \ carrier_mat m m \ invertible_mat P \ A = P * algorithm A)" have some_P: "?some_P \ carrier_mat m m \ invertible_mat ?some_P \ A = ?some_P * algorithm A" - by (smt P verit_sko_ex_indirect) + by (metis (mono_tags, lifting) P someI_ex) moreover have "algorithm A \ carrier_mat (dim_row A) (dim_col A)" and "Hermite_JNF associates res (algorithm A)" using s unfolding is_sound_HNF'_def Let_def by auto ultimately show "?some_P \ carrier_mat m m \ algorithm A \ carrier_mat m (dim_col A) \ invertible_mat ?some_P \ A = ?some_P * algorithm A \ Hermite_JNF associates res (algorithm A)" unfolding is_sound_HNF_def Let_def m_def by (auto split: prod.split) qed context proper_mod_operation begin corollary is_sound_HNF'_HNF_algorithm: "is_sound_HNF' (HNF_algorithm abs_flag) (range ass_function_euclidean) (\c. range (res_int c))" proof - have "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (HNF_algorithm abs_flag A)" for A using HNF_algorithm_soundness by blast moreover have "HNF_algorithm abs_flag A \ carrier_mat (dim_row A) (dim_col A)" for A by (metis HNF_algorithm_soundness carrier_matI mult_carrier_mat) moreover have "\P. P \ carrier_mat (dim_row A) (dim_row A) \ invertible_mat P \ A = P * HNF_algorithm abs_flag A" for A proof - have "\P. P \ carrier_mat (dim_row A) (dim_row A) \ invertible_mat P \ HNF_algorithm abs_flag A = P * A" using HNF_algorithm_soundness by blast from this obtain P where P: "P \ carrier_mat (dim_row A) (dim_row A)" and inv_P: "invertible_mat P" and H_PA: "HNF_algorithm abs_flag A = P * A" by blast obtain P' where PP': "inverts_mat P P'" and P'P: "inverts_mat P' P" using inv_P unfolding invertible_mat_def by auto have P': "P' \ carrier_mat (dim_row A) (dim_row A) " by (metis P PP' P'P carrier_matD carrier_mat_triv index_mult_mat(3) index_one_mat(3) inverts_mat_def) moreover have inv_P': "invertible_mat P'" by (metis P' P'P PP' carrier_matD(1) carrier_matD(2) invertible_mat_def square_mat.simps) moreover have "A = P' * HNF_algorithm abs_flag A" - by (smt H_PA P P'P assoc_mult_mat calculation(1) carrier_matD(1) carrier_matI inverts_mat_def left_mult_one_mat') + by (smt (verit) H_PA P P'P assoc_mult_mat calculation(1) carrier_matD(1) carrier_matI inverts_mat_def left_mult_one_mat') ultimately show ?thesis by auto qed ultimately show ?thesis unfolding is_sound_HNF'_def Let_def by auto qed corollary is_sound_HNF'_HNF_algorithm_from_HA: "is_sound_HNF' (HNF_algorithm_from_HA) (range ass_function_euclidean) (\c. range (res_int c))" proof - have "Hermite_JNF (range ass_function_euclidean) (\c. range (res_int c)) (HNF_algorithm_from_HA A)" for A using HNF_algorithm_from_HA_soundness by blast moreover have "HNF_algorithm_from_HA A \ carrier_mat (dim_row A) (dim_col A)" for A by (metis HNF_algorithm_from_HA_soundness carrier_matI mult_carrier_mat) moreover have "\P. P \ carrier_mat (dim_row A) (dim_row A) \ invertible_mat P \ A = P * HNF_algorithm_from_HA A" for A proof - have "\P. P \ carrier_mat (dim_row A) (dim_row A) \ invertible_mat P \ HNF_algorithm_from_HA A = P * A" using HNF_algorithm_from_HA_soundness by blast from this obtain P where P: "P \ carrier_mat (dim_row A) (dim_row A)" and inv_P: "invertible_mat P" and H_PA: "HNF_algorithm_from_HA A = P * A" by blast obtain P' where PP': "inverts_mat P P'" and P'P: "inverts_mat P' P" using inv_P unfolding invertible_mat_def by auto have P': "P' \ carrier_mat (dim_row A) (dim_row A) " by (metis P PP' P'P carrier_matD carrier_mat_triv index_mult_mat(3) index_one_mat(3) inverts_mat_def) moreover have inv_P': "invertible_mat P'" by (metis P' P'P PP' carrier_matD(1) carrier_matD(2) invertible_mat_def square_mat.simps) moreover have "A = P' * HNF_algorithm_from_HA A" - by (smt H_PA P P'P assoc_mult_mat calculation(1) carrier_matD(1) carrier_matI inverts_mat_def left_mult_one_mat') + by (smt (verit) H_PA P P'P assoc_mult_mat calculation(1) carrier_matD(1) carrier_matI inverts_mat_def left_mult_one_mat') ultimately show ?thesis by auto qed ultimately show ?thesis unfolding is_sound_HNF'_def Let_def by auto qed end text \Some work to make the algorithm executable\ definition find_non0' :: "nat \ nat \ 'a::comm_ring_1 mat \ nat option" where "find_non0' i k A = (let is = [i ..< dim_row A]; Ais = filter (\j. A $$ (j, k) \ 0) is in case Ais of [] \ None | _ \ Some (Ais!0))" lemma find_non0': assumes A: "A \ carrier_mat m n" and res: "find_non0' i k A = Some j" shows "A $$ (j,k) \ 0" "i \ j" "j < dim_row A" proof - let ?xs = "filter (\j. A $$ (j,k) \ 0) [i ..< dim_row A]" from res[unfolded find_non0'_def Let_def] have xs: "?xs \ []" by (cases ?xs, auto) have j_in_xs: "j \ set ?xs" using res unfolding find_non0'_def Let_def by (metis (no_types, lifting) length_greater_0_conv list.case(2) list.exhaust nth_mem option.simps(1) xs) show "A $$ (j,k) \ 0" "i \ j" "j < dim_row A" using j_in_xs by auto+ qed lemma find_non0'_w_zero_before: assumes A: "A \ carrier_mat m n" and res: "find_non0' i k A = Some j" shows "\j'\{i.. []" by (cases ?xs, auto) have j_in_xs: "j \ set ?xs" using res unfolding find_non0'_def Let_def by (metis (no_types, lifting) length_greater_0_conv list.case(2) list.exhaust nth_mem option.simps(1) xs) have j_xs0: "j = ?xs ! 0" - by (smt res[unfolded find_non0'_def Let_def] list.case(2) list.exhaust option.inject xs) + by (smt (verit) res[unfolded find_non0'_def Let_def] list.case(2) list.exhaust option.inject xs) show "\j'\{i.. 0" have j'j: "j' set ?xs" by (metis (mono_tags, lifting) A Alj' Set.member_filter atLeastLessThan_iff filter_set find_non0'(3) j' nat_SN.gt_trans res set_upt) have l_rw: "[i..j. A $$ (j,k) \ 0) ([i ..j. A $$ (j,k) \ 0) [i .. carrier_mat m n" and res: "find_non0' i k A = Some j" shows "j = (LEAST n. A $$ (n,k) \ 0 \ i\n)" proof (rule Least_equality[symmetric]) show " A $$ (j, k) \ 0 \ i \ j" using A res find_non0'[OF A] by auto show " \y. A $$ (y, k) \ 0 \ i \ y \ j \ y" by (meson A res atLeastLessThan_iff find_non0'_w_zero_before linorder_not_le) qed lemma echelon_form_of_column_k_JNF_code[code]: "echelon_form_of_column_k_JNF bezout (A,i) k = (if (i = dim_row A) \ (\m \ {i..m\{i+1.. ((i = dim_row A) \ (\m \ {i.. \ (\m\{i+1.. 0 \ i \ n)" proof (rule find_non0'_LEAST) have "find_non0' i k A \ None" using True unfolding find_non0'_def Let_def by (auto split: list.split) (metis (mono_tags, lifting) atLeastLessThan_iff atLeastLessThan_upt empty_filter_conv) thus "find_non0' i k A = Some (the (find_non0' i k A))" by auto qed (auto) show ?thesis unfolding echelon_form_of_column_k_JNF_def Let_def f_rw using True by auto next case False then show ?thesis unfolding echelon_form_of_column_k_JNF_def by auto qed subsection \Instantiation of the HNF-algorithm with modulo-operation\ text \We currently use a Boolean flag to indicate whether standard-mod or symmetric modulo should be used.\ lemma sym_mod: "proper_mod_operation sym_mod sym_div" by (unfold_locales, auto simp: sym_mod_sym_div) lemma standard_mod: "proper_mod_operation (mod) (div)" by (unfold_locales, auto, intro HOL.nitpick_unfold(7)) definition HNF_algorithm :: "bool \ int mat \ int mat" where "HNF_algorithm use_sym_mod = (if use_sym_mod then mod_operation.HNF_algorithm sym_mod False else mod_operation.HNF_algorithm (mod) True)" definition HNF_algorithm_from_HA :: "bool \ int mat \ int mat" where "HNF_algorithm_from_HA use_sym_mod = (if use_sym_mod then mod_operation.HNF_algorithm_from_HA sym_mod else mod_operation.HNF_algorithm_from_HA (mod))" corollary is_sound_HNF'_HNF_algorithm: "is_sound_HNF' (HNF_algorithm use_sym_mod) (range ass_function_euclidean) (\c. range (res_int c))" using proper_mod_operation.is_sound_HNF'_HNF_algorithm[OF sym_mod] proper_mod_operation.is_sound_HNF'_HNF_algorithm[OF standard_mod] unfolding HNF_algorithm_def by (cases use_sym_mod, auto) corollary is_sound_HNF'_HNF_algorithm_from_HA: "is_sound_HNF' (HNF_algorithm_from_HA use_sym_mod) (range ass_function_euclidean) (\c. range (res_int c))" using proper_mod_operation.is_sound_HNF'_HNF_algorithm_from_HA[OF sym_mod] proper_mod_operation.is_sound_HNF'_HNF_algorithm_from_HA[OF standard_mod] unfolding HNF_algorithm_from_HA_def by (cases use_sym_mod, auto) (*Examples:*) (*Rectangular matrix (6x4)*) value [code]"let A = mat_of_rows_list 4 ( [[0,3,1,4], [7,1,0,0], [8,0,19,16], [2,0,0,3::int], [9,-3,2,5], [6,3,2,4]]) in show (HNF_algorithm True A)" (*Rectangular matrix (4x6)*) value [code]"let A = mat_of_rows_list 6 ( [[0,3,1,4,8,7], [7,1,0,0,4,1], [8,0,19,16,33,5], [2,0,0,3::int,-5,8]]) in show (HNF_algorithm False A)" (*Singular matrix*) value [code]"let A = mat_of_rows_list 6 ( [[0,3,1,4,8,7], [7,1,0,0,4,1], [8,0,19,16,33,5], [0,3,1,4,8,7], [2,0,0,3::int,-5,8], [2,4,6,8,10,12]]) in show (Determinant.det A, HNF_algorithm True A)" (*Invertible matrix*) value [code]"let A = mat_of_rows_list 6 ( [[0,3,1,4,8,7], [7,1,0,0,4,1], [8,0,19,16,33,5], [5,6,1,2,8,7], [2,0,0,3::int,-5,8], [2,4,6,8,10,12]]) in show (Determinant.det A, HNF_algorithm True A)" end \ No newline at end of file diff --git a/thys/Source_Coding_Theorem/Source_Coding_Theorem.thy b/thys/Source_Coding_Theorem/Source_Coding_Theorem.thy --- a/thys/Source_Coding_Theorem/Source_Coding_Theorem.thy +++ b/thys/Source_Coding_Theorem/Source_Coding_Theorem.thy @@ -1,603 +1,603 @@ (* Title: One Part of Shannon's Source Coding Theorem Author: Quentin Hibon , Lawrence Paulson , 2014 Maintainer: Quentin Hibon *) theory Source_Coding_Theorem imports "HOL-Probability.Information" begin section\Basic types\ type_synonym bit = bool type_synonym bword = "bit list" type_synonym letter = nat type_synonym 'b word = "'b list" type_synonym 'b encoder = "'b word \ bword" type_synonym 'b decoder = "bword \ 'b word option" section\Locale for the source coding theorem\ locale source_code = information_space + fixes fi :: "'b \ real" fixes X :: "'a \ 'b" assumes distr_i: "simple_distributed M X fi" assumes b_val: "b = 2" fixes enc::"'b encoder" fixes dec::"'b decoder" assumes real_code: "dec (enc x) = Some x" "enc w = [] \ w = []" "x \ [] \ enc x = enc [hd x] @ enc (tl x)" section\Source coding theorem, direct: the entropy is a lower bound of the code rate\ context source_code begin subsection\The letter set\ definition L :: "'b set" where "L \ X ` space M" lemma fin_L: "finite L" using L_def distr_i by auto lemma emp_L: "L \ {}" using L_def subprob_not_empty by auto subsection\Codes and words\ abbreviation real_word :: "'b word \ bool" where "real_word w \ (set w \ L)" abbreviation k_words :: "nat \ ('b word) set" where "k_words k \ {w. length w = k \ real_word w}" lemma rw_tail: assumes "real_word w" shows "w = [] \ real_word (tl w)" by (meson assms list.set_sel(2) subset_code(1)) definition code_word_length :: "'e encoder \ 'e \ nat" where "code_word_length e l = length (e [l])" abbreviation cw_len :: "'b \ nat" where "cw_len l \ code_word_length enc l" definition code_rate :: "'e encoder \ ('a \ 'e) \ real" where "code_rate e Xo = expectation (\a. (code_word_length e ((Xo) a)))" lemma fi_pos: "i\ L \ 0 \ fi i" using simple_distributed_nonneg[OF distr_i] L_def by auto lemma (in prob_space) simp_exp_composed: assumes X: "simple_distributed M X Px" shows "expectation (\a. f (X a)) = (\x \ X`space M. f x * Px x)" using distributed_integral[OF simple_distributed[OF X], of f] simple_distributed_nonneg[OF X] lebesgue_integral_count_space_finite[OF simple_distributed_finite[OF X], of "\x. f x * Px x"] by (simp add: ac_simps) lemma cr_rw: "code_rate enc X = (\i \ X ` space M. fi i * cw_len i)" using simp_exp_composed[OF distr_i, of "cw_len"] by (simp add: mult.commute code_rate_def) abbreviation cw_len_concat :: "'b word \ nat" where "cw_len_concat w \ foldr (\x s. (cw_len x) + s) w 0" lemma cw_len_length: "cw_len_concat w = length (enc w)" proof (induction w) case Nil show ?case using real_code by simp case (Cons a w) have "cw_len_concat (a # w) = cw_len a + cw_len_concat w" by simp thus ?case using code_word_length_def real_code Cons by (metis length_append list.distinct(1) list.sel(1) list.sel(3)) qed lemma maj_fold: assumes "\l. l\L \ f l \ bound" assumes "real_word w" shows "foldr (\x s. f x + s) w 0 \ length w * bound" using assms by(induction w) (simp,fastforce) definition max_len :: "nat" where "max_len = Max ((\x. cw_len x) ` L)" lemma max_cw: "l \ L \ cw_len l \ max_len" by (simp add: max_len_def fin_L) subsection\Related to the Kraft theorem\ definition \ :: "real" where "\ = (\i\L. 1 / b ^ (cw_len i))" lemma pos_cw_len: "0 < 1 / b ^ cw_len i" using b_gt_1 by simp lemma \_pos: "0 < \" using emp_L fin_L pos_cw_len sum_pos \_def by metis lemma \_pow: "\ = (\i\L. 1 / b powr cw_len i)" using powr_realpow b_gt_1 by (simp add: \_def) lemma k_words_rel: "k_words (Suc k) = {w. (hd w \ L \ tl w \ k_words k \ w \ [])}" proof fix k show "k_words (Suc k) \ {w. (hd w \ L \ tl w \ k_words k \ w \ [] )}" (is "?l \ ?r") proof fix w assume w_kw: "w \ k_words (Suc k)" hence "real_word w" by simp hence "hd w \ L" by (metis (mono_tags) w_kw hd_in_set list.size(3) mem_Collect_eq nat.distinct(1) subset_code(1)) moreover have "length w = Suc k" using w_kw by simp moreover hence "w \ []" by auto moreover have "real_word (tl w)" using \real_word w\ calculation(3) rw_tail by auto ultimately show "w \ ?r" using w_kw by simp qed next fix k show "k_words (Suc k) \ {w. (hd w \ L \ tl w \ k_words k \ w \ [])}" proof fix w assume asm: "w \ {w. hd w \ L \ tl w \ {w. length w = k \ real_word w} \ w \ []}" hence "hd w \ L \ length (tl w) = k \ real_word (tl w)" by simp hence "real_word w" by (metis empty_iff insert_subset list.collapse list.set(1) set_simps(2) subsetI) moreover hence "length w = Suc k" using asm by auto ultimately show "w \ k_words (Suc k)" by simp qed qed lemma bij_k_words: shows "bij_betw (\wi. Cons (fst wi) (snd wi)) (L \ k_words k) (k_words (Suc k))" unfolding bij_betw_def proof fix k let ?f = "(\wi. Cons (fst wi) (snd wi))" let ?S = "L \ (k_words k)" let ?T = "k_words (Suc k)" show "inj_on ?f ?S" by (simp add: inj_on_def) show "?f`?S = ?T" proof (rule ccontr) assume "?f ` ?S \ ?T" hence "\w. w\ ?T \ w \ ?f`?S" by auto then obtain w where asm: "w\ ?T \ w \ ?f`?S" by blast hence "w = ?f (hd w,tl w)" using k_words_rel by simp moreover have "(hd w,tl w) \ ?S" using k_words_rel asm by simp ultimately have "w \ ?f`?S" by blast thus "False" using asm by simp qed qed lemma finite_k_words: "finite (k_words k)" proof (induct k) case 0 show ?case by simp case (Suc n) thus ?case using bij_k_words bij_betw_finite fin_L by blast qed lemma cartesian_product: fixes f::"('c \ real)" fixes g::"('d \ real)" assumes "finite A" assumes "finite B" shows "(\b\B. g b) * (\a\A. f a) = (\ab\A\B. f (fst ab) * g (snd ab))" using bilinear_times bilinear_sum[where h="(\x y. x * y)" and f="f" and g="g"] assms by (metis (erased, lifting) sum.cong split_beta' Groups.ab_semigroup_mult_class.mult.commute) lemma \_power: shows "\^k = (\w \ (k_words k). 1 / b^(cw_len_concat w))" proof (induct k) case 0 have "k_words 0 = {[]}" by auto thus ?case by simp next case (Suc n) have " \ ^Suc n = \ ^n * \ " by simp also have "\ = (\w \ k_words n. 1 / b^cw_len_concat w) * (\i\L. 1 / b^cw_len i)" using Suc.hyps \_def by auto also have "\ = (\wi \ L \ k_words n. 1/b^cw_len (fst wi) * (1 / b^cw_len_concat (snd wi)))" using fin_L finite_k_words cartesian_product by blast also have "\ = (\wi \ L \ k_words n. 1 / b^(cw_len_concat (snd wi) + cw_len (fst wi)))" by (metis (no_types, lifting) power_add add.commute power_one_over) also have "\ = (\wi \ L \ k_words n. 1 / b^cw_len_concat (fst wi # snd wi))" by (metis (erased, lifting) add.commute comp_apply foldr.simps(2)) also have "\ = (\w \ (k_words (Suc n)). 1 / b^(cw_len_concat w))" using sum.reindex_bij_betw [OF bij_k_words] by fastforce finally show ?case by simp qed lemma bound_len_concat: shows "w \ k_words k \ cw_len_concat w \ k * max_len" using max_cw maj_fold by blast subsection\Inequality of the kraft sum (source coding theorem, direct)\ subsubsection\Sum manipulation lemmas and McMillan theorem\ lemma sum_vimage_proof: fixes g::"nat \ real" assumes "\w. f w < bd" shows "finite S \ (\w\S. g (f w)) = (\ m=0.. S) )* g m)" (is "_ \ _ = (\ m=0.. {0..h::(nat \ real). (\m=0..y\({0..m = 0..m\{0.. F) * g (f x) + g (f x)" by (simp add: semiring_normalization_rules(2), simp add: insert) ultimately have "(\m = 0..m\{0.. real" assumes bounded: "\w. w \ S \ f w < bd" and "0 < bd" assumes finite: "finite S" shows "(\w\S. g (f w)) = (\ m=0.. S) ) * g m)" (is "?s1 = ?s2") proof - let ?ff = "(\x. if x\S then f x else 0)" let ?ss1 = "(\w\S. g (?ff w))" let ?ss2 = "(\ m=0.. S) ) * g m)" have "?s1 =?ss1" by simp moreover have"\m. ?ff -`{m} \ S = f-`{m} \ S" by auto moreover hence "?s2 = ?ss2" by simp moreover have "\w . ?ff w < bd" using assms by simp moreover hence "?ss1 = ?ss2" using sum_vimage_proof[of "?ff"] finite by blast ultimately show "?s1 = ?s2" by metis qed lemma \_rw: "(\w \ (k_words k). 1 / b^(cw_len_concat w)) = (\m=0.. ((cw_len_concat) -` {m})) * (1 / b^m))" (is "?L = ?R") proof - have "\w. w \ k_words k \ cw_len_concat w < Suc ( k * max_len)" by (simp add: bound_len_concat le_imp_less_Suc) moreover have "?R = (\m = 0.. k_words k)) * (1 / b ^ m))" by (metis Int_commute) moreover have "0 < Suc (k*max_len)" by simp ultimately show ?thesis using finite_k_words sum_vimage[where f="cw_len_concat" and g = "\i. 1/ (b^i)"] by fastforce qed definition set_of_k_words_length_m :: "nat \ nat \ 'b word set" where "set_of_k_words_length_m k m = {xk. xk \ k_words k} \ (cw_len_concat)-`{m}" lemma am_inj_code: "inj_on enc ((cw_len_concat)-`{m})" (is "inj_on _ ?s") using inj_on_def[of enc "?s"] real_code by (metis option.inject) lemma img_inc: "enc`cw_len_concat-`{m} \ {bl. length bl = m}" using cw_len_length by auto lemma bool_lists_card: "card {bl::bool list. length bl = m} = b^m" using card_lists_length_eq[of "UNIV::bool set"] by (simp add: b_val) lemma bool_list_fin: "finite {bl::bool list. length bl = m}" using finite_lists_length_eq[of "UNIV::bool set"] by (simp add: b_val) lemma set_of_k_words_bound: shows "card (set_of_k_words_length_m k m) \ b^m" (is "?c \ ?b") proof - have card_w_len_m_bound: "card (cw_len_concat-`{m}) \ b^m" by (metis (no_types, lifting) am_inj_code bool_list_fin bool_lists_card card_image card_mono img_inc of_nat_le_iff) have "set_of_k_words_length_m k m \ (cw_len_concat)-`{m}" by (simp add: set_of_k_words_length_m_def) hence "card (set_of_k_words_length_m k m) \ card ((cw_len_concat)-`{m})" by (metis (no_types, lifting) am_inj_code bool_list_fin card.infinite card_0_eq card_image card_mono empty_iff finite_subset img_inc inf_img_fin_dom) thus ?thesis using card_w_len_m_bound by simp qed lemma empty_set_k_words: assumes "0 < k" shows "set_of_k_words_length_m k 0 = {}" proof(rule ccontr) assume "\ set_of_k_words_length_m k 0 = {}" hence "\x. x \ set_of_k_words_length_m k 0" by auto then obtain x where x_def: "x \ set_of_k_words_length_m k 0" by auto hence "x \ []" unfolding set_of_k_words_length_m_def using assms by auto moreover have "cw_len_concat (hd x#tl x) = cw_len_concat (tl x) + cw_len (hd x)" by (metis add.commute comp_apply foldr.simps(2)) moreover have "enc [(hd x)] \ []" using assms real_code by blast moreover hence "0 < cw_len (hd x)" unfolding code_word_length_def by simp ultimately have "x \ set_of_k_words_length_m k 0" by (simp add:set_of_k_words_length_m_def) thus "False" using x_def by simp qed lemma \_rw2: assumes "0 < k" shows "(\m=0.. (k * max_len)" proof - have "(\m=1.. (\m=1..m. (card (set_of_k_words_length_m k m))/b^m)" "\m. b^m /b^m"] by simp moreover have"(\m=1..m=1..m=1..m = 1.. k * max_len" by (metis One_nat_def card_atLeastLessThan card_eq_sum diff_Suc_Suc real_of_card) thus ?thesis using empty_set_k_words assms by (simp add: sum_shift_lb_Suc0_0_upt split: if_split_asm) qed lemma \_power_bound : assumes "0 < k" shows " \^k \ k * max_len" using assms \_power \_rw \_rw2 by (simp add: set_of_k_words_length_m_def) theorem McMillan : shows "\ \ 1" proof - have ineq: "\k. 0 < k \ \ \ root k k * root k max_len" using \_pos \_power_bound by (metis (no_types, opaque_lifting) not_less of_nat_0_le_iff of_nat_mult power_strict_mono real_root_mult real_root_pos_pos_le real_root_pos_unique real_root_power) hence "0 < max_len \ (\k. root k k * root k max_len) \ 1" by (auto intro!: tendsto_eq_intros LIMSEQ_root LIMSEQ_root_const) moreover have "\n\1. \ \ root n n * root n max_len" using ineq by simp moreover have "max_len = 0 \ \ \ 1" using ineq by fastforce ultimately show " \ \ 1" using LIMSEQ_le_const by blast qed lemma entropy_rw: "\(X) = -(\i \ L. fi i * log b (fi i))" using entropy_simple_distributed[OF distr_i] by (simp add: L_def) subsubsection\Technical lemmas about the logarithm\ lemma log_mult_ext3: "0 \ x \ 0 < y \ 0 < z \ x * log b (x*y*z) = x * log b (x*y) + x * log b z" by(cases "x=0")(simp add: log_mult_eq abs_of_pos distrib_left less_eq_real_def)+ lemma log_mult_ext2: "0 \ x \ 0 < y \ x * log b (x*y) = x * log b x + x * log b y" using log_mult_ext3[where y=1] by simp subsubsection \KL divergence and properties\ definition KL_div ::"'b set \ ('b \ real) \ ('b \ real) \ real" where "KL_div S a d = (\ i \ S. a i * log b (a i / d i))" lemma KL_div_mul: assumes "0 < d" "d \ 1" assumes "\i. i\S \ 0 \ a i" assumes "\i. i\S \ 0 < e i" shows "KL_div S a e \ KL_div S a (\i. e i / d)" unfolding KL_div_def proof - { fix i assume "i\S" hence "a i / (e i / d) \ a i / e i" using assms by (metis (no_types) div_by_1 frac_le less_imp_triv not_less) hence "log b (a i / (e i / d)) \ log b (a i / e i)" using assms(1) by (metis (full_types) b_gt_1 divide_divide_eq_left inverse_divide le_less_linear log_le log_neg_const order_refl times_divide_eq_right zero_less_mult_iff) } thus "(\i\S. a i * log b (a i / (e i / d))) \ (\i\S. a i * log b (a i / e i))" by (meson mult_left_mono assms sum_mono) qed lemma KL_div_pos: fixes a e::"'b \ real" assumes fin: "finite S" assumes nemp: "S \ {}" assumes non_null: "\i. i\S \ 0 < a i" "\i. i\ S \ 0 < e i" assumes sum_a_one: "(\ i \ S. a i) = 1" assumes sum_c_one: "(\ i \ S. e i) = 1" shows "0 \ KL_div S a e" unfolding KL_div_def proof - let ?f = "\i. e i / a i" have f_pos: "\i. i\S \ 0 < ?f i" using non_null by simp have a_pos: "\i. i\ S \ 0 \ a i" using non_null by (simp add: order.strict_implies_order) have "- log b (\i\S. a i * e i / a i) \ (\i\S. a i * - log b (e i / a i))" - using convex_on_sum[OF fin nemp minus_log_convex[OF b_gt_1] convex_real_interval(3) + using convex_on_sum[OF fin nemp minus_log_convex[OF b_gt_1] sum_a_one a_pos, of "\i. e i / a i"] f_pos by simp also have "-log b (\i\S. a i * e i / a i) = -log b (\i\S. e i)" proof - from non_null(1) have "\i. i \ S \ a i * e i / a i = e i" by force thus ?thesis by simp qed finally have "0 \ (\i\S. a i * - log b (e i / a i))" by (simp add: sum_c_one) thus "0 \ (\i\S. a i * log b (a i / e i))" using b_gt_1 log_divide non_null by simp qed lemma KL_div_pos_emp: "0 \ KL_div {} a e" by (simp add: KL_div_def) lemma KL_div_pos_gen: fixes a d::"'b \ real" assumes fin: "finite S" assumes non_null: "\i. i\S \ 0 < a i" "\i. i\ S \ 0 < d i" assumes sum_a_one: "(\ i \ S. a i) = 1" assumes sum_d_one: "(\ i \ S. d i) = 1" shows "0 \ KL_div S a d" using KL_div_pos KL_div_pos_emp assms by metis theorem KL_div_pos2: fixes a d::"'b \ real" assumes fin: "finite S" assumes non_null: "\i. i\S \ 0 \ a i" "\i. i\ S \ 0 < d i" assumes sum_a_one: "(\ i \ S. a i) = 1" assumes sum_c_one: "(\ i \ S. d i) = 1" shows "0 \ KL_div S a d" proof - have "S = (S \ {i. 0 < a i}) \ (S \ {i. 0 = a i})" using non_null(1) by fastforce moreover have "(S \ {i. 0 < a i}) \ (S \ {i. 0 = a i}) = {}" by auto ultimately have eq: "KL_div S a d = KL_div (S \ {i. 0 < a i}) a d + KL_div (S \ {i. 0 = a i}) a d" unfolding KL_div_def by (metis (mono_tags, lifting) fin finite_Un sum.union_disjoint) have "KL_div (S \ {i. 0 = a i}) a d = 0" unfolding KL_div_def by simp hence "KL_div S a d = KL_div (S \ {i. 0 < a i}) a d" using eq by simp moreover have "0 \ KL_div (S \ {i. 0 < a i}) a d" proof(cases "(S \ {i. 0 < a i}) = {}") case True thus ?thesis unfolding KL_div_def by simp next case False let ?c = "\i. d i / (\j \(S \ {i. 0 < a i}). d j)" have 1: "(\i. i \ S \ {i. 0 < a i} \ 0 < a i)" by simp have 2: "(\i. i \ S \ {i. 0 < a i} \ 0 < ?c i)" by (metis False IntD1 divide_pos_pos fin finite_Int non_null(2) sum_pos) have 3: "(\i\ (S \ {i. 0 < a i}). a i) = 1" using sum.cong[of S, of S, of "(\x. if x \ {i. 0 < a i} then a x else 0)", of a] sum.inter_restrict[OF fin, of a] non_null(1) sum_a_one by fastforce have "(\i\S \ {j. 0 < a j}. ?c i) = (\i\S \ {j. 0 < a j}. d i) / (\i\S \ {j. 0 < a j}. d i)" by (metis sum_divide_distrib) hence 5: "(\i\S \ {j. 0 < a j}. ?c i) = 1" using 2 False by force hence "0 \ KL_div (S \ {j. 0 < a j}) a ?c" using KL_div_pos_gen[ OF finite_Int[OF disjI1, of S, of "{j. 0 < a j}"], of a, of ?c ] 1 2 3 by (metis fin) have fstdb: "0 < (\i\S \ {i. 0 < a i}. d i)" using non_null(2) False by (metis Int_Collect fin finite_Int sum_pos) have 6: "0 \ KL_div (S \ {i. 0 < a i}) a (\i. d i / (\i\(S \ {i. 0 < a i}). d i))" using 2 3 5 KL_div_pos_gen[ OF finite_Int[OF disjI1, OF fin], of "{i. 0 < a i}", of "a", of "?c" ] by simp hence "KL_div (S \ {j. 0 < a j}) a (\i. d i / (\i\(S \ {i. 0 < a i}). d i)) \ KL_div (S \ {j. 0 < a j}) a d" using non_null sum.inter_restrict[OF fin, of d, of "{i. 0 < a i}"] sum_mono[of S, of "(\x. if x \ {i. 0 < a i} then d x else 0)", of d] non_null(2) sum_c_one non_null(2) fstdb KL_div_mul by force moreover have "0 \ KL_div (S \ {j. 0 < a j}) a (\i. d i / (\i\(S \ {i. 0 < a i}). d i))" using KL_div_pos_gen[ OF finite_Int[OF disjI1, OF fin]] using 2 3 5 by fastforce ultimately show "0 \ KL_div (S \ {j. 0 < a j}) a d" by simp qed ultimately show ?thesis by simp qed lemma sum_div_1: fixes f::"'b \ 'c::field" assumes "(\i\A. f i) \ 0" shows "(\i\A. f i / (\j\A. f j)) = 1" by (metis (no_types) assms right_inverse_eq sum_divide_distrib) theorem rate_lower_bound: shows "\(X) \ code_rate enc X" proof - let ?cr = "code_rate enc X" let ?r = "(\i. 1 / ((b powr cw_len i) * \))" have pos_pi: "\i. i \ L \ 0 \ fi i" using fi_pos by simp { fix i assume "i \ L" hence "fi i * (log b (1 / (1 / b powr (cw_len i))) + log b (fi i)) = fi i * log b (fi i / (1 / b powr (cw_len i)))" using log_mult_ext2 [OF pos_pi, of i] b_gt_1 by simp (simp add: algebra_simps) } hence eqpi: "\i. i\ L \ fi i * (log b (1 / (1 / b powr (cw_len i))) + log b (fi i)) = fi i * log b (fi i / (1 / b powr (cw_len i)))" by simp have sum_one_L: "(\ i \ L. fi i) = 1" using simple_distributed_sum_space[OF distr_i] by (simp add: L_def) { fix i assume "i \ L" hence h1: "0 \ fi i" using pos_pi by blast have h2: "0 < \ / (1/b powr cw_len i)" using b_gt_1 \_pos by auto have h3: "0 < 1 / \" using \_pos by simp have "fi i * log b (fi i * \ / (1/b powr cw_len i) * (1/ \)) = fi i * log b (fi i * \ / (1/b powr cw_len i)) + fi i * log b (1/ \)" using log_mult_ext3[OF h1 h2 h3] by (metis times_divide_eq_right) } hence big_eq: "\i. i \ L \ fi i * log b (fi i * \ / (1/b powr cw_len i) * (1 / \)) = fi i * log b (fi i * \ / (1/b powr cw_len i)) + fi i * log b (1 / \)" by (simp add: inverse_eq_divide) have 1: "?cr - \(X) = (\i \ L. fi i * cw_len i) + (\i \ L. fi i * log b (fi i))" using \_def entropy_rw cr_rw L_def by simp also have 2: "(\i\L. fi i * cw_len i) = (\i \ L. fi i * (-log b (1/(b powr (cw_len i)))))" using b_gt_1 log_divide by simp also have "\ = -1 * (\i \ L. fi i * (log b (1/(b powr (cw_len i)))))" using sum_distrib_left[of "-1" "(\i. fi i * (- 1 * log b (1 / b powr (cw_len i))))" L] by simp finally have "?cr - \(X) = -(\i \ L. fi i * log b (1/b powr cw_len i)) + (\i \ L. fi i * log b (fi i))" by simp have "?cr - \(X) = (\i \ L. fi i * ((log b (1/ (1/(b powr (cw_len i))))) + log b (fi i)))" using b_gt_1 1 by (simp add: distrib_left sum.distrib) also have "\ = (\i \ L. fi i *((log b (fi i / (1/(b powr (cw_len i)))))))" using Finite_Cartesian_Product.sum_cong_aux[OF eqpi] by simp also from big_eq have "\ = (\i\L. fi i * (log b (fi i * \ / (1 / b powr (cw_len i))))) + (\i \ L. fi i) * log b (1/ \)" using \_pos by (simp add: sum_distrib_right sum.distrib) also have "\ = (\i\L. fi i * (log b (fi i * \ / (1 / b powr (cw_len i))))) - log b (\)" using \_pos by (simp add: log_inverse_eq divide_inverse sum_one_L) also have "\ = (\ i \ L. fi i * log b (fi i / ?r i)) - log b (\)" by (metis (mono_tags, opaque_lifting) divide_divide_eq_left divide_divide_eq_right) also have "\ = KL_div L fi ?r - log b ( \)" using b_gt_1 \_pos log_inverse KL_div_def by simp also have "\ = KL_div L fi ?r + log b (1 / \)" using log_inverse b_val \_pos by (simp add: inverse_eq_divide) finally have code_ent_kl_log: "?cr - \(X) = KL_div L fi ?r + log b (1 / \)" by simp have "(\i\L. ?r i) = 1" using sum_div_1[of "\i. 1 / (b powr (cw_len i))"] \_pos \_pow by simp moreover have "\i. 0 < ?r i" using b_gt_1 \_pos by simp moreover have "(\i\L. fi i) = 1" using sum_one_L by simp ultimately have "0 \ KL_div L fi ?r" using KL_div_pos2[OF fin_L fi_pos] by simp hence "log b (1 / \) \ ?cr - \(X)" using code_ent_kl_log by simp moreover from McMillan have "0 \ log b (1 / \)" using \_pos by (simp add: b_gt_1) ultimately show ?thesis by simp qed end end