Theory Lazy_Greedy_Stateful_Approx

theory Lazy_Greedy_Stateful_Approx
  imports
    Greedy_Submodular_Approx
    Lazy_Greedy_Stateful_StepSpec
begin

text ‹
  Approximation guarantee for the verified stateful lazy greedy construction.

  This theory treats the stateful lazy algorithm as an implementation-oriented
  variant of the greedy construction. It reuses the optimal-value infrastructure
  from the greedy approximation development, together with the per-iteration
  lemmas from the lazy step-spec theory, and proves a corresponding gap
  recurrence for the lazy construction.

  In particular, this theory does not instantiate the stateless step-spec
  locale. Instead, it works directly with the verified lazy run and its
  sequence-level properties.
›

context Cardinality_Constraint
begin

definition gapL :: "nat  real" where
  "gapL i = OPT_k - f (lazy_set i)"

lemma lazy_set_0[simp]: "lazy_set 0 = {}"
  by (simp add: lazy_set_def init_state_def)

lemma lazy_set_subset_V[simp]: "lazy_set i  V"
  using lazy_state_subset_V[of i]
  by (simp add: lazy_set_def)

lemma lazy_set_finite[simp]: "finite (lazy_set i)"
  using finite_V lazy_set_subset_V
  by (meson finite_subset)

lemma remaining_lazy_state[simp]: "remaining (lazy_state i) = V - lazy_set i"
  by (simp add: remaining_def lazy_set_def)

lemma card_lazy_le_i: "card (lazy_set i)  i"
proof (induction i)
  case 0
  then show ?case by simp
next
  case (Suc i)
  show ?case
  proof (cases "V - lazy_set i = {}")
    case True
    have "lazy_step (lazy_state i) = lazy_state i"
      using lazy_step_idle[of "lazy_state i"] True by simp
    hence "lazy_set (Suc i) = lazy_set i"
      by (simp add: lazy_set_def)
    thus ?thesis using Suc.IH by simp
  next
    case False
    have ins: "lazy_set (Suc i) = insert (lazy_choice i) (lazy_set i)"
      using lazy_set_Suc_insert_V_minus_S[OF False] .
    have xin: "lazy_choice i  V - lazy_set i"
      using lazy_choice_in_V_minus_S[OF False] .
    have xnot: "lazy_choice i  lazy_set i" using xin by simp
    have "card (lazy_set (Suc i)) = card (lazy_set i) + 1"
      using ins xnot by simp
    thus ?thesis using Suc.IH by simp
  qed
qed

lemma card_lazy_lt_k:
  "i < k  card (lazy_set i) < k"
  using card_lazy_le_i by (meson le_less_trans)

lemma lazy_remainder_nonempty:
  "i < k  V - lazy_set i  {}"
proof -
  assume i_lt_k: "i < k"

  have "card (lazy_set i)  i"
    by (rule card_lazy_le_i)
  also have "... < k"
    using i_lt_k by simp
  also have "...  card V"
    using k_le_cardV by simp
  finally have ltV: "card (lazy_set i) < card V" .

  have S_sub: "lazy_set i  V"
    by simp

  show "V - lazy_set i  {}"
  proof
    assume empty: "V - lazy_set i = {}"
    have V_sub: "V  lazy_set i"
      using empty by auto
    have eq: "lazy_set i = V"
      using subset_antisym[OF S_sub V_sub] by simp
    thus False
      using ltV by simp
  qed
qed

lemma lazy_set_feasible:
  assumes "i  k"
  shows "feasible (lazy_set i)"
proof -
  have sub: "lazy_set i  V" by simp
  have card_le_k: "card (lazy_set i)  k"
    using card_lazy_le_i assms by (rule le_trans)
  show ?thesis
    using sub card_le_k
    by (simp add: feasible_def)
qed

lemma gapL_nonneg:
  assumes "i  k"
  shows "0  gapL i"
proof -
  have feas: "feasible (lazy_set i)"
    using lazy_set_feasible[OF assms] .
  have ub: "f (lazy_set i)  OPT_k"
    by (rule OPT_k_upper_bound[OF feas])
  show ?thesis
    using ub by (simp add: gapL_def)
qed

lemma lazy_step_ineq:
  "i < k  gain (lazy_set i) (lazy_choice i)  gapL i / real k"
proof -
  assume i_lt_k: "i < k"

  have S_sub: "lazy_set i  V"
    by simp
  have cardS_lt_k: "card (lazy_set i) < k"
    using card_lazy_lt_k[OF i_lt_k] .

  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

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

  have rem_ne: "V - lazy_set i  {}"
    using lazy_remainder_nonempty[OF i_lt_k] .

  have argmax:
    "yV - lazy_set i. gain (lazy_set i) y  gain (lazy_set i) (lazy_choice i)"
    using lazy_choice_argmax_V_minus_S[OF rem_ne] .

  have e_le: "gain (lazy_set i) e  gain (lazy_set i) (lazy_choice i)"
    using argmax e_in by auto

  have e_lb': "gapL i / real k  gain (lazy_set i) e"
    using e_lb X_opt
    by (simp add: gapL_def)

  have "gapL i / real k  gain (lazy_set i) (lazy_choice i)"
    using order_trans[OF e_lb' e_le] .

  thus "gain (lazy_set i) (lazy_choice i)  gapL i / real k"
    by simp
qed

lemma gapL_step:
  "i < k  gapL (Suc i)  (1 - 1 / real k) * gapL i"
proof -
  assume i_lt_k: "i < k"

  have rem_ne: "V - lazy_set i  {}"
    using lazy_remainder_nonempty[OF i_lt_k] .

  have ins: "lazy_set (Suc i) = insert (lazy_choice i) (lazy_set i)"
    using lazy_set_Suc_insert_V_minus_S[OF rem_ne] .

  have step_gain:
    "f (lazy_set (Suc i)) = f (lazy_set i) + gain (lazy_set i) (lazy_choice i)"
    using ins by (simp add: gain_def algebra_simps)

  have gap_suc: "gapL (Suc i) = gapL i - gain (lazy_set i) (lazy_choice i)"
    by (simp add: gapL_def step_gain)

  have gain_lb: "gain (lazy_set i) (lazy_choice i)  gapL i / real k"
    using lazy_step_ineq[OF i_lt_k] .

  have "gapL (Suc i)  gapL i - gapL i / real k"
    using gap_suc gain_lb by linarith
  also have "... = (1 - 1 / real k) * gapL i"
    by (simp add: algebra_simps)
  finally show "gapL (Suc i)  (1 - 1 / real k) * gapL i" .
qed

lemma gapL_geometric:
  "k > 0  i  k  gapL i  (1 - 1 / real k) ^ i * OPT_k"
proof (induction i)
  case 0
  then show ?case
    by (simp add: gapL_def f_empty)
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 step: "gapL (Suc i)  (1 - 1 / real k) * gapL i"
    using gapL_step[OF i_lt_k] .

  have coef_nonneg: "0  (1 - 1 / real k)"
  proof -
    have "1  real k"
      using Suc.prems(1) by simp
    then have "1 / real k  1"
      by (simp add: field_simps)
    thus ?thesis
      by simp
  qed

  have IH: "gapL i  (1 - 1 / real k) ^ i * OPT_k"
    using Suc.IH[OF Suc.prems(1) i_le_k] .

  have mult_mono:
    "(1 - 1 / real k) * gapL i
      (1 - 1 / real k) * ((1 - 1 / real k) ^ i * OPT_k)"
    using IH coef_nonneg
    by (rule mult_left_mono)

  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)

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

theorem lazy_stateful_approximation:
  assumes k_pos: "k > 0"
  shows "f (lazy_set k)  (1 - 1 / exp 1) * OPT_k"
proof -
  have gap_bound: "gapL k  (1 - 1 / real k) ^ k * OPT_k"
    using gapL_geometric[OF k_pos, of k]
    by simp

  have f_eq: "f (lazy_set k) = OPT_k - gapL k"
    by (simp add: gapL_def)

  have lower: "OPT_k - gapL k  OPT_k - (1 - 1 / real k) ^ k * OPT_k"
    using gap_bound by linarith

  have base_bound: "f (lazy_set k)  (1 - (1 - 1 / real k) ^ k) * OPT_k"
  proof -
    have "f (lazy_set k)  OPT_k - (1 - 1 / real k) ^ k * OPT_k"
      using f_eq lower by simp
    also have "OPT_k - (1 - 1 / real k) ^ k * OPT_k
               = (1 - (1 - 1 / real k) ^ k) * OPT_k"
      by (simp add: algebra_simps)
    finally show ?thesis .
  qed

  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)

  show "f (lazy_set k)  (1 - 1 / exp 1) * OPT_k"
    using base_bound coeff_mono
    by (meson order_trans)
qed

end

section ‹Acknowledgements›

text ‹
  The author is grateful to Wenda Li for careful reviews, comments, and
  guidance from the early stages of this project through the preparation of
  this AFP entry.
›

end