Theory Gradient_Descent_Rates

theory Gradient_Descent_Rates
  imports
    Gradient_Descent
    Abstract_Descent
begin

section ‹Rate infrastructure for gradient descent›

text ‹
  This theory collects the first rate-style consequences of the
  gradient descent development.

  The purpose of this file is intentionally modest.  It does not yet prove
  the full O(1/N) function-value convergence theorem for smooth convex
  minimization.  Instead, it packages the telescoping arguments that follow
  directly from the one-step progress estimate already proved in
  @{text ‹Gradient_Descent›}.

  These lemmas are meant to be reusable later for projected gradient descent
  and other descent methods.
›

subsection ‹Finite-sum bounds for gradient descent›

text ‹
  The main direct consequence of the one-step progress inequality is that
  the weighted sum of squared gradient norms is bounded by the total decrease
  in objective value.
›

lemma gradient_descent_sum_weighted_gradient_norm_sq_bound:
  fixes f :: "'a::real_inner  real"
    and G :: "'a  'a"
  assumes smooth: "smooth_upper_bound_on L S f G"
  assumes gd: "gradient_descent_iterates alpha G x"
  assumes feasible: "feasible_iterates S x"
  assumes alpha_nonneg: "0  alpha"
  assumes step_size: "alpha * L  1"
  shows
    "sum (λn. (alpha / 2) * norm (G (x n)) ^ 2) {..<N}
       f (x 0) - f (x N)"
proof (rule sum_progress_le_initial_gap)
  fix n
  assume "n < N"
  show "(alpha / 2) * norm (G (x n)) ^ 2
       f (x n) - f (x (Suc n))"
    using gradient_descent_step_progress[
      OF smooth gd feasible alpha_nonneg step_size, of n] .
qed

text ‹
  A lower-bound version of the same result.
›

lemma gradient_descent_sum_weighted_gradient_norm_sq_bound_below:
  fixes f :: "'a::real_inner  real"
    and G :: "'a  'a"
  assumes smooth: "smooth_upper_bound_on L S f G"
  assumes gd: "gradient_descent_iterates alpha G x"
  assumes feasible: "feasible_iterates S x"
  assumes alpha_nonneg: "0  alpha"
  assumes step_size: "alpha * L  1"
  assumes lower: "B  f (x N)"
  shows
    "sum (λn. (alpha / 2) * norm (G (x n)) ^ 2) {..<N}
       f (x 0) - B"
proof -
  have "sum (λn. (alpha / 2) * norm (G (x n)) ^ 2) {..<N}
       f (x 0) - f (x N)"
    using gradient_descent_sum_weighted_gradient_norm_sq_bound[
      OF smooth gd feasible alpha_nonneg step_size] .
  also have "...  f (x 0) - B"
    using lower by linarith
  finally show ?thesis .
qed

text ‹
  If the step size is strictly positive, the coefficient alpha / 2 can be
  divided out.  This gives the standard finite-sum squared-gradient bound.
›

lemma gradient_descent_sum_gradient_norm_sq_bound:
  fixes f :: "'a::real_inner  real"
    and G :: "'a  'a"
  assumes smooth: "smooth_upper_bound_on L S f G"
  assumes gd: "gradient_descent_iterates alpha G x"
  assumes feasible: "feasible_iterates S x"
  assumes alpha_pos: "0 < alpha"
  assumes step_size: "alpha * L  1"
  shows
    "sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / alpha) * (f (x 0) - f (x N))"
proof -
  have alpha_nonneg: "0  alpha"
    using alpha_pos by simp

  have weighted:
    "sum (λn. (alpha / 2) * norm (G (x n)) ^ 2) {..<N}
       f (x 0) - f (x N)"
    using gradient_descent_sum_weighted_gradient_norm_sq_bound[
      OF smooth gd feasible alpha_nonneg step_size] .

  have coeff_pos: "0 < alpha / 2"
    using alpha_pos by simp

  have weighted_eq:
    "sum (λn. (alpha / 2) * norm (G (x n)) ^ 2) {..<N}
      = (alpha / 2) * sum (λn. norm (G (x n)) ^ 2) {..<N}"
    by (simp add: sum_distrib_left)

  have "(alpha / 2) * sum (λn. norm (G (x n)) ^ 2) {..<N}
       f (x 0) - f (x N)"
    using weighted weighted_eq by simp

  then show ?thesis
    using coeff_pos by (simp add: field_simps)
qed

lemma gradient_descent_sum_gradient_norm_sq_bound_below:
  fixes f :: "'a::real_inner  real"
    and G :: "'a  'a"
  assumes smooth: "smooth_upper_bound_on L S f G"
  assumes gd: "gradient_descent_iterates alpha G x"
  assumes feasible: "feasible_iterates S x"
  assumes alpha_pos: "0 < alpha"
  assumes step_size: "alpha * L  1"
  assumes lower: "B  f (x N)"
  shows
    "sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / alpha) * (f (x 0) - B)"
proof -
  have alpha_nonneg: "0  alpha"
    using alpha_pos by simp

  have weighted:
    "sum (λn. (alpha / 2) * norm (G (x n)) ^ 2) {..<N}
       f (x 0) - B"
    using gradient_descent_sum_weighted_gradient_norm_sq_bound_below[
      OF smooth gd feasible alpha_nonneg step_size lower] .

  have coeff_pos: "0 < alpha / 2"
    using alpha_pos by simp

  have weighted_eq:
    "sum (λn. (alpha / 2) * norm (G (x n)) ^ 2) {..<N}
      = (alpha / 2) * sum (λn. norm (G (x n)) ^ 2) {..<N}"
    by (simp add: sum_distrib_left)

  have "(alpha / 2) * sum (λn. norm (G (x n)) ^ 2) {..<N}
       f (x 0) - B"
    using weighted weighted_eq by simp

  then show ?thesis
    using coeff_pos by (simp add: field_simps)
qed


subsection ‹Average and small-gradient consequences›

text ‹
  The finite-sum bound immediately implies an average squared-gradient bound.
›

lemma gradient_descent_average_gradient_norm_sq_bound:
  fixes f :: "'a::real_inner  real"
    and G :: "'a  'a"
  assumes smooth: "smooth_upper_bound_on L S f G"
  assumes gd: "gradient_descent_iterates alpha G x"
  assumes feasible: "feasible_iterates S x"
  assumes alpha_pos: "0 < alpha"
  assumes step_size: "alpha * L  1"
  assumes N_pos: "N > 0"
  shows
    "(1 / real N) * sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / (alpha * real N)) * (f (x 0) - f (x N))"
proof -
  have sum_bound:
    "sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / alpha) * (f (x 0) - f (x N))"
    using gradient_descent_sum_gradient_norm_sq_bound[
      OF smooth gd feasible alpha_pos step_size] .

  have N_real_pos: "0 < real N"
    using N_pos by simp

  have "(1 / real N) * sum (λn. norm (G (x n)) ^ 2) {..<N}
       (1 / real N) * ((2 / alpha) * (f (x 0) - f (x N)))"
    using sum_bound N_real_pos by (intro mult_left_mono) simp_all
  also have "... = (2 / (alpha * real N)) * (f (x 0) - f (x N))"
    using alpha_pos N_real_pos by (simp add: field_simps)
  finally show ?thesis .
qed

lemma gradient_descent_average_gradient_norm_sq_bound_below:
  fixes f :: "'a::real_inner  real"
    and G :: "'a  'a"
  assumes smooth: "smooth_upper_bound_on L S f G"
  assumes gd: "gradient_descent_iterates alpha G x"
  assumes feasible: "feasible_iterates S x"
  assumes alpha_pos: "0 < alpha"
  assumes step_size: "alpha * L  1"
  assumes lower: "B  f (x N)"
  assumes N_pos: "N > 0"
  shows
    "(1 / real N) * sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / (alpha * real N)) * (f (x 0) - B)"
proof -
  have sum_bound:
    "sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / alpha) * (f (x 0) - B)"
    using gradient_descent_sum_gradient_norm_sq_bound_below[
      OF smooth gd feasible alpha_pos step_size lower] .

  have N_real_pos: "0 < real N"
    using N_pos by simp

  have "(1 / real N) * sum (λn. norm (G (x n)) ^ 2) {..<N}
       (1 / real N) * ((2 / alpha) * (f (x 0) - B))"
    using sum_bound N_real_pos by (intro mult_left_mono) simp_all
  also have "... = (2 / (alpha * real N)) * (f (x 0) - B)"
    using alpha_pos N_real_pos by (simp add: field_simps)
  finally show ?thesis .
qed

text ‹
  The next theorem states the usual small-gradient consequence: among the
  first N iterates, at least one iterate has squared gradient norm bounded
  by the average finite-sum bound.
›

lemma gradient_descent_exists_small_gradient_norm_sq:
  fixes f :: "'a::real_inner  real"
    and G :: "'a  'a"
  assumes smooth: "smooth_upper_bound_on L S f G"
  assumes gd: "gradient_descent_iterates alpha G x"
  assumes feasible: "feasible_iterates S x"
  assumes alpha_pos: "0 < alpha"
  assumes step_size: "alpha * L  1"
  assumes N_pos: "N > 0"
  shows
    "n<N. norm (G (x n)) ^ 2
       (2 / (alpha * real N)) * (f (x 0) - f (x N))"
proof -
  have sum_bound:
    "sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / alpha) * (f (x 0) - f (x N))"
    using gradient_descent_sum_gradient_norm_sq_bound[
      OF smooth gd feasible alpha_pos step_size] .

  have nonneg: "n. n < N  0  norm (G (x n)) ^ 2"
    by simp

  obtain n where n_lt: "n < N"
    and n_bound:
      "norm (G (x n)) ^ 2
         ((2 / alpha) * (f (x 0) - f (x N))) / real N"
    using exists_le_average_of_sum_bound[OF N_pos nonneg sum_bound] by auto

  have rewrite:
    "((2 / alpha) * (f (x 0) - f (x N))) / real N
      = (2 / (alpha * real N)) * (f (x 0) - f (x N))"
    using alpha_pos N_pos by (simp add: field_simps)

  have "norm (G (x n)) ^ 2
       (2 / (alpha * real N)) * (f (x 0) - f (x N))"
    using n_bound rewrite by simp

  then show ?thesis
    using n_lt by auto
qed

lemma gradient_descent_exists_small_gradient_norm_sq_below:
  fixes f :: "'a::real_inner  real"
    and G :: "'a  'a"
  assumes smooth: "smooth_upper_bound_on L S f G"
  assumes gd: "gradient_descent_iterates alpha G x"
  assumes feasible: "feasible_iterates S x"
  assumes alpha_pos: "0 < alpha"
  assumes step_size: "alpha * L  1"
  assumes lower: "B  f (x N)"
  assumes N_pos: "N > 0"
  shows
    "n<N. norm (G (x n)) ^ 2
       (2 / (alpha * real N)) * (f (x 0) - B)"
proof -
  have sum_bound:
    "sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / alpha) * (f (x 0) - B)"
    using gradient_descent_sum_gradient_norm_sq_bound_below[
      OF smooth gd feasible alpha_pos step_size lower] .

  have nonneg: "n. n < N  0  norm (G (x n)) ^ 2"
    by simp

  obtain n where n_lt: "n < N"
    and n_bound:
      "norm (G (x n)) ^ 2
         ((2 / alpha) * (f (x 0) - B)) / real N"
    using exists_le_average_of_sum_bound[OF N_pos nonneg sum_bound] by auto

  have rewrite:
    "((2 / alpha) * (f (x 0) - B)) / real N
      = (2 / (alpha * real N)) * (f (x 0) - B)"
    using alpha_pos N_pos by (simp add: field_simps)

  have "norm (G (x n)) ^ 2
       (2 / (alpha * real N)) * (f (x 0) - B)"
    using n_bound rewrite by simp

  then show ?thesis
    using n_lt by auto
qed


subsection ‹Weighted small-gradient consequences›

text ‹
  The weighted version does not require dividing by alpha.  It is therefore
  available even for the degenerate case alpha = 0, although the resulting
  statement is mainly useful when alpha is positive.
›

lemma gradient_descent_exists_small_weighted_gradient_norm_sq:
  fixes f :: "'a::real_inner  real"
    and G :: "'a  'a"
  assumes smooth: "smooth_upper_bound_on L S f G"
  assumes gd: "gradient_descent_iterates alpha G x"
  assumes feasible: "feasible_iterates S x"
  assumes alpha_nonneg: "0  alpha"
  assumes step_size: "alpha * L  1"
  assumes N_pos: "N > 0"
  shows
    "n<N. (alpha / 2) * norm (G (x n)) ^ 2
       (f (x 0) - f (x N)) / real N"
proof -
  have sum_bound:
    "sum (λn. (alpha / 2) * norm (G (x n)) ^ 2) {..<N}
       f (x 0) - f (x N)"
    using gradient_descent_sum_weighted_gradient_norm_sq_bound[
      OF smooth gd feasible alpha_nonneg step_size] .

  have nonneg:
    "n. n < N  0  (alpha / 2) * norm (G (x n)) ^ 2"
  proof -
    fix n
    assume "n < N"
    have "0  alpha / 2"
      using alpha_nonneg by simp
    moreover have "0  norm (G (x n)) ^ 2"
      by simp
    ultimately show "0  (alpha / 2) * norm (G (x n)) ^ 2"
      by (rule mult_nonneg_nonneg)
  qed

  show ?thesis
    using exists_le_average_of_sum_bound[OF N_pos nonneg sum_bound] .
qed


subsection ‹Locale form›

context gradient_descent
begin

lemma sum_weighted_gradient_norm_sq_bound:
  "sum (λn. (alpha / 2) * norm (G (x n)) ^ 2) {..<N}
     f (x 0) - f (x N)"
  using gradient_descent_sum_weighted_gradient_norm_sq_bound[
    OF smooth_bound iterates feasible alpha_nonneg step_size] .

lemma sum_weighted_gradient_norm_sq_bound_below:
  assumes lower: "B  f (x N)"
  shows
    "sum (λn. (alpha / 2) * norm (G (x n)) ^ 2) {..<N}
       f (x 0) - B"
  using gradient_descent_sum_weighted_gradient_norm_sq_bound_below[
    OF smooth_bound iterates feasible alpha_nonneg step_size lower] .

lemma exists_small_weighted_gradient_norm_sq:
  assumes N_pos: "N > 0"
  shows
    "n<N. (alpha / 2) * norm (G (x n)) ^ 2
       (f (x 0) - f (x N)) / real N"
  using gradient_descent_exists_small_weighted_gradient_norm_sq[
    OF smooth_bound iterates feasible alpha_nonneg step_size N_pos] .

lemma sum_gradient_norm_sq_bound:
  assumes alpha_pos: "0 < alpha"
  shows
    "sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / alpha) * (f (x 0) - f (x N))"
  using gradient_descent_sum_gradient_norm_sq_bound[
    OF smooth_bound iterates feasible alpha_pos step_size] .

lemma sum_gradient_norm_sq_bound_below:
  assumes alpha_pos: "0 < alpha"
  assumes lower: "B  f (x N)"
  shows
    "sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / alpha) * (f (x 0) - B)"
  using gradient_descent_sum_gradient_norm_sq_bound_below[
    OF smooth_bound iterates feasible alpha_pos step_size lower] .

lemma average_gradient_norm_sq_bound:
  assumes alpha_pos: "0 < alpha"
  assumes N_pos: "N > 0"
  shows
    "(1 / real N) * sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / (alpha * real N)) * (f (x 0) - f (x N))"
  using gradient_descent_average_gradient_norm_sq_bound[
    OF smooth_bound iterates feasible alpha_pos step_size N_pos] .

lemma average_gradient_norm_sq_bound_below:
  assumes alpha_pos: "0 < alpha"
  assumes lower: "B  f (x N)"
  assumes N_pos: "N > 0"
  shows
    "(1 / real N) * sum (λn. norm (G (x n)) ^ 2) {..<N}
       (2 / (alpha * real N)) * (f (x 0) - B)"
  using gradient_descent_average_gradient_norm_sq_bound_below[
    OF smooth_bound iterates feasible alpha_pos step_size lower N_pos] .

lemma exists_small_gradient_norm_sq:
  assumes alpha_pos: "0 < alpha"
  assumes N_pos: "N > 0"
  shows
    "n<N. norm (G (x n)) ^ 2
       (2 / (alpha * real N)) * (f (x 0) - f (x N))"
  using gradient_descent_exists_small_gradient_norm_sq[
    OF smooth_bound iterates feasible alpha_pos step_size N_pos] .

lemma exists_small_gradient_norm_sq_below:
  assumes alpha_pos: "0 < alpha"
  assumes lower: "B  f (x N)"
  assumes N_pos: "N > 0"
  shows
    "n<N. norm (G (x n)) ^ 2
       (2 / (alpha * real N)) * (f (x 0) - B)"
  using gradient_descent_exists_small_gradient_norm_sq_below[
    OF smooth_bound iterates feasible alpha_pos step_size lower N_pos] .

end


text ‹
  This file gives the first rate-style consequences of the descent estimate
  for gradient descent.  The next natural step is to prove a stronger
  distance-to-solution one-step inequality under convexity, which can then be
  telescoped to obtain the standard O(1/N) function-value convergence rate.
›

end