-- FVIntmax/Lemma3.lean

import FVIntmax.Balance

namespace Intmax

section Lemma3

variable
  {Pi C Sigma : Type}
  {K₁ : Type} [Finite K₁]
  {K₂ : Type} [Finite K₂]
  {V : Type} [Lattice V] [AddCommGroup V]
             [CovariantClass V V (· + ·) (· ≤ ·)]
             [CovariantClass V V (Function.swap (· + ·)) (· ≤ ·)]

variable {Tc : Τc K₁ K₂ V} {T : Τ K₁ K₂ V} {b : S K₁ K₂ V} {Tstar : List (Τ K₁ K₂ V)}

-- Repository definitions used:
content: def isComplete (τ : Τ K₁ K₂ V) :=
  match τ with | ⟨(_, _, v), _⟩ => v.isSome

content: abbrev Τ (K₁ K₂ V : Type) [PreWithZero V] := { τ : Τ' K₁ K₂ V // τ.isValid }

content: abbrev Τ' (K₁ K₂ V : Type) [PreWithZero V] := Kbar K₁ K₂ × Kbar K₁ K₂ × Option V₊

content: inductive Kbar (K₁ K₂ : Type) where
  | key (k : Key K₁ K₂)
  | Source
deriving DecidableEq

content: abbrev Key (K₁ K₂ : Type) := K₁ ⊕ K₂

content: class abbrev PreWithZero (α : Type) := Preorder α, Zero α

content: def NonNeg (α : Type) [PreWithZero α] := { a : α // 0 ≤ a }

content: abbrev Τc (K₁ K₂ V : Type) [PreWithZero V] : Type := { τ : Τ K₁ K₂ V // τ.isComplete }

content: def V' (b : S K₁ K₂ V) (T : Τ K₁ K₂ V) (k : Kbar K₁ K₂) : Set V :=
  { v : V | v ∈ (fc · k) '' boundedBelow b T }

content: abbrev boundedBelow (b : S K₁ K₂ V) (T : Τ K₁ K₂ V) :=
  { a : Τc K₁ K₂ V × S K₁ K₂ V | (T, b) ≤ (↑a.1, a.2) }

content: abbrev S (K₁ K₂ V : Type) [PreWithZero V] := { s : S' K₁ K₂ V // s.isValid }

content: abbrev S' (K₁ K₂ V : Type) := Kbar K₁ K₂ → V

content: def fc (τcXb : Τc K₁ K₂ V × S K₁ K₂ V) : S K₁ K₂ V :=
  ⟨λ k : Kbar K₁ K₂ ↦
    match τcXb with
    | ⟨⟨⟨⟨s, r, v⟩, _⟩, hτ⟩, b⟩ =>
      let v' := v' (v.get hτ) b s
      b k + (e r - e s) k • v',
  by admit /- proof elided -/
  ⟩

content: def e (i : Kbar K₁ K₂) : Kbar K₁ K₂ → ℤ := λ j ↦ if i = j then 1 else 0

content: def f (b : S K₁ K₂ V) (T : Τ K₁ K₂ V) : S K₁ K₂ V :=
  ⟨
    λ k ↦
      have : InfSet V := infV b T k
      ⨅ x : boundedBelow b T, fc x.1 k,
    by admit /- proof elided -/
  ⟩

content: def infV (b : S K₁ K₂ V) (T : Τ K₁ K₂ V) (k : Kbar K₁ K₂) :
  InfSet V where
    sInf := λ s ↦ if s = V' b T k
                  then (exists_inf b T).1 k
                  else 0

content: def exists_inf (b : S K₁ K₂ V) (T : Τ K₁ K₂ V) : { s : S K₁ K₂ V // ∀ k, IsGLB (V' b T k) (s k) } :=
  ⟨
    f' b T,
    λ k ↦
      have f'_codomain : (f' b T) k ∈ V' b T k := by admit /- proof elided -/
  ⟩

content: def f' (b : S K₁ K₂ V) (T : Τ K₁ K₂ V) : S K₁ K₂ V := 
  ⟨
    λ k ↦
      match h : T with
      | ⟨(_, _, .some _), hT⟩ => fc (⟨T, by admit /- proof elided -/
      ⟩, b) k
      | ⟨(s, _, .none), _⟩ => if k = s then 0 else b k,
    by admit /- proof elided -/
  ⟩

content: class Injective {α ω : Type} (f : α → ω) where
  h : ComputationallyInfeasible (¬ Function.Injective f)

content: postfix:max "₊" => NonNeg

-- Repository lemmas used:
content: lemma f_IsGLB_of_V' {b : S K₁ K₂ V} {T : Τ K₁ K₂ V} {k : Kbar K₁ K₂} :
  IsGLB (V' b T k) (f b T k)

-- Local definitions used:

-- Local lemmas used:
content: @[simp]
lemma sum_fc_eq_sum : ∑ (k : Kbar K₁ K₂), fc (Tc, b) k = ∑ (k : Kbar K₁ K₂), b k

-- Target theorem and proof:
lemma sum_f_le_sum : ∑ (k : Kbar K₁ K₂), f b T k ≤ ∑ (k : Kbar K₁ K₂), b k
:= by
  by_cases eq : T.isComplete
  · conv_rhs => rw [←sum_fc_eq_sum (Tc := ⟨T, eq⟩)]
    refine' Finset.sum_le_sum (λ k _ ↦ _)
    have fcInV' : fc (⟨T, eq⟩, b) k ∈ V' b T k := by
      dsimp [V']
      rw [Set.mem_image]
      use (⟨T, eq⟩, b)
      simp
    exact f_IsGLB_of_V'.1 fcInV'
  · rcases T with ⟨⟨s, r, v⟩, h⟩
    let Tc : Τc K₁ K₂ V := ⟨⟨(s, r, some 0), by valid⟩, by simp⟩
    conv_rhs => rw [←sum_fc_eq_sum (Tc := Tc)]
    refine' (Finset.sum_le_sum (λ k _ ↦ _))
    have fcInV' : fc (Tc, b) k ∈ V' b ⟨(s, r, v), h⟩ k := by
      dsimp [V']
      rw [Set.mem_image]
      use (⟨⟨(s, r, some 0), by valid⟩, by valid⟩, b)
      have : v = none := by aesop
      simp [this, (·≤·)]
    exact f_IsGLB_of_V'.1 fcInV'