diff --git a/thys/LLL_Basis_Reduction/Gram_Schmidt_2.thy b/thys/LLL_Basis_Reduction/Gram_Schmidt_2.thy --- a/thys/LLL_Basis_Reduction/Gram_Schmidt_2.thy +++ b/thys/LLL_Basis_Reduction/Gram_Schmidt_2.thy @@ -1,2823 +1,2820 @@ (* Authors: Ralph Bottesch Jose Divasón Maximilian Haslbeck Sebastiaan Joosten René Thiemann Akihisa Yamada License: BSD *) section \Gram-Schmidt\ theory Gram_Schmidt_2 imports Jordan_Normal_Form.Gram_Schmidt Jordan_Normal_Form.Show_Matrix Jordan_Normal_Form.Matrix_Impl Norms Int_Rat_Operations begin (* TODO: Documentation and add references to computer algebra book *) no_notation Group.m_inv ("inv\ _" [81] 80) (* TODO: Is a function like this already in the library find_index is used to rewrite the sumlists in the lattice_of definition to finsums *) fun find_index :: "'b list \ 'b \ nat" where "find_index [] _ = 0" | "find_index (x#xs) y = (if x = y then 0 else find_index xs y + 1)" lemma find_index_not_in_set: "x \ set xs \ find_index xs x = length xs" by (induction xs) auto lemma find_index_in_set: "x \ set xs \ xs ! (find_index xs x) = x" by (induction xs) auto lemma find_index_inj: "inj_on (find_index xs) (set xs)" by (induction xs) (auto simp add: inj_on_def) lemma find_index_leq_length: "find_index xs x < length xs \ x \ set xs" by (induction xs) (auto) (* TODO: move *) lemma rev_unsimp: "rev xs @ (r # rs) = rev (r#xs) @ rs" by(induct xs,auto) (* TODO: unify *) lemma corthogonal_is_orthogonal[simp]: "corthogonal (xs :: 'a :: trivial_conjugatable_ordered_field vec list) = orthogonal xs" unfolding corthogonal_def orthogonal_def by simp (* TODO: move *) context vec_module begin definition lattice_of :: "'a vec list \ 'a vec set" where "lattice_of fs = range (\ c. sumlist (map (\ i. of_int (c i) \\<^sub>v fs ! i) [0 ..< length fs]))" lemma lattice_of_finsum: assumes "set fs \ carrier_vec n" shows "lattice_of fs = range (\ c. finsum V (\ i. of_int (c i) \\<^sub>v fs ! i) {0 ..< length fs})" proof - have "sumlist (map (\ i. of_int (c i) \\<^sub>v fs ! i) [0 ..< length fs]) = finsum V (\ i. of_int (c i) \\<^sub>v fs ! i) {0 ..< length fs}" for c using assms by (subst sumlist_map_as_finsum) (fastforce)+ then show ?thesis unfolding lattice_of_def by auto qed lemma in_latticeE: assumes "f \ lattice_of fs" obtains c where "f = sumlist (map (\ i. of_int (c i) \\<^sub>v fs ! i) [0 ..< length fs])" using assms unfolding lattice_of_def by auto lemma in_latticeI: assumes "f = sumlist (map (\ i. of_int (c i) \\<^sub>v fs ! i) [0 ..< length fs])" shows "f \ lattice_of fs" using assms unfolding lattice_of_def by auto lemma finsum_over_indexes_to_vectors: assumes "set vs \ carrier_vec n" "l = length vs" shows "\c. (\\<^bsub>V\<^esub>x\{0..\<^sub>v vs ! x) = (\\<^bsub>V\<^esub>v\set vs. of_int (c v) \\<^sub>v v)" using assms proof (induction l arbitrary: vs) case (Suc l) then obtain vs' v where vs'_def: "vs = vs' @ [v]" by (metis Zero_not_Suc length_0_conv rev_exhaust) have c: "\c. (\\<^bsub>V\<^esub>i\{0..\<^sub>v vs' ! i) = (\\<^bsub>V\<^esub>v\set vs'. of_int (c v) \\<^sub>v v)" using Suc vs'_def by (auto) then obtain c where c_def: "(\\<^bsub>V\<^esub>x\{0..\<^sub>v vs' ! x) = (\\<^bsub>V\<^esub>v\set vs'. of_int (c v) \\<^sub>v v)" by blast have "(\\<^bsub>V\<^esub>x\{0..\<^sub>v vs ! x) = of_int (g l) \\<^sub>v vs ! l + (\\<^bsub>V\<^esub>x\{0..\<^sub>v vs ! x)" using Suc by (subst finsum_insert[symmetric]) (fastforce intro!: finsum_cong')+ also have "vs = vs' @ [v]" using vs'_def by simp also have "(\\<^bsub>V\<^esub>x\{0..\<^sub>v (vs' @ [v]) ! x) = (\\<^bsub>V\<^esub>x\{0..\<^sub>v vs' ! x)" using Suc vs'_def by (intro finsum_cong') (auto simp add: in_mono append_Cons_nth_left) also note c_def also have "(vs' @ [v]) ! l = v" using Suc vs'_def by auto also have "\d'. of_int (g l) \\<^sub>v v + (\\<^bsub>V\<^esub>v\set vs'. of_int (c v) \\<^sub>v v) = (\\<^bsub>V\<^esub>v\set vs. of_int (d' v) \\<^sub>v v)" proof (cases "v \ set vs'") case True then have I: "set vs' = insert v (set vs' - {v})" by blast define c' where "c' x = (if x = v then c x + g l else c x)" for x have "of_int (g l) \\<^sub>v v + (\\<^bsub>V\<^esub>v\set vs'. of_int (c v) \\<^sub>v v) = of_int (g l) \\<^sub>v v + (of_int (c v) \\<^sub>v v + (\\<^bsub>V\<^esub>v\set vs' - {v}. of_int (c v) \\<^sub>v v))" using Suc vs'_def by (subst I, subst finsum_insert) fastforce+ also have "\ = of_int (g l) \\<^sub>v v + of_int (c v) \\<^sub>v v + (\\<^bsub>V\<^esub>v\set vs' - {v}. of_int (c v) \\<^sub>v v)" using Suc vs'_def by (subst a_assoc) (auto intro!: finsum_closed) also have "of_int (g l) \\<^sub>v v + of_int (c v) \\<^sub>v v = of_int (c' v) \\<^sub>v v" unfolding c'_def by (auto simp add: add_smult_distrib_vec) also have "(\\<^bsub>V\<^esub>v\set vs' - {v}. of_int (c v) \\<^sub>v v) = (\\<^bsub>V\<^esub>v\set vs' - {v}. of_int (c' v) \\<^sub>v v)" using Suc vs'_def unfolding c'_def by (intro finsum_cong') (auto) also have "of_int (c' v) \\<^sub>v v + (\\<^bsub>V\<^esub>v\set vs' - {v}. of_int (c' v) \\<^sub>v v) = (\\<^bsub>V\<^esub>v\insert v (set vs'). of_int (c' v) \\<^sub>v v)" using Suc vs'_def by (subst finsum_insert[symmetric]) (auto) finally show ?thesis using vs'_def by force next case False define c' where "c' x = (if x = v then g l else c x)" for x have "of_int (g l) \\<^sub>v v + (\\<^bsub>V\<^esub>v\set vs'. of_int (c v) \\<^sub>v v) = of_int (c' v) \\<^sub>v v + (\\<^bsub>V\<^esub>v\set vs'. of_int (c v) \\<^sub>v v)" unfolding c'_def by simp also have "(\\<^bsub>V\<^esub>v\set vs'. of_int (c v) \\<^sub>v v) = (\\<^bsub>V\<^esub>v\set vs'. of_int (c' v) \\<^sub>v v)" unfolding c'_def using Suc False vs'_def by (auto intro!: finsum_cong') also have "of_int (c' v) \\<^sub>v v + (\\<^bsub>V\<^esub>v\set vs'. of_int (c' v) \\<^sub>v v) = (\\<^bsub>V\<^esub>v\insert v (set vs'). of_int (c' v) \\<^sub>v v)" using False Suc vs'_def by (subst finsum_insert[symmetric]) (auto) also have "(\\<^bsub>V\<^esub>v\set vs'. of_int (c' v) \\<^sub>v v) = (\\<^bsub>V\<^esub>v\set vs'. of_int (c v) \\<^sub>v v)" unfolding c'_def using False Suc vs'_def by (auto intro!: finsum_cong') finally show ?thesis using vs'_def by auto qed finally show ?case unfolding vs'_def by blast qed (auto) lemma lattice_of_altdef: assumes "set vs \ carrier_vec n" shows "lattice_of vs = range (\c. \\<^bsub>V\<^esub>v\set vs. of_int (c v) \\<^sub>v v)" proof - have "v \ lattice_of vs" if "v \ range (\c. \\<^bsub>V\<^esub>v\set vs. of_int (c v) \\<^sub>v v)" for v proof - obtain c where v: "v = (\\<^bsub>V\<^esub>v\set vs. of_int (c v) \\<^sub>v v)" using \v \ range (\c. \\<^bsub>V\<^esub>v\set vs. of_int (c v) \\<^sub>v v)\ by (auto) define c' where "c' i = (if find_index vs (vs ! i) = i then c (vs ! i) else 0)" for i have "v = (\\<^bsub>V\<^esub>v\set vs. of_int (c' (find_index vs v)) \\<^sub>v vs ! (find_index vs v))" unfolding v using assms by (auto intro!: finsum_cong' simp add: c'_def find_index_in_set in_mono) also have "\ = (\\<^bsub>V\<^esub>i\find_index vs ` (set vs). of_int (c' i) \\<^sub>v vs ! i)" using assms find_index_in_set find_index_inj by (subst finsum_reindex) fastforce+ also have "\ = (\\<^bsub>V\<^esub>i\set [0..\<^sub>v vs ! i)" proof - have "i \ find_index vs ` set vs" if "i < length vs" "find_index vs (vs ! i) = i" for i using that by (metis imageI nth_mem) then show ?thesis unfolding c'_def using find_index_leq_length assms by (intro add.finprod_mono_neutral_cong_left) (auto simp add: in_mono find_index_leq_length) qed also have "\ = sumlist (map (\i. of_int (c' i) \\<^sub>v vs ! i) [0.. range (\c. \\<^bsub>V\<^esub>v\set vs. of_int (c v) \\<^sub>v v)" if "v \ lattice_of vs" for v proof - obtain c where "v = sumlist (map (\i. of_int (c i) \\<^sub>v vs ! i) [0..v \ lattice_of vs\ unfolding lattice_of_def by (auto) also have "\ = (\\<^bsub>V\<^esub>x\{0..\<^sub>v vs ! x)" using that assms by (subst sumlist_map_as_finsum) fastforce+ also obtain d where "\ = (\\<^bsub>V\<^esub>v\set vs. of_int (d v) \\<^sub>v v)" using finsum_over_indexes_to_vectors assms by blast finally show ?thesis by blast qed ultimately show ?thesis by fastforce qed lemma basis_in_latticeI: assumes fs: "set fs \ carrier_vec n" and "f \ set fs" shows "f \ lattice_of fs" proof - define c :: "'a vec \ int" where "c v = (if v = f then 1 else 0)" for v have "f = (\\<^bsub>V\<^esub>v\{f}. of_int (c v) \\<^sub>v v)" using assms by (auto simp add: c_def) also have "\ = (\\<^bsub>V\<^esub>v\set fs. of_int (c v) \\<^sub>v v)" using assms by (intro add.finprod_mono_neutral_cong_left) (auto simp add: c_def) finally show ?thesis using assms lattice_of_altdef by blast qed lemma lattice_of_eq_set: assumes "set fs = set gs" "set fs \ carrier_vec n" shows "lattice_of fs = lattice_of gs" using assms lattice_of_altdef by simp lemma lattice_of_swap: assumes fs: "set fs \ carrier_vec n" and ij: "i < length fs" "j < length fs" "i \ j" and gs: "gs = fs[ i := fs ! j, j := fs ! i]" shows "lattice_of gs = lattice_of fs" using assms mset_swap by (intro lattice_of_eq_set) auto lemma lattice_of_add: assumes fs: "set fs \ carrier_vec n" and ij: "i < length fs" "j < length fs" "i \ j" and gs: "gs = fs[ i := fs ! i + of_int l \\<^sub>v fs ! j]" shows "lattice_of gs = lattice_of fs" proof - { fix i j l and fs :: "'a vec list" assume *: "i < j" "j < length fs" and fs: "set fs \ carrier_vec n" note * = ij(1) * let ?gs = "fs[ i := fs ! i + of_int l \\<^sub>v fs ! j]" let ?len = "[0.. i. i < length fs \ fs ! i \ carrier_vec n" unfolding set_conv_nth by auto from fs have fsd: "\ i. i < length fs \ dim_vec (fs ! i) = n" by auto from fsd[of i] fsd[of j] * have fsd: "dim_vec (fs ! i) = n" "dim_vec (fs ! j) = n" by auto { fix f assume "f \ lattice_of fs" from in_latticeE[OF this, unfolded len] obtain c where f: "f = sumlist (map (\i. of_int (c i) \\<^sub>v fs ! i) ?len)" by auto define sc where "sc = (\ xs. sumlist (map (\i. of_int (c i) \\<^sub>v fs ! i) xs))" define d where "d = (\ k. if k = j then c j - c i * l else c k)" define sd where "sd = (\ xs. sumlist (map (\i. of_int (d i) \\<^sub>v ?gs ! i) xs))" have isc: "set is \ {0 ..< length fs} \ sc is \ carrier_vec n" for "is" unfolding sc_def by (intro sumlist_carrier, auto simp: fs) have isd: "set is \ {0 ..< length fs} \ sd is \ carrier_vec n" for "is" unfolding sd_def using * by (intro sumlist_carrier, auto, rename_tac k, case_tac "k = i", auto simp: fs) let ?a = "sc [0.. ?CC" "?b \ ?CC" "?c \ ?CC" "?d \ ?CC" "?e \ ?CC" using * by (auto intro: isc) have AE: "?A \ ?CC" "?B \ ?CC" "?C \ ?CC" "?D \ ?CC" "?E \ ?CC" using * by (auto intro: isd) have sc_sd: "{i,j} \ set is \ {} \ sc is = sd is" for "is" unfolding sc_def sd_def by (rule arg_cong[of _ _ sumlist], rule map_cong, auto simp: d_def, rename_tac k, case_tac "i = k", auto) have "f = ?a + (?b + (?c + (?d + ?e)))" unfolding f map_append sc_def using fs * by ((subst sumlist_append, force, force)+, simp) also have "\ = ?a + ((?b + ?d) + (?c + ?e))" using ae by auto also have "\ = ?A + ((?b + ?d) + (?C + ?E))" using * by (auto simp: sc_sd) also have "?b + ?d = ?B + ?D" unfolding sd_def sc_def d_def sumlist_def by (rule eq_vecI, insert * fsd, auto simp: algebra_simps) finally have "f = ?A + (?B + (?C + (?D + ?E)))" using AE by auto also have "\ = sumlist (map (\i. of_int (d i) \\<^sub>v ?gs ! i) ?len)" unfolding f map_append sd_def using fs * by ((subst sumlist_append, force, force)+, simp) also have "\ = sumlist (map (\i. of_int (d i) \\<^sub>v ?gs ! i) [0 ..< length ?gs])" unfolding len[symmetric] by simp finally have "f = sumlist (map (\i. of_int (d i) \\<^sub>v ?gs ! i) [0 ..< length ?gs])" . from in_latticeI[OF this] have "f \ lattice_of ?gs" . } hence "lattice_of fs \ lattice_of ?gs" by blast } note main = this { fix i j and fs :: "'a vec list" assume *: "i < j" "j < length fs" and fs: "set fs \ carrier_vec n" let ?gs = "fs[ i := fs ! i + of_int l \\<^sub>v fs ! j]" define gs where "gs = ?gs" from main[OF * fs, of l, folded gs_def] have one: "lattice_of fs \ lattice_of gs" . have *: "i < j" "j < length gs" "set gs \ carrier_vec n" using * fs unfolding gs_def set_conv_nth by (auto, rename_tac k, case_tac "k = i", (force intro!: add_carrier_vec)+) from fs have fs: "\ i. i < length fs \ fs ! i \ carrier_vec n" unfolding set_conv_nth by auto from fs have fsd: "\ i. i < length fs \ dim_vec (fs ! i) = n" by auto from fsd[of i] fsd[of j] * have fsd: "dim_vec (fs ! i) = n" "dim_vec (fs ! j) = n" by (auto simp: gs_def) from main[OF *, of "-l"] have "lattice_of gs \ lattice_of (gs[i := gs ! i + of_int (- l) \\<^sub>v gs ! j])" . also have "gs[i := gs ! i + of_int (- l) \\<^sub>v gs ! j] = fs" unfolding gs_def by (rule nth_equalityI, auto, insert * fsd, rename_tac k, case_tac "k = i", auto) ultimately have "lattice_of fs = lattice_of ?gs" using one unfolding gs_def by auto } note main = this show ?thesis proof (cases "i < j") case True from main[OF this ij(2) fs] show ?thesis unfolding gs by simp next case False with ij have ji: "j < i" by auto define hs where "hs = fs[i := fs ! j, j := fs ! i]" define ks where "ks = hs[j := hs ! j + of_int l \\<^sub>v hs ! i]" from ij fs have ij': "i < length hs" "set hs \ carrier_vec n" unfolding hs_def by auto hence ij'': "set ks \ carrier_vec n" "i < length ks" "j < length ks" "i \ j" using ji unfolding ks_def set_conv_nth by (auto, rename_tac k, case_tac "k = i", force, case_tac "k = j", (force intro!: add_carrier_vec)+) from lattice_of_swap[OF fs ij refl] have "lattice_of fs = lattice_of hs" unfolding hs_def by auto also have "\ = lattice_of ks" using main[OF ji ij'] unfolding ks_def . also have "\ = lattice_of (ks[i := ks ! j, j := ks ! i])" by (rule sym, rule lattice_of_swap[OF ij'' refl]) also have "ks[i := ks ! j, j := ks ! i] = gs" unfolding gs ks_def hs_def by (rule nth_equalityI, insert ij, auto, rename_tac k, case_tac "k = i", force, case_tac "k = j", auto) finally show ?thesis by simp qed qed definition "orthogonal_complement W = {x. x \ carrier_vec n \ (\y \ W. x \ y = 0)}" lemma orthogonal_complement_subset: assumes "A \ B" shows "orthogonal_complement B \ orthogonal_complement A" unfolding orthogonal_complement_def using assms by auto end context vec_space begin lemma in_orthogonal_complement_span[simp]: assumes [intro]:"S \ carrier_vec n" shows "orthogonal_complement (span S) = orthogonal_complement S" proof show "orthogonal_complement (span S) \ orthogonal_complement S" by(fact orthogonal_complement_subset[OF in_own_span[OF assms]]) {fix x :: "'a vec" fix a fix A :: "'a vec set" assume x [intro]:"x \ carrier_vec n" and f: "finite A" and S:"A \ S" assume i0:"\y\S. x \ y = 0" have "x \ lincomb a A = 0" unfolding comm_scalar_prod[OF x lincomb_closed[OF subset_trans[OF S assms]]] proof(insert S,atomize(full),rule finite_induct[OF f],goal_cases) case 1 thus ?case using assms x by force next case (2 f F) { assume i:"insert f F \ S" hence F:"F \ S" and f: "f \ S" by auto from F f assms have [intro]:"F \ carrier_vec n" and fc[intro]:"f \ carrier_vec n" and [intro]:"x \ F \ x \ carrier_vec n" for x by auto have laf:"lincomb a F \ x = 0" using F 2 by auto have [simp]:"(\u\F. (a u \\<^sub>v u) \ x) = 0" by(insert laf[unfolded lincomb_def],atomize(full),subst finsum_scalar_prod_sum) auto from f i0 have [simp]:"f \ x = 0" by (subst comm_scalar_prod) auto from lincomb_closed[OF subset_trans[OF i assms]] have "lincomb a (insert f F) \ x = 0" unfolding lincomb_def apply(subst finsum_scalar_prod_sum,force,force) using 2(1,2) smult_scalar_prod_distrib[OF fc x] by auto } thus ?case by auto qed } thus "orthogonal_complement S \ orthogonal_complement (span S)" unfolding orthogonal_complement_def span_def by auto qed end context cof_vec_space begin definition lin_indpt_list :: "'a vec list \ bool" where "lin_indpt_list fs = (set fs \ carrier_vec n \ distinct fs \ lin_indpt (set fs))" definition basis_list :: "'a vec list \ bool" where "basis_list fs = (set fs \ carrier_vec n \ length fs = n \ carrier_vec n \ span (set fs))" lemma upper_triangular_imp_lin_indpt_list: assumes A: "A \ carrier_mat n n" and tri: "upper_triangular A" and diag: "0 \ set (diag_mat A)" shows "lin_indpt_list (rows A)" using upper_triangular_imp_distinct[OF assms] using upper_triangular_imp_lin_indpt_rows[OF assms] A unfolding lin_indpt_list_def by (auto simp: rows_def) lemma basis_list_basis: assumes "basis_list fs" shows "distinct fs" "lin_indpt (set fs)" "basis (set fs)" proof - from assms[unfolded basis_list_def] have len: "length fs = n" and C: "set fs \ carrier_vec n" and span: "carrier_vec n \ span (set fs)" by auto show b: "basis (set fs)" proof (rule dim_gen_is_basis[OF finite_set C]) show "card (set fs) \ dim" unfolding dim_is_n unfolding len[symmetric] by (rule card_length) show "span (set fs) = carrier_vec n" using span C by auto qed thus "lin_indpt (set fs)" unfolding basis_def by auto show "distinct fs" proof (rule ccontr) assume "\ distinct fs" hence "card (set fs) < length fs" using antisym_conv1 card_distinct card_length by auto also have "\ = dim" unfolding len dim_is_n .. finally have "card (set fs) < dim" by auto also have "\ \ card (set fs)" using span finite_set[of fs] using b basis_def gen_ge_dim by auto finally show False by simp qed qed lemma basis_list_imp_lin_indpt_list: assumes "basis_list fs" shows "lin_indpt_list fs" using basis_list_basis[OF assms] assms unfolding lin_indpt_list_def basis_list_def by auto lemma basis_det_nonzero: assumes db:"basis (set G)" and len:"length G = n" shows "det (mat_of_rows n G) \ 0" proof - have M_car1:"mat_of_rows n G \ carrier_mat n n" using assms by auto hence M_car:"(mat_of_rows n G)\<^sup>T \ carrier_mat n n" by auto have li:"lin_indpt (set G)" and inc_2:"set G \ carrier_vec n" and issp:"carrier_vec n = span (set G)" and RG_in_carr:"\i. i < length G \ G ! i \ carrier_vec n" using assms[unfolded basis_def] by auto hence "basis_list G" unfolding basis_list_def using len by auto from basis_list_basis[OF this] have di:"distinct G" by auto have "det ((mat_of_rows n G)\<^sup>T) \ 0" unfolding det_0_iff_vec_prod_zero[OF M_car] proof assume "\v. v \ carrier_vec n \ v \ 0\<^sub>v n \ (mat_of_rows n G)\<^sup>T *\<^sub>v v = 0\<^sub>v n" then obtain v where v:"v \ span (set G)" "v \ 0\<^sub>v n" "(mat_of_rows n G)\<^sup>T *\<^sub>v v = 0\<^sub>v n" unfolding issp by blast from finite_in_span[OF finite_set inc_2 v(1)] obtain a where aA: "v = lincomb a (set G)" by blast from v(1,2)[folded issp] obtain i where i:"v $ i \ 0" "i < n" by fastforce hence inG:"G ! i \ set G" using len by auto have di2: "distinct [0..l. \i \ set [0..ia\[0..v v = 0\<^sub>v n" unfolding transpose_mat_of_rows by auto with mat_of_cols_mult_as_finsum[OF v(1)[folded issp len] RG_in_carr] have f:"lincomb f (set G) = 0\<^sub>v n" unfolding len f_def by auto note [simp] = list_trisect[OF i(2)[folded len],unfolded len] note x = i(2)[folded len] have [simp]:"(\x\[0..x\[Suc i.. 0" unfolding f' by auto from lin_dep_crit[OF finite_set subset_refl TrueI inG this f] have "lin_dep (set G)". thus False using li by auto qed thus det0:"det (mat_of_rows n G) \ 0" by (unfold det_transpose[OF M_car1]) qed lemma lin_indpt_list_add_vec: assumes i: "j < length us" "i < length us" "i \ j" and indep: "lin_indpt_list us" shows "lin_indpt_list (us [i := us ! i + c \\<^sub>v us ! j])" (is "lin_indpt_list ?V") proof - from indep[unfolded lin_indpt_list_def] have us: "set us \ carrier_vec n" and dist: "distinct us" and indep: "lin_indpt (set us)" by auto let ?E = "set us - {us ! i}" let ?us = "insert (us ! i) ?E" let ?v = "us ! i + c \\<^sub>v us ! j" from us i have usi: "us ! i \ carrier_vec n" "us ! i \ ?E" "us ! i \ set us" and usj: "us ! j \ carrier_vec n" by auto from usi usj have v: "?v \ carrier_vec n" by auto have fin: "finite ?E" by auto have id: "set us = insert (us ! i) (set us - {us ! i})" using i(2) by auto from dist i have diff': "us ! i \ us ! j" unfolding distinct_conv_nth by auto from subset_li_is_li[OF indep] have indepE: "lin_indpt ?E" by auto have Vid: "set ?V = insert ?v ?E" using set_update_distinct[OF dist i(2)] by auto have E: "?E \ carrier_vec n" using us by auto have V: "set ?V \ carrier_vec n" using us v unfolding Vid by auto from dist i have diff: "us ! i \ us ! j" unfolding distinct_conv_nth by auto have vspan: "?v \ span ?E" proof assume mem: "?v \ span ?E" from diff i have "us ! j \ ?E" by auto hence "us ! j \ span ?E" using E by (metis span_mem) hence "- c \\<^sub>v us ! j \ span ?E" using smult_in_span[OF E] by auto from span_add1[OF E mem this] have "?v + (- c \\<^sub>v us ! j) \ span ?E" . also have "?v + (- c \\<^sub>v us ! j) = us ! i" using usi usj by auto finally have mem: "us ! i \ span ?E" . from in_spanE[OF this] obtain a A where lc: "us ! i = lincomb a A" and A: "finite A" "A \ set us - {us ! i}" by auto let ?a = "a (us ! i := -1)" let ?A = "insert (us ! i) A" from A have fin: "finite ?A" by auto have lc: "lincomb ?a A = us ! i" unfolding lc by (rule lincomb_cong, insert A us lc, auto) have "lincomb ?a ?A = 0\<^sub>v n" by (subst lincomb_insert2[OF A(1)], insert A us lc usi diff, auto) from not_lindepD[OF indep _ _ _ this] A usi show False by auto qed hence vmem: "?v \ ?E" using span_mem[OF E, of ?v] by auto from lin_dep_iff_in_span[OF E indepE v this] vspan have indep1: "lin_indpt (set ?V)" unfolding Vid by auto from vmem dist have "distinct ?V" by (metis distinct_list_update) with indep1 V show ?thesis unfolding lin_indpt_list_def by auto qed lemma scalar_prod_lincomb_orthogonal: assumes ortho: "orthogonal gs" and gs: "set gs \ carrier_vec n" shows "k \ length gs \ sumlist (map (\ i. g i \\<^sub>v gs ! i) [0 ..< k]) \ sumlist (map (\ i. h i \\<^sub>v gs ! i) [0 ..< k]) = sum_list (map (\ i. g i * h i * (gs ! i \ gs ! i)) [0 ..< k])" proof (induct k) case (Suc k) note ortho = orthogonalD[OF ortho] let ?m = "length gs" from gs Suc(2) have gsi[simp]: "\ i. i \ k \ gs ! i \ carrier_vec n" by auto from Suc have kn: "k \ ?m" and k: "k < ?m" by auto let ?v1 = "sumlist (map (\i. g i \\<^sub>v gs ! i) [0..i. g i \\<^sub>v gs ! i) [0..i. h i \\<^sub>v gs ! i) [0.. carrier_vec n" by (rule sumlist_carrier, insert Suc(2), auto) have v2: "?v2 \ carrier_vec n" by (insert Suc(2), auto) have w1: "?w1 \ carrier_vec n" by (rule sumlist_carrier, insert Suc(2), auto) have w2: "?w2 \ carrier_vec n" by (insert Suc(2), auto) have gsk: "gs ! k \ carrier_vec n" by simp have v12: "?v1 + ?v2 \ carrier_vec n" using v1 v2 by auto have w12: "?w1 + ?w2 \ carrier_vec n" using w1 w2 by auto have 0: "\ g h. i < k \ (g \\<^sub>v gs ! i) \ (h \\<^sub>v gs ! k) = 0" for i by (subst scalar_prod_smult_distrib[OF _ gsk], (insert k, auto)[1], subst smult_scalar_prod_distrib[OF _ gsk], (insert k, auto)[1], insert ortho[of i k] k, auto) have 1: "?v1 \ ?w2 = 0" by (subst scalar_prod_left_sum_distrib[OF _ w2], (insert Suc(2), auto)[1], rule sum_list_neutral, insert 0, auto) have 2: "?v2 \ ?w1 = 0" unfolding comm_scalar_prod[OF v2 w1] apply (subst scalar_prod_left_sum_distrib[OF _ v2]) apply ((insert gs, force)[1]) apply (rule sum_list_neutral) by (insert 0, auto) show ?case unfolding id unfolding scalar_prod_add_distrib[OF v12 w1 w2] add_scalar_prod_distrib[OF v1 v2 w1] add_scalar_prod_distrib[OF v1 v2 w2] scalar_prod_smult_distrib[OF w2 gsk] smult_scalar_prod_distrib[OF gsk gsk] unfolding Suc(1)[OF kn] by (simp add: 1 2 comm_scalar_prod[OF v2 w1]) qed auto end locale gram_schmidt = cof_vec_space n f_ty for n :: nat and f_ty :: "'a :: {trivial_conjugatable_linordered_field} itself" begin definition Gramian_matrix where "Gramian_matrix G k = (let M = mat k n (\ (i,j). (G ! i) $ j) in M * M\<^sup>T)" lemma Gramian_matrix_alt_def: "k \ length G \ Gramian_matrix G k = (let M = mat_of_rows n (take k G) in M * M\<^sup>T)" unfolding Gramian_matrix_def Let_def by (rule arg_cong[of _ _ "\ x. x * x\<^sup>T"], unfold mat_of_rows_def, intro eq_matI, auto) definition Gramian_determinant where "Gramian_determinant G k = det (Gramian_matrix G k)" lemma Gramian_determinant_0 [simp]: "Gramian_determinant G 0 = 1" unfolding Gramian_determinant_def Gramian_matrix_def Let_def by (simp add: times_mat_def) lemma orthogonal_imp_lin_indpt_list: assumes ortho: "orthogonal gs" and gs: "set gs \ carrier_vec n" shows "lin_indpt_list gs" proof - from corthogonal_distinct[of gs] ortho have dist: "distinct gs" by simp show ?thesis unfolding lin_indpt_list_def proof (intro conjI gs dist finite_lin_indpt2 finite_set) fix lc assume 0: "lincomb lc (set gs) = 0\<^sub>v n" (is "?lc = _") have lc: "?lc \ carrier_vec n" by (rule lincomb_closed[OF gs]) let ?m = "length gs" from 0 have "0 = ?lc \ ?lc" by simp also have "?lc = lincomb_list (\i. lc (gs ! i)) gs" unfolding lincomb_as_lincomb_list_distinct[OF gs dist] .. also have "\ = sumlist (map (\i. lc (gs ! i) \\<^sub>v gs ! i) [0..< ?m])" unfolding lincomb_list_def by auto also have "\ \ \ = (\i\[0.. x. x \ set ?sum \ x \ 0" using zero_le_square[of "lc (gs ! i)" for i] sq_norm_vec_ge_0[of "gs ! i" for i] by auto { fix x assume x: "x \ set gs" then obtain i where i: "i < ?m" and x: "x = gs ! i" unfolding set_conv_nth by auto hence "lc x * lc x * sq_norm x \ set ?sum" by auto with sum_list_nonneg_eq_0_iff[of ?sum, OF nonneg] sum_0 have "lc x = 0 \ sq_norm x = 0" by auto with orthogonalD[OF ortho, OF i i, folded x] have "lc x = 0" by (auto simp: sq_norm_vec_as_cscalar_prod) } thus "\v\set gs. lc v = 0" by auto qed qed lemma orthocompl_span: assumes "\ x. x \ S \ v \ x = 0" "S \ carrier_vec n" and [intro]: "v \ carrier_vec n" and "y \ span S" shows "v \ y = 0" proof - {fix a A assume "y = lincomb a A" "finite A" "A \ S" note assms = assms this hence [intro!]:"lincomb a A \ carrier_vec n" "(\v. a v \\<^sub>v v) \ A \ carrier_vec n" by auto have "\x\A. (a x \\<^sub>v x) \ v = 0" proof fix x assume "x \ A" note assms = assms this hence x:"x \ S" by auto with assms have [intro]:"x \ carrier_vec n" by auto from assms(1)[OF x] have "x \ v = 0" by(subst comm_scalar_prod) force+ thus "(a x \\<^sub>v x) \ v = 0" apply(subst smult_scalar_prod_distrib) by force+ qed hence "v \ lincomb a A = 0" apply(subst comm_scalar_prod) apply force+ unfolding lincomb_def apply(subst finsum_scalar_prod_sum) by force+ } thus ?thesis using \y \ span S\ unfolding span_def by auto qed lemma orthogonal_sumlist: assumes ortho: "\ x. x \ set S \ v \ x = 0" and S: "set S \ carrier_vec n" and v: "v \ carrier_vec n" shows "v \ sumlist S = 0" by (rule orthocompl_span[OF ortho S v sumlist_in_span[OF S span_mem[OF S]]]) lemma oc_projection_alt_def: assumes carr:"(W::'a vec set) \ carrier_vec n" "x \ carrier_vec n" and alt1:"y1 \ W" "x - y1 \ orthogonal_complement W" and alt2:"y2 \ W" "x - y2 \ orthogonal_complement W" shows "y1 = y2" proof - have carr:"y1 \ carrier_vec n" "y2 \ carrier_vec n" "x \ carrier_vec n" "- y1 \ carrier_vec n" "0\<^sub>v n \ carrier_vec n" using alt1 alt2 carr by auto hence "y1 - y2 \ carrier_vec n" by auto note carr = this carr from alt1 have "ya\W \ (x - y1) \ ya = 0" for ya unfolding orthogonal_complement_def by blast hence "(x - y1) \ y2 = 0" "(x - y1) \ y1 = 0" using alt2 alt1 by auto hence eq1:"y1 \ y2 = x \ y2" "y1 \ y1 = x \ y1" using carr minus_scalar_prod_distrib by force+ from this(1) have eq2:"y2 \ y1 = x \ y2" using carr comm_scalar_prod by force from alt2 have "ya\W \ (x - y2) \ ya = 0" for ya unfolding orthogonal_complement_def by blast hence "(x - y2) \ y1 = 0" "(x - y2) \ y2 = 0" using alt2 alt1 by auto hence eq3:"y2 \ y2 = x \ y2" "y2 \ y1 = x \ y1" using carr minus_scalar_prod_distrib by force+ with eq2 have eq4:"x \ y1 = x \ y2" by auto have "\(y1 - y2)\\<^sup>2 = 0" unfolding sq_norm_vec_as_cscalar_prod cscalar_prod_is_scalar_prod using carr apply(subst minus_scalar_prod_distrib) apply force+ apply(subst (0 0) scalar_prod_minus_distrib) apply force+ unfolding eq1 eq2 eq3 eq4 by auto with sq_norm_vec_eq_0[of "(y1 - y2)"] carr have "y1 - y2 = 0\<^sub>v n" by fastforce hence "y1 - y2 + y2 = y2" using carr by fastforce also have "y1 - y2 + y2 = y1" using carr by auto finally show "y1 = y2" . qed definition "is_oc_projection w S v = (w \ carrier_vec n \ v - w \ span S \ (\ u. u \ S \ w \ u = 0))" lemma is_oc_projection_sq_norm: assumes "is_oc_projection w S v" and S: "S \ carrier_vec n" and v: "v \ carrier_vec n" shows "sq_norm w \ sq_norm v" proof - from assms[unfolded is_oc_projection_def] have w: "w \ carrier_vec n" and vw: "v - w \ span S" and ortho: "\ u. u \ S \ w \ u = 0" by auto have "sq_norm v = sq_norm ((v - w) + w)" using v w by (intro arg_cong[of _ _ sq_norm_vec], auto) also have "\ = ((v - w) + w) \ ((v - w) + w)" unfolding sq_norm_vec_as_cscalar_prod by simp also have "\ = (v - w) \ ((v - w) + w) + w \ ((v - w) + w)" by (rule add_scalar_prod_distrib, insert v w, auto) also have "\ = ((v - w) \ (v - w) + (v - w) \ w) + (w \ (v - w) + w \ w)" by (subst (1 2) scalar_prod_add_distrib, insert v w, auto) also have "\ = sq_norm (v - w) + 2 * (w \ (v - w)) + sq_norm w" unfolding sq_norm_vec_as_cscalar_prod using v w by (auto simp: comm_scalar_prod[of w _ "v - w"]) also have "\ \ 2 * (w \ (v - w)) + sq_norm w" using sq_norm_vec_ge_0[of "v - w"] by auto also have "w \ (v - w) = 0" using orthocompl_span[OF ortho S w vw] by auto finally show ?thesis by auto qed definition oc_projection where "oc_projection S fi \ (SOME v. is_oc_projection v S fi)" lemma inv_in_span: assumes incarr[intro]:"U \ carrier_vec n" and insp:"a \ span U" shows "- a \ span U" proof - from insp[THEN in_spanE] obtain aa A where a:"a = lincomb aa A" "finite A" "A \ U" by auto with assms have [intro!]:"(\v. aa v \\<^sub>v v) \ A \ carrier_vec n" by auto from a(1) have e1:"- a = lincomb (\ x. - 1 * aa x) A" unfolding smult_smult_assoc[symmetric] lincomb_def by(subst finsum_smult[symmetric]) force+ show ?thesis using e1 a span_def by blast qed lemma non_span_det_zero: assumes len: "length G = n" and nonb:"\ (carrier_vec n \ span (set G))" and carr:"set G \ carrier_vec n" shows "det (mat_of_rows n G) = 0" unfolding det_0_iff_vec_prod_zero proof - let ?A = "(mat_of_rows n G)\<^sup>T" let ?B = "1\<^sub>m n" from carr have carr_mat:"?A \ carrier_mat n n" "?B \ carrier_mat n n" "mat_of_rows n G \ carrier_mat n n" using len mat_of_rows_carrier(1) by auto from carr have g_len:"\ i. i < length G \ G ! i \ carrier_vec n" by auto from nonb obtain v where v:"v \ carrier_vec n" "v \ span (set G)" by fast hence "v \ 0\<^sub>v n" using span_zero by auto obtain B C where gj:"gauss_jordan ?A ?B = (B,C)" by force note gj = carr_mat(1,2) gj hence B:"B = fst (gauss_jordan ?A ?B)" by auto from gauss_jordan[OF gj] have BC:"B \ carrier_mat n n" by auto from gauss_jordan_transform[OF gj] obtain P where P:"P\Units (ring_mat TYPE('a) n ?B)" "B = P * ?A" by fast hence PC:"P \ carrier_mat n n" unfolding Units_def by (simp add: ring_mat_simps) from mat_inverse[OF PC] P obtain PI where "mat_inverse P = Some PI" by fast from mat_inverse(2)[OF PC this] have PI:"P * PI = 1\<^sub>m n" "PI * P = 1\<^sub>m n" "PI \ carrier_mat n n" by auto have "B \ 1\<^sub>m n" proof assume "B = ?B" hence "?A * P = ?B" unfolding P using PC P(2) carr_mat(1) mat_mult_left_right_inverse by blast hence "?A * P *\<^sub>v v = v" using v by auto hence "?A *\<^sub>v (P *\<^sub>v v) = v" unfolding assoc_mult_mat_vec[OF carr_mat(1) PC v(1)]. hence v_eq:"mat_of_cols n G *\<^sub>v (P *\<^sub>v v) = v" unfolding transpose_mat_of_rows by auto have pvc:"P *\<^sub>v v \ carrier_vec (length G)" using PC v len by auto from mat_of_cols_mult_as_finsum[OF pvc g_len,unfolded v_eq] obtain a where "v = lincomb a (set G)" by auto hence "v \ span (set G)" by (intro in_spanI[OF _ finite_set subset_refl]) thus False using v by auto qed with det_non_zero_imp_unit[OF carr_mat(1)] show ?thesis unfolding gauss_jordan_check_invertable[OF carr_mat(1,2)] B det_transpose[OF carr_mat(3)] by metis qed lemma span_basis_det_zero_iff: assumes "length G = n" "set G \ carrier_vec n" shows "carrier_vec n \ span (set G) \ det (mat_of_rows n G) \ 0" (is ?q1) "carrier_vec n \ span (set G) \ basis (set G)" (is ?q2) "det (mat_of_rows n G) \ 0 \ basis (set G)" (is ?q3) proof - have dc:"det (mat_of_rows n G) \ 0 \ carrier_vec n \ span (set G)" using assms non_span_det_zero by auto have cb:"carrier_vec n \ span (set G) \ basis (set G)" using assms basis_list_basis by (auto simp: basis_list_def) have bd:"basis (set G) \ det (mat_of_rows n G) \ 0" using assms basis_det_nonzero by auto show ?q1 ?q2 ?q3 using dc cb bd by metis+ qed lemma lin_indpt_list_nonzero: assumes "lin_indpt_list G" shows "0\<^sub>v n \ set G" proof- from assms[unfolded lin_indpt_list_def] have "lin_indpt (set G)" by auto from vs_zero_lin_dep[OF _ this] assms[unfolded lin_indpt_list_def] show zero: "0\<^sub>v n \ set G" by auto qed lemma is_oc_projection_eq: assumes ispr:"is_oc_projection a S v" "is_oc_projection b S v" and carr: "S \ carrier_vec n" "v \ carrier_vec n" shows "a = b" proof - from carr have c2:"span S \ carrier_vec n" "v \ carrier_vec n" by auto have a:"v - (v - a) = a" using carr ispr by auto have b:"v - (v - b) = b" using carr ispr by auto have "(v - a) = (v - b)" apply(rule oc_projection_alt_def[OF c2]) using ispr a b unfolding in_orthogonal_complement_span[OF carr(1)] unfolding orthogonal_complement_def is_oc_projection_def by auto hence "v - (v - a) = v - (v - b)" by metis thus ?thesis unfolding a b. qed fun adjuster_wit :: "'a list \ 'a vec \ 'a vec list \ 'a list \ 'a vec" where "adjuster_wit wits w [] = (wits, 0\<^sub>v n)" | "adjuster_wit wits w (u#us) = (let a = (w \ u)/ sq_norm u in case adjuster_wit (a # wits) w us of (wit, v) \ (wit, -a \\<^sub>v u + v))" fun sub2_wit where "sub2_wit us [] = ([], [])" | "sub2_wit us (w # ws) = (case adjuster_wit [] w us of (wit,aw) \ let u = aw + w in case sub2_wit (u # us) ws of (wits, vvs) \ (wit # wits, u # vvs))" definition main :: "'a vec list \ 'a list list \ 'a vec list" where "main us = sub2_wit [] us" end locale gram_schmidt_fs = fixes n :: nat and fs :: "'a :: {trivial_conjugatable_linordered_field} vec list" begin sublocale gram_schmidt n "TYPE('a)" . fun gso and \ where "gso i = fs ! i + sumlist (map (\ j. - \ i j \\<^sub>v gso j) [0 ..< i])" | "\ i j = (if j < i then (fs ! i \ gso j)/ sq_norm (gso j) else if i = j then 1 else 0)" declare gso.simps[simp del] declare \.simps[simp del] lemma gso_carrier'[intro]: assumes "\ i. i \ j \ fs ! i \ carrier_vec n" shows "gso j \ carrier_vec n" using assms proof(induct j rule:nat_less_induct[rule_format]) case (1 j) then show ?case unfolding gso.simps[of j] by (auto intro!:sumlist_carrier add_carrier_vec) qed lemma adjuster_wit: assumes res: "adjuster_wit wits w us = (wits',a)" and w: "w \ carrier_vec n" and us: "\ i. i \ j \ fs ! i \ carrier_vec n" and us_gs: "us = map gso (rev [0 ..< j])" and wits: "wits = map (\ i) [j ..< i]" and j: "j \ n" "j \ i" and wi: "w = fs ! i" shows "adjuster n w us = a \ a \ carrier_vec n \ wits' = map (\ i) [0 ..< i] \ (a = sumlist (map (\j. - \ i j \\<^sub>v gso j) [0.. n" "jj < n" "jj \ i" "jj < i" by auto have zj: "[0 ..< j] = [0 ..< jj] @ [jj]" unfolding j by simp have jjn: "[jj ..< i] = jj # [j ..< i]" using jj unfolding j by (metis upt_conv_Cons) from us_gs[unfolded zj] have ugs: "u = gso jj" and us: "us = map gso (rev [0.. i jj" unfolding \.simps[of i jj] ugs wi sq_norm_vec_as_cscalar_prod using jj by auto have wwits: "?w # wits = map (\ i) [jj.. i) [0..j. - \ i j \\<^sub>v gso j) [0.. carrier_vec n" by auto from Cons(2)[simplified, unfolded Let_def rec split sq_norm_vec_as_cscalar_prod cscalar_prod_is_scalar_prod] have id: "wits' = wwits" and a: "a = - ?w \\<^sub>v u + b" by auto have 1: "adjuster n w (u # us) = a" unfolding a IH(1)[symmetric] by auto from id IH(2) have wits': "wits' = map (\ i) [0..j. - \ i j \\<^sub>v gso j) [0.. carrier_vec n" "set (map (\j. - \ i j \\<^sub>v gso j) [0.. carrier_vec n" and u:"u \ carrier_vec n" using Cons j by (auto intro!:gso_carrier') from u b a have ac: "a \ carrier_vec n" "dim_vec (-?w \\<^sub>v u) = n" "dim_vec b = n" "dim_vec u = n" by auto show ?case apply (intro conjI[OF 1] ac exI conjI wits') unfolding carr a IH zj muij ugs[symmetric] map_append apply (subst sumlist_append) using Cons.prems j apply force using b u ugs IH(3) by auto qed auto lemma sub2_wit: assumes "set us \ carrier_vec n" "set ws \ carrier_vec n" "length us + length ws = m" and "ws = map (\ i. fs ! i) [i ..< m]" and "us = map gso (rev [0 ..< i])" and us: "\ j. j < m \ fs ! j \ carrier_vec n" and mn: "m \ n" shows "sub2_wit us ws = (wits,vvs) \ gram_schmidt_sub2 n us ws = vvs \ vvs = map gso [i ..< m] \ wits = map (\ i. map (\ i) [0.. m" by (cases "i < m", auto)+ hence i_m: "[i ..< m] = i # [Suc i ..< m]" by (metis upt_conv_Cons) from \i < m\ mn have "i < n" "i \ n" "i \ m" by auto hence i_n: "[i ..< n] = i # [Suc i ..< n]" by (metis upt_conv_Cons) from wsf' i_m have wsf: "ws = map (\ i. fs ! i) [Suc i ..< m]" and fiw: "fs ! i = w" by auto from wws have w: "w \ carrier_vec n" and ws: "set ws \ carrier_vec n" by auto have list: "map (\ i) [i ..< i] = []" by auto let ?a = "adjuster_wit [] w us" obtain wit a where a: "?a = (wit,a)" by force obtain wits' vv where gs: "sub2_wit ((a + w) # us) ws = (wits',vv)" by force from adjuster_wit[OF a w Cons(8) us_gs list[symmetric] \i \ n\ _ fiw[symmetric]] us wws \i < m\ have awus: "set ((a + w) # us) \ carrier_vec n" and aa: "adjuster n w us = a" "a \ carrier_vec n" and aaa: "a = sumlist (map (\j. - \ i j \\<^sub>v gso j) [0.. i) [0..i. map (\ i) [0.. m" "m \ n" "set us \ carrier_vec n" "snd (main us) = vs" "us = take k fs" "set fs \ carrier_vec n" shows "gram_schmidt n us = vs" "vs = map gso [0.. fs ! j \ carrier_vec n" for j using assms by auto note assms(5)[unfolded main_def] have "gram_schmidt_sub2 n [] (take k fs) = vvs \ vvs = map gso [0.. wits = map (\i. map (\ i) [0.. (fst (adjuster_wit v a xs) = x1 \ x2 = adjuster n a xs)" proof(induct xs arbitrary: a v x1 x2) case (Cons a xs) then show ?case by (auto simp:Let_def sq_norm_vec_as_cscalar_prod split:prod.splits) qed auto lemma sub2: "rev xs @ snd (sub2_wit xs us) = rev (gram_schmidt_sub n xs us)" proof - have "sub2_wit xs us = (x1, x2) \ rev xs @ x2 = rev (gram_schmidt_sub n xs us)" for x1 x2 xs us apply(induct us arbitrary: xs x1 x2) by (auto simp:Let_def rev_unsimp adjuster_wit_small split:prod.splits simp del:rev.simps) thus ?thesis apply (cases us) by (auto simp:Let_def rev_unsimp adjuster_wit_small split:prod.splits simp del:rev.simps) qed lemma gso_connect: "snd (main us) = gram_schmidt n us" unfolding main_def gram_schmidt_def using sub2[of Nil us] by auto definition weakly_reduced :: "'a \ nat \ bool" (* for k = n, this is reduced according to "Modern Computer Algebra" *) where "weakly_reduced \ k = (\ i. Suc i < k \ sq_norm (gso i) \ \ * sq_norm (gso (Suc i)))" definition reduced :: "'a \ nat \ bool" (* this is reduced according to LLL original paper *) where "reduced \ k = (weakly_reduced \ k \ (\ i j. i < k \ j < i \ abs (\ i j) \ 1/2))" end (* gram_schmidt_fs *) locale gram_schmidt_fs_Rn = gram_schmidt_fs + assumes fs_carrier: "set fs \ carrier_vec n" begin abbreviation (input) m where "m \ length fs" definition M where "M k = mat k k (\ (i,j). \ i j)" lemma f_carrier[simp]: "i < m \ fs ! i \ carrier_vec n" using fs_carrier unfolding set_conv_nth by force lemma gso_carrier[simp]: "i < m \ gso i \ carrier_vec n" using gso_carrier' f_carrier by auto lemma gso_dim[simp]: "i < m \ dim_vec (gso i) = n" by auto lemma f_dim[simp]: "i < m \ dim_vec (fs ! i) = n" by auto lemma fs0_gso0: "0 < m \ fs ! 0 = gso 0" unfolding gso.simps[of 0] using f_dim[of 0] by (cases fs, auto simp add: upt_rec) lemma fs_by_gso_def : assumes i: "i < m" shows "fs ! i = gso i + M.sumlist (map (\ja. \ i ja \\<^sub>v gso ja) [0..ja. f ja \\<^sub>v gso ja) [0.. carrier_vec n" using gso_carrier i by (intro M.sumlist_carrier, auto) hence "dim_vec (M.sumlist (map (\ja. f ja \\<^sub>v gso ja) [0.. carrier_vec n" using i by simp have "gso i + ?sum = fs ! i + M.sumlist (map (\j. - \ i j \\<^sub>v gso j) [0.. n" shows "gram_schmidt n fs = map gso [0.. snd (sub2_wit [] fs) = map gso [0.. wits = map (\i. map (\ i) [0.. vs = map gso [0.. k \ k \ m \ Suc i < k \ sq_norm (gso i) \ \ * sq_norm (gso (Suc i))" unfolding weakly_reduced_def by auto abbreviation (input) FF where "FF \ mat_of_rows n fs" abbreviation (input) Fs where "Fs \ mat_of_rows n (map gso [0.. carrier_mat m n" unfolding mat_of_rows_def by (auto) lemma Fs_dim[simp]: "dim_row Fs = m" "dim_col Fs = n" "Fs \ carrier_mat m n" unfolding mat_of_rows_def by (auto simp: main_connect) lemma M_dim[simp]: "dim_row (M m) = m" "dim_col (M m) = m" "(M m) \ carrier_mat m m" unfolding M_def by auto lemma FF_index[simp]: "i < m \ j < n \ FF $$ (i,j) = fs ! i $ j" unfolding mat_of_rows_def by auto lemma M_index[simp]:"i < m \ j < m \ (M m) $$ (i,j) = \ i j" unfolding M_def by auto (* equation 2 on page 463 of textbook *) lemma matrix_equality: "FF = (M m) * Fs" proof - let ?P = "(M m) * Fs" have dim: "dim_row FF = m" "dim_col FF = n" "dim_row ?P = m" "dim_col ?P = n" "dim_row (M m) = m" "dim_col (M m) = m" "dim_row Fs = m" "dim_col Fs = n" by (auto simp: mat_of_rows_def mat_of_rows_list_def main_connect) show ?thesis proof (rule eq_matI; unfold dim) fix i j assume i: "i < m" and j: "j < n" from i have split: "[0 ..< m] = [0 ..< i] @ [i] @ [Suc i ..< m]" by (metis append_Cons append_self_conv2 less_Suc_eq_le less_imp_add_positive upt_add_eq_append upt_rec zero_less_Suc) let ?prod = "\ k. \ i k * gso k $ j" have dim2: "dim_vec (col Fs j) = m" using j dim by auto define idx where "idx = [0.. {0 ..< i}" unfolding idx_def using i by auto let ?vec = "sumlist (map (\j. - \ i j \\<^sub>v gso j) idx)" have vec: "?vec \ carrier_vec n" by (rule sumlist_carrier, insert idx gso_carrier i, auto) hence dimv: "dim_vec ?vec = n" by auto have "?P $$ (i,j) = row (M m) i \ col Fs j" using dim i j by auto also have "\ = (\ k = 0.. = (\ k = 0.. = sum_list (map ?prod [0 ..< m])" by (subst sum_list_distinct_conv_sum_set, auto) also have "\ = sum_list (map ?prod idx) + ?prod i + sum_list (map ?prod [Suc i ..< m])" unfolding split idx_def by auto also have "?prod i = gso i $ j" unfolding \.simps by simp also have "\ = fs ! i $ j + sum_list (map (\k. - \ i k * gso k $ j) idx)" unfolding gso.simps[of i] idx_def[symmetric] by (subst index_add_vec, unfold dimv, rule j, subst sumlist_vec_index[OF _ j], insert idx gso_carrier i j, auto simp: o_def intro!: arg_cong[OF map_cong]) also have "sum_list (map (\k. - \ i k * gso k $ j) idx) = - sum_list (map (\k. \ i k * gso k $ j) idx)" by (induct idx, auto) also have "sum_list (map ?prod [Suc i ..< m]) = 0" by (rule sum_list_neutral, auto simp: \.simps) finally have "?P $$ (i,j) = fs ! i $ j" by simp with FF_index[OF i j] show "FF $$ (i,j) = ?P $$ (i,j)" by simp qed auto qed lemma fi_is_sum_of_mu_gso: assumes i: "i < m" shows "fs ! i = sumlist (map (\ j. \ i j \\<^sub>v gso j) [0 ..< Suc i])" proof - let ?l = "sumlist (map (\ j. \ i j \\<^sub>v gso j) [0 ..< Suc i])" have "?l \ carrier_vec n" by (rule sumlist_carrier, insert gso_carrier i, auto) hence dim: "dim_vec ?l = n" by (rule carrier_vecD) show ?thesis proof (rule eq_vecI, unfold dim f_dim[OF i]) fix j assume j: "j < n" from i have split: "[0 ..< m] = [0 ..< Suc i] @ [Suc i ..< m]" by (metis Suc_lessI append.assoc append_same_eq less_imp_add_positive order_refl upt_add_eq_append zero_le) let ?prod = "\ k. \ i k * gso k $ j" have "fs ! i $ j = FF $$ (i,j)" using i j by simp also have "\ = ((M m) * Fs) $$ (i,j)" using matrix_equality by simp also have "\ = row (M m) i \ col Fs j" using i j by auto also have "\ = (\ k = 0.. = (\ k = 0.. = sum_list (map ?prod [0 ..< m])" by (subst sum_list_distinct_conv_sum_set, auto) also have "\ = sum_list (map ?prod [0 ..< Suc i]) + sum_list (map ?prod [Suc i ..< m])" unfolding split by auto also have "sum_list (map ?prod [Suc i ..< m]) = 0" by (rule sum_list_neutral, auto simp: \.simps) also have "sum_list (map ?prod [0 ..< Suc i]) = ?l $ j" by (subst sumlist_vec_index[OF _ j], (insert i, auto simp: intro!: gso_carrier)[1], rule arg_cong[of _ _ sum_list], insert i j, auto) finally show "fs ! i $ j = ?l $ j" by simp qed simp qed lemma gi_is_fi_minus_sum_mu_gso: assumes i: "i < m" shows "gso i = fs ! i - sumlist (map (\ j. \ i j \\<^sub>v gso j) [0 ..< i])" (is "_ = _ - ?sum") proof - have sum: "?sum \ carrier_vec n" by (rule sumlist_carrier, insert gso_carrier i, auto) show ?thesis unfolding fs_by_gso_def[OF i] by (intro eq_vecI, insert gso_carrier[OF i] sum, auto) qed (* Theorem 16.5 (iv) *) lemma det: assumes m: "m = n" shows "det FF = det Fs" unfolding matrix_equality apply (subst det_mult[OF M_dim(3)], (insert Fs_dim(3) m, auto)[1]) apply (subst det_lower_triangular[OF _ M_dim(3)]) by (subst M_index, (auto simp: \.simps)[3], unfold prod_list_diag_prod, auto simp: \.simps) end locale gram_schmidt_fs_lin_indpt = gram_schmidt_fs_Rn + assumes lin_indpt: "lin_indpt (set fs)" and dist: "distinct fs" begin lemmas loc_assms = lin_indpt dist lemma mn: shows "m \ n" proof - have n: "n = dim" by (simp add: dim_is_n) have m: "m = card (set fs)" using distinct_card loc_assms by metis from m n have mn: "m \ n \ card (set fs) \ dim" by simp show ?thesis unfolding mn by (rule li_le_dim, use loc_assms fs_carrier in auto) qed lemma shows span_gso: "span (gso ` {0.. {0.. {0.. m" shows "span (gso ` {0 ..< i}) = span (set (take i fs))" proof - let ?f = "\ i. fs ! i" let ?us = "take i fs" have len: "length ?us = i" using i by auto from fs_carrier i have us: "set ?us \ carrier_vec n" by (meson set_take_subset subset_trans) obtain vi where main: "snd (main ?us) = vi" by force from dist have dist: "distinct ?us" by auto from lin_indpt have indpt: "lin_indpt (set ?us)" using supset_ld_is_ld[of "set ?us", of "set (?us @ drop i fs)"] by (auto simp: set_take_subset) from partial_connect[OF _ i mn us main refl fs_carrier] assms have gso: "vi = gram_schmidt n ?us" and vi: "vi = map gso [0 ..< i]" by auto from cof_vec_space.gram_schmidt_result(1)[OF us dist indpt gso, unfolded vi] show ?thesis by auto qed lemma partial_span': assumes i: "i \ m" shows "span (gso ` {0 ..< i}) = span ((\ j. fs ! j) ` {0 ..< i})" unfolding partial_span[OF i] by (rule arg_cong[of _ _ span], subst nth_image, insert i loc_assms, auto) (* Theorem 16.5 (iii) *) lemma orthogonal: assumes "i < m" "j < m" "i \ j" shows "gso i \ gso j = 0" using assms mn orthogonal_gso[unfolded orthogonal_def] by auto (* Theorem 16.5 (i) not in full general form *) lemma same_base: shows "span (set fs) = span (gso ` {0.. sq_norm (fs ! i)" proof - have id: "[0 ..< Suc i] = [0 ..< i] @ [i]" by simp let ?sum = "sumlist (map (\j. \ i j \\<^sub>v gso j) [0.. carrier_vec n" and gsoi: "gso i \ carrier_vec n" using i by (auto intro!: sumlist_carrier gso_carrier) from fi_is_sum_of_mu_gso[OF i, unfolded id] have "sq_norm (fs ! i) = sq_norm (sumlist (map (\j. \ i j \\<^sub>v gso j) [0...simps) also have "\ = sq_norm (?sum + gso i)" by (subst sumlist_append, insert gso_carrier i, auto) also have "\ = (?sum + gso i) \ (?sum + gso i)" by (simp add: sq_norm_vec_as_cscalar_prod) also have "\ = ?sum \ (?sum + gso i) + gso i \ (?sum + gso i)" by (rule add_scalar_prod_distrib[OF sum gsoi], insert sum gsoi, auto) also have "\ = (?sum \ ?sum + ?sum \ gso i) + (gso i \ ?sum + gso i \ gso i)" by (subst (1 2) scalar_prod_add_distrib[of _ n], insert sum gsoi, auto) also have "?sum \ ?sum = sq_norm ?sum" by (simp add: sq_norm_vec_as_cscalar_prod) also have "gso i \ gso i = sq_norm (gso i)" by (simp add: sq_norm_vec_as_cscalar_prod) also have "gso i \ ?sum = ?sum \ gso i" using gsoi sum by (simp add: comm_scalar_prod) finally have "sq_norm (fs ! i) = sq_norm ?sum + 2 * (?sum \ gso i) + sq_norm (gso i)" by simp also have "\ \ 2 * (?sum \ gso i) + sq_norm (gso i)" using sq_norm_vec_ge_0[of ?sum] by simp also have "?sum \ gso i = (\v\map (\j. \ i j \\<^sub>v gso j) [0.. gso i)" by (subst scalar_prod_left_sum_distrib[OF _ gsoi], insert i gso_carrier, auto) also have "\ = 0" proof (rule sum_list_neutral, goal_cases) case (1 x) then obtain j where j: "j < i" and x: "x = (\ i j \\<^sub>v gso j) \ gso i" by auto from j i have gsoj: "gso j \ carrier_vec n" by auto have "x = \ i j * (gso j \ gso i)" using gsoi gsoj unfolding x by simp also have "gso j \ gso i = 0" by (rule orthogonal, insert j i assms, auto) finally show "x = 0" by simp qed finally show ?thesis by simp qed (* Theorem 16.5 (ii), first half *) lemma oc_projection_exist: assumes i: "i < m" shows "fs ! i - gso i \ span (gso ` {0.. carrier_vec n" using gso_dim assms by auto let "?a v" = "\n\[0.. i n else 0" have d:"(sumlist (map (\j. - \ i j \\<^sub>v gso j) [0.. carrier_vec n" using gso.simps[of i] gso_dim[OF i] unfolding carrier_vec_def by auto note [intro] = f_carrier[OF i] gso_carrier[OF i] d have [intro!]:"(\v. ?a v \\<^sub>v v) \ gso ` {0.. carrier_vec n" using gso_carrier assms by auto {fix ia assume ia[intro]:"ia < n" have "(\x\gso ` {0..\<^sub>v x) $ ia) = - (\x\map (\j. - \ i j \\<^sub>v gso j) [0..[0..n\[0.. i n else 0) = \ i x" unfolding sum_list_map_filter'[symmetric] by auto with ia gso_dim x show ?case apply(subst index_smult_vec) by force+ qed hence "(\\<^bsub>V\<^esub>v\gso ` {0..\<^sub>v v) $ ia = (- local.sumlist (map (\j. - \ i j \\<^sub>v gso j) [0..\<^bsub>V\<^esub>v\?A. ?a v \\<^sub>v v) = - sumlist (map (\j. - \ i j \\<^sub>v gso j) [0.. carrier_vec n" "\ x. x \ gso ` {0.. v \ x = 0" "fs ! i - v \ span (gso ` {0.. carrier_vec n" by(intro span_is_subset2) auto from assms have carr: "gso ` {0.. carrier_vec n" by auto from assms have eq:"fs ! i - (fs ! i - v) = v" for v by auto from orthocompl_span[OF _ carr] assms have "y \ span (gso ` {0.. v \ y = 0" for y by auto hence oc1:"fs ! i - (fs ! i - v) \ orthogonal_complement (span (gso ` {0..< i}))" unfolding eq orthogonal_complement_def using assms by auto have "x \ gso ` {0.. gso i \ x = 0" for x using assms orthogonal by auto hence "y \ span (gso ` {0.. gso i \ y = 0" for y by (rule orthocompl_span) (use carr gso_carrier assms in auto) hence oc2:"fs ! i - (fs ! i - gso i) \ orthogonal_complement (span (gso ` {0..< i}))" unfolding eq orthogonal_complement_def using assms by auto note pe= oc_projection_exist[OF assms(1)] note prerec = carr_span f_carrier[OF assms(1)] assms(4) oc1 oc_projection_exist[OF assms(1)] oc2 note prerec = carr_span f_carrier[OF assms(1)] assms(4) oc1 oc_projection_exist[OF assms(1)] oc2 have gsoi: "gso i \ carrier_vec n" "fs ! i \ carrier_vec n" by (rule gso_carrier[OF \i < m\], rule f_carrier[OF \i < m\]) note main = arg_cong[OF oc_projection_alt_def[OF carr_span f_carrier[OF assms(1)] assms(4) oc1 pe oc2], of "\ v. - v $ j + fs ! i $ j" for j] show "v = gso i" proof (intro eq_vecI) fix j show "j < dim_vec (gso i) \ v $ j = gso i $ j" using assms gsoi main[of j] by (auto) qed (insert assms gsoi, auto) qed lemma gso_oc_projection: assumes "i < m" shows "gso i = oc_projection (gso ` {0.. xa. xa < i \ gso i \ gso xa = 0" by (rule orthogonal,insert assms, auto) show "gso i \ carrier_vec n \ fs ! i - gso i \ span (gso ` {0.. (\x. x \ gso ` {0.. gso i \ x = 0)" using gso_carrier oc_projection_exist assms orthogonal by auto qed auto lemma gso_oc_projection_span: assumes "i < m" shows "gso i = oc_projection (span (gso ` {0.. carrier_vec n" using assms by auto have *: "\ xa. xa < i \ gso i \ gso xa = 0" by (rule orthogonal,insert assms, auto) have orthogonal:"\x. x \ span (gso ` {0.. gso i \ x = 0" apply(rule orthocompl_span) using assms * by auto show "?P (gso i)" "?P (gso i)" unfolding span_span[OF carr] using gso_carrier oc_projection_exist assms orthogonal by auto fix v assume p:"?P v" then show "v \ carrier_vec n" by auto from p show "fs ! i - v \ span (gso ` {0.. gso ` {0.. span (gso ` {0.. xa = 0" using p by auto qed lemma gso_is_oc_projection: assumes "i < m" shows "is_oc_projection (gso i) (set (take i fs)) (fs ! i)" proof - have [simp]: "v \ carrier_vec n" if "v \ set (take i fs)" for v using that by (meson contra_subsetD fs_carrier in_set_takeD) have "span (gso ` {0.. span (set (take i fs))" by (auto intro!: span_mem) ultimately show ?thesis unfolding is_oc_projection_def by (subst (asm) span_span) (auto) qed lemma fi_scalar_prod_gso: assumes i: "i < m" and j: "j < m" shows "fs ! i \ gso j = \ i j * \gso j\\<^sup>2" proof - let ?mu = "\j. \ i j \\<^sub>v gso j" from i have list1: "[0..< m] = [0..< Suc i] @ [Suc i ..< m]" by (intro nth_equalityI, auto simp: nth_append, rename_tac j, case_tac "j - i", auto) from j have list2: "[0..< m] = [0..< j] @ [j] @ [Suc j ..< m]" by (intro nth_equalityI, auto simp: nth_append, rename_tac k, case_tac "k - j", auto) have "fs ! i \ gso j = sumlist (map ?mu [0.. gso j" unfolding fi_is_sum_of_mu_gso[OF i] by simp also have "\ = (\v\map ?mu [0.. gso j) + 0" by (subst scalar_prod_left_sum_distrib, insert gso_carrier assms, auto) also have "\ = (\v\map ?mu [0.. gso j) + (\v\map ?mu [Suc i.. gso j)" by (subst (3) sum_list_neutral, insert assms gso_carrier, auto intro!: orthogonal simp: \.simps) also have "\ = (\v\map ?mu [0..< m]. v \ gso j)" unfolding list1 by simp also have "\ = (\v\map ?mu [0..< j]. v \ gso j) + ?mu j \ gso j + (\v\map ?mu [Suc j..< m]. v \ gso j)" unfolding list2 by simp also have "(\v\map ?mu [0..< j]. v \ gso j) = 0" by (rule sum_list_neutral, insert assms gso_carrier, auto intro!: orthogonal) also have "(\v\map ?mu [Suc j..< m]. v \ gso j) = 0" by (rule sum_list_neutral, insert assms gso_carrier, auto intro!: orthogonal) also have "?mu j \ gso j = \ i j * sq_norm (gso j)" using gso_carrier[OF j] by (simp add: sq_norm_vec_as_cscalar_prod) finally show ?thesis by simp qed lemma gso_scalar_zero: assumes "k < m" "i < k" shows "(gso k) \ (fs ! i) = 0" by (subst comm_scalar_prod[OF gso_carrier]; (subst fi_scalar_prod_gso)?, insert assms, auto simp: \.simps) lemma scalar_prod_lincomb_gso: assumes k: "k \ m" shows "sumlist (map (\ i. g i \\<^sub>v gso i) [0 ..< k]) \ sumlist (map (\ i. h i \\<^sub>v gso i) [0 ..< k]) = sum_list (map (\ i. g i * h i * (gso i \ gso i)) [0 ..< k])" proof - have id1: "map (\i. g i \\<^sub>v map (gso) [0..i. g i \\<^sub>v gso i) [0..i\[0.. map (gso) [0..i\[0.. gso i))" using k by (intro arg_cong[OF map_cong], auto) define gs where "gs = map (gso) [0..i. g i \\<^sub>v gs ! i) [0.. M.sumlist (map (\i. h i \\<^sub>v gs ! i) [0..i\[0.. gs ! i))" unfolding gs_def using assms orthogonal_gso by (intro scalar_prod_lincomb_orthogonal) auto also have "map (\i. g i \\<^sub>v gs ! i) [0..i. g i \\<^sub>v gso i) [0..i. h i \\<^sub>v gs ! i) [0..i. h i \\<^sub>v gso i) [0..i. g i * h i * (gs ! i \ gs ! i)) [0..i. g i * h i * (gso i \ gso i)) [0.. gso j = sq_norm (gso j)" by (subst fi_scalar_prod_gso, insert assms, auto simp: \.simps) (* Lemma 16.7 *) lemma gram_schmidt_short_vector: assumes in_L: "h \ lattice_of fs - {0\<^sub>v n}" shows "\ i < m. \h\\<^sup>2 \ \gso i\\<^sup>2" proof - from in_L have non_0: "h \ 0\<^sub>v n" by auto from in_L[unfolded lattice_of_def] obtain lam where h: "h = sumlist (map (\ i. of_int (lam i) \\<^sub>v fs ! i) [0 ..< length fs])" by auto have in_L: "h = sumlist (map (\ i. of_int (lam i) \\<^sub>v fs ! i) [0 ..< m])" unfolding length_map h by (rule arg_cong[of _ _ sumlist], rule map_cong, auto) let ?n = "[0 ..< m]" let ?f = "(\ i. of_int (lam i) \\<^sub>v fs ! i)" let ?vs = "map ?f ?n" let ?P = "\ k. k < m \ lam k \ 0" define k where "k = (GREATEST kk. ?P kk)" { assume *: "\ i < m. lam i = 0" have vs: "?vs = map (\ i. 0\<^sub>v n) ?n" by (rule map_cong, insert f_dim *, auto) have "h = 0\<^sub>v n" unfolding in_L vs by (rule sumlist_neutral, auto) with non_0 have False by auto } then obtain kk where "?P kk" by auto from GreatestI_nat[of ?P, OF this, of m] have Pk: "?P k" unfolding k_def by auto hence kn: "k < m" by auto let ?gso = "(\i j. \ i j \\<^sub>v gso j)" have k: "k < i \ i < m \ lam i = 0" for i using Greatest_le_nat[of ?P i m, folded k_def] by auto define l where "l = lam k" from Pk have l: "l \ 0" unfolding l_def by auto define idx where "idx = [0 ..< k]" have idx: "\ i. i \ set idx \ i < k" "\ i. i \ set idx \ i < m" unfolding idx_def using kn by auto from Pk have split: "[0 ..< m] = idx @ [k] @ [Suc k ..< m]" unfolding idx_def by (metis append_Cons append_self_conv2 less_Suc_eq_le less_imp_add_positive upt_add_eq_append upt_rec zero_less_Suc) define gg where "gg = sumlist (map (\i. of_int (lam i) \\<^sub>v fs ! i) idx) + of_int l \\<^sub>v sumlist (map (\j. \ k j \\<^sub>v gso j) idx)" have "h = sumlist ?vs" unfolding in_L .. also have "\ = sumlist ((map ?f idx @ [?f k]) @ map ?f [Suc k ..< m])" unfolding split by auto also have "\ = sumlist (map ?f idx @ [?f k]) + sumlist (map ?f [Suc k ..< m])" by (rule sumlist_append, auto intro!: f_carrier, insert Pk idx, auto) also have "sumlist (map ?f [Suc k ..< m]) = 0\<^sub>v n" by (rule sumlist_neutral, auto simp: k) also have "sumlist (map ?f idx @ [?f k]) = sumlist (map ?f idx) + ?f k" by (subst sumlist_append, auto intro!: f_carrier, insert Pk idx, auto) also have "fs ! k = sumlist (map (?gso k) [0.. = sumlist (map (?gso k) idx @ [gso k])" by (simp add: \.simps[of k k] idx_def) also have "\ = sumlist (map (?gso k) idx) + gso k" by (subst sumlist_append, auto intro!: f_carrier, insert Pk idx, auto) also have "of_int (lam k) \\<^sub>v \ = of_int (lam k) \\<^sub>v (sumlist (map (?gso k) idx)) + of_int (lam k) \\<^sub>v gso k" unfolding idx_def by (rule smult_add_distrib_vec[OF sumlist_carrier], auto intro!: gso_carrier, insert kn, auto) finally have "h = sumlist (map ?f idx) + (of_int (lam k) \\<^sub>v sumlist (map (?gso k) idx) + of_int (lam k) \\<^sub>v gso k) + 0\<^sub>v n " by simp also have "\ = gg + of_int l \\<^sub>v gso k" unfolding gg_def l_def by (rule eq_vecI, insert idx kn, auto simp: sumlist_vec_index, subst index_add_vec, auto simp: sumlist_dim kn, subst sumlist_dim, auto) finally have hgg: "h = gg + of_int l \\<^sub>v gso k" . let ?k = "[0 ..< k]" define R where "R = {gg. \ nu. gg = sumlist (map (\ i. nu i \\<^sub>v gso i) idx)}" { fix nu have "dim_vec (sumlist (map (\ i. nu i \\<^sub>v gso i) idx)) = n" by (rule sumlist_dim, insert kn, auto simp: idx_def) } note dim_nu[simp] = this define kk where "kk = ?k" { fix v assume "v \ R" then obtain nu where v: "v = sumlist (map (\ i. nu i \\<^sub>v gso i) idx)" unfolding R_def by auto have "dim_vec v = n" unfolding gg_def v by simp } note dim_R = this { fix v1 v2 assume "v1 \ R" "v2 \ R" then obtain nu1 nu2 where v1: "v1 = sumlist (map (\ i. nu1 i \\<^sub>v gso i) idx)" and v2: "v2 = sumlist (map (\ i. nu2 i \\<^sub>v gso i) idx)" unfolding R_def by auto have "v1 + v2 \ R" unfolding R_def by (standard, rule exI[of _ "\ i. nu1 i + nu2 i"], unfold v1 v2, rule eq_vecI, (subst sumlist_vec_index, insert idx, auto intro!: gso_carrier simp: o_def)+, unfold sum_list_addf[symmetric], induct idx, auto simp: algebra_simps) } note add_R = this have "gg \ R" unfolding gg_def proof (rule add_R) show "of_int l \\<^sub>v sumlist (map (\j. \ k j \\<^sub>v gso j) idx) \ R" unfolding R_def by (standard, rule exI[of _ "\i. of_int l * \ k i"], rule eq_vecI, (subst sumlist_vec_index, insert idx, auto intro!: gso_carrier simp: o_def)+, induct idx, auto simp: algebra_simps) show "sumlist (map ?f idx) \ R" using idx proof (induct idx) case Nil show ?case by (simp add: R_def, intro exI[of _ "\ i. 0"], rule eq_vecI, (subst sumlist_vec_index, insert idx, auto intro!: gso_carrier simp: o_def)+, induct idx, auto) next case (Cons i idxs) have "sumlist (map ?f (i # idxs)) = sumlist ([?f i] @ map ?f idxs)" by simp also have "\ = ?f i + sumlist (map ?f idxs)" by (subst sumlist_append, insert Cons(3), auto intro!: f_carrier) finally have id: "sumlist (map ?f (i # idxs)) = ?f i + sumlist (map ?f idxs)" . show ?case unfolding id proof (rule add_R[OF _ Cons(1)[OF Cons(2-3)]]) from Cons(2-3) have i: "i < m" "i < k" by auto hence idx_split: "idx = [0 ..< Suc i] @ [Suc i ..< k]" unfolding idx_def by (metis Suc_lessI append_Nil2 less_imp_add_positive upt_add_eq_append upt_rec zero_le) { fix j assume j: "j < n" define idxs where "idxs = [0 ..< Suc i]" let ?f = "\ x. ((if x < Suc i then of_int (lam i) * \ i x else 0) \\<^sub>v gso x) $ j" have "(\x\idx. ?f x) = (\x\[0 ..< Suc i]. ?f x) + (\x\ [Suc i ..< k]. ?f x)" unfolding idx_split by auto also have "(\x\ [Suc i ..< k]. ?f x) = 0" by (rule sum_list_neutral, insert j kn, auto) also have "(\x\[0 ..< Suc i]. ?f x) = (\x\idxs. of_int (lam i) * (\ i x \\<^sub>v gso x) $ j)" unfolding idxs_def by (rule arg_cong[of _ _ sum_list], rule map_cong[OF refl], subst index_smult_vec, insert j i kn, auto) also have "\ = of_int (lam i) * ((\x\[0.. i x \\<^sub>v gso x) $ j))" unfolding idxs_def[symmetric] by (induct idxs, auto simp: algebra_simps) finally have "(\x\idx. ?f x) = of_int (lam i) * ((\x\[0.. i x \\<^sub>v gso x) $ j))" by simp } note main = this show "?f i \ R" unfolding fi_is_sum_of_mu_gso[OF i(1)] R_def apply (standard, rule exI[of _ "\ j. if j < Suc i then of_int (lam i) * \ i j else 0"], rule eq_vecI) apply (subst sumlist_vec_index, insert idx i, auto intro!: gso_carrier sumlist_dim simp: o_def) apply (subst index_smult_vec, subst sumlist_dim, auto) apply (subst sumlist_vec_index, auto, insert idx i main, auto simp: o_def) done qed auto qed qed then obtain nu where gg: "gg = sumlist (map (\ i. nu i \\<^sub>v gso i) idx)" unfolding R_def by auto let ?ff = "sumlist (map (\i. nu i \\<^sub>v gso i) idx) + of_int l \\<^sub>v gso k" define hh where "hh = (\ i. (if i < k then nu i else of_int l))" let ?hh = "sumlist (map (\ i. hh i \\<^sub>v gso i) [0 ..< Suc k])" have ffhh: "?hh = sumlist (map (\ i. hh i \\<^sub>v gso i) [0 ..< k] @ [hh k \\<^sub>v gso k])" by simp also have "\ = sumlist (map (\ i. hh i \\<^sub>v gso i) [0 ..< k]) + sumlist [hh k \\<^sub>v gso k]" by (rule sumlist_append, insert kn, auto) also have "sumlist [hh k \\<^sub>v gso k] = hh k \\<^sub>v gso k" using kn by auto also have "\ = of_int l \\<^sub>v gso k" unfolding hh_def by auto also have "map (\ i. hh i \\<^sub>v gso i) [0 ..< k] = map (\ i. nu i \\<^sub>v gso i) [0 ..< k]" by (rule map_cong, auto simp: hh_def) finally have ffhh: "?ff = ?hh" by (simp add: idx_def) from hgg[unfolded gg] have h: "h = ?ff" by auto have "gso k \ gso k \ 1 * (gso k \ gso k)" by simp also have "\ \ of_int (l * l) * (gso k \ gso k)" proof (rule mult_right_mono) from l have "l * l \ 1" by (meson eq_iff int_one_le_iff_zero_less mult_le_0_iff not_le) thus "1 \ (of_int (l * l) :: 'a)" by presburger show "0 \ gso k \ gso k" by (rule scalar_prod_ge_0) qed also have "\ = 0 + of_int (l * l) * (gso k \ gso k)" by simp also have "\ \ sum_list (map (\ i. (nu i * nu i) * (gso i \ gso i)) idx) + of_int (l * l) * (gso k \ gso k)" by (rule add_right_mono, rule sum_list_nonneg, auto, rule mult_nonneg_nonneg, auto simp: scalar_prod_ge_0) also have "map (\ i. (nu i * nu i) * (gso i \ gso i)) idx = map (\ i. hh i * hh i * (gso i \ gso i)) [0..i\[0.. gso i)) + hh k * hh k * (gso k \ gso k) = (\i\[0.. gso i))" by simp also have "\ = ?hh \ ?hh" by (rule sym, rule scalar_prod_lincomb_gso, insert kn assms, auto) also have "\ = ?ff \ ?ff" by (simp add: ffhh) also have "\ = h \ h" unfolding h .. finally show ?thesis using kn unfolding sq_norm_vec_as_cscalar_prod by auto qed (* Theorem 16.9 (bound in textbook looks better as it uses 2^((n-1)/2), but this difference is caused by the fact that we here we look at the squared norms) *) lemma weakly_reduced_imp_short_vector: assumes "weakly_reduced \ m" and in_L: "h \ lattice_of fs - {0\<^sub>v n}" and \_pos:"\ \ 1" shows "fs \ [] \ sq_norm (fs ! 0) \ \^(m-1) * sq_norm h" proof - from gram_schmidt_short_vector assms obtain i where i: "i < m" and le: "sq_norm (gso i) \ sq_norm h" by auto have small: "sq_norm (fs ! 0) \ \^i * sq_norm (gso i)" using i proof (induct i) case 0 show ?case unfolding fs0_gso0[OF 0] by auto next case (Suc i) hence "sq_norm (fs ! 0) \ \^i * sq_norm (gso i)" by auto also have "\ \ \^i * (\ * (sq_norm (gso (Suc i))))" using reduced_gso_E[OF assms(1) le_refl Suc(2)] \_pos by auto finally show ?case unfolding class_semiring.nat_pow_Suc[of \ i] by auto qed also have "\ \ \^(m-1) * sq_norm h" by (rule mult_mono[OF power_increasing le], insert i \_pos, auto) finally show ?thesis using i by (cases fs, auto) qed lemma sq_norm_pos: assumes j: "j < m" shows "sq_norm (gso j) > 0" proof - from j have jj: "j < m - 0" by simp from orthogonalD[OF orthogonal_gso, unfolded length_map length_upt, OF jj jj] assms have "sq_norm (gso j) \ 0" using j by (simp add: sq_norm_vec_as_cscalar_prod) moreover have "sq_norm (gso j) \ 0" by auto ultimately show "0 < sq_norm (gso j)" by auto qed lemma Gramian_determinant: assumes k: "k \ m" shows "Gramian_determinant fs k = (\ j 0" proof - define Gk where "Gk = mat k n (\ (i,j). fs ! i $ j)" have Gk: "Gk \ carrier_mat k n" unfolding Gk_def by auto define Mk where "Mk = mat k k (\ (i,j). \ i j)" have Mk_\: "i < k \ j < k \ Mk $$ (i,j) = \ i j" for i j unfolding Mk_def using k by auto have Mk: "Mk \ carrier_mat k k" and [simp]: "dim_row Mk = k" "dim_col Mk = k" unfolding Mk_def by auto have "det Mk = prod_list (diag_mat Mk)" by (rule det_lower_triangular[OF _ Mk], auto simp: Mk_\ \.simps) also have "\ = 1" by (rule prod_list_neutral, auto simp: diag_mat_def Mk_\ \.simps) finally have detMk: "det Mk = 1" . define Gsk where "Gsk = mat k n (\ (i,j). gso i $ j)" have Gsk: "Gsk \ carrier_mat k n" unfolding Gsk_def by auto have Gsk': "Gsk\<^sup>T \ carrier_mat n k" using Gsk by auto let ?Rn = "carrier_vec n" have id: "Gk = Mk * Gsk" proof (rule eq_matI) from Gk Mk Gsk have dim: "dim_row Gk = k" "dim_row (Mk * Gsk) = k" "dim_col Gk = n" "dim_col (Mk * Gsk) = n" by auto from dim show "dim_row Gk = dim_row (Mk * Gsk)" "dim_col Gk = dim_col (Mk * Gsk)" by auto fix i j assume "i < dim_row (Mk * Gsk)" "j < dim_col (Mk * Gsk)" hence ij: "i < k" "j < n" and i: "i < m" using dim k by auto have Gi: "fs ! i \ ?Rn" using i by simp have "Gk $$ (i, j) = fs ! i $ j" unfolding Gk_def using ij k Gi by auto also have "... = FF $$ (i,j)" using ij i by simp also have "FF = (M m) * Fs" by (rule matrix_equality) also have "\ $$ (i,j) = row (M m) i \ col Fs j" by (rule index_mult_mat(1), insert i ij, auto simp: mat_of_rows_list_def) also have "row (M m) i = vec m (\ j. if j < k then Mk $$ (i,j) else 0)" (is "_ = vec m ?Mk") unfolding Mk_def using ij i by (auto simp: mat_of_rows_list_def \.simps) also have "col Fs j = vec m (\ i'. if i' < k then Gsk $$ (i',j) else (Fs $$ (i',j)))" (is "_ = vec m ?Gsk") unfolding Gsk_def using ij i by (auto simp: mat_of_rows_def) also have "vec m ?Mk \ vec m ?Gsk = (\ i \ {0 ..< m}. ?Mk i * ?Gsk i)" unfolding scalar_prod_def by auto also have "\ = (\ i \ {0 ..< k} \ {k ..< m}. ?Mk i * ?Gsk i)" by (rule sum.cong, insert k, auto) also have "\ = (\ i \ {0 ..< k}. ?Mk i * ?Gsk i) + (\ i \ {k ..< m}. ?Mk i * ?Gsk i)" by (rule sum.union_disjoint, auto) also have "(\ i \ {k ..< m}. ?Mk i * ?Gsk i) = 0" by (rule sum.neutral, auto) also have "(\ i \ {0 ..< k}. ?Mk i * ?Gsk i) = (\ i' \ {0 ..< k}. Mk $$ (i,i') * Gsk $$ (i',j))" by (rule sum.cong, auto) also have "\ = row Mk i \ col Gsk j" unfolding scalar_prod_def using ij by (auto simp: Gsk_def Mk_def) also have "\ = (Mk * Gsk) $$ (i, j)" using ij Mk Gsk by simp finally show "Gk $$ (i, j) = (Mk * Gsk) $$ (i, j)" by simp qed have cong: "\ a b c d. a = b \ c = d \ a * c = b * d" by auto have "Gramian_determinant fs k = det (Gk * Gk\<^sup>T)" unfolding Gramian_determinant_def Gramian_matrix_def Let_def by (rule arg_cong[of _ _ det], rule cong, insert k, auto simp: Gk_def) also have "Gk\<^sup>T = Gsk\<^sup>T * Mk\<^sup>T" (is "_ = ?TGsk * ?TMk") unfolding id by (rule transpose_mult[OF Mk Gsk]) also have "Gk = Mk * Gsk" by fact also have "\ * (?TGsk * ?TMk) = Mk * (Gsk * (?TGsk * ?TMk))" by (rule assoc_mult_mat[OF Mk Gsk, of _ k], insert Gsk Mk, auto) also have "det \ = det Mk * det (Gsk * (?TGsk * ?TMk))" by (rule det_mult[OF Mk], insert Gsk Mk, auto) also have "\ = det (Gsk * (?TGsk * ?TMk))" using detMk by simp also have "Gsk * (?TGsk * ?TMk) = (Gsk * ?TGsk) * ?TMk" by (rule assoc_mult_mat[symmetric, OF Gsk], insert Gsk Mk, auto) also have "det \ = det (Gsk * ?TGsk) * det ?TMk" by (rule det_mult, insert Gsk Mk, auto) also have "\ = det (Gsk * ?TGsk)" using detMk det_transpose[OF Mk] by simp also have "Gsk * ?TGsk = mat k k (\ (i,j). if i = j then sq_norm (gso j) else 0)" (is "_ = ?M") proof (rule eq_matI) show "dim_row (Gsk * ?TGsk) = dim_row ?M" unfolding Gsk_def by auto show "dim_col (Gsk * ?TGsk) = dim_col ?M" unfolding Gsk_def by auto fix i j assume "i < dim_row ?M" "j < dim_col ?M" hence ij: "i < k" "j < k" and ijn: "i < m" "j < m" using k by auto { fix i assume "i < k" hence "i < m" using k by auto hence Gs: "gso i \ ?Rn" by auto have "row Gsk i = gso i" unfolding row_def Gsk_def by (rule eq_vecI, insert Gs \i < k\, auto) } note row = this have "(Gsk * ?TGsk) $$ (i,j) = row Gsk i \ row Gsk j" using ij Gsk by auto also have "\ = gso i \ gso j" using row ij by simp also have "\ = (if i = j then sq_norm (gso j) else 0)" proof (cases "i = j") assume "i = j" thus ?thesis by (simp add: sq_norm_vec_as_cscalar_prod) next assume "i \ j" from \i \ j\ orthogonalD[OF orthogonal_gso] ijn assms show ?thesis by auto qed also have "\ = ?M $$ (i,j)" using ij by simp finally show "(Gsk * ?TGsk) $$ (i,j) = ?M $$ (i,j)" . qed also have "det ?M = prod_list (diag_mat ?M)" by (rule det_upper_triangular, auto) also have "diag_mat ?M = map (\ j. sq_norm (gso j)) [0 ..< k]" unfolding diag_mat_def by auto also have "prod_list \ = (\ j < k. sq_norm (gso j))" by (subst prod.distinct_set_conv_list[symmetric], force, rule prod.cong, auto) finally show "Gramian_determinant fs k = (\jgso j\\<^sup>2)" . also have "\ > 0" by (rule prod_pos, intro ballI sq_norm_pos, insert k assms, auto) finally show "0 < Gramian_determinant fs k" by auto qed lemma Gramian_determinant_div: assumes "l < m" shows "Gramian_determinant fs (Suc l) / Gramian_determinant fs l = \gso l\\<^sup>2" proof - note gram = Gramian_determinant(1)[symmetric] from assms have le: "Suc l \ m" "l \ m" by auto have "(\jgso j\\<^sup>2) = (\j \ {0.. {l}. \gso j\\<^sup>2)" using assms by (intro prod.cong) (auto) also have "\ = (\jgso j\\<^sup>2) * \gso l\\<^sup>2" using assms by (subst prod_Un) (auto simp add: atLeast0LessThan) finally show ?thesis unfolding gram[OF le(1)] gram[OF le(2)] using Gramian_determinant(2)[OF le(2)] assms by auto qed end lemma (in gram_schmidt_fs_Rn) Gramian_determinant_Ints: assumes "k \ m" "\i j. i < n \ j < m \ fs ! j $ i \ \" shows "Gramian_determinant fs k \ \" proof - let ?oi = "of_int :: int \ 'a" from assms have "\ i. i < n \ \j. \ c. j < m \ fs ! j $ i = ?oi c" unfolding Ints_def by auto from choice[OF this] have "\ i. \ c. \ j. i < n \ j < m \ fs ! j $ i = ?oi (c j)" by blast from choice[OF this] obtain c where c: "\ i j. i < n \ j < m \ fs ! j $ i = ?oi (c i j)" by blast define d where "d = map (\ j. vec n (\ i. c i j)) [0..(i, y). map (map_vec ?oi) d ! i $ y) = map_mat of_int (mat k n (\(i, y). d ! i $ y))" by (rule eq_matI, insert \k \ m\, auto simp: d_def o_def) show ?thesis unfolding fs Gramian_determinant_def Gramian_matrix_def Let_def id map_mat_transpose by (subst of_int_hom.mat_hom_mult[symmetric], auto) qed locale gram_schmidt_fs_int = gram_schmidt_fs_lin_indpt + assumes fs_int: "\i j. i < n \ j < m \ fs ! j $ i \ \" begin lemma Gramian_determinant_ge1: assumes "k \ m" shows "1 \ Gramian_determinant fs k" proof - have "0 < Gramian_determinant fs k" by (simp add: assms Gramian_determinant(2) less_or_eq_imp_le) moreover have "Gramian_determinant fs k \ \" by (simp add: Gramian_determinant_Ints assms fs_int) ultimately show ?thesis using Ints_nonzero_abs_ge1 by fastforce qed lemma mu_bound_Gramian_determinant: assumes "l < k" "k < m" shows "(\ k l)\<^sup>2 \ Gramian_determinant fs l * \fs ! k\\<^sup>2" proof - have "(\ k l)\<^sup>2 = (fs ! k \ gso l)\<^sup>2 / (\gso l\\<^sup>2)\<^sup>2" using assms by (simp add: power_divide \.simps) also have "\ \ (\fs ! k\\<^sup>2 * \gso l\\<^sup>2) / (\gso l\\<^sup>2)\<^sup>2" using assms by (auto intro!: scalar_prod_Cauchy divide_right_mono) also have "\ = \fs ! k\\<^sup>2 / \gso l\\<^sup>2" by (auto simp add: field_simps power2_eq_square) also have "\ = \fs ! k\\<^sup>2 / (Gramian_determinant fs (Suc l) / Gramian_determinant fs l)" using assms by (subst Gramian_determinant_div[symmetric]) auto also have "\ = Gramian_determinant fs l * \fs ! k\\<^sup>2 / Gramian_determinant fs (Suc l)" by (auto simp add: field_simps) also have "\ \ Gramian_determinant fs l * \fs ! k\\<^sup>2 / 1" by (rule divide_left_mono, insert Gramian_determinant_ge1[of l] Gramian_determinant_ge1[of "Suc l"] assms, auto intro!: mult_nonneg_nonneg) finally show ?thesis by simp qed end (* gram_schmidt_fs_int *) context gram_schmidt begin lemma gso_cong: fixes f1 f2 :: "'a vec list" assumes "\ i. i \ x \ f1 ! i = f2 ! i" shows "gram_schmidt_fs.gso n f1 x = gram_schmidt_fs.gso n f2 x" using assms proof(induct x rule:nat_less_induct[rule_format]) case (1 x) interpret f1: gram_schmidt_fs n f1 . interpret f2: gram_schmidt_fs n f2 . have *: "map (\j. - f1.\ x j \\<^sub>v f1.gso j) [0..j. - f2.\ x j \\<^sub>v f2.gso j) [0...simps f2.\.simps) show ?case using 1 by (subst f1.gso.simps, subst f2.gso.simps, subst *) auto qed lemma \_cong: fixes f1 f2 :: "'a vec list" assumes "\ k. j < i \ k \ j \ f1 ! k = f2 ! k" and "j < i \ f1 ! i = f2 ! i" shows "gram_schmidt_fs.\ n f1 i j = gram_schmidt_fs.\ n f2 i j" proof - interpret f1: gram_schmidt_fs n f1 . interpret f2: gram_schmidt_fs n f2 . from gso_cong[of j f1 f2] assms have id: "j < i \ f1.gso j = f2.gso j" by auto show ?thesis unfolding f1.\.simps f2.\.simps using assms id by auto qed end lemma prod_list_le_mono: fixes us :: "'a :: {linordered_nonzero_semiring,ordered_ring} list" assumes "length us = length vs" and "\ i. i < length vs \ 0 \ us ! i \ us ! i \ vs ! i" shows "0 \ prod_list us \ prod_list us \ prod_list vs" using assms proof (induction us vs rule: list_induct2) case (Cons u us v vs) have "0 \ prod_list us \ prod_list us \ prod_list vs" by (rule Cons.IH, insert Cons.prems[of "Suc i" for i], auto) moreover have "0 \ u \ u \ v" using Cons.prems[of 0] by auto ultimately show ?case by (auto intro: mult_mono) qed simp lemma lattice_of_of_int: assumes G: "set F \ carrier_vec n" and "f \ vec_module.lattice_of n F" shows "map_vec rat_of_int f \ vec_module.lattice_of n (map (map_vec of_int) F)" (is "?f \ vec_module.lattice_of _ ?F") proof - let ?sl = "abelian_monoid.sumlist (module_vec TYPE('a::semiring_1) n)" note d = vec_module.lattice_of_def note dim = vec_module.sumlist_dim note sumlist_vec_index = vec_module.sumlist_vec_index from G have Gi: "\ i. i < length F \ F ! i \ carrier_vec n" by auto from Gi have Gid: "\ i. i < length F \ dim_vec (F ! i) = n" by auto from assms(2)[unfolded d] obtain c where ffc: "f = ?sl (map (\i. of_int (c i) \\<^sub>v F ! i) [0..i. of_int (c i) \\<^sub>v ?F ! i) [0.. vec_module.lattice_of n ?F" unfolding d by auto qed (* Theorem 16.6, difficult part *) lemma Hadamard's_inequality: fixes A::"real mat" assumes A: "A \ carrier_mat n n" shows "abs (det A) \ sqrt (prod_list (map sq_norm (rows A)))" proof - let ?us = "map (row A) [0 ..< n]" interpret gso: gram_schmidt_fs n ?us . have len: "length ?us = n" by simp have us: "set ?us \ carrier_vec n" using A by auto let ?vs = "map gso.gso [0.. gso.span (set ?us)") case True with us len have basis: "gso.basis_list ?us" unfolding gso.basis_list_def by auto note in_dep = gso.basis_list_imp_lin_indpt_list[OF basis] interpret gso: gram_schmidt_fs_lin_indpt n ?us by (standard) (use in_dep gso.lin_indpt_list_def in auto) have last: "0 \ prod_list (map sq_norm ?vs) \ prod_list (map sq_norm ?vs) \ prod_list (map sq_norm ?us)" proof (rule prod_list_le_mono, force, unfold length_map length_upt) fix i assume "i < n - 0" hence i: "i < n" by simp have vsi: "map sq_norm ?vs ! i = sq_norm (?vs ! i)" using i by simp have usi: "map sq_norm ?us ! i = sq_norm (row A i)" using i by simp have zero: "0 \ sq_norm (?vs ! i)" by auto have le: "sq_norm (?vs ! i) \ sq_norm (row A i)" using gso.sq_norm_gso_le_f i by simp show "0 \ map sq_norm ?vs ! i \ map sq_norm ?vs ! i \ map sq_norm ?us ! i" unfolding vsi usi using zero le by auto qed have Fs: "gso.FF \ carrier_mat n n" by auto have A_Fs: "A = gso.FF" by (rule eq_matI, subst gso.FF_index, insert A, auto) hence "abs (det A) = abs (det (gso.FF))" by simp (* the following three steps are based on a discussion with Bertram Felgenhauer *) also have "\ = abs (sqrt (det (gso.FF) * det (gso.FF)))" by simp also have "det (gso.FF) * det (gso.FF) = det (gso.FF) * det (gso.FF)\<^sup>T" unfolding det_transpose[OF Fs] .. also have "\ = det (gso.FF * (gso.FF)\<^sup>T)" by (subst det_mult[OF Fs], insert Fs, auto) also have "\ = gso.Gramian_determinant ?us n" unfolding gso.Gramian_matrix_def gso.Gramian_determinant_def Let_def A_Fs[symmetric] by (rule arg_cong[of _ _ det], rule arg_cong2[of _ _ _ _ "(*)"], insert A, auto) also have "\ = (\j \ set [0 ..< n]. \?vs ! j\\<^sup>2)" by (subst gso.Gramian_determinant) (auto intro!: prod.cong) also have "\ = prod_list (map (\ i. sq_norm (?vs ! i)) [0 ..< n])" by (subst prod.distinct_set_conv_list, auto) also have "map (\ i. sq_norm (?vs ! i)) [0 ..< n] = map sq_norm ?vs" by (intro nth_equalityI, auto) also have "abs (sqrt (prod_list \)) \ sqrt (prod_list (map sq_norm ?us))" using last by simp also have "?us = rows A" unfolding rows_def using A by simp finally show ?thesis . next case False from mat_of_rows_rows[unfolded rows_def,of A] A gram_schmidt.non_span_det_zero[OF len False us] have zero: "det A = 0" by auto have ge: "prod_list (map sq_norm (rows A)) \ 0" by (rule prod_list_nonneg, auto simp: sq_norm_vec_ge_0) show ?thesis unfolding zero using ge by simp qed qed definition "gram_schmidt_wit = gram_schmidt.main" declare gram_schmidt.adjuster_wit.simps[code] declare gram_schmidt.sub2_wit.simps[code] declare gram_schmidt.main_def[code] definition gram_schmidt_int :: "nat \ int vec list \ rat list list \ rat vec list" where "gram_schmidt_int n us = gram_schmidt_wit n (map (map_vec of_int) us)" lemma snd_gram_schmidt_int : "snd (gram_schmidt_int n us) = gram_schmidt n (map (map_vec of_int) us)" unfolding gram_schmidt_int_def gram_schmidt_wit_def gram_schmidt_fs.gso_connect by metis text \Faster implementation for rational vectors which also avoid recomputations of square-norms\ fun adjuster_triv :: "nat \ rat vec \ (rat vec \ rat) list \ rat vec" where "adjuster_triv n w [] = 0\<^sub>v n" | "adjuster_triv n w ((u,nu)#us) = -(w \ u)/ nu \\<^sub>v u + adjuster_triv n w us" fun gram_schmidt_sub_triv where "gram_schmidt_sub_triv n us [] = us" | "gram_schmidt_sub_triv n us (w # ws) = (let u = adjuster_triv n w us + w in gram_schmidt_sub_triv n ((u, sq_norm_vec_rat u) # us) ws)" definition gram_schmidt_triv :: "nat \ rat vec list \ (rat vec \ rat) list" where "gram_schmidt_triv n ws = rev (gram_schmidt_sub_triv n [] ws)" lemma adjuster_triv: "adjuster_triv n w (map (\ x. (x,sq_norm x)) us) = adjuster n w us" by (induct us, auto simp: sq_norm_vec_as_cscalar_prod) lemma gram_schmidt_sub_triv: "gram_schmidt_sub_triv n ((map (\ x. (x,sq_norm x)) us)) ws = map (\ x. (x, sq_norm x)) (gram_schmidt_sub n us ws)" by (rule sym, induct ws arbitrary: us, auto simp: adjuster_triv o_def Let_def) lemma gram_schmidt_triv[simp]: "gram_schmidt_triv n ws = map (\ x. (x,sq_norm x)) (gram_schmidt n ws)" unfolding gram_schmidt_def gram_schmidt_triv_def rev_map[symmetric] by (auto simp: gram_schmidt_sub_triv[symmetric]) context gram_schmidt begin fun mus_adjuster :: "'a vec \ ('a vec \ 'a) list \ 'a list \ 'a vec \ 'a list \ 'a vec" where "mus_adjuster f [] mus g' = (mus, g')" | "mus_adjuster f ((g, ng)#n_gs) mus g' = (let a = (f \ g) / ng in mus_adjuster f n_gs (a # mus) (-a \\<^sub>v g + g'))" fun norms_mus' where "norms_mus' [] n_gs mus = (map snd n_gs, mus)" | "norms_mus' (f # fs) n_gs mus = (let (mus_row, g') = mus_adjuster f n_gs [] (0\<^sub>v n); g = g' + f in norms_mus' fs ((g, sq_norm_vec g) # n_gs) (mus_row#mus))" lemma adjuster_wit_carrier_vec: assumes "f \ carrier_vec n" "set gs \ carrier_vec n" shows "snd (adjuster_wit mus f gs) \ carrier_vec n" using assms by (induction mus f gs rule: adjuster_wit.induct) (auto simp add: Let_def case_prod_beta') lemma adjuster_wit'': assumes "adjuster_wit mus_acc f gs = (mus, g')" "n_gs = map (\x. (x, sq_norm_vec x)) gs" "f \ carrier_vec n" "acc \ carrier_vec n" "set gs \ carrier_vec n" shows "mus_adjuster f n_gs mus_acc acc = (mus, acc + g')" using assms proof(induction f n_gs mus_acc acc arbitrary: g' gs mus rule: mus_adjuster.induct) case (1 mus' f acc g) then show ?case by auto next case (2 f g n_g n_gs mus_acc acc g' gs mus) let ?gg = "snd (adjuster_wit (f \ g / n_g # mus_acc) f (tl gs))" from 2 have l: "gs = g # tl gs" by auto have gg: "?gg \ carrier_vec n" using 2 by (auto intro!: adjuster_wit_carrier_vec) then have [simp]: "g' = (- (f \ g / \g\\<^sup>2) \\<^sub>v g + ?gg)" using 2 by (auto simp add: Let_def case_prod_beta') have "mus_adjuster f ((g, n_g) # n_gs) mus_acc acc = mus_adjuster f n_gs (f \ g / n_g # mus_acc) (- (f \ g / n_g) \\<^sub>v g + acc)" by (auto simp add: Let_def) also have "\ = (mus, - (f \ g / n_g) \\<^sub>v g + acc + ?gg)" proof - have "adjuster_wit (f \ g / n_g # mus_acc) f (tl gs) = (mus, ?gg)" using 2 by (subst (asm) l) (auto simp add: Let_def case_prod_beta') then show ?thesis using 2 by (subst 2(1)[of _ "tl gs"]) (auto simp add: Let_def case_prod_beta') qed finally show ?case using 2 gg by auto qed lemma adjuster_wit': assumes "n_gs = map (\x. (x, sq_norm_vec x)) gs" "f \ carrier_vec n" "set gs \ carrier_vec n" shows "mus_adjuster f n_gs mus_acc (0\<^sub>v n) = adjuster_wit mus_acc f gs" proof - let ?g = "snd (adjuster_wit mus_acc f gs)" let ?mus = "fst (adjuster_wit mus_acc f gs)" have "?g \ carrier_vec n" using assms by (auto intro!: adjuster_wit_carrier_vec) then show ?thesis using assms by (subst adjuster_wit''[of _ _ gs ?mus ?g]) (auto simp add: case_prod_beta') qed lemma sub2_wit_norms_mus': assumes "n_gs' = map (\v. (v, sq_norm_vec v)) gs'" "sub2_wit gs' fs = (mus, gs)" "set fs \ carrier_vec n" "set gs' \ carrier_vec n" shows "norms_mus' fs n_gs' mus_acc = (map sq_norm_vec (rev gs @ gs'), rev mus @ mus_acc)" using assms proof (induction fs n_gs' mus_acc arbitrary: gs' mus gs rule: norms_mus'.induct) case (1 n_gs mus_acc) then show ?case by (auto simp add: rev_map) next case (2 f fs n_gs mus_acc) note aw1 = conjunct1[OF conjunct2[OF gram_schmidt_fs.adjuster_wit]] let ?aw = "mus_adjuster f n_gs [] (0\<^sub>v n)" have aw: "?aw = adjuster_wit [] f gs'" apply(subst adjuster_wit') using 2 by auto have "sub2_wit ((snd ?aw + f) # gs') fs = sub2_wit ((snd (adjuster_wit [] f gs') + f) # gs') fs" apply(subst adjuster_wit') using 2 by auto also have "\ = (tl mus, tl gs)" using 2 by (auto simp add: Let_def case_prod_beta') finally have sub_tl: "sub2_wit ((snd ?aw + f) # gs') fs = (tl mus, tl gs)" by simp have aw_c: "snd ?aw \ carrier_vec n" apply(subst adjuster_wit'[of _ gs']) using 2 adjuster_wit_carrier_vec by (auto) have gs: "gs = (snd ?aw + f) # tl gs" apply(subst aw) using 2 by (auto simp add: Let_def case_prod_beta') have mus: "mus = fst ?aw # tl mus" apply(subst aw) using 2 by (auto simp add: Let_def case_prod_beta') show ?case apply(simp add: Let_def case_prod_beta') apply(subst 2(1)[of _ _ _ _ "(snd ?aw + f)#gs'" "tl mus" "tl gs"]) apply(simp) defer apply(simp) apply (simp add: "2.prems"(1)) using sub_tl apply(simp) using 2 apply(simp) subgoal using 2 aw_c by (auto) defer apply(simp) apply(auto) using gs apply(subst gs) apply(subst (2) gs) apply (metis list.simps(9) rev.simps(2) rev_map) using mus by (metis rev.simps(2)) qed lemma sub2_wit_gram_schmidt_sub_triv'': assumes "sub2_wit [] fs = (mus, gs)" "set fs \ carrier_vec n" shows "norms_mus' fs [] [] = (map sq_norm_vec (rev gs), rev mus)" using assms by (subst sub2_wit_norms_mus') (simp)+ definition norms_mus where "norms_mus fs = (let (n_gs, mus) = norms_mus' fs [] [] in (rev n_gs, rev mus))" lemma sub2_wit_gram_schmidt_norm_mus: assumes "sub2_wit [] fs = (mus, gs)" "set fs \ carrier_vec n" shows "norms_mus fs = (map sq_norm_vec gs, mus)" unfolding norms_mus_def using assms sub2_wit_gram_schmidt_sub_triv'' by (auto simp add: Let_def case_prod_beta' rev_map) lemma (in gram_schmidt_fs_Rn) norms_mus: assumes "set fs \ carrier_vec n" "length fs \ n" shows "norms_mus fs = (map (\j. \gso j\\<^sup>2) [0..i. map (\ i) [0.. snd ?s = map (gso) [0.. fst ?s = map (\i. map (\ i) [0..i. map (\ i) [0.. (rat vec \ rat) list \ rat list \ rat vec \ rat list \ rat vec" where "mus_adjuster_rat f [] mus g' = (mus, g')" | "mus_adjuster_rat f ((g, ng)#n_gs) mus g' = (let a = (f \ g) / ng in mus_adjuster_rat f n_gs (a # mus) (-a \\<^sub>v g + g'))" fun norms_mus_rat' where "norms_mus_rat' n [] n_gs mus = (map snd n_gs, mus)" | "norms_mus_rat' n (f # fs) n_gs mus = (let (mus_row, g') = mus_adjuster_rat f n_gs [] (0\<^sub>v n); g = g' + f in norms_mus_rat' n fs ((g, sq_norm_vec g) # n_gs) (mus_row#mus))" definition norms_mus_rat where "norms_mus_rat n fs = (let (n_gs, mus) = norms_mus_rat' n fs [] [] in (rev n_gs, rev mus))" lemma norms_mus_rat_norms_mus: "norms_mus_rat n fs = gram_schmidt.norms_mus n fs" proof - have "mus_adjuster_rat f n_gs mus_acc g_acc = gram_schmidt.mus_adjuster f n_gs mus_acc g_acc" for f n_gs mus_acc g_acc by(induction f n_gs mus_acc g_acc rule: mus_adjuster_rat.induct) (auto simp add: gram_schmidt.mus_adjuster.simps) then have "norms_mus_rat' n fs n_gs mus = gram_schmidt.norms_mus' n fs n_gs mus" for n fs n_gs mus by(induction n fs n_gs mus rule: norms_mus_rat'.induct) (auto simp add: gram_schmidt.norms_mus'.simps case_prod_beta') then show ?thesis unfolding norms_mus_rat_def gram_schmidt.norms_mus_def by auto qed lemma of_int_dvd: - assumes "b \ 0" "of_int a / (of_int b :: 'a :: field_char_0) \ \" - shows "b dvd a" - using assms apply(elim Ints_cases) - unfolding dvd_def - by (metis nonzero_mult_div_cancel_left of_int_0_eq_iff of_int_eq_iff of_int_simps(4) times_divide_eq_right) - + "b dvd a" if "of_int a / (of_int b :: 'a :: field_char_0) \ \" "b \ 0" + using that by (cases rule: Ints_cases) + (simp add: field_simps flip: of_int_mult) lemma denom_dvd_ints: fixes i::int assumes "quotient_of r = (z, n)" "of_int i * r \ \" shows "n dvd i" proof - have "rat_of_int i * (rat_of_int z / rat_of_int n) \ \" using assms quotient_of_div by blast then have "n dvd i * z" using quotient_of_denom_pos assms by (auto intro!: of_int_dvd) then show "n dvd i" using assms algebraic_semidom_class.coprime_commute quotient_of_coprime coprime_dvd_mult_left_iff by blast qed lemma quotient_of_bounds: assumes "quotient_of r = (n, d)" "rat_of_int i * r \ \" "0 < i" "\r\ \ b" shows "of_int \n\ \ of_int i * b" "d \ i" proof - show ni: "d \ i" using assms denom_dvd_ints by (intro zdvd_imp_le) blast+ have "\r\ = \rat_of_int n / rat_of_int d\" using assms quotient_of_div by blast also have "\ = rat_of_int \n\ / rat_of_int d" using assms using quotient_of_denom_pos by force finally have "of_int \n\ = rat_of_int d * \r\" using assms by auto also have "\ \ rat_of_int d * b" using assms quotient_of_denom_pos by auto also have "\ \ rat_of_int i * b" using ni assms of_int_le_iff by (auto intro!: mult_right_mono) finally show "rat_of_int \n\ \ rat_of_int i * b" by simp qed context gram_schmidt_fs_Rn begin (* Lemma 16.17 *) lemma ex_\: assumes "i < length fs" "l \ i" shows "\\. sumlist (map (\j. - \ i j \\<^sub>v gso j) [0 ..< l]) = sumlist (map (\j. \ j \\<^sub>v fs ! j) [0 ..< l])" (is "\\. ?Prop l i \") using assms proof (induction l arbitrary: i) case (Suc l) then obtain \\<^sub>i where \\<^sub>i_def: "?Prop l i \\<^sub>i" by force from Suc obtain \\<^sub>l where \\<^sub>l_def: "?Prop l l \\<^sub>l" by force have [simp]: "dim_vec (M.sumlist (map (\j. f j \\<^sub>v fs ! j) [0.. Suc l" for f y using Suc that by (auto intro!: dim_sumlist) define \ where "\ = (\x. (if x < l then \\<^sub>i x - \\<^sub>l x * \ i l else - \ i l))" let ?sum = "\i. sumlist (map (\j. - \ i j \\<^sub>v gso j) [0..j. - \ i j \\<^sub>v gso j) [0..j. \\<^sub>i j \\<^sub>v fs ! j) [0.. i l \\<^sub>v gso l" using Suc by (subst \\<^sub>i_def[symmetric], subst sumlist_snoc[symmetric]) (auto) also have "gso l = fs ! l + M.sumlist (map (\j. \\<^sub>l j \\<^sub>v fs ! j) [0..\<^sub>l_def) also have "M.sumlist (map (\j. \\<^sub>i j \\<^sub>v fs ! j) [0.. i l \\<^sub>v (fs ! l + M.sumlist (map (\j. \\<^sub>l j \\<^sub>v fs ! j) [0..j. \ j \\<^sub>v fs ! j) [0..j. \\<^sub>i j \\<^sub>v fs ! j) [0.. i l \\<^sub>v (fs ! l + M.sumlist (map (\j. \\<^sub>l j \\<^sub>v fs ! j) [0..j. \\<^sub>i j \\<^sub>v fs ! j) [0.. i l * (fs ! l $ k + M.sumlist (map (\j. \\<^sub>l j \\<^sub>v fs ! j) [0.. = (\j = 0..\<^sub>i j * fs ! j $ k) + (- \ i l * (\j = 0..\<^sub>l j * fs ! j $ k)) - \ i l * fs ! l $ k" using that Suc by (auto simp add: algebra_simps sumlist_nth) also have "- \ i l * (\j = 0..\<^sub>l j * fs ! j $ k) = (\j = 0.. i l * (\\<^sub>l j * fs ! j $ k))" using sum_distrib_left by blast also have "(\j = 0..\<^sub>i j * fs ! j $ k) + (\j = 0.. i l * (\\<^sub>l j * fs ! j $ k)) = (\x = 0..\<^sub>i x - \\<^sub>l x * \ i l) * fs ! x $ k)" by (subst sum.distrib[symmetric]) (simp add: algebra_simps) also have "\ = (\x = 0.. x * fs ! x $ k)" unfolding \_def by (rule sum.cong) (auto) also have "(\x = 0.. x * fs ! x $ k) - \ i l * fs ! l $ k = (\x = 0.. x * fs ! x $ k) + (\x = l.. x * fs ! x $ k)" unfolding \_def by auto also have "\ = (\x = 0.. x * fs ! x $ k)" by (subst sum.union_disjoint[symmetric]) auto also have "\ = (\x = 0.. x \\<^sub>v fs ! x) $ k)" using that Suc by auto also have "\ = M.sumlist (map (\j. \ j \\<^sub>v fs ! j) [0..]) simp qed auto definition \_SOME_def: "\ = (SOME \. \i l. i < length fs \ l \ i \ sumlist (map (\j. - \ i j \\<^sub>v gso j) [0..j. \ i l j \\<^sub>v fs ! j) [0.._def: assumes "i < length fs" "l \ i" shows "sumlist (map (\j. - \ i j \\<^sub>v gso j) [0..j. \ i l j \\<^sub>v fs ! j) [0.. have "\ i. \ l. \\. ?P i l \" by blast from choice[OF this] have "\i. \\. \ l. ?P i l (\ l)" by blast from choice[OF this] have "\\. \i l. ?P i l (\ i l)" by blast from someI_ex[OF this] show ?thesis unfolding \_SOME_def using assms by blast qed lemma (in gram_schmidt_fs_lin_indpt) fs_i_sumlist_\: assumes "i < m" "l \ i" "j < l" shows "(fs ! i + sumlist (map (\j. \ i l j \\<^sub>v fs ! j) [0.. fs ! j = 0" proof - have "fs ! i + sumlist (map (\j. \ i l j \\<^sub>v fs ! j) [0..j. \ i j \\<^sub>v gso j) [0.._def[symmetric]) (auto simp add: dim_sumlist sumlist_nth sum_negf) also have "\ = M.sumlist (map (\j. \ i j \\<^sub>v gso j) [l..j. \ i j \\<^sub>v gso j) [0.. = M.sumlist (map (\j. \ i j \\<^sub>v gso j) [0..j. \ i j \\<^sub>v gso j) [l..j. \ i l j \\<^sub>v fs ! j) [0..j. \ i j \\<^sub>v gso j) [l.. \ (fs ! j) = 0" using assms gso_carrier assms unfolding lin_indpt_list_def by (subst scalar_prod_left_sum_distrib) (auto simp add: algebra_simps dim_sumlist gso_scalar_zero intro!: sum_list_zero) ultimately show ?thesis using assms by auto qed end (* gram_schmidt_fs_Rn *) lemma Ints_sum: assumes "\a. a \ A \ f a \ \" shows "sum f A \ \" using assms by (induction A rule: infinite_finite_induct) auto lemma Ints_prod: assumes "\a. a \ A \ f a \ \" shows "prod f A \ \" using assms by (induction A rule: infinite_finite_induct) auto lemma Ints_scalar_prod: "v \ carrier_vec n \ w \ carrier_vec n \ (\ i. i < n \ v $ i \ \) \ (\ i. i < n \ w $ i \ \) \ v \ w \ \" unfolding scalar_prod_def by (intro Ints_sum Ints_mult, auto) lemma Ints_det: assumes "\ i j. i < dim_row A \ j < dim_col A \ A $$ (i,j) \ \" shows "det A \ \" proof (cases "dim_row A = dim_col A") case True show ?thesis unfolding Determinant.det_def using True assms by (auto intro!: Ints_sum Ints_mult Ints_prod simp: signof_def) next case False show ?thesis unfolding Determinant.det_def using False by simp qed lemma (in gram_schmidt_fs_Rn) Gramian_matrix_alt_alt_def: assumes "k \ m" shows "Gramian_matrix fs k = mat k k (\(i,j). fs ! i \ fs ! j)" proof - have *: "vec n (($) (fs ! i)) = fs ! i" if "i < m" for i using that by auto then show ?thesis unfolding Gramian_matrix_def using assms by (intro eq_matI) (auto simp add: Let_def) qed lemma (in gram_schmidt_fs_int) fs_scalar_Ints: assumes "i < m" "j < m" shows "fs ! i \ fs ! j \ \" by (rule Ints_scalar_prod[of _ n], insert fs_int assms, auto) abbreviation (in gram_schmidt_fs_lin_indpt) d where "d \ Gramian_determinant fs" lemma (in gram_schmidt_fs_lin_indpt) fs_i_fs_j_sum_\ : assumes "i < m" "l \ i" "j < l" shows "- (fs ! i \ fs ! j) = (\t = 0.. fs ! j * \ i l t)" proof - have [simp]: "M.sumlist (map (\j. \ i l j \\<^sub>v fs ! j) [0.. carrier_vec n" using assms by (auto intro!: sumlist_carrier simp add: dim_sumlist) have "0 = (fs ! i + M.sumlist (map (\j. \ i l j \\<^sub>v fs ! j) [0.. fs ! j" using fs_i_sumlist_\ assms by simp also have "\ = fs ! i \ fs ! j + M.sumlist (map (\j. \ i l j \\<^sub>v fs ! j) [0.. fs ! j" using assms by (subst add_scalar_prod_distrib[of _ n]) (auto) also have "M.sumlist (map (\j. \ i l j \\<^sub>v fs ! j) [0.. fs ! j = (\v\map (\j. \ i l j \\<^sub>v fs ! j) [0.. fs ! j)" using assms by (intro scalar_prod_left_sum_distrib) (auto) also have "\ = (\t\[0.. i l t \\<^sub>v fs ! t) \ fs ! j)" by (rule arg_cong[where f=sum_list]) (auto) also have "\ = (\t = 0.. i l t \\<^sub>v fs ! t) \ fs ! j) " by (subst interv_sum_list_conv_sum_set_nat) (auto) also have "\ = (\t = 0.. fs ! j * \ i l t)" using assms by (intro sum.cong) auto finally show ?thesis by (simp add: field_simps) qed lemma (in gram_schmidt_fs_lin_indpt) Gramian_matrix_times_\ : assumes "i < m" "l \ i" shows "Gramian_matrix fs l *\<^sub>v (vec l (\t. \ i l t)) = (vec l (\j. - (fs ! i \ fs ! j)))" proof - have "- (fs ! i \ fs ! j) = (\t = 0.. fs ! j * \ i l t)" if "j < l" for j using fs_i_fs_j_sum_\ assms that by simp then show ?thesis using assms by (subst Gramian_matrix_alt_alt_def) (auto simp add: scalar_prod_def algebra_simps) qed lemma (in gram_schmidt_fs_int) d_\_Ints : assumes "i < m" "l \ i" "t < l" shows "d l * \ i l t \ \" proof - let ?A = "Gramian_matrix fs l" let ?B = "replace_col ?A (Gramian_matrix fs l *\<^sub>v vec l (\ i l)) t" have deteq: "d l = det ?A" unfolding Gramian_determinant_def using Gramian_determinant_Ints by auto have **: "Gramian_matrix fs l \ carrier_mat l l" unfolding Gramian_matrix_def Let_def using fs_carrier by auto then have " \ i l t * det ?A = det ?B" using assms fs_carrier cramer_lemma_mat[of ?A l " (vec l (\t. \ i l t))" t] by auto also have " ... \ \ " proof - have *: "t (?A *\<^sub>v vec l (\ i l)) $ t \ \" for t using assms apply(subst Gramian_matrix_times_\, force, force) using fs_int fs_carrier by (auto intro!: fs_scalar_Ints Ints_minus) define B where "B = ?B" have Bint: "t1 s1 < l \ B $$ (t1,s1) \ \" for t1 s1 proof (cases "s1 = t") case True from * ** this show ?thesis unfolding replace_col_def B_def by auto next case False from * ** Gramian_matrix_def this fs_carrier assms show ?thesis unfolding replace_col_def B_def by (auto simp: Gramian_matrix_def Let_def scalar_prod_def intro!: Ints_sum Ints_mult fs_int) qed have B: "B \ carrier_mat l l" using ** replace_col_def unfolding B_def by (auto simp: replace_col_def) have "det B \ \" using B Bint assms det_col[of B l] by (auto intro!: Ints_sum Ints_mult Ints_prod simp: signof_def) thus ?thesis unfolding B_def. qed finally show ?thesis using deteq by (auto simp add: algebra_simps) qed lemma (in gram_schmidt_fs_int) d_gso_Ints: assumes "i < n" "k < m" shows "(d k \\<^sub>v (gso k)) $ i \ \" proof - note d_\_Ints[intro!] then have "(d k * \ k k j) * fs ! j $ i \ \" if "j < k" for j using that fs_int assms by (auto intro: Ints_mult ) moreover have "(d k * \ k k j) * fs ! j $ i = d k * \ k k j * fs ! j $ i" for j by (auto simp add: field_simps) ultimately have "d k * (\j = 0.. k k j * fs ! j $ i) \ \" by (subst sum_distrib_left) (auto simp add: field_simps intro!: Ints_sum) moreover have "(gso k) $ i = fs ! k $ i + sum (\j. (\ k k j \\<^sub>v fs ! j) $ i) {0..j. \ k k j \\<^sub>v fs ! j) [0.._def) qed ultimately show ?thesis using assms by (auto simp add: distrib_left Gramian_determinant_Ints fs_int intro!: Ints_mult Ints_add) qed lemma (in gram_schmidt_fs_int) d_mu_Ints: assumes "l \ k" "k < m" shows "d (Suc l) * \ k l \ \" proof (cases "l < k") case True have ll: "d l * gso l $ i = (d l \\<^sub>v gso l) $ i" if "i < n" for i using that assms by auto have "d (Suc l) * \ k l =d (Suc l) * (fs ! k \ gso l) / \gso l\\<^sup>2 " using assms True unfolding \.simps by simp also have "\ = fs ! k \ (d l \\<^sub>v gso l)" using assms Gramian_determinant(2)[of "Suc l"] by (subst Gramian_determinant_div[symmetric]) (auto) also have "\ \ \" proof - have "d l * gso l $ i \ \" if "i < n" for i using assms d_gso_Ints that ll by (simp) then show ?thesis using assms by (auto intro!: Ints_sum simp add: fs_int scalar_prod_def) qed finally show ?thesis by simp next case False with assms have l: "l = k" by auto show ?thesis unfolding l \.simps using Gramian_determinant_Ints fs_int assms by simp qed lemma max_list_Max: "ls \ [] \ max_list ls = Max (set ls)" by (induction ls) (auto simp add: max_list_Cons) subsection \Explicit Bounds for Size of Numbers that Occur During GSO Algorithm \ context gram_schmidt_fs_lin_indpt begin definition "N = Max (sq_norm ` set fs)" lemma N_ge_0: assumes "0 < m" shows "0 \ N" proof - have "x \ sq_norm ` set fs \ 0 \ x" for x by auto then show ?thesis using assms unfolding N_def by auto qed lemma N_fs: assumes "i < m" shows "\fs ! i\\<^sup>2 \ N" using assms unfolding N_def by (auto) lemma N_gso: assumes "i < m" shows "\gso i\\<^sup>2 \ N" using assms N_fs sq_norm_gso_le_f by fastforce lemma N_d: assumes "i \ m" shows "Gramian_determinant fs i \ N ^ i" proof - have "(\jgso j\\<^sup>2) \ (\j {}" shows "\a \ A. Max (f ` A) = f a" proof - have "Max (f ` A) \ f ` A" using assms by (auto intro!: Max_in) then show ?thesis using assms imageE by blast qed context gram_schmidt_fs_int begin lemma fs_int': "k < n \ f \ set fs \ f $ k \ \" by (metis fs_int in_set_conv_nth) lemma assumes "i < m" shows fs_sq_norm_Ints: "\fs ! i\\<^sup>2 \ \" and fs_sq_norm_ge_1: "1 \ \fs ! i\\<^sup>2" proof - show fs_Ints: "\fs ! i\\<^sup>2 \ \" using assms fs_int' carrier_vecD fs_carrier by (auto simp add: sq_norm_vec_as_cscalar_prod scalar_prod_def intro!: Ints_sum Ints_mult) have "fs ! i \ 0\<^sub>v n" using assms fs_carrier loc_assms nth_mem vs_zero_lin_dep by force then have *: "0 \ \fs ! i\\<^sup>2" using assms sq_norm_vec_eq_0 f_carrier by metis show "1 \ \fs ! i\\<^sup>2" by (rule Ints_cases[OF fs_Ints]) (use * sq_norm_vec_ge_0[of "fs ! i"] assms in auto) qed lemma assumes "set fs \ {}" shows N_Ints: "N \ \" and N_1: "1 \ N" proof - have "\v\<^sub>m \ set fs. N = sq_norm v\<^sub>m" unfolding N_def using assms by (auto intro!: ex_MAXIMUM) then obtain v\<^sub>m::"'a vec" where v\<^sub>m_def: "v\<^sub>m \ set fs" "N = sq_norm v\<^sub>m" by blast then show N_Ints: "N \ \" using fs_int' carrier_vecD fs_carrier by (auto simp add: sq_norm_vec_as_cscalar_prod scalar_prod_def intro!: Ints_sum Ints_mult) have *: "0 \ N" using N_gso sq_norm_pos assms by fastforce show "1 \ N" by (rule Ints_cases[OF N_Ints]) (use * N_ge_0 assms in force)+ qed lemma N_mu: assumes "i < m" "j \ i" shows "(\ i j)\<^sup>2 \ N ^ (Suc j)" proof - { assume ji: "j < i" have "(\ i j)\<^sup>2 \ Gramian_determinant fs j * \fs ! i\\<^sup>2" using assms ji by (intro mu_bound_Gramian_determinant) auto also have "\ \ N ^ j * \fs ! i\\<^sup>2" using assms N_d N_ge_0 by (intro mult_mono) fastforce+ also have "N ^ j * \fs ! i\\<^sup>2 \ N ^ j * N" using assms N_fs N_ge_0 by (intro mult_mono) fastforce+ also have "\ = N ^ (Suc j)" by auto finally have ?thesis by simp } moreover { assume ji: "j = i" have "(\ i j)\<^sup>2 = 1" using ji by (simp add: \.simps) also have "\ \ N" using assms N_1 by fastforce also have "\ \ N ^ (Suc j)" using assms N_1 by fastforce finally have ?thesis by simp } ultimately show ?thesis using assms by fastforce qed end lemma vec_hom_Ints: assumes "i < n" "xs \ carrier_vec n" shows "of_int_hom.vec_hom xs $ i \ \" using assms by auto lemma division_to_div: "(of_int x :: 'a :: floor_ceiling) = of_int y / of_int z \ x = y div z" by (metis floor_divide_of_int_eq floor_of_int) lemma exact_division: assumes "of_int x / (of_int y :: 'a :: floor_ceiling) \ \" shows "of_int (x div y) = of_int x / (of_int y :: 'a)" using assms by (metis Ints_cases division_to_div) lemma int_via_rat_eqI: "rat_of_int x = rat_of_int y \ x = y" by auto locale fs_int = fixes n :: nat (* n-dimensional vectors, *) and fs_init :: "int vec list" (* initial basis *) begin sublocale vec_module "TYPE(int)" n . abbreviation RAT where "RAT \ map (map_vec rat_of_int)" abbreviation (input) m where "m \ length fs_init" sublocale gs: gram_schmidt_fs n "RAT fs_init" . definition d :: "int vec list \ nat \ int" where "d fs k = gs.Gramian_determinant fs k" definition D :: "int vec list \ nat" where "D fs = nat (\ i < length fs. d fs i)" lemma of_int_Gramian_determinant: assumes "k \ length F" "\i. i < length F \ dim_vec (F ! i) = n" shows "gs.Gramian_determinant (map of_int_hom.vec_hom F) k = of_int (gs.Gramian_determinant F k)" unfolding gs.Gramian_determinant_def of_int_hom.hom_det[symmetric] proof (rule arg_cong[of _ _ det]) let ?F = "map of_int_hom.vec_hom F" have cong: "\ a b c d. a = b \ c = d \ a * c = b * d" by auto show "gs.Gramian_matrix ?F k = map_mat of_int (gs.Gramian_matrix F k)" unfolding gs.Gramian_matrix_def Let_def proof (subst of_int_hom.mat_hom_mult[of _ k n _ k], (auto)[2], rule cong) show id: "mat k n (\ (i,j). ?F ! i $ j) = map_mat of_int (mat k n (\ (i, j). F ! i $ j))" (is "?L = map_mat _ ?R") proof (rule eq_matI, goal_cases) case (1 i j) hence ij: "i < k" "j < n" "i < length F" "dim_vec (F ! i) = n" using assms by auto show ?case using ij by simp qed auto show "?L\<^sup>T = map_mat of_int ?R\<^sup>T" unfolding id by (rule eq_matI, auto) qed qed end locale fs_int_indpt = fs_int n fs for n fs + assumes lin_indep: "gs.lin_indpt_list (RAT fs)" begin sublocale gs: gram_schmidt_fs_lin_indpt n "RAT fs" by (standard) (use lin_indep gs.lin_indpt_list_def in auto) sublocale gs: gram_schmidt_fs_int n "RAT fs" by (standard) (use gs.f_carrier lin_indep gs.lin_indpt_list_def in \auto intro!: vec_hom_Ints\) lemma f_carrier[dest]: "i < m \ fs ! i \ carrier_vec n" and fs_carrier [simp]: "set fs \ carrier_vec n" using lin_indep gs.f_carrier gs.gso_carrier unfolding gs.lin_indpt_list_def by auto lemma Gramian_determinant: assumes k: "k \ m" shows "of_int (gs.Gramian_determinant fs k) = (\ j 0" (is ?g2) proof - have hom: "gs.Gramian_determinant (RAT fs) k = of_int (gs.Gramian_determinant fs k)" using k by (intro of_int_Gramian_determinant) auto show ?g1 unfolding hom[symmetric] using gs.Gramian_determinant assms by auto show ?g2 using hom gs.Gramian_determinant assms by fastforce qed lemma fs_int_d_pos [intro]: assumes k: "k \ m" shows "d fs k > 0" unfolding d_def using Gramian_determinant[OF k] by auto lemma fs_int_d_Suc: assumes k: "k < m" shows "of_int (d fs (Suc k)) = sq_norm (gs.gso k) * of_int (d fs k)" proof - from k have k: "k \ m" "Suc k \ m" by auto show ?thesis unfolding Gramian_determinant[OF k(1)] Gramian_determinant[OF k(2)] d_def by (subst prod.remove[of _ k], force+, rule arg_cong[of _ _ "\ x. _ * x"], rule prod.cong, auto) qed lemma fs_int_D_pos: shows "D fs > 0" proof - have "(\ j < m. d fs j) > 0" by (rule prod_pos, insert fs_int_d_pos, auto) thus ?thesis unfolding D_def by auto qed definition "d\ i j = int_of_rat (of_int (d fs (Suc j)) * gs.\ i j)" lemma fs_int_mu_d_Z: assumes j: "j \ ii" and ii: "ii < m" shows "of_int (d fs (Suc j)) * gs.\ ii j \ \" proof - have id: "of_int (d fs (Suc j)) = gs.Gramian_determinant (RAT fs) (Suc j)" unfolding d_def by (rule of_int_Gramian_determinant[symmetric], insert j ii , auto) have "of_int_hom.vec_hom (fs ! j) $ i \ \" if "i < n" "j < length fs" for i j using that by (intro vec_hom_Ints) auto then show ?thesis unfolding id using j ii unfolding gs.lin_indpt_list_def by (intro gs.d_mu_Ints) (auto) qed lemma fs_int_mu_d_Z_m_m: assumes j: "j < m" and ii: "ii < m" shows "of_int (d fs (Suc j)) * gs.\ ii j \ \" proof (cases "j \ ii") case True thus ?thesis using fs_int_mu_d_Z[OF True ii] by auto next case False thus ?thesis by (simp add: gs.\.simps) qed lemma sq_norm_fs_via_sum_mu_gso: assumes i: "i < m" shows "of_int \fs ! i\\<^sup>2 = (\j\[0.. i j)\<^sup>2 * \gs.gso j\\<^sup>2)" proof - let ?G = "map (gs.gso) [0 ..< m]" let ?gso = "\ fs j. ?G ! j" have "of_int \fs ! i\\<^sup>2 = \RAT fs ! i\\<^sup>2" unfolding sq_norm_of_int[symmetric] using insert i by auto also have "RAT fs ! i = gs.sumlist (map (\j. gs.\ i j \\<^sub>v gs.gso j) [0..j. gs.\ i j \\<^sub>v gs.gso j) [0..j. gs.\ i j \\<^sub>v ?gso fs j) [0..) = sum_list (map sq_norm (map (\j. gs.\ i j \\<^sub>v gs.gso j) [0.. length ?G" using i by auto show "set ?G \ carrier_vec n" using gs.gso_carrier by auto show "orthogonal ?G" using gs.orthogonal_gso by auto qed (rule arg_cong[of _ _ sum_list], intro nth_equalityI, insert i, auto simp: nth_append) also have "map sq_norm (map (\j. gs.\ i j \\<^sub>v gs.gso j) [0..j. (gs.\ i j)^2 * sq_norm (gs.gso j)) [0..: assumes "j < m" "ii < m" shows "of_int (d\ ii j) = of_int (d fs (Suc j)) * gs.\ ii j" unfolding d\_def using fs_int_mu_d_Z_m_m assms by auto end end diff --git a/thys/Probabilistic_Timed_Automata/library/Lib.thy b/thys/Probabilistic_Timed_Automata/library/Lib.thy --- a/thys/Probabilistic_Timed_Automata/library/Lib.thy +++ b/thys/Probabilistic_Timed_Automata/library/Lib.thy @@ -1,816 +1,817 @@ theory Lib imports "Timed_Automata.Timed_Automata" "Timed_Automata.Approx_Beta" "MDP_Aux" "Finiteness" "Sequence_LTL" "Instantiate_Existentials" "Graphs" begin section \Misc\ lemma measurable_pred_stream[measurable]: fixes P shows "Measurable.pred (stream_space (count_space UNIV)) (pred_stream P)" proof - have [measurable]: "Measurable.pred (count_space UNIV) P" by measurable then show ?thesis unfolding stream.pred_set sset_range by simp qed lemma pmf_map_pmf_cong: fixes f g and \ :: "'a pmf" assumes "\ x. x \ \ \ f x = y1 \ g x = y2" shows "pmf (map_pmf f \) y1 = pmf (map_pmf g \) y2" unfolding pmf_map by (rule measure_pmf.finite_measure_eq_AE; simp add: AE_measure_pmf_iff assms split: split_indicator ) lemma collect_pair_finite[intro]: notes finite_subset[intro] assumes "finite {x. P x}" "finite {x. Q x}" shows "finite {(x, y) . P x \ Q y \ R x y}" using assms proof - from assms have "finite {(x, y) . P x \ Q y}" by auto moreover have "{(x, y) . P x \ (Q y \ R x y)} \ {(x, y) . P x \ Q y}" by auto ultimately show ?thesis by blast qed lemma collect_pair_finite'[intro]: notes finite_subset[intro] assumes "finite {(x, y). P x y}" shows "finite {(x, y) . P x y \ R x y}" using assms proof - from assms have "finite {(x, y) . P x y}" by auto moreover have "{(x, y) . P x y \ R x y} \ {(x, y) . P x y}" by auto ultimately show ?thesis by blast qed text \This is what we actually need in this theory\ lemma collect_pair_finite''[intro]: notes finite_subset[intro] assumes "finite {(x, y). P x \ Q y}" shows "finite {(x, y) . P x \ Q y \ R x y}" using assms proof - from assms have "finite {(x, y) . P x \ Q y}" by auto moreover have "{(x, y) . P x \ Q y \ R x y} \ {(x, y) . P x \ Q y}" by auto ultimately show ?thesis by blast qed lemma finite_imageI'[intro]: assumes "finite {(x, y). P x y}" shows "finite {f x y | x y. P x y}" proof - from assms have "finite ((\ (x, y). f x y) ` {(x, y). P x y})" by auto moreover have "((\ (x, y). f x y) ` {(x, y). P x y}) = {f x y | x y. P x y}" by auto ultimately show ?thesis by auto qed lemma finite_imageI''[intro]: assumes "finite (A \ B)" shows "finite {f x y | x y. x \ A \ y \ B \ R x y}" proof - from assms have "finite {f x y | x y. x \ A \ y \ B}" by auto moreover have "{f x y | x y. x \ A \ y \ B \ R x y} \ {f x y | x y. x \ A \ y \ B}" by auto ultimately show ?thesis by (blast intro: finite_subset) qed (* TODO: Move/should be somewhere already *) lemma pred_stream_stl: "pred_stream \ xs \ pred_stream \ (stl xs)" by (cases xs) auto (* TODO: Should be somewhere already *) lemma stream_all_pred_stream: "stream_all = pred_stream" by (intro ext) (simp add: stream.pred_set) lemma pred_stream_iff: "pred_stream P s \ Ball (sset s) P" using stream_all_iff[unfolded stream_all_pred_stream] . (* TODO: Move *) lemma measure_pmf_eq_1_iff: "emeasure (measure_pmf \) {x} = 1 \ \ = return_pmf x" using measure_pmf.prob_eq_1[of "{x}" \] set_pmf_subset_singleton[of \ x] by (auto simp: measure_pmf.emeasure_eq_measure AE_measure_pmf_iff) lemma HLD_mono: "HLD S \" if "HLD R \" "R \ S" using that unfolding HLD_iff by auto lemma alw_HLD_smap: "alw (HLD (f ` S)) (smap f \)" if "alw (HLD S) \" using that by (auto 4 3 elim: HLD_mono alw_mono) lemma alw_disjoint_ccontr: assumes "alw (HLD S) \" "ev (alw (HLD R)) \" "R \ S = {}" shows False proof - from assms(1,2) obtain \ where "alw (HLD S) \" "alw (HLD R) \" by (auto intro: alw_sdrop sdrop_wait) with \R \ S = {}\ show False by (auto 4 3 simp: HLD_iff dest: alwD) qed (* TODO: Move *) lemma stream_all2_refl: "stream_all2 P x x = pred_stream (\ x. P x x) x" by (simp add: stream.pred_rel eq_onp_def) (standard; coinduction arbitrary: x; auto) lemma AE_all_imp_countable: assumes "countable {x. Q x}" shows "(AE x in M. \y. Q y \ P x y) = (\y. Q y \ (AE x in M. P x y))" using assms by (auto dest: AE_ball_countable) lemma AE_conj: "almost_everywhere M P = almost_everywhere M (\ x. P x \ Q x)" if "almost_everywhere M Q" by (auto intro: AE_mp[OF that]) (* TODO: move *) lemma list_hd_lastD: assumes "length xs > 1" obtains x y ys where "xs = x # ys @ [y]" using assms by atomize_elim (cases xs; simp; metis rev_exhaust) (* TODO: Move *) lemma SUP_eq_and_INF_eq: assumes "\i. i \ A \ \j\B. f i = g j" and "\j. j \ B \ \i\A. g j = f i" shows "\((f :: _ \ _ :: complete_lattice) ` A) = \(g ` B) \ \(f ` A) = \(g ` B)" by (auto 4 3 intro!: INF_eq SUP_eq dest: assms) (* TODO: Move *) lemma measurable_alw_stream[measurable]: fixes P assumes [measurable]: "Measurable.pred (stream_space (count_space UNIV)) P" shows "Measurable.pred (stream_space (count_space UNIV)) (alw P)" unfolding alw_iff_sdrop by measurable (* TODO: Move *) lemma ev_neq_start_implies_ev_neq: assumes "ev (Not o HLD {y}) (y ## xs)" shows "ev (\ xs. shd xs \ shd (stl xs)) (y ## xs)" using assms apply (induction "y ## xs" arbitrary: xs rule: ev.induct) apply (simp; fail) subgoal for xs apply (cases "shd xs = y") subgoal apply safe apply (rule ev.step) apply simp using stream.collapse[of xs, symmetric] by blast subgoal by auto done done (* TODO: Move *) lemma ev_sdropD: assumes "ev P xs" obtains i where "P (sdrop i xs)" using assms apply atomize_elim apply (induction rule: ev.induct) apply (inst_existentials "0 :: nat"; simp; fail) apply (erule exE) subgoal for xs i by (inst_existentials "i + 1") simp done (* TODO: Move *) lemma pred_stream_sconst: "pred_stream ((=) x) (sconst x)" by coinduction simp (* TODO: Move *) lemma alw_Stream: "alw P (x ## s) \ P (x ## s) \ alw P s" by (subst alw.simps) simp (* TODO: Move *) lemma alw_True: "alw (\x. True) \" by (auto intro: all_imp_alw) (* TODO: Move *) lemma alw_conjI: "alw (P aand Q) xs" if "alw P xs" "alw Q xs" using that by (simp add: alw_aand) (* TODO: Move *) lemma alw_ev_cong: "alw (ev S) xs = alw (ev R) xs" if "alw P xs" "\ x. P x \ S x \ R x" by (rule alw_cong[where P = "alw P"]) (auto simp: HLD_iff that elim!: ev_cong) lemma alw_ev_HLD_cong: "alw (ev (HLD S)) xs = alw (ev (HLD R)) xs" if "alw (HLD P) xs" "\ x. x \ P \ x \ S \ x \ R" by (rule alw_ev_cong, rule that; simp add: HLD_iff that) (* TODO: Move *) lemma measurable_eq_stream_space[measurable (raw)]: assumes [measurable]: "f \ M \\<^sub>M stream_space (count_space UNIV)" shows "Measurable.pred M (\x. f x = c)" proof - have *: "(\x. f x = c) = (\x. \i. f x !! i = c !! i)" by (auto intro: eqI_snth simp: fun_eq_iff) show ?thesis unfolding * by measurable qed (* TODO: rename, and change to LTL constants i.e. HLD, aand, nxt etc. *) lemma prop_nth_sdrop: assumes "\ i\j. P (\ !! i)" shows "\ i. P (sdrop j \ !! i)" using assms by (induction j arbitrary: \) fastforce+ lemma prop_nth_sdrop_pair: assumes "\ i. P (\ !! i) (\' !! i)" shows "\ i. P (sdrop j \ !! i) (sdrop j \' !! i)" using assms by (induction j arbitrary: \ \') (auto, metis snth.simps(2)) lemma prop_nth_stl: "\ i. P (xs !! i) \ \ i. P (stl xs !! i)" by (metis snth.simps(2)) context Graph_Defs begin lemma steps_SCons_iff: "steps (x # y # xs) \ E x y \ steps (y # xs)" by (auto elim: steps.cases) lemma steps_Single_True: "steps [x] = True" by auto lemma add_step_iff: "(\ xs y. steps (x # xs @ [y]) \ length xs = Suc n \ P xs y) \ (\ z xs y. steps (x # z # xs @ [y]) \ length xs = n \ P (z # xs) y)" apply safe apply fastforce subgoal for xs y by (cases xs) auto done lemma compower_stepsD: assumes "(E ^^ n) s s'" obtains xs where "steps xs" "hd xs = s" "last xs = s'" "length xs = n + 1" using assms apply atomize_elim proof (induction n arbitrary: s') case 0 then show ?case by auto next case (Suc n) from Suc.prems show ?case by (auto 4 4 intro: steps_append_single dest: Suc.IH) qed lemma compower_stepsD': assumes "(E ^^ n) s s'" "n > 0" obtains xs where "steps (s # xs @ [s'])" "length xs + 1 = n" apply (rule compower_stepsD[OF assms(1)]) subgoal for xs by (auto simp: \n > 0\ intro: list_hd_lastD[of xs]) done end context MC_syntax begin theorem AE_T_iff_n: fixes P :: "'s stream \ bool" and x :: "'s" assumes "Measurable.pred (stream_space (count_space UNIV)) P" "n > 0" shows "almost_everywhere (T x) P = (\xs y. Graph_Defs.steps (\ a b. b \ K a) (x # xs @ [y]) \ length xs + 1 = n \ (AE \ in T y. P (xs @- y ## \)))" using assms apply (induction n arbitrary: x P) apply (simp; fail) subgoal for n x P apply (cases n) subgoal by (subst AE_T_iff) (auto simp: Graph_Defs.steps_SCons_iff Graph_Defs.steps_Single_True) subgoal premises prems for n' proof - have *: "Measurable.pred (stream_space (count_space UNIV)) (\ \. P (y ## \))" for y using prems(2) by measurable with prems(1)[OF *] prems(3-) show ?thesis by (auto simp: AE_T_iff[OF prems(2)] Graph_Defs.steps_SCons_iff Graph_Defs.add_step_iff) qed done done lemma AE_alw_accD: fixes P assumes P: "Measurable.pred (stream_space (count_space UNIV)) P" assumes *: "almost_everywhere (T s) (alw P)" "(s, s') \ acc" shows "almost_everywhere (T s') (alw P)" using *(2,1) proof induction case (step y z) then have "almost_everywhere (T y) (alw P)" "z \ K y" by auto then have "AE \ in T z. alw P (z ## \)" unfolding AE_T_iff[OF measurable_alw_stream[OF P], of y] by auto then show ?case by eventually_elim auto qed lemma acc_relfunD: assumes "(s, s') \ acc" obtains n where "((\ a b. b \ K a) ^^ n) s s'" using assms apply atomize_elim apply (drule rtrancl_imp_relpow) apply (erule exE) subgoal for n by (inst_existentials n) (induction n arbitrary: s'; auto) done (* TODO: If we can show measurable_alw_stream, then this subsumed by the lemma above *) lemma AE_all_accD: assumes "almost_everywhere (T s) (pred_stream P)" "(s, s') \ acc" shows "almost_everywhere (T s') (pred_stream P)" proof - from acc_relfunD[OF \_ \ acc\] obtain n where *: "((\ a b. b \ K a) ^^ n) s s'" . show ?thesis proof (cases "n = 0") case True with * assms(1) show ?thesis by auto next case False then have "n > 0" by simp with * obtain xs where "Graph_Defs.steps (\a b. b \ set_pmf (K a)) (s # xs @ [s'])" "Suc (length xs) = n" by (auto elim: Graph_Defs.compower_stepsD') with assms(1)[unfolded AE_T_iff_n[OF measurable_pred_stream \n > 0\, of P s]] show ?thesis by auto qed qed lemma AE_T_ev_HLD_infinite_strong': assumes "0 \ r" "r < 1" and r: "\x. x \ X \ Y \ measure_pmf.prob (K x) Y \ r" and ae: "AE \ in T x. alw (\ \. HLD Y \ \ ev (HLD X) \) \" shows "AE \ in T x. ev (HLD (- Y)) \" proof - define run where "run F = (HLD (Y - X)) suntil ((X \ Y) \ Y \ F)" for F have le_gfp: "alw (HLD Y) aand alw (\ \. HLD Y \ \ ev (HLD X) \) \ gfp run" proof (rule gfp_upperbound; clarsimp) fix \ assume "alw (HLD Y) \" "alw (\\. HLD Y \ \ ev (HLD X) \) \" then have "ev (HLD X) \" "alw (HLD Y) \" "alw (\\. HLD Y \ \ ev (HLD X) \) \" by auto then show "run (\xs. alw (HLD Y) xs \ alw (\\. HLD Y \ \ ev (HLD X) \) xs) \" proof (induction \ rule: ev_induct_strong) case (base \) then show ?case by (cases \) (auto intro!: suntil.base simp: alw_Stream run_def) next case (step \) show ?case unfolding run_def using \\ HLD X \\ \alw (HLD Y) \\ step(3)[unfolded run_def] step(4,5) by (auto 0 4 simp: HLD_def intro: suntil.step) qed qed have cont_run: "inf_continuous run" apply (auto simp: inf_continuous_def fun_eq_iff run_def) subgoal premises that for M x f by (rule suntil_mono[OF _ _ that(2) alw_True]) auto subgoal premises that for M x using that(2)[THEN spec, of 0] that(2) proof (induction rule: suntil_induct_strong) case (base \) then show ?case by (cases \) (simp add: suntil_Stream) next case (step \) then show ?case by (cases \) (simp add: suntil_Stream) qed done have [measurable]: "Measurable.pred (stream_space (count_space UNIV)) (gfp run)" apply measurable apply (rule measurable_gfp[OF cont_run]) apply (auto simp: run_def) done have "emeasure (T x) {\ \ space (T x). alw (HLD Y) \} \ emeasure (T x) {\ \ space (T x). ((alw (HLD Y)) aand (alw (\ \. HLD Y \ \ ev (HLD X) \))) \}" apply (rule emeasure_mono_AE) subgoal using ae by eventually_elim auto by measurable also have "\ \ emeasure (T x) {\ \ space (T x). gfp run \}" apply (rule emeasure_mono) subgoal using le_gfp by auto by measurable also have "\ \ r ^ n" for n proof (induction n arbitrary: x) case 0 then show ?case by (simp add: T.emeasure_le_1) next case (Suc n) { fix x have "(\\<^sup>+ t. \\<^sup>+ t'. emeasure (T t') {x\space S. t\X \ t\Y \ t'\Y \ gfp run x} \K t \K x) \ (\\<^sup>+ t. indicator (X \ Y) t * \\<^sup>+ t'. indicator Y t' * ennreal (r ^ n) \K t \K x)" using Suc by (auto intro!: nn_integral_mono split: split_indicator) also have "\ \ (\\<^sup>+ t. indicator (X \ Y) t * r \K x) * ennreal (r^n)" by (auto intro!: nn_integral_mono mult_right_mono r ennreal_leI split: split_indicator simp: nn_integral_multc mult.assoc[symmetric] measure_pmf.emeasure_eq_measure) also have "\ = emeasure (K x) (X \ Y) * r^(Suc n)" by (simp add: ennreal_mult \0 \ r\ nn_integral_multc ennreal_indicator mult.assoc) finally have *: "(\\<^sup>+ t. \\<^sup>+ t'. emeasure (T t') {x\space S. t \ X \ t \ Y \ t' \ Y \ gfp run x} \K t \K x) \ emeasure (K x) (X \ Y) * r^Suc n" . have "(\\<^sup>+ t. \\<^sup>+ t'. emeasure (T t') {x \ space S. t \ X \ t \ Y \ t' \ Y \ gfp run x} \K t \K x) + ennreal (r^Suc n) * emeasure (measure_pmf (K x)) (Y - X) \ emeasure (K x) (X \ Y) * ennreal (r^Suc n) + ennreal (r^Suc n) * emeasure (measure_pmf (K x)) (Y - X)" by (intro add_mono_left *) also have "\ = emeasure (K x) ((X \ Y) \ (Y - X)) * ennreal (r^Suc n)" by (subst plus_emeasure[symmetric]) (auto simp: field_simps) also have "\ \ 1 * ennreal (r^Suc n)" by (intro mult_right_mono measure_pmf.emeasure_le_1) simp finally have "(\\<^sup>+ t. \\<^sup>+ t'. emeasure (T t') {x \ space MC_syntax.S. t \ X \ t \ Y \ t' \ Y \ gfp run x} \K t \K x) + ennreal (r^Suc n) * emeasure (measure_pmf (K x)) (Y - X) \ 1 * ennreal (r^Suc n)" by simp } note * = this show ?case apply (subst gfp_unfold[OF inf_continuous_mono[OF cont_run]]) apply (subst run_def) apply (subst emeasure_suntil_disj) apply measurable [] subgoal for s by (rule AE_I2) (auto simp: HLD_iff) apply (rule le_funD[of _ _ x]) apply (rule lfp_lowerbound) apply (rule le_funI) apply (subst emeasure_Collect_T) apply measurable [] apply (subst emeasure_Collect_T) apply simp apply (simp add: nn_integral_cmult) using * by simp qed finally have "emeasure (T x) {\ \ space (T x). alw (HLD Y) \} \ r^n" for n . then have "emeasure (T x) {\ \ space (T x). alw (HLD Y) \} \ ennreal 0" using \0 \ r\ \r < 1\ by (intro LIMSEQ_le_const[OF tendsto_ennrealI[OF LIMSEQ_power_zero[of r]]]) auto then have *: "emeasure (T x) {\ \ space (T x). alw (HLD Y) \} = 0" by simp show ?thesis by (rule AE_I[OF _ *]) (auto simp: not_ev_iff not_HLD[symmetric]) qed end context Markov_Decision_Process begin lemma cfg_on_inv: "pred_stream (\ cfg. cfg \ cfg_on (state cfg)) \" if "MC.enabled cfg \" "cfg \ cfg_on s" using that proof (coinduction arbitrary: \ cfg s) case prems: stream_pred note [simp] = \_ = \\[symmetric] from prems(2) have "a \ set_pmf (K_cfg cfg)" "MC.enabled a w" by (auto simp: MC.enabled_Stream) moreover from \a \ _\ have "a \ cont cfg ` set_pmf (action cfg)" by (simp add: set_K_cfg) ultimately show ?case using \cfg \ _\ by auto qed lemma MC_T_not_sconst_strong: assumes "\ l. \ cfg \ (\ x \ f -` {u}. cfg_on x) \ Y \ X. measure_pmf (action cfg) (f -` {u}) \ r" "r < 1" "cfg \ cfg_on x" "AE \ in MC.T cfg. pred_stream (\ x. x \ X) \" "AE \ in MC.T cfg. alw (\ \. HLD (f -` {u}) (smap state \) \ ev (HLD Y) \) \" shows "AE \ in MC.T cfg. smap (f o state) \ \ sconst u" proof - let ?U = "f -` {u}" let ?S = "(\ x \ f -` {u}. cfg_on x) \ X" let ?T = "Y \ ((\ x \ f -` {u}. cfg_on x) \ X)" have *: "emeasure (K_cfg cfg) ?S \ r" if "cfg \ ?T" for cfg proof - have "emeasure (K_cfg cfg) ?S \ emeasure (measure_pmf (action cfg)) ?U" unfolding K_cfg_def by (auto dest: cfg_onD_state intro!: emeasure_mono) also from assms(1) \cfg \ ?T\ have "\ \ r" by auto finally show ?thesis . qed have "AE \ in MC.T cfg. ev (HLD (- ?S)) \" apply (rule MC.AE_T_ev_HLD_infinite_strong'[where r = "enn2real r" and ?X = Y]) apply (simp; fail) subgoal using \r < 1\ by (metis ennreal_enn2real_if ennreal_less_one_iff zero_less_one) subgoal for x by (drule *) (metis Sigma_Algebra.measure_def assms(2) enn2real_mono ennreal_one_less_top less_trans) subgoal using assms(5) by (rule AE_mp) (rule AE_I2, intro impI, auto simp: HLD_iff elim: alw_mono) done then show ?thesis apply (rule AE_mp) proof (rule AE_mp[OF assms(4)], rule AE_mp[OF MC.AE_T_enabled], rule AE_I2, safe) fix \ assume "\ \ space (MC.T cfg)" "pred_stream (\\. \ \ X) \" "MC.enabled cfg \" "ev (HLD (- ?S)) \" "smap (f \ state) \ = sconst u" from this(2,3) \cfg \ _\ have "pred_stream (\ x. x \ cfg_on (state x)) \" by (auto dest: cfg_onD_state intro!: cfg_on_inv) from \smap _ \ = _\ have "pred_stream (\ y. y \ (\ x \ ?U. cfg_on x)) \" proof - have "(f o state) cfg = u" if "cfg \ sset \" for cfg using stream.set_map[of "f o state" \] that \smap _ \ = _\ by fastforce with \pred_stream (\ x. x \ cfg_on (state x)) \\ show ?thesis by (auto elim!: stream.pred_mono_strong) qed with \pred_stream (\\. \ \ X) \\ have "pred_stream (\ x. x \ ?S) \" by (coinduction arbitrary: \) auto then have "alw (HLD ?S) \" by (simp add: alw_holds_pred_stream_iff HLD_def) with \ev (HLD (- ?S)) \\ show False unfolding not_ev_not[symmetric] not_HLD by simp qed qed lemma MC_T_not_sconst: assumes "\ l. \ cfg \ (\ x \ f -` {u}. cfg_on x) \ X. measure_pmf (action cfg) (f -` {u}) \ r" "r < 1" "cfg \ cfg_on x" "AE \ in MC.T cfg. pred_stream (\ x. x \ X) \" shows "AE \ in MC.T cfg. smap (f o state) \ \ sconst u" proof - let ?U = "f -` {u}" let ?S = "(\ x \ f -` {u}. cfg_on x) \ X" have *: "emeasure (K_cfg cfg) ?S \ r" if "cfg \ ?S" for cfg proof - have "emeasure (K_cfg cfg) ?S \ emeasure (measure_pmf (action cfg)) ?U" unfolding K_cfg_def by (auto dest: cfg_onD_state intro!: emeasure_mono) also from assms(1) \cfg \ ?S\ have "\ \ r" by auto finally show ?thesis . qed have "AE \ in MC.T cfg. ev (HLD (- ?S)) \" apply (rule MC.AE_T_ev_HLD_infinite[where r = "enn2real r"]) subgoal using \r < 1\ by (metis ennreal_enn2real_if ennreal_less_one_iff zero_less_one) apply (drule *) by (metis Sigma_Algebra.measure_def assms(2) enn2real_mono ennreal_one_less_top less_trans) then show ?thesis apply (rule AE_mp) proof (rule AE_mp[OF assms(4)], rule AE_mp[OF MC.AE_T_enabled], rule AE_I2, safe) fix \ assume "\ \ space (MC.T cfg)" "pred_stream (\\. \ \ X) \" "MC.enabled cfg \" "ev (HLD (- ?S)) \" "smap (f \ state) \ = sconst u" from this(2,3) \cfg \ _\ have "pred_stream (\ x. x \ cfg_on (state x)) \" by (auto dest: cfg_onD_state intro!: cfg_on_inv) from \smap _ \ = _\ have "pred_stream (\ y. y \ (\ x \ ?U. cfg_on x)) \" proof - have "(f o state) cfg = u" if "cfg \ sset \" for cfg using stream.set_map[of "f o state" \] that \smap _ \ = _\ by fastforce with \pred_stream (\ x. x \ cfg_on (state x)) \\ show ?thesis by (auto elim!: stream.pred_mono_strong) qed with \pred_stream (\\. \ \ X) \\ have "pred_stream (\ x. x \ ?S) \" by (coinduction arbitrary: \) auto then have "alw (HLD ?S) \" by (simp add: alw_holds_pred_stream_iff HLD_def) with \ev (HLD (- ?S)) \\ show False unfolding not_ev_not[symmetric] not_HLD by simp qed qed lemma MC_T_not_sconst': assumes "\ cfg \ cfg_on x \ X. measure_pmf (action cfg) {x} \ r" "r < 1" "cfg \ cfg_on x'" "AE \ in MC.T cfg. pred_stream (\ x. x \ X) \" shows "AE \ in MC.T cfg. smap state \ \ sconst x" using assms by (rule MC_T_not_sconst[where f = id, simplified]) lemma K_cfg_cfg_onI: "cfg' \ cfg_on (state cfg')" if "cfg \ cfg_on x" "cfg' \ K_cfg cfg" using that by (force simp: set_K_cfg) lemma MC_acc_cfg_onI: "cfg' \ cfg_on (state cfg')" if "(cfg, cfg') \ MC.acc" "cfg \ cfg_on x" proof - from that(1) obtain n where "((\ a b. b \ K_cfg a) ^^ n) cfg cfg'" by (erule MC.acc_relfunD) with \cfg \ cfg_on x\ show ?thesis by (induction n arbitrary: cfg') (auto intro: K_cfg_cfg_onI) qed lemma non_loop_tail_strong: assumes "\ l. \ cfg \ (\ x \ f -` {u}. cfg_on x) \ Y \ X. measure_pmf (action cfg) (f -` {u}) \ r" "r < 1" "cfg \ cfg_on x" "AE \ in MC.T cfg. pred_stream (\ x. x \ X) \" "AE \ in MC.T cfg. alw (\ \. HLD (f -` {u}) (smap state \) \ ev (HLD Y) \) \" shows "AE \ in MC.T cfg. \ (ev (alw (\ xs. shd xs = u))) (smap (f o state) \)" (is "AE \ in ?M. ?P \") proof - have *: "?P \ \ alw (\ xs. smap (f o state) xs \ sconst u) \" for \ apply (simp add: not_ev_iff) apply (rule arg_cong2[where f = alw]) apply (rule ext) subgoal for xs using MC.alw_HLD_iff_sconst[of u "smap (f o state) xs"] by (simp add: HLD_iff) by (rule HOL.refl) have "AE \ in ?M. alw (\ xs. smap (f o state) xs \ sconst u) \" apply (rule MC.AE_T_alw) subgoal by (intro pred_intros_logic measurable_eq_stream_space) measurable using assms by - (erule MC_T_not_sconst_strong, auto intro: MC.AE_all_accD MC.AE_alw_accD elim: MC_acc_cfg_onI ) with * show ?thesis by simp qed lemma non_loop_tail: assumes "\ l. \ cfg \ (\ x \ f -` {u}. cfg_on x) \ X. measure_pmf (action cfg) (f -` {u}) \ r" "r < 1" "cfg \ cfg_on x" "AE \ in MC.T cfg. pred_stream (\ x. x \ X) \" shows "AE \ in MC.T cfg. \ (ev (alw (\ xs. shd xs = u))) (smap (f o state) \)" (is "AE \ in ?M. ?P \") proof - have *: "?P \ \ alw (\ xs. smap (f o state) xs \ sconst u) \" for \ apply (simp add: not_ev_iff) apply (rule arg_cong2[where f = alw]) apply (rule ext) subgoal for xs using MC.alw_HLD_iff_sconst[of u "smap (f o state) xs"] by (simp add: HLD_iff) by (rule HOL.refl) have "AE \ in ?M. alw (\ xs. smap (f o state) xs \ sconst u) \" apply (rule MC.AE_T_alw) subgoal by (intro pred_intros_logic measurable_eq_stream_space) measurable using assms by - (erule MC_T_not_sconst, auto intro: MC.AE_all_accD elim: MC_acc_cfg_onI) with * show ?thesis by simp qed lemma non_loop_tail': assumes "\ cfg \ cfg_on x \ X. measure_pmf (action cfg) {x} \ r" "r < 1" "cfg \ cfg_on y" "AE \ in MC.T cfg. pred_stream (\ x. x \ X) \" shows "AE \ in MC.T cfg. \ (ev (alw (\ xs. shd xs = x))) (smap state \)" using assms by simp (erule non_loop_tail[where f = id, simplified]) end lemma (in Regions) intv_const_mono: assumes "u \ region X I r" "c1 \ X" "c2 \ X" "u c1 \ u c2" "\ isGreater (I c2)" shows "intv_const (I c1) \ intv_const (I c2)" proof - from assms have "intv_elem c1 u (I c1)" "intv_elem c2 u (I c2)" by auto with \u c1 \ u c2\ \\ _\ show ?thesis by (cases "I c1"; cases "I c2"; auto) qed lemma sset_sdrop: assumes "x \ sset (sdrop i xs)" shows "x \ sset xs" using assms by (auto simp: sset_range) lemma holds_untilD: assumes "(holds P until holds Q) xs" "\ i \ j. \ Q (xs !! i)" shows "P (xs !! j)" using assms proof (induction j arbitrary: xs) case 0 then show ?case by cases auto next case (Suc j) from Suc.prems show ?case by cases (auto dest!: Suc.IH) qed (* TODO: Move *) lemma frac_le_self: assumes "x \ 0" shows "frac x \ x" -using assms by (metis dual_order.trans frac_eq frac_lt_1 le_less not_le) + using assms less_trans [of "frac x" 1 x] + by (auto simp add: le_less frac_eq not_less frac_lt_1) lemma frac_le_1I: assumes "0 \ x" "x \ 1" "x \ y" shows "frac x \ y" -using assms by (metis dual_order.trans frac_eq frac_of_int le_less of_int_simps(2)) + using assms dual_order.trans frac_le_self by auto lemma frac_le_1I': assumes "0 \ x" "x \ y" "y < 1" shows "frac x \ frac y" proof - from assms have "frac y = y" by (simp add: frac_eq) moreover from assms have "frac x \ y" by (auto intro: frac_le_1I) ultimately show ?thesis by simp qed (* XXX Move *) lemmas [intro] = order.strict_implies_order[OF frac_lt_1] lemma nat_eventually_critical: assumes "P i" "\ P j" "i < j" shows "\ k \ i. P k \ \ P (Suc k)" using assms by (metis dec_induct less_le) lemma nat_eventually_critical_path: fixes i :: nat assumes "P i" "\ P j" "i < j" shows "\ k > i. k \ j \ \ P k \ (\ m \ i. m < k \ P m)" proof - let ?S = "{k. i < k \ k \ j \ \ P k}" let ?k = "Min ?S" from assms have "j \ ?S" by auto moreover have "finite ?S" by auto ultimately have "i < ?k" "?k \ j" "\ P ?k" using Min_in[of ?S] by blast+ moreover have "P m" if "i \ m" "m < ?k" for m proof (cases "i = m") case True with \P i\ show ?thesis by simp next case False with \i \ m\ have "i < m" by simp with Min_le[OF \finite _\] \m < ?k\ \?k \ j\ show ?thesis by fastforce qed ultimately show ?thesis using \P i\ by - (rule exI[where x = ?k]; blast) qed subsection \MDP Invariant\ locale Markov_Decision_Process_Invariant = Markov_Decision_Process K for K :: "'s \ 's pmf set"+ fixes S :: "'s set" assumes invariant: "\ s D. s \ S \ D \ K s \ (\s' \ D. s' \ S)" begin lemma E_invariant: "{s'. (s, s') \ E} \ S" if "s \ S" using that by (auto dest: invariant simp: E_def) definition "valid_cfg = (\s\S. cfg_on s)" lemma valid_cfgI: "s \ S \ cfg \ cfg_on s \ cfg \ valid_cfg" by (auto simp: valid_cfg_def) lemma valid_cfgD: "cfg \ valid_cfg \ cfg \ cfg_on (state cfg)" by (auto simp: valid_cfg_def) lemma action_closed: "s \ S \ cfg \ cfg_on s \ t \ action cfg \ t \ S" using cfg_onD_action[of cfg s] invariant[of s] by auto lemma shows valid_cfg_state_in_S: "cfg \ valid_cfg \ state cfg \ S" and valid_cfg_action: "cfg \ valid_cfg \ s \ action cfg \ s \ S" and valid_cfg_cont: "cfg \ valid_cfg \ s \ action cfg \ cont cfg s \ valid_cfg" by (auto simp: valid_cfg_def intro!: bexI[of _ s] intro: action_closed) lemma valid_K_cfg[intro]: "cfg \ valid_cfg \ cfg' \ K_cfg cfg \ cfg' \ valid_cfg" by (auto simp add: K_cfg_def valid_cfg_cont) lemma pred_stream_valid_cfg: assumes valid: "cfg \ valid_cfg" assumes enabled: "MC.enabled cfg xs" shows "pred_stream (\ cfg. cfg \ valid_cfg) xs" using assms by (coinduction arbitrary: cfg xs) (subst (asm) MC.enabled_iff; auto) lemma pred_stream_cfg_on: assumes valid: "cfg \ valid_cfg" assumes enabled: "MC.enabled cfg xs" shows "pred_stream (\ cfg. state cfg \ S \ cfg \ cfg_on (state cfg)) xs" using valid pred_stream_valid_cfg[OF _ enabled] unfolding stream.pred_set by (auto intro: valid_cfgI dest: valid_cfgD valid_cfg_state_in_S) lemma alw_S: "almost_everywhere (T cfg) (pred_stream (\s. s \ S))" if "cfg \ valid_cfg" unfolding T_def using pred_stream_cfg_on \cfg \ valid_cfg\ by (subst AE_distr_iff) (measurable, auto simp: stream.pred_set intro: AE_mp[OF MC.AE_T_enabled]) end context Finite_Markov_Decision_Process begin sublocale Invariant: Markov_Decision_Process_Invariant rewrites "Invariant.valid_cfg = valid_cfg" proof - show "Markov_Decision_Process_Invariant K S" by standard (auto dest: set_pmf_closed) then show "Markov_Decision_Process_Invariant.valid_cfg K S = valid_cfg" by (subst Markov_Decision_Process_Invariant.valid_cfg_def; simp add: valid_cfg_def) qed lemmas pred_stream_cfg_on = Invariant.pred_stream_cfg_on and pred_stream_valid_cfg = Invariant.pred_stream_valid_cfg and alw_S = Invariant.alw_S and valid_cfg_state_in_S = Invariant.valid_cfg_state_in_S end end