Theory Additional_Lemmas

theory Additional_Lemmas

imports 
  Main
  infnorm
  Partition
  Lattice_int
  Digits_int
begin

section ‹Additional Lemmas›

text ‹Lemma about length and concat.›
lemma length_concat_map_5: 
  "length (concat (map (λi. [f1 i, f2 i, f3 i, f4 i, f5 i]) xs)) = length xs * 5" 
by (induct xs, auto)

text ‹Lemma about splitting the index of sums.›
lemma sum_split_idx_prod:
  "(i=0..<k*l::nat. f i) = (i=0..<k. (j=0..<l. f (i*l+j)))"
proof -
  have set_rew: "{0..<k*l} = (λ(i,j). i*l+j) ` ({0..<k} × {0..<l})"
  proof (safe, goal_cases)
    case (1 x)
    have "x = (λ(i,j). i*l+j) (x div l, x mod l)" by auto
    moreover have "(x div l, x mod l){0..<k} × {0..<l}" using 1 less_mult_imp_div_less
      by (metis le_less_trans lessThan_atLeast0 lessThan_iff mem_Sigma_iff
        mod_less_divisor mult_zero_right neq0_conv zero_le)
    ultimately show ?case by blast
  next
    case (2 x i j)
    then show ?case 
    by (auto, metis less_nat_zero_code linorder_neqE_nat mod_lemma mult.commute nat_mod_lem)
  qed
  have inj: "inj_on (λ(i, y). i * l + y) ({0..<k} × {0..<l})" 
    unfolding inj_on_def by (auto) 
      (metis add.commute add_right_imp_eq linorder_neqE_nat mod_mult_self2 mult.commute 
        mult_cancel_right nat_mod_lem not_less_zero, 
       metis add.commute le0 le_less_trans mod_mult_self2 mult.commute nat_mod_lem)
  have "( i{0..<k*l}. f i) = ((i,j){0..<k}×{0..<l}. f (i*l+j))" 
    unfolding set_rew using inj
    by (subst sum.reindex[of "(λ(i, j). i * l + j)" "({0..<k} × {0..<l})" f])
       (auto simp add: prod.case_distrib)
  also have " = (i{0..<k}. (j{0..<l}. f (i*l+j)))"
    using sum.cartesian_product[of "(λi j. f (i*l+j))" "{0..<l}" "{0..<k}", symmetric]
    by auto
  finally show ?thesis by auto
qed

text ‹Helping lemma to split sums.›

lemma lt_M:
  assumes "M > (i<(n::nat). ¦b i¦::int)"
          "i<n. ¦x i¦  1" 
  shows "¦(i<n. x i * b i)¦ < M"
proof - 
  have "¦(i<(n::nat). x i * b i)::int¦  (i<n. ¦x i * b i¦)" using sum_abs by auto
  moreover have " = (i<n. ¦x i¦ * ¦b i¦)" using abs_mult by metis
  moreover have "  (i<n. ¦b i¦)" using assms 
    by (smt (verit, best) lessThan_iff mult_cancel_right2 sum_mono zero_less_mult_iff)
  moreover have " = (i<n. ¦b i¦)" using sum_distrib_left by metis
  ultimately have "¦(i<n. x i * b i)¦  (i<n. ¦b i¦)" by linarith
  then show ?thesis using assms by auto
qed



lemma split_sum:
  "(i<(n::nat). x i * (a i + M * b i)::int) = (i<n. x i * a i) + M * (i<n. x i * b i)"
proof -
  have "(i<(n::nat). x i * (a i + M * b i)) = (i<n. x i * a i) + (i<n. M * x i * b i)"
    by (simp add: distrib_left mult.commute mult.left_commute)
  also have " = (i<n. x i * a i) + M * (i<n. x i * b i)"
    using sum_distrib_left[symmetric, where r=M and f="(λi. x i*b i)" and A = "{0..<n}"]  
    by (metis (no_types, lifting) lessThan_atLeast0 mult.assoc sum.cong)
  finally show ?thesis by blast
qed



lemma split_eq_system:
  assumes "M > (i<n::nat. ¦a i¦::int)"
          "i<n. ¦x i¦  1" 
          "(i<n. x i * (a i + M * b i)) = 0" 
  shows   "(i<n. x i * a i) = 0  (i<n. x i * b i) = 0"
using assms proof (safe, goal_cases)
  case 1
  then show ?case 
  proof (cases "(i<n. x i * b i) = 0")
    case True
    then show ?thesis using assms(3) split_sum[of x a M b n] by auto
  next
    case False
    then have "¦(i<n. x i * a i)¦ < M * ¦(i<n. x i * b i)¦" 
      using lt_M[OF assms(1) assms(2)] False
      by (smt (verit, best) mult_less_cancel_left2)
    moreover have "¦(i<n. x i * a i)¦ = M * ¦(i<n. x i * b i)¦" 
      using assms(3) split_sum[of x a M b n] calculation by linarith
    ultimately have False by linarith 
    then show ?thesis by auto
  qed
next
  case 2
  then show ?case 
  proof (cases "(i<n. x i * b i) = 0")
    case True
    then show ?thesis using split_sum 2 using lt_M[OF assms(1) assms(2)]
       by auto
  next
    case False
    then have "¦(i<n. x i * a i)¦ < M * ¦(i<n. x i * b i)¦" 
      using lt_M[OF assms(1) assms(2)] False
      by (smt (verit, best) mult_less_cancel_left2)
    moreover have "¦(i<n. x i * a i)¦ = M * ¦(i<n. x i * b i)¦" 
      using split_sum[of x a M b n] assms calculation by linarith
    ultimately have False by linarith 
    then show ?thesis by auto
  qed
qed


text ‹Lemmas about splitting into 4 or 5 cases.›
text ‹Split into $4$ modulo classes›
lemma lt_4_split: "(i::nat) < 4  i = 0  i = 1  i = 2  i = 3"
by auto 

lemma mod_exhaust_less_4_int: "(i::int) mod 4 = 0  i mod 4 = 1  i mod 4 = 2  i mod 4 = 3"
using MacLaurin.mod_exhaust_less_4 by auto

lemma mod_4_choices:
  assumes "i mod 4 = 0  P i"
          "i mod 4 = 1  P i"
          "i mod 4 = 2  P i"
          "i mod 4 = 3  P i"
  shows "P (i::nat)"
using assms mod_exhaust_less_4 by auto

lemma mod_4_if_split:
  assumes "i mod 4 = 0  P = P0 i"
          "i mod 4 = 1  P = P1 i"
          "i mod 4 = 2  P = P2 i"
          "i mod 4 = 3  P = P3 i"
  shows "P = (if i mod 4 = 0 then P0 i else
               (if i mod 4 = 1 then P1 i else
               (if i mod 4 = 2 then P2 i else P3 (i::nat))))" (is "?P i")
using mod_exhaust_less_4  by (auto simp add: assms)

text ‹Split into $5$ modulo classes›

lemma lt_5_split: "(i::nat) < 5  i = 0  i = 1  i = 2  i = 3  i = 4"
by auto

lemma mod_exhaust_less_5_int: 
  "(i::int) mod 5 = 0  i mod 5 = 1  i mod 5 = 2  i mod 5 = 3  i mod 5 = 4"
using lt_5_split by linarith

lemma mod_exhaust_less_5: 
  "(i::nat) mod 5 = 0  i mod 5 = 1  i mod 5 = 2  i mod 5 = 3  i mod 5 = 4"
using lt_5_split by linarith

lemma mod_5_choices:
  assumes "i mod 5 = 0  P i"
          "i mod 5 = 1  P i"
          "i mod 5 = 2  P i"
          "i mod 5 = 3  P i"
          "i mod 5 = 4  P i"
  shows "P (i::nat)"
using assms mod_exhaust_less_5 by auto

lemma mod_5_if_split:
  assumes "i mod 5 = 0  P = P0 i"
          "i mod 5 = 1  P = P1 i"
          "i mod 5 = 2  P = P2 i"
          "i mod 5 = 3  P = P3 i"
          "i mod 5 = 4  P = P4 i"
  shows "P = (if i mod 5 = 0 then P0 i else
               (if i mod 5 = 1 then P1 i else
               (if i mod 5 = 2 then P2 i else
               (if i mod 5 = 3 then P3 i else
                                    P4 (i::nat)))))" (is "?P i")
using mod_exhaust_less_5  by (auto simp add: assms)

text ‹Representation of natural number in interval using lower bound.›

lemma split_lower_plus_diff:
  assumes "s  {n..<m::nat}"
  obtains j where "s = n+j" and "j<m-n"
using assms 
by (metis atLeastLessThan_iff diff_diff_left le_Suc_ex zero_less_diff)


end