import Mathlib
import Optlib


open Filter Topology Set InnerProductSpace Finset

open Finset

theorem extracted_formal_statement_7.{u_1} {E : Type u_1} [inst : NormedAddCommGroup E] [inst_1 : InnerProductSpace ℝ E]
  [inst_2 : CompleteSpace E] {f : E → ℝ} (xm x₀ : E) {alg : subgradient_method f x₀} {s : ℝ}
  (hm : IsMinOn f Set.univ xm) (ha' : ∀ (n : ℕ), subgradient_method.a f x₀ n * ‖subgradient_method.g f x₀ n‖ = s)
  (hs : s > 0) (k : ℕ)
  (heq :
    (Set.range fun x => f (subgradient_method.x f x₀ ↑x)) =
      {x | ∃ i ∈ Finset.range (k + 1), f (subgradient_method.x f x₀ i) = x})
  (hnek : Nonempty { x // x ∈ Finset.range (k + 1) })
  (h' : ∀ ⦃x g : E⦄, g ∈ SubderivAt f x → ‖g‖ ≤ ↑(subgradient_method.G f x₀)) ⦃i : ℕ⦄ (left : i ≥ 0) (hi₂ : i ≤ k)
  (h_original_goal :
    ‖subgradient_method.x f x₀ (i + 1) - xm‖ ^ 2 ≤
      ‖subgradient_method.x f x₀ i - xm‖ ^ 2 -
          2 * subgradient_method.a f x₀ i *
            (sInf {x | ∃ i ∈ Finset.range (k + 1), f (subgradient_method.x f x₀ i) = x} - f xm) +
        ‖subgradient_method.a f x₀ i‖ ^ 2 * ‖subgradient_method.g f x₀ i‖ ^ 2) :
  ‖subgradient_method.x f x₀ i - xm‖ ^ 2 +
      (-(2 * ⟪subgradient_method.x f x₀ i - xm, subgradient_method.a f x₀ i • subgradient_method.g f x₀ i⟫_ℝ) +
        ‖subgradient_method.a f x₀ i‖ ^ 2 * ‖subgradient_method.g f x₀ i‖ ^ 2) ≤
    ‖subgradient_method.x f x₀ i - xm‖ ^ 2 +
      (-(2 * subgradient_method.a f x₀ i *
            (sInf {x | ∃ i ∈ Finset.range (k + 1), f (subgradient_method.x f x₀ i) = x} - f xm)) +
        ‖subgradient_method.a f x₀ i‖ ^ 2 * ‖subgradient_method.g f x₀ i‖ ^ 2) := sorry

Tactic state before:
E : Type u_1
inst✝² : NormedAddCommGroup E
inst✝¹ : InnerProductSpace ℝ E
inst✝ : CompleteSpace E
f : E → ℝ
xm x₀ : E
alg : subgradient_method f x₀
s : ℝ
hm : IsMinOn f Set.univ xm
ha' : ∀ (n : ℕ), subgradient_method.a f x₀ n * ‖subgradient_method.g f x₀ n‖ = s
hs : s > 0
k : ℕ
heq :
  (Set.range fun x => f (subgradient_method.x f x₀ ↑x)) =
    {x | ∃ i ∈ Finset.range (k + 1), f (subgradient_method.x f x₀ i) = x}
hnek : Nonempty { x // x ∈ Finset.range (k + 1) }
h' : ∀ ⦃x g : E⦄, g ∈ SubderivAt f x → ‖g‖ ≤ ↑(subgradient_method.G f x₀)
i : ℕ
left✝ : i ≥ 0
hi₂ : i ≤ k
⊢ ‖subgradient_method.x f x₀ (i + 1) - xm‖ ^ 2 ≤
    ‖subgradient_method.x f x₀ i - xm‖ ^ 2 -
        2 * subgradient_method.a f x₀ i *
          (sInf {x | ∃ i ∈ Finset.range (k + 1), f (subgradient_method.x f x₀ i) = x} - f xm) +
      ‖subgradient_method.a f x₀ i‖ ^ 2 * ‖subgradient_method.g f x₀ i‖ ^ 2

Tactic:
rw [alg.update i, sub_right_comm, norm_sub_sq_real, norm_smul, mul_pow, sub_eq_add_neg]
    have :
  ‖alg.x i - xm‖ ^ 2 - 2 * alg.a i * (sInf {x | ∃ i ∈ Finset.range (k + 1), f (alg.x i) = x} - f xm) +
      ‖alg.a i‖ ^ 2 * ‖alg.g i‖ ^ 2 =
    ‖alg.x i - xm‖ ^ 2 + -(2 * alg.a i * (sInf {x | ∃ i ∈ Finset.range (k + 1), f (alg.x i) = x} - f xm)) +
      ‖alg.a i‖ ^ 2 * ‖alg.g i‖ ^ 2 :=
  by ring
    rw [this]
    have inq₂ :
  2 * alg.a i * (sInf {x | ∃ i ∈ Finset.range (k + 1), f (alg.x i) = x} - f xm) ≤
    2 * inner (alg.x i - xm) (alg.a i • alg.g i) :=
  by
  rw [mul_assoc]; apply (mul_le_mul_left two_pos).mpr
  rw [inner_smul_right]; apply (mul_le_mul_left (alg.ha i)).mpr
  rcases(alg.hg i) xm with hxm
  calc
    _ = sInf (Set.range fun (x : Finset.range (k + 1)) => f (alg.x x)) - f xm := by rw [← heq]
    _ ≤ f (alg.x i) - f xm := by
      simp
      have : f (alg.x i) ∈ Set.range fun (x : Finset.range (k + 1)) => f (alg.x x) :=
        by
        simp; use i
        constructor
        · apply lt_of_le_of_lt hi₂; apply (Nat.lt_succ_self k)
        · simp
      apply csInf_le _ this; apply Finite.bddBelow_range
    _ ≤ inner (alg.x i - xm) (alg.g i) := by
      simp; apply le_add_of_sub_left_le
      rw [sub_eq_add_neg, ← inner_neg_left, neg_sub, real_inner_comm]; apply hxm
    rw [add_assoc, add_assoc]

Tactic state after:
[E : Type u_1
 inst✝² : NormedAddCommGroup E
 inst✝¹ : InnerProductSpace ℝ E
 inst✝ : CompleteSpace E
 f : E → ℝ
 xm x₀ : E
 alg : subgradient_method f x₀
 s : ℝ
 hm : IsMinOn f Set.univ xm
 ha' : ∀ (n : ℕ), subgradient_method.a f x₀ n * ‖subgradient_method.g f x₀ n‖ = s
 hs : s > 0
 k : ℕ
 heq :
   (Set.range fun x => f (subgradient_method.x f x₀ ↑x)) =
     {x | ∃ i ∈ Finset.range (k + 1), f (subgradient_method.x f x₀ i) = x}
 hnek : Nonempty { x // x ∈ Finset.range (k + 1) }
 h' : ∀ ⦃x g : E⦄, g ∈ SubderivAt f x → ‖g‖ ≤ ↑(subgradient_method.G f x₀)
 i : ℕ
 left✝ : i ≥ 0
 hi₂ : i ≤ k
 this :
   ‖subgradient_method.x f x₀ i - xm‖ ^ 2 -
         2 * subgradient_method.a f x₀ i *
           (sInf {x | ∃ i ∈ Finset.range (k + 1), f (subgradient_method.x f x₀ i) = x} - f xm) +
       ‖subgradient_method.a f x₀ i‖ ^ 2 * ‖subgradient_method.g f x₀ i‖ ^ 2 =
     ‖subgradient_method.x f x₀ i - xm‖ ^ 2 +
         -(2 * subgradient_method.a f x₀ i *
             (sInf {x | ∃ i ∈ Finset.range (k + 1), f (subgradient_method.x f x₀ i) = x} - f xm)) +
       ‖subgradient_method.a f x₀ i‖ ^ 2 * ‖subgradient_method.g f x₀ i‖ ^ 2
 inq₂ :
   2 * subgradient_method.a f x₀ i *
       (sInf {x | ∃ i ∈ Finset.range (k + 1), f (subgradient_method.x f x₀ i) = x} - f xm) ≤
     2 * ⟪subgradient_method.x f x₀ i - xm, subgradient_method.a f x₀ i • subgradient_method.g f x₀ i⟫_ℝ
 ⊢ ‖subgradient_method.x f x₀ i - xm‖ ^ 2 +
       (-(2 * ⟪subgradient_method.x f x₀ i - xm, subgradient_method.a f x₀ i • subgradient_method.g f x₀ i⟫_ℝ) +
         ‖subgradient_method.a f x₀ i‖ ^ 2 * ‖subgradient_method.g f x₀ i‖ ^ 2) ≤
     ‖subgradient_method.x f x₀ i - xm‖ ^ 2 +
       (-(2 * subgradient_method.a f x₀ i *
             (sInf {x | ∃ i ∈ Finset.range (k + 1), f (subgradient_method.x f x₀ i) = x} - f xm)) +
         ‖subgradient_method.a f x₀ i‖ ^ 2 * ‖subgradient_method.g f x₀ i‖ ^ 2)]