Theory Linear_Bound_Argument

(* Title: Linear_Bound_Argument.thy
   Author: Chelsea Edmonds
*)
section ‹Linear Bound Argument - General ›
text ‹Lemmas to enable general reasoning using the linear bound argument for combinatorial proofs.
Jukna cite"juknaExtremalCombinatorics2011" presents a good overview of the mathematical background 
this theory is based on and applications ›
theory Linear_Bound_Argument imports Incidence_Matrices Jordan_Normal_Form.DL_Rank 
Jordan_Normal_Form.Ring_Hom_Matrix
begin

subsection ‹Vec Space Extensions›
text ‹Simple extensions to the existing vector space locale on linear independence ›
context vec_space
begin 
lemma lin_indpt_set_card_lt_dim: 
  fixes A :: "'a vec set"
  assumes "A  carrier_vec n"
  assumes "lin_indpt A"
  shows "card A  dim"
  using assms(1) assms(2) fin_dim li_le_dim(2) by blast

lemma lin_indpt_dim_col_lt_dim: 
  fixes A :: "'a mat"
  assumes "A  carrier_mat n nc"
  assumes "distinct (cols A)"
  assumes "lin_indpt (set (cols A))"
  shows "nc  dim"
proof -
  have b: "card (set (cols A)) = dim_col A" using cols_length assms(2)
    by (simp add: distinct_card) 
  have "set (cols A)  carrier_vec n" using assms(1) cols_dim by blast
  thus ?thesis using lin_indpt_set_card_lt_dim assms b by auto
qed

lemma lin_comb_imp_lin_dep_fin: 
  fixes A :: "'a vec set"
  assumes "finite A"
  assumes "A  carrier_vec n"
  assumes "lincomb c A = 0v n"
  assumes " a. a  A  c a  0"
  shows "lin_dep A"
  unfolding lin_dep_def using assms lincomb_as_lincomb_list_distinct sumlist_nth by auto

text ‹While a trivial definition, this enables us to directly reference the definition outside
of a locale context, as @{term "lin_indpt"} is an inherited definition ›
definition lin_indpt_vs:: "'a vec set  bool" where
"lin_indpt_vs A  lin_indpt A"

lemma lin_comb_sum_lin_indpt: 
  fixes A :: "'a vec list"
  assumes "set (A)  carrier_vec n"
  assumes "distinct A"
  assumes " f. lincomb_list (λi. f (A ! i)) A = 0v n  v (set A). f v = 0"
  shows "lin_indpt (set A)"
  by (rule finite_lin_indpt2, auto simp add: assms lincomb_as_lincomb_list_distinct)

lemma lin_comb_mat_lin_indpt: 
  fixes A :: "'a vec list"
  assumes "set (A)  carrier_vec n"
  assumes "distinct A"
  assumes " f. mat_of_cols n A *v vec (length A) (λi. f (A ! i))  = 0v n  v (set A). f v = 0"
  shows "lin_indpt (set A)"
proof (rule lin_comb_sum_lin_indpt, auto simp add: assms)
  fix f v 
  have " v. v  set A  dim_vec v = n"
    using assms by auto
  then show "lincomb_list (λi. f (A ! i)) A = 0v n  v  set A  f v = 0"
    using  lincomb_list_as_mat_mult[of A "(λi. f (A ! i))"] assms(3)[of f] by auto
qed

lemma lin_comb_mat_lin_indpt_vs: 
  fixes A :: "'a vec list"
  assumes "set (A)  carrier_vec n"
  assumes "distinct A"
  assumes " f. mat_of_cols n A *v vec (length A) (λi. f (A ! i))  = 0v n  v (set A). f v = 0"
  shows "lin_indpt_vs (set A)"
  using lin_comb_mat_lin_indpt lin_indpt_vs_def assms by auto


end

subsection ‹Linear Bound Argument Lemmas›

