Theory Greedy_Submodular_Approx

theory Greedy_Submodular_Approx
  imports
    Greedy_Step_Spec
begin

text ‹
  We first derive analytic bounds for the coefficient
  1 - (1 - 1/k)^k› appearing in the Nemhauser–Wolsey approximation ratio.
  These bounds are later combined with the greedy gap recurrence to obtain
  the standard 1 - 1/exp 1› guarantee.
›

text ‹
  First, we relate the finite quantity (1 - 1/k)^k› to the exponential
  function via a standard exponential inequality.
›

lemma pow_one_minus_inv_le_exp_neg1:
  fixes k :: nat
  assumes "k  1"
  shows "(1 - 1 / real k) ^ k  exp (-1 :: real)"
proof -
  have f1: "0 < k"
    using assms by auto
  have "1  real k"
    using assms one_of_nat_le_iff by blast
  then show ?thesis
    using f1 exp_ge_one_minus_x_over_n_power_n by presburger
qed

text ‹
  As a corollary, we obtain a uniform lower bound
  1 - (1 - 1/k)^k ≥ 1 - 1/exp 1› for all k ≥ 1›.
›

lemma coeff_ge_1_minus_inv_exp:
  fixes k :: nat
  assumes "k  1"
  shows "1 - (1 - 1 / real k) ^ k  1 - 1 / exp 1"
proof -
  from pow_one_minus_inv_le_exp_neg1[OF assms]
  have "(1 - 1 / real k) ^ k  exp (-1 :: real)" .
  then have "1 - (1 - 1 / real k) ^ k  1 - exp (-1 :: real)"
    by simp
  also have "exp (-1 :: real) = 1 / exp 1"
    by (simp add: exp_minus field_simps)
  finally show ?thesis .
qed


context Greedy_Setup
begin

section ‹Greedy approximation for monotone submodular maximization›

text ‹
  In this section we formalize the classical Nemhauser–Wolsey guarantee:
  for a non-negative, monotone, submodular function on a finite ground set,
  the greedy algorithm that selects k› elements achieves at least
  1 - (1 - 1/k)^k› times the optimal value. Combining this with the analytic
  bound above yields the familiar 1 - 1/e› approximation factor.
›

text ‹Elementary algebraic identity used in the gap recurrence.›
lemma one_minus_inv_times:
  fixes x :: real
  shows "(1 - 1 / real k) * x = x - x / real k"
  by (simp add: left_diff_distrib)

subsection ‹Greedy gap analysis›

text ‹
  We use the problem-level optimal value and the reusable marginal-gain
  averaging lemma from the base cardinality context to derive the greedy
  gap recurrence.
›

subsubsection ‹Gap sequence›

text ‹
  We introduce the gap sequence gap i = OPT_k - f (greedy_set i)› and
  show that it satisfies a simple linear recurrence under the greedy update.
›

definition gap :: "nat  real" where
  "gap i = OPT_k - f (greedy_set i)"

text ‹
  One-step inequality: the marginal gain of the greedy choice lower-bounds
  the average improvement towards OPT_k›.
›
lemma greedy_step_ineq:
  assumes "i < k"
    and S_sub: "greedy_set i  V"
    and R_nonempty: "V - greedy_set i  {}"
  shows "gain (greedy_set i)
           (argmax_gain (greedy_set i) (V - greedy_set i))
          (OPT_k - f (greedy_set i)) / real k"
