/-
Copyright (c) 2024 Shengyang Xu, Chenyi Li. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Shengyang Xu, Chenyi Li
-/
import Mathlib.Analysis.Convex.Cone.Basic
import Mathlib.Analysis.Calculus.LocalExtr.Basic
import Mathlib.Analysis.NormedSpace.HahnBanach.Separation
import Mathlib.Analysis.InnerProductSpace.PiL2
import Mathlib.Data.Matrix.Rank
import Mathlib.LinearAlgebra.FiniteDimensional
import Optlib.Differential.Calculation
import Optlib.Convex.ClosedCone

/-!
# Farkas

## Main results

This file contains the proof of the Farkas lemma.
$p$ and $q \in \mathbb{N}$ Given sets of vectors $ \{a_i \in \mathbb{R}^n | i = 1, 2, \ldots, p\} $
and $ \{b_i \in \mathbb{R}^n | i = 1, 2, \ldots, q\} $,
and a vector $ c \in \mathbb{R}^n $, the following conditions are equivalent:

1. There does not exist a vector $ d \in \mathbb{R}^n $ such that:
   - $ d^T a_i = 0 $ for all $ i = 1, 2, \ldots, p $
   - $ d^T b_i \geq 0 $ for all $ i = 1, 2, \ldots, q $
   - $ d^T c < 0 $

2. The vector $ c $ can be expressed as a linear combination of the vectors
   $ a_i $ and $ b_i $ with coefficients $ \lambda_i $ and $ \mu_i $, respectively, where:
   - $ \lambda_i $ can be any real number for all $ i = 1, 2, \ldots, p $
   - $ \mu_i \geq 0 $ for all $ i = 1, 2, \ldots, q $
   - $ c = \sum_{i=1}^p \lambda_i a_i + \sum_{i=1}^q \mu_i b_i $

-/

variable {τ σ : Finset ℕ} {n : ℕ} {a : ℕ → EuclideanSpace ℝ (Fin n)}
variable {b : ℕ → EuclideanSpace ℝ (Fin n)} {c : EuclideanSpace ℝ (Fin n)}


open Finset InnerProductSpace BigOperators

lemma polyhedra_iff_cone {σ : Finset ℕ} : ∀ (b : ℕ → EuclideanSpace ℝ (Fin n)),
    {z | ∃ (mu : σ → ℝ), (∀ i, 0 ≤ mu i) ∧ z =
    Finset.sum univ (fun i ↦ mu i • b i)} = cone σ b := by
  intro b
  simp only [cone, quadrant]
  ext z; constructor
  · simp; intro c cpos h
    let c1 : ℕ → ℝ := fun i => if w : i ∈ σ then c {val := i, property := w} else 0
    use c1; constructor
    · intro i; simp [c1];
      by_cases ht : i ∈ σ
      simp [ht]; specialize cpos i ht; exact cpos; simp [ht]
    rw [h]
    let f : ℕ → EuclideanSpace ℝ (Fin n) := fun i ↦ (c1 i) • (b i)
    have htt : ∑ x in σ.attach, f x = Finset.sum (attach σ) fun x => (c1 x • b x) := by simp [f]
    have h1 : ∀ i : σ, c1 i • b i = c i • b i := by intro i; simp [c1]
    have ht : ∑ x in σ.attach, f x = Finset.sum (attach σ) fun x => (c x • b x) := by
      rw [← htt]; apply Finset.sum_congr; simp
      intro i _; simp [f, c1]
    nth_rw 1 [Finset.sum_attach] at htt
    rw [← ht, ← htt]
  simp; intro c cpos h
  let c1 : σ → ℝ := fun i => c i
  use c1; constructor
  · intro i _; exact cpos i
  let f : ℕ → EuclideanSpace ℝ (Fin n) := fun i ↦ (c i) • (b i)
  have : ∑ x in σ.attach, f x = Finset.sum (attach σ) fun x => (c x • b x) := by simp [f]
  rw [← h]; simp [c1]; rw [← this, Finset.sum_attach]

private lemma leq_tendsto_zero {a x : ℝ} (ha : a < 0) (h : ∀ t > 0, t * x > a) : 0 ≤ x := by
  by_contra h'; push_neg at h';
  have : 2 * a / x > 0 := by
    rw [← mul_div]; apply mul_pos; norm_num; apply div_pos_of_neg_of_neg ha h'
  specialize h (2 * a / x) this
  have : 2 * a / x * x = 2 * a := by
    ring_nf; simp; field_simp; rw [← mul_div, div_self (by linarith)]; linarith
  rw [this] at h; linarith

private lemma geq_tendsto_zero {a x : ℝ} (ha : a < 0) (h : ∀ t < 0, t * x > a) : 0 ≥ x := by
  by_contra h'; push_neg at h';
  have : 2 * a / x < 0 := by
    rw [← mul_div]; apply mul_neg_of_pos_of_neg; norm_num; apply div_neg_of_neg_of_pos ha h'
  specialize h (2 * a / x) this
  have : 2 * a / x * x = 2 * a := by ring_nf; simp; field_simp;
  rw [this] at h; linarith

private lemma decompose_pn : ∀ (lam : τ → ℝ), ∃ (lamp lamn : ℕ → ℝ),
    ∀ i : τ, (0 ≤ lamp i) ∧ (0 ≤ lamn i) ∧ (lam i = (lamp i) - (lamn i)) := by
  intro lam
  let lamp : ℕ → ℝ := fun j => if h : (j ∈ τ) then if _ : (0 ≤ lam ⟨j, h⟩) then lam ⟨j, h⟩ else 0 else 0
  let lamn : ℕ → ℝ := fun j => if h : (j ∈ τ) then if _ : (0 ≤ lam ⟨j, h⟩) then 0 else -lam ⟨j, h⟩ else 0
  use lamp; use lamn
  intro i
  by_cases hpos : 0 ≤ lam i
  · simp [lamp, lamn, hpos]
  · simp [lamp, lamn, hpos]; linarith

private lemma shift_sum (τ : Finset ℕ) (m : ℕ) (f : ℕ → EuclideanSpace ℝ (Fin n)) :
    (∑ i : τ, f i) = (∑ i : (Finset.image (fun x => x + m) τ), f (i - m)) := by
  let h : ℕ → ℕ := fun i => i + m
  let g : ℕ → EuclideanSpace ℝ (Fin n) := fun i => f (i - m)
  have eq : f = g ∘ h := by ext i j; simp [g, h]
  have aux : ∀ x ∈ τ, ∀ y ∈ τ, h x = h y → x = y := by
    intro x _ y _; simp [h]
  show (∑ i : τ, f i) = (∑ i : (Finset.image h τ), g i); simp
  rw [Finset.sum_attach, Finset.sum_attach, Finset.sum_image aux, eq]; simp

private lemma shift_not_in (τ : Finset ℕ) (m : ℕ) (hm : ∀ i : τ, i < m): m ∉ τ := by
  contrapose hm; simp; simp at hm; use m

private lemma mem_lt_m {m i : ℕ} {σ τ : Finset ℕ} (he : (τ ∪ σ).Nonempty)
    (hm : m = (Finset.max' (τ ∪ σ) he).succ) : (i ∈ (τ ∪ σ)) → (i < m) := by
  intro iin; rw [hm]; apply Nat.lt_succ_of_le
  apply Finset.le_max' (τ ∪ σ) i iin

private lemma exist_of_mem_shift {x m : ℕ} {τ : Finset ℕ}:
    x ∈ (Finset.image (fun x => x + m) τ) → ∃ a : τ, x = a + m := by
  simp; intro a ain eq; use a; use ain; rw [← eq]

private lemma s_inter_t1_empty {m : ℕ} {σ τ : Finset ℕ} (he : (τ ∪ σ).Nonempty)
    (hm : m = (Finset.max' (τ ∪ σ) he).succ) : σ ∩ (Finset.image (fun x => x + m) τ) = ∅ := by
  by_contra neq; push_neg at neq; rw [← Finset.nonempty_iff_ne_empty] at neq
  rcases neq with ⟨x, xin⟩
  absurd Finset.mem_of_mem_inter_left xin
  apply shift_not_in; intro i
  calc
    i.1 < m := by apply mem_lt_m he hm; simp [i.2]
    m ≤ x := by
      rcases exist_of_mem_shift (Finset.mem_of_mem_inter_right xin) with ⟨a, _, aeq⟩; linarith

private lemma s_inter_t2_empty {m : ℕ} {σ τ : Finset ℕ} (he : (τ ∪ σ).Nonempty)
    (hm : m = (Finset.max' (τ ∪ σ) he).succ) : σ ∩ (Finset.image (fun x => x + 2 * m) τ) = ∅ := by
  by_contra neq; push_neg at neq; rw [← Finset.nonempty_iff_ne_empty] at neq
  rcases neq with ⟨x, xin⟩
  absurd Finset.mem_of_mem_inter_left xin
  apply shift_not_in; intro i
  calc
    i.1 < m := by apply mem_lt_m he hm; simp [i.2]
    m ≤ 2 * m := by linarith
    2 * m ≤ x := by
      rcases exist_of_mem_shift (Finset.mem_of_mem_inter_right xin) with ⟨a, _, aeq⟩; linarith

private lemma t1_inter_t2_empty {m : ℕ} {σ τ : Finset ℕ} (he : (τ ∪ σ).Nonempty)
    (hm : m = (Finset.max' (τ ∪ σ) he).succ) :
    (Finset.image (fun x => x + m) τ) ∩ (Finset.image (fun x => x + 2 * m) τ) = ∅ := by
  by_contra neq; push_neg at neq; rw [← Finset.nonempty_iff_ne_empty] at neq
  rcases neq with ⟨x, xin⟩
  absurd Finset.mem_of_mem_inter_left xin
  apply shift_not_in; intro i
  rcases exist_of_mem_shift (Finset.mem_of_mem_inter_right xin) with ⟨a, aeq⟩
  rcases exist_of_mem_shift i.2 with ⟨b, beq⟩
  calc
    i.1 < 2 * m := by
      rw [beq, two_mul]; apply Nat.add_lt_add_right; apply mem_lt_m he hm; simp
    2 * m ≤ x := by rw [aeq]; simp

lemma general_polyhedra_is_polyhedra_empty (τ σ : Finset ℕ) (he : ¬(τ ∪ σ).Nonempty) :
    ∀ (a : ℕ → EuclideanSpace ℝ (Fin n)), ∀ (b : ℕ → EuclideanSpace ℝ (Fin n)),
    ∃ μ c, {z | ∃ (lam : τ → ℝ), ∃ (mu : σ → ℝ), (∀ i, 0 ≤ mu i) ∧ z =
    Finset.sum univ (fun i ↦ lam i • a i) + Finset.sum univ (fun i ↦ mu i • b i)} =
    cone μ c := by
  simp at he; rw [Finset.union_eq_empty] at he
  intro a b; simp [he]
  use ∅; use (fun _ => 0)
  simp [cone, quadrant]; ext x; simp; constructor
  · intro x0; simp [x0]; use (fun _ => 0); simp
  · intro cond; simp [cond.2]

lemma general_polyhedra_is_polyhedra_ne (τ σ : Finset ℕ) (he : (τ ∪ σ).Nonempty) :
    ∀ (a : ℕ → EuclideanSpace ℝ (Fin n)), ∀ (b : ℕ → EuclideanSpace ℝ (Fin n)),
    ∃ μ c, {z | ∃ (lam : τ → ℝ), ∃ (mu : σ → ℝ), (∀ i, 0 ≤ mu i) ∧ z =
    Finset.sum univ (fun i ↦ lam i • a i) + Finset.sum univ (fun i ↦ mu i • b i)} =
    cone μ c := by
  intro a b
  let m := (Finset.max' (τ ∪ σ) he).succ
  let τ1 := Finset.image (fun x => x + m) τ
  let τ2 := Finset.image (fun x => x + 2 * m) τ
  let μ := σ ∪ τ1 ∪ τ2
  have mt1emp : σ ∩ τ1 = ∅ := by
    simp only [τ1]; apply s_inter_t1_empty he; simp
  have mt2emp : σ ∩ τ2 = ∅ := by
    simp only [τ2]; apply s_inter_t2_empty he; simp
  have t1t2emp : τ1 ∩ τ2 = ∅ := by
    simp only [τ1, τ2]; apply t1_inter_t2_empty he; simp
  have disj_st : Disjoint σ (τ1 ∪ τ2) := by
    rw [Finset.disjoint_iff_inter_eq_empty, Finset.inter_union_distrib_left]; simp [mt1emp, mt2emp]
  have disj_tt : Disjoint τ1 τ2 := by
    rw [Finset.disjoint_iff_inter_eq_empty]; simp [t1t2emp]
  let cσ : ℕ → EuclideanSpace ℝ (Fin n) := fun i => if i ∈ σ then b i else 0
  let cτ1 : ℕ → EuclideanSpace ℝ (Fin n) := fun i => if i ∈ τ then a i else 0
  let cτ2 : ℕ → EuclideanSpace ℝ (Fin n) := fun i => if i ∈ τ then -a i else 0
  let c : ℕ → EuclideanSpace ℝ (Fin n) := fun i => if i ∈ σ then cσ i else
      if i ∈ τ1 then cτ1 (i - m) else if i ∈ τ2 then cτ2 (i - 2 * m) else 0
  use μ; use c; simp only [cone, quadrant]; ext x; constructor
  · rintro ⟨lam, mu, munneg, xeq⟩
    obtain ⟨lamp, lamn, lameq⟩ := decompose_pn lam
    have tau_decpn : ∑ x : τ, lam x • a x =
        ∑ x : τ, (fun y => lamp y • cτ1 y) x + ∑ x : τ, (fun y => lamn y • cτ2 y) x := by
      have aux : ∑ x : τ, lam x • a x =
          ∑ x : τ, (lamp x • a x - lamn x • a x) := by
        congr; ext i j
        obtain ⟨_, _, eq⟩ := lameq i; simp; rw [eq, sub_mul]
      rw [aux]; simp [cτ1, cτ2]; rw [sub_eq_add_neg]
    simp
    let w : ℕ → ℝ := fun i => if h : i ∈ σ then mu ⟨i, h⟩ else
      if i ∈ τ1 then lamp (i - m) else if i ∈ τ2 then lamn (i - 2 * m) else 0
    have wnneg : ∀ i : ℕ, 0 ≤ w i := by
      intro i; simp [w]; by_cases hs : i ∈ σ
      · simp [hs]; linarith [munneg ⟨i, hs⟩]
      by_cases ht1 : i ∈ τ1
      · simp [hs, ht1]; simp [τ1] at ht1; rcases ht1 with ⟨a, ain, aeq⟩
        rw [← aeq]; simp; linarith [lameq ⟨a, ain⟩]
      by_cases ht2 : i ∈ τ2
      · simp [hs, ht1, ht2]; simp [τ2] at ht2; rcases ht2 with ⟨a, ain, aeq⟩
        rw [← aeq]; simp; linarith [lameq ⟨a, ain⟩]
      simp [hs, ht1, ht2]
    use w; use wnneg
    rw [xeq, tau_decpn]
    have eq1 : ∑ x : { x // x ∈ σ }, mu x • b x = ∑ x in σ, (fun y => w y • c y) x := by
      nth_rw 2 [← Finset.sum_attach]; simp; congr
      ext x j; simp [w, c, cσ]
    have eq2 : ∑ x : τ, (fun y => lamp y • cτ1 y) x = ∑ x in τ1, (fun y => w y • c y) x := by
      rw [shift_sum τ m (fun y => lamp y • cτ1 y)]
      nth_rw 2 [← Finset.sum_attach]; simp; congr
      ext x j
      have hns : x.1 ∉ σ := by
        contrapose mt1emp; simp at mt1emp; push_neg; rw [← Finset.nonempty_iff_ne_empty]
        use x; simp [τ1, mt1emp, x.2]
      simp [w, c, hns]
    have eq3 : ∑ x : τ, (fun y => lamn y • cτ2 y) x = ∑ x in τ2, (fun y => w y • c y) x := by
      rw [shift_sum τ (2 * m) (fun y => lamn y • cτ2 y)]
      nth_rw 2 [← Finset.sum_attach]; simp; congr
      ext x j
      have hns : x.1 ∉ σ := by
        contrapose mt2emp; simp at mt2emp; push_neg; rw [← Finset.nonempty_iff_ne_empty]
        use x; simp [τ2, mt2emp, x.2]
      have hnt : x.1 ∉ τ1 := by
        contrapose t1t2emp; simp at t1t2emp; push_neg; rw [← Finset.nonempty_iff_ne_empty]
        use x; simp [τ2, t1t2emp, x.2]
      simp [w, c, hns, hnt]
    rw [eq1, eq2, eq3]; simp [μ]
    rw [Finset.sum_union disj_st, Finset.sum_union disj_tt, add_comm]
  · intro cond; simp at cond; rcases cond with ⟨w, wnneg, xeq⟩
    simp [μ] at xeq
    rw [Finset.sum_union disj_st, Finset.sum_union disj_tt] at xeq
    let lamp : ℕ → ℝ := fun i => if i ∈ τ then w (i + m) else 0
    let lamn : ℕ → ℝ := fun i => if i ∈ τ then w (i + 2 * m) else 0
    let lam : τ → ℝ := fun i => lamp i.1 - lamn i.1
    let mu : ℕ → ℝ := fun i => if i ∈ σ then w i else 0
    have eq1 : ∑ x : { x // x ∈ σ }, mu x • b x = ∑ x in σ, (fun y => w y • c y) x := by
      nth_rw 2 [← Finset.sum_attach]; simp; congr
      ext x j; simp [mu, c, cσ]
    have eq2 : ∑ x : τ, (fun y => lamp y • cτ1 y) x = ∑ x in τ1, (fun y => w y • c y) x := by
      rw [shift_sum τ m (fun y => lamp y • cτ1 y)]
      nth_rw 2 [← Finset.sum_attach]; simp; congr
      ext x j
      have hns : x.1 ∉ σ := by
        contrapose mt1emp; simp at mt1emp; push_neg; rw [← Finset.nonempty_iff_ne_empty]
        use x; simp [τ1, mt1emp, x.2]
      rcases exist_of_mem_shift x.2 with ⟨a, eq⟩
      have hin : x.1 - m ∈ τ := by rw [eq]; simp
      simp [mu, lamp, c, hns, hin]; rw [eq]; simp
    have eq3 : ∑ x : τ, (fun y => lamn y • cτ2 y) x = ∑ x in τ2, (fun y => w y • c y) x := by
      rw [shift_sum τ (2 * m) (fun y => lamn y • cτ2 y)]
      nth_rw 2 [← Finset.sum_attach]; simp; congr
      ext x j
      have hns : x.1 ∉ σ := by
        contrapose mt2emp; simp at mt2emp; push_neg; rw [← Finset.nonempty_iff_ne_empty]
        use x; simp [τ2, mt2emp, x.2]
      have hnt : x.1 ∉ τ1 := by
        contrapose t1t2emp; simp at t1t2emp; push_neg; rw [← Finset.nonempty_iff_ne_empty]
        use x; simp [τ2, t1t2emp, x.2]
      rcases exist_of_mem_shift x.2 with ⟨a, eq⟩
      have hin : x.1 - 2 * m ∈ τ := by rw [eq]; simp
      simp [mu, lamn, c, hns, hnt, hin]; rw [eq]; simp
    rw [← eq1, ← eq2, ← eq3] at xeq; simp at xeq
    simp; use lam; use (fun i => mu i); constructor
    · intro a ain; simp [mu, ain]; linarith [wnneg a]
    · simp [lam]
      rw [← xeq, add_comm]; simp [cτ1, cτ2]; rw [← sub_eq_add_neg, ← Finset.sum_sub_distrib]
      congr; ext x j; rw [sub_smul]

lemma general_polyhedra_is_polyhedra (τ σ : Finset ℕ) :
    ∀ (a : ℕ → EuclideanSpace ℝ (Fin n)), ∀ (b : ℕ → EuclideanSpace ℝ (Fin n)),
    ∃ μ c, {z | ∃ (lam : τ → ℝ), ∃ (mu : σ → ℝ), (∀ i, 0 ≤ mu i) ∧ z =
    Finset.sum univ (fun i ↦ lam i • a i) + Finset.sum univ (fun i ↦ mu i • b i)} =
    cone μ c := by
  by_cases trivial : (τ ∪ σ).Nonempty
  · exact general_polyhedra_is_polyhedra_ne τ σ trivial
  · exact general_polyhedra_is_polyhedra_empty τ σ trivial

lemma general_polyhedra_is_closed : IsClosed {z | ∃ (lam : τ → ℝ), ∃ (mu : σ → ℝ),
    (∀ i, 0 ≤ mu i) ∧ z = Finset.sum univ (fun i ↦ lam i • a i) +
    Finset.sum univ (fun i ↦ mu i • b i)} := by
  rcases general_polyhedra_is_polyhedra τ σ a b with ⟨μ, c, h⟩
  rw [h]; exact closed_conic μ c

theorem Farkas :
  (∃ (lam : τ → ℝ), ∃ (mu : σ → ℝ), (∀ i, 0 ≤ mu i) ∧ c =
    Finset.sum univ (fun i ↦ lam i • a i) + Finset.sum univ (fun i ↦ mu i • b i)) ↔
    ¬ (∃ (z : EuclideanSpace ℝ (Fin n)), (∀ i ∈ τ, inner (a i) z = (0 : ℝ))
    ∧ (∀ i ∈ σ, inner (b i) z ≥ (0 : ℝ)) ∧ (inner c z < (0 : ℝ))) := by
  constructor
  intro h; rcases h with ⟨lam, mu, ⟨h1, h2⟩⟩
  by_contra h3
  rcases h3 with ⟨z, ⟨h31, ⟨h32, h33⟩⟩⟩
  have : inner c z ≥ (0 : ℝ) := by
    calc
      _ = inner (Finset.sum univ (fun i ↦ lam i • a i)) z
          + inner (Finset.sum univ (fun i ↦ mu i • b i)) z := by rw [h2]; simp [inner_add_left]
      _ = Finset.sum univ (fun i ↦ inner (lam i • a i) z)
          + Finset.sum univ (fun i ↦ inner (mu i • b i) z) := by
        rw [sum_inner, sum_inner]
      _ = Finset.sum univ (fun i ↦ lam i * inner (a i) z)
          + Finset.sum univ (fun i ↦ mu i * inner (b i) z) := by
        congr; ext i; rw [inner_smul_left]; simp
        ext i; rw [inner_smul_left]; simp
      _ = Finset.sum univ (fun i ↦ mu i * inner (b i) z) := by simp [h31]
      _ ≥ 0 := by
        apply Finset.sum_nonneg; intro i _
        obtain h1i := h1 i; obtain h2i := h32 i i.2; positivity
  linarith

  intro h; by_contra h1
  let S := {z | ∃ (lam : τ → ℝ), ∃ (mu : σ → ℝ), (∀ i, 0 ≤ mu i) ∧ z =
    Finset.sum univ (fun i ↦ lam i • a i) + Finset.sum univ (fun i ↦ mu i • b i)}
  have sc : IsClosed S := by exact general_polyhedra_is_closed
  have scon : Convex ℝ S := by
    apply convex_iff_forall_pos.mpr
    intro x xs y ys a1 b1 anng bnng _
    rcases xs with ⟨sx, ⟨tx, ⟨txcond, eqx⟩⟩⟩
    rcases ys with ⟨sy, ⟨ty, ⟨tycond, eqy⟩⟩⟩
    use (a1 • sx + b1 • sy)
    use (a1 • tx + b1 • ty)
    constructor
    . show 0 ≤ (a1 • tx + b1 • ty)
      apply add_nonneg; apply smul_nonneg
      apply le_of_lt anng; apply txcond
      apply smul_nonneg; apply le_of_lt bnng
      apply tycond
    . rw [eqx, eqy, smul_add, smul_add]
      simp
      rw [Finset.smul_sum, Finset.smul_sum, Finset.smul_sum, Finset.smul_sum]
      rw [add_assoc]; nth_rw 2 [add_comm]
      rw [← add_assoc, ← add_assoc, add_assoc]
      have aux1 : ((Finset.sum (attach τ) fun x => a1 • sx x • a ↑x) + Finset.sum (attach τ) fun x
        => b1 • sy x • a ↑x) = (Finset.sum (attach τ) fun x => (a1 * sx x + b1 * sy x) • a ↑x) := by
        rw [← Finset.sum_add_distrib]
        apply Finset.sum_congr
        simp; intro i _
        rw [smul_smul, smul_smul, ← add_smul]
      have aux2 : ((Finset.sum (attach σ) fun x => b1 • ty x • b ↑x) + Finset.sum (attach σ) fun x
        => a1 • tx x • b ↑x) = Finset.sum (attach σ) fun x => (a1 * tx x + b1 * ty x) • b ↑x := by
        rw [← Finset.sum_add_distrib]
        apply Finset.sum_congr
        simp; intro i _
        rw [smul_smul, smul_smul, ← add_smul, add_comm]
      rw [aux1, aux2]
  have cn : c ∉ S := by
    by_contra cn; simp only [Set.mem_setOf_eq, S] at cn;
    rcases cn with ⟨lam, mu, ⟨cn1, cn2⟩⟩
    apply h1; use lam; use mu
  obtain sep := geometric_hahn_banach_point_closed scon sc cn
  rcases sep with ⟨f, u, ⟨sep1, sep2⟩⟩
  have feq : ∃ d : EuclideanSpace ℝ (Fin n), ∀ x, f x = inner d x := by
    use ((toDual ℝ (EuclideanSpace ℝ (Fin n))).symm f); simp
  rcases feq with ⟨d, feq⟩
  have uleq : u < 0 := by
    have : 0 ∈ S := by simp [S]; use 0; use 0; simp
    specialize sep2 0 this; rw [feq 0, inner_zero_right] at sep2; exact sep2
  have hc : inner c d < (0 : ℝ) := by
    rw [real_inner_comm, ← feq c]
    apply lt_trans sep1 uleq
  have hb : ∀ i : σ, inner (b i) d ≥ (0 : ℝ) := by
    intro i
    have : ∀ t > (0 : ℝ), (t • b i) ∈ S := by
      intro t ht
      simp only [S]; use 0; use (fun j ↦ if j = i then t else 0)
      constructor; intro j; by_cases h : j = i; simp [h]
      linarith; simp [h]; simp
    apply leq_tendsto_zero uleq
    intro t ht
    specialize sep2 (t • b i) (this t ht);
    rw [feq, inner_smul_right, real_inner_comm] at sep2; exact sep2
  have ha : ∀ i : τ, inner (a i) d = (0 : ℝ) := by
    intro i
    have : ∀ t : ℝ, (t • a i) ∈ S := by
      intro t
      simp only [S]; use (fun j ↦ if j = i then t else 0); use 0;
      constructor; intro _; simp; simp only [Pi.zero_apply, zero_smul, sum_const_zero,
        ite_smul, zero_add]; simp
    rw [le_antisymm_iff]; constructor
    · apply geq_tendsto_zero uleq
      intro t _
      specialize sep2 (t • a i) (this t); rw [feq, inner_smul_right, real_inner_comm] at sep2
      linarith
    apply leq_tendsto_zero uleq
    intro t _
    specialize sep2 (t • a i) (this t); rw [feq, inner_smul_right, real_inner_comm] at sep2
    linarith
  apply absurd h
  push_neg; use d;
  constructor
  · intro i hi; specialize ha {val := i, property := hi}; simp [ha]
  constructor
  intro i hi; specialize hb {val := i, property := hi}; simp at hb; simp; exact hb
  exact hc