text ‹Three general representations of the linear bound argument, requiring a direct fact of 
linear independence onthe rows of the vector space over either a set A of vectors, list xs of vectors
or a Matrix' columns ›
lemma lin_bound_arg_general_set: 
  fixes A ::"('a :: {field})vec set"
  assumes "A  carrier_vec nr"
  assumes "vec_space.lin_indpt_vs nr A"
  shows "card A  nr"
  using vec_space.lin_indpt_set_card_lt_dim[of "A" "nr"] vec_space.lin_indpt_vs_def[of nr A] 
    vec_space.dim_is_n assms by metis 

lemma lin_bound_arg_general_list: 
  fixes xs ::"('a :: {field})vec list"
  assumes "distinct xs"
  assumes "(set xs)  carrier_vec nr"
  assumes "vec_space.lin_indpt_vs nr (set xs)"
  shows "length (xs)  nr"
  using lin_bound_arg_general_set[of "set xs" nr] distinct_card assms
  by force 

lemma lin_bound_arg_general: 
  fixes A ::"('a :: {field}) mat"
  assumes "distinct (cols A)"
  assumes "A  carrier_mat nr nc"
  assumes "vec_space.lin_indpt_vs nr (set (cols A))"
  shows "nc  nr"
proof -
  have ss: "set (cols A)  carrier_vec nr" using assms cols_dim by blast 
  have "length (cols A) = nc"
    using assms(2) cols_length by blast 
  thus ?thesis using lin_bound_arg_general_list[of "cols A" "nr"] ss assms by simp
qed

text‹The linear bound argument lemma on a matrix requiring the lower level assumption on a linear
combination. This removes the need to directly refer to any aspect of the linear algebra libraries ›
lemma lin_bound_argument: 
  fixes A :: "('a :: {field}) mat"
  assumes "distinct (cols A)"
  assumes "A  carrier_mat nr nc"
  assumes " f. A *v vec nc (λi. f (col A i)) = 0v nr  v (set (cols A)). f v = 0"
  shows "nc  nr"
proof (intro lin_bound_arg_general[of "A" nr nc] vec_space.lin_comb_mat_lin_indpt_vs, simp_all add: assms)
  show "set (cols A)  carrier_vec nr" using assms cols_dim by blast
next
  have mA: "mat_of_cols nr (cols A) = A" using mat_of_cols_def assms by auto
  have " f. vec (dim_col A) (λi. f (cols A ! i)) = vec nc (λi. f (col A i))"
  proof (intro eq_vecI, simp_all add: assms)
    show "f i. i < nc  vec (dim_col A) (λi. f (cols A ! i)) $ i = f (col A i)"
      using assms(2) by force
    show "dim_col A = nc " using assms by simp
  qed
  then show "f. mat_of_cols nr (cols A) *v vec (dim_col A) (λi. f (cols A ! i)) = 0v nr  
      vset (cols A). f v = 0"
    using mA assms(3) by metis
qed

text ‹A further extension to present the linear combination directly as a sum. This manipulation from 
vector product to a summation was found to commonly be repeated in proofs applying this rule ›
lemma lin_bound_argument2: 
  fixes A :: "('a :: {field}) mat"
  assumes "distinct (cols A)"
  assumes "A  carrier_mat nr nc"
  assumes " f. vec nr (λi.  j  {0..<nc} . f (col A j) * (col A j) $ i) = 0v nr  
    v (set (cols A)). f v = 0"
  shows "nc  nr"
proof (intro lin_bound_argument[of A nr nc], simp add: assms, simp add: assms)
  fix f 
  have "A *v vec nc (λi. f (col A i)) = 
      vec (dim_row A) (λi.  j  {0..<nc} . (row A i $ j) * f (col A j))"
    by (auto simp add: mult_mat_vec_def scalar_prod_def assms(2)) 
  also have "... = vec (dim_row A) (λi.  j  {0..<nc} . f (col A j) * (col A j $ i))"
    using assms(2) by (intro eq_vecI, simp_all) (meson mult.commute) 
  finally show "A *v vec nc (λi. f (col A i)) = 0v nr  vset (cols A). f v = 0" 
    using assms(3)[of f] assms(2) by fastforce 
qed

end