proof -
  let ?S = "greedy_set i"
  let ?R = "V - ?S"

  obtain X where X_feas: "feasible X" and X_opt: "f X = OPT_k"
    using exists_opt_set by blast
  from X_feas have X_sub: "X  V" and cardX_le_k: "card X  k"
    unfolding feasible_def by auto

  have S_sub': "?S  V"
    using S_sub .

  have cardS_lt_k: "card ?S < k"
  proof -
    have "card ?S  i"
      by (rule card_greedy_le_i)
    with assms(1) show ?thesis
      by (meson le_less_trans)
  qed

  from marginal_gain_lower_bound[
        OF S_sub' X_sub cardS_lt_k cardX_le_k]
  obtain e where e_inR: "e  V - ?S"
    and e_lb: "gain ?S e  (f X - f ?S) / real k"
    by blast

  have finV: "finite V"
    by (rule finite_V)

  have finR: "finite ?R"
    using finV by auto
  have R_nonempty': "?R  {}"
    using R_nonempty by simp

  have argmax_max:
    "y?R. gain ?S y  gain ?S (argmax_gain ?S ?R)"
    using argmax_gain_max[OF finR R_nonempty'] .

  from argmax_max e_inR
  have e_le_argmax:
    "gain ?S e  gain ?S (argmax_gain ?S ?R)"
    by auto

  have argmax_lb:
    "gain ?S (argmax_gain ?S ?R)
        (f X - f ?S) / real k"
    using e_lb e_le_argmax by linarith

  have "(f X - f ?S) / real k = (OPT_k - f ?S) / real k"
    using X_opt by simp

  with argmax_lb
  have "gain ?S (argmax_gain ?S ?R)
         (OPT_k - f ?S) / real k"
    by simp

  thus ?thesis
    by simp
qed

text ‹Greedy sets are feasible whenever their size is at most k›.›

lemma greedy_set_feasible:
  assumes S_sub: "greedy_set i  V"
      and card_le_i: "card (greedy_set i)  i"
      and i_le_k: "i  k"
  shows "feasible (greedy_set i)"
proof -
  have "card (greedy_set i)  k"
    using card_le_i i_le_k by (meson order_trans)
  with S_sub show ?thesis
    unfolding feasible_def by auto
qed

corollary greedy_feasible:
  assumes "i  k"
  shows "feasible (greedy_set i)"
  using greedy_set_feasible[OF greedy_subset_V card_greedy_le_i assms] .

text ‹The gap is non-negative along the greedy sequence.›
lemma gap_nonneg:
  assumes S_sub: "greedy_set i  V"
      and card_le_i: "card (greedy_set i)  i"
      and i_le_k: "i  k"
  shows "0  gap i"
proof -
  have S_feas: "feasible (greedy_set i)"
    using greedy_set_feasible[OF S_sub card_le_i i_le_k] .
  have "f (greedy_set i)  OPT_k"
    using OPT_k_upper_bound[OF S_feas] .
  then have "0  OPT_k - f (greedy_set i)"
    by simp
  thus ?thesis
    unfolding gap_def by simp
qed

corollary greedy_gap_nonneg:
  assumes "i  k"
  shows "0  gap i"
  using gap_nonneg[OF greedy_subset_V card_greedy_le_i assms] .

corollary greedy_remainder_nonempty:
  assumes "i < k"
  shows "V - greedy_set i  {}"
proof -
  have "card (greedy_set i)  i"
    by (rule card_greedy_le_i)
  also have "... < k"
    using assms by simp
  also have "...  card V"
    using k_le_cardV by simp
  finally have "card (greedy_set i) < card V" .
  thus ?thesis
    by (rule remainder_nonempty_if_card_ltV)
qed

text ‹
  Gap recurrence: each step reduces the gap by at least a 1/k› fraction.
›
lemma gap_step_diff:
  assumes "i < k"
    and S_sub: "greedy_set i  V"
    and R_nonempty: "V - greedy_set i  {}"
  shows "gap (Suc i)  gap i - gap i / real k"
proof -
  let ?S = "greedy_set i"

  have base:
    "gain ?S (argmax_gain ?S (V - ?S))
        (OPT_k - f ?S) / real k"
    using greedy_step_ineq[OF assms] by simp

  have gap_Suc_eq:
    "gap (Suc i)
       = OPT_k - f ?S
         - gain ?S (argmax_gain ?S (V - ?S))"
  proof -
    have "gap (Suc i) = OPT_k - f (greedy_set (Suc i))"
      by (simp add: gap_def)
    also have " = OPT_k
                 - (f ?S
                    + gain ?S (argmax_gain ?S (V - ?S)))"
      using greedy_step_f_eq[OF R_nonempty] by simp
    also have " = OPT_k - f ?S
                   - gain ?S (argmax_gain ?S (V - ?S))"
      by simp
    finally show ?thesis .
  qed

  have "OPT_k - f ?S
        - gain ?S (argmax_gain ?S (V - ?S))
       OPT_k - f ?S
        - (OPT_k - f ?S) / real k"
    using base by linarith
  hence "gap (Suc i)
          OPT_k - f ?S - (OPT_k - f ?S) / real k"
    using gap_Suc_eq by simp

  also have "OPT_k - f ?S - (OPT_k - f ?S) / real k
             = gap i - gap i / real k"
    by (simp add: gap_def)

  finally show ?thesis .
qed

text ‹
  In multiplicative form, the gap shrinks by a factor of at most
  1 - 1/real k› per step.
›
lemma gap_step:
  assumes "i < k"
    and "greedy_set i  V"
    and "V - greedy_set i  {}"
  shows "gap (Suc i)  (1 - 1 / real k) * gap i"
proof -
  have "gap (Suc i)  gap i - gap i / real k"
    using gap_step_diff[OF assms] .
  also have "gap i - gap i / real k
             = (1 - 1 / real k) * gap i"
    using one_minus_inv_times[of "gap i"] by simp
  finally show ?thesis .
qed

lemma gap_0[simp]: "gap 0 = OPT_k"
proof -
  have "gap 0 = OPT_k - f (greedy_set 0)"
    by (simp add: gap_def)
  also have "greedy_set 0 = {}" by simp
  also have "f {} = 0" by (rule f_empty)
  finally show ?thesis by simp
qed

text ‹
  Geometric decay of the gap: after i› greedy steps the remaining gap is
  bounded by (1 - 1/real k)^i * OPT_k›.
›
lemma gap_geometric:
  assumes k_pos: "k > 0"
    and i_le_k: "i  k"
  shows "gap i  (1 - 1 / real k) ^ i * OPT_k"
using i_le_k
proof (induction i)
  case 0
  have "gap 0 = OPT_k" by simp
  thus ?case by simp
next
  case (Suc i)
  have i_le_k: "i  k" using Suc.prems by simp
  have i_lt_k: "i < k" using Suc.prems by simp

  have S_sub: "greedy_set i  V"
    by (rule greedy_subset_V)

  have cardSi_lt_V: "card (greedy_set i) < card V"
  proof -
    have "card (greedy_set i)  i"
      by (rule card_greedy_le_i)
    also have "... < k" using i_lt_k by simp
    also have "...  card V" using k_le_cardV by simp
    finally show ?thesis .
  qed

  have R_nonempty: "V - greedy_set i  {}"
    using remainder_nonempty_if_card_ltV[OF cardSi_lt_V] .

  have step:
    "gap (Suc i)  (1 - 1 / real k) * gap i"
    using gap_step[OF i_lt_k S_sub R_nonempty] .

  have coef_nonneg: "0  (1 - 1 / real k)"
  proof -
    have "1  real k" using k_pos by simp
    then have "1 / real k  1"
      by (simp add: field_simps)
    then show ?thesis
      by simp
  qed

  have mult_mono:
    "(1 - 1 / real k) * gap i
       (1 - 1 / real k) * ((1 - 1 / real k) ^ i * OPT_k)"
  proof -
    have IH: "gap i  (1 - 1 / real k) ^ i * OPT_k"
      using Suc.IH i_le_k by simp
    from IH coef_nonneg show ?thesis
      by (rule mult_left_mono)
  qed

  have pow_Suc:
   "(1 - 1 / real k) * ((1 - 1 / real k) ^ i * OPT_k)
     = (1 - 1 / real k) ^ Suc i * OPT_k"
   by (simp add: mult_ac)

  from step mult_mono have
    "gap (Suc i)
        (1 - 1 / real k) * ((1 - 1 / real k) ^ i * OPT_k)"
    by (rule order_trans)
  hence "gap (Suc i)
          (1 - 1 / real k) ^ Suc i * OPT_k"
    by (simp add: pow_Suc)
  thus ?case
    by simp
qed

text ‹
  As a consequence, the value of the greedy solution after k› steps is
  at least (1 - (1 - 1/real k)^k) * OPT_k›.
›
lemma greedy_sequence_bound:
  assumes k_pos: "k > 0"
  shows "f (greedy_set k)  (1 - (1 - 1 / real k) ^ k) * OPT_k"
proof -
  have gap_bound:
    "gap k  (1 - 1 / real k) ^ k * OPT_k"
    using gap_geometric[OF k_pos le_refl] .

  have f_eq:
    "f (greedy_set k) = OPT_k - gap k"
    by (simp add: gap_def)

  have lower_bound:
    "OPT_k - gap k  OPT_k - (1 - 1 / real k) ^ k * OPT_k"
  proof -
    have "- gap k  - ((1 - 1 / real k) ^ k * OPT_k)"
      using gap_bound by simp
    thus ?thesis
      by simp
  qed

  have "f (greedy_set k)  OPT_k - (1 - 1 / real k) ^ k * OPT_k"
    using f_eq lower_bound by simp

  also have "OPT_k - (1 - 1 / real k) ^ k * OPT_k
             = (1 - (1 - 1 / real k) ^ k) * OPT_k"
  proof -
    have "OPT_k - (1 - 1 / real k) ^ k * OPT_k
          = 1 * OPT_k - (1 - 1 / real k) ^ k * OPT_k"
      by simp
    also have "... = (1 - (1 - 1 / real k) ^ k) * OPT_k"
      by (simp add: left_diff_distrib)
    finally show ?thesis .
  qed

  finally show ?thesis .
qed

subsection ‹Non-negativity of OPT and approximation ratio›

text ‹
  Combining the discrete bound with the analytic inequality for
  1 - (1 - 1/k)^k› yields the standard 1 - 1/e› approximation factor.
›
theorem greedy_approximation:
  assumes k_pos: "k > 0"
  shows "f (greedy_set k)  (1 - 1 / exp 1) * OPT_k"
proof -
  have base_bound:
    "f (greedy_set k)  (1 - (1 - 1 / real k) ^ k) * OPT_k"
    using greedy_sequence_bound[OF k_pos] .

  have k_ge1: "k  1"
    using k_pos by simp

  have coeff_bound:
    "1 - (1 - 1 / real k) ^ k  1 - 1 / exp 1"
    using coeff_ge_1_minus_inv_exp[OF k_ge1] .

  have nonneg: "0  OPT_k"
    by (rule OPT_k_nonneg)

  have coeff_mono:
    "(1 - (1 - 1 / real k) ^ k) * OPT_k
       (1 - 1 / exp 1) * OPT_k"
    using coeff_bound nonneg
    by (rule mult_right_mono)

  from base_bound coeff_mono
  have "f (greedy_set k)  (1 - 1 / exp 1) * OPT_k"
    by (meson order_trans)
  thus ?thesis .
qed

subsection ‹Corollaries›

text ‹
  Define the approximation ratio of the greedy algorithm for a given k›
  (with the convention that the ratio is 1› when OPT_k = 0›), and show
  that it is always at least 1 - 1/exp 1›.
›
definition greedy_ratio :: real where
  "greedy_ratio = (if OPT_k = 0 then 1 else f (greedy_set k) / OPT_k)"

corollary greedy_ratio_ge_1_minus_inv_exp:
  assumes "k > 0"
  shows "greedy_ratio  1 - 1 / exp 1"
proof (cases "OPT_k = 0")
  case True
  then show ?thesis
    unfolding greedy_ratio_def
    by simp
next
  case False
  then have OPT_pos: "OPT_k > 0"
    using OPT_k_nonneg by auto
  have main: "f (greedy_set k)  (1 - 1 / exp 1) * OPT_k"
    using greedy_approximation[OF assms] .
  show ?thesis
    unfolding greedy_ratio_def
    using main False OPT_pos
    by (simp add: field_simps)
qed

end

section ‹Step-spec corollary›

text ‹
  Since Greedy_Step_Oracle› is a named instance of Greedy_Setup›, the
  Nemhauser--Wolsey approximation guarantee transfers directly to any oracle
  satisfying the step-specification assumptions.
›

context Greedy_Step_Oracle
begin

theorem greedy_step_oracle_approximation:
  assumes "k > 0"
  shows
    "f (Greedy_Setup.greedy_set V select k)
        (1 - 1 / exp 1) * OPT_k"
  using greedy_approximation[OF assms] .

end

end