Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linear programming according to Antoine Chambert-Loir's book — affine version #10159

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -2463,6 +2463,7 @@ import Mathlib.LinearAlgebra.Isomorphisms
import Mathlib.LinearAlgebra.Lagrange
import Mathlib.LinearAlgebra.LinearIndependent
import Mathlib.LinearAlgebra.LinearPMap
import Mathlib.LinearAlgebra.LinearProgramming
import Mathlib.LinearAlgebra.Matrix.AbsoluteValue
import Mathlib.LinearAlgebra.Matrix.Adjugate
import Mathlib.LinearAlgebra.Matrix.Basis
Expand Down
82 changes: 82 additions & 0 deletions Mathlib/LinearAlgebra/LinearProgramming.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/-
Copyright (c) 2023 Martin Dvorak. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Martin Dvorak, Antoine Chambert-Loir
-/
import Mathlib.Analysis.Convex.Cone.Pointed
import Mathlib.Algebra.Order.Group.Defs

/-!

# Linear programming

TODO

-/

/-- Typically `M` is `ℝ^m` and `N` is `ℝ^n` -/
structure ConeProgram (R V W M N : Type*) [OrderedRing R]
[AddCommGroup V] [Module R V] [AddTorsor V M]
[AddCommGroup W] [Module R W] [AddTorsor W N]
where
/-- Linear map -/
linmap : M →ᵃ[R] N
/-- Right-hand side -/
upper : N
Comment on lines +22 to +25
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need for upper here, the point of the affine refactor is that it becomes part of linmap.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I refactored it to not use upper, it ended up looking very strange:

/-- Typically `M` is `ℝ^m` and `N` is `ℝ^n` -/
structure LinearProgram (R V M N : Type*) [OrderedRing R]
    [AddCommGroup V] [Module R V] [AddTorsor V M]
    [AddCommGroup N] [Module R N]
    where
  /-- Affine map -/
  themap : M →ᵃ[R] N
  /-- Objective function -/
  objective : M →ᵃ[R] R
  /-- Cone defines nonnegative elements -/
  cone : PointedCone R N

variable {R V W M N : Type*} [OrderedRing R]
    [AddCommGroup V] [Module R V] [AddTorsor V M]
    [AddCommGroup N] [Module R N]

/-- `LP.primal = { x : M | LP.themap x ≤ LP.upper }` -/
def LinearProgram.primal (LP : LinearProgram R V M N) :=
  { x : M | -LP.themap x ∈ LP.cone }

/-- `LP.dual = { g : N →ᵃ[R] R | LP.objective = g ∘ LP.themap ∧ ∀ a, ∀ b, a ≤ b → g a ≤ g b }` -/
def LinearProgram.dual (LP : LinearProgram R V M N) :=
  { g : N →ᵃ[R] R | LP.objective = g ∘ LP.themap ∧
      ∀ a : N, ∀ b : N, (b -ᵥ a) ∈ LP.cone → g a ≤ g b }

-- From here on, we will need more assumptions than currently written

theorem LinearProgram.weakDuality (LP : LinearProgram R V M N)
    {c : M} (hc : c ∈ LP.primal) {d : N →ᵃ[R] R} (hd : d ∈ LP.dual) :
    LP.objective c ≤ d 0 := by
  simp_all [LinearProgram.primal, LinearProgram.dual]

Since we are maximizing in the primal, the feasibility condition ends up being { x : M | -LP.themap x ∈ LP.cone }, which is ugly af.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you really want me to do it, I can flip the sign and proceed with this setting, but I am not happy about it, since we seemed to finally reached the consensus that Antoine Chambert-Loir's definition is the one we want to have in Mathlib.

/-- Objective function -/
objective : M →ᵃ[R] R
/-- Cone defines nonnegative elements -/
cone : PointedCone R W

abbrev LinearProgram {R V W M N : Type*} [OrderedRing R]
[AddCommGroup V] [Module R V] [AddTorsor V M]
[OrderedAddCommGroup W] [Module R W] [OrderedSMul R W] [AddTorsor W N]
(l : M →ᵃ[R] N) (u : N) (o : M →ᵃ[R] R) :=
ConeProgram.mk l u o (PointedCone.positive R W)

variable {R V W M N : Type*} [OrderedRing R]
[AddCommGroup V] [Module R V] [AddTorsor V M]
[AddCommGroup W] [Module R W] [AddTorsor W N]

/-- `LP.primal = { x : M | LP.linmap x ≤ LP.upper }` -/
def ConeProgram.primal (LP : ConeProgram R V W M N) :=
{ x : M | LP.upper -ᵥ LP.linmap x ∈ LP.cone }

/-- `LP.dual = { g : N →ᵃ[R] R | LP.objective = g ∘ LP.linmap ∧ ∀ a, ∀ b, a ≤ b → g a ≤ g b }` -/
def ConeProgram.dual (LP : ConeProgram R V W M N) :=
{ g : N →ᵃ[R] R | LP.objective = g ∘ LP.linmap ∧
∀ a : N, ∀ b : N, (b -ᵥ a) ∈ LP.cone → g a ≤ g b }

-- From here on, we will need more assumptions than currently written

theorem ConeProgram.weakDuality (LP : ConeProgram R V W M N)
{c : M} (hc : c ∈ LP.primal) {d : N →ᵃ[R] R} (hd : d ∈ LP.dual) :
LP.objective c ≤ d LP.upper := by
simp_all [ConeProgram.primal, ConeProgram.dual]

/-- Theorem 1.4.1.a, TODO we probably need more assumptions (finite-dimensional `M` and `N` ?) -/
theorem ConeProgram.strongDuality (LP : ConeProgram R V W M N)

Check warning on line 58 in Mathlib/LinearAlgebra/LinearProgramming.lean

View workflow job for this annotation

GitHub Actions / Build

declaration uses 'sorry'
(hC : LP.primal.Nonempty) (hD : LP.dual.Nonempty) :
∃ c ∈ LP.primal, ∃ d ∈ LP.dual, LP.objective c = d LP.upper :=
sorry

/-- Theorem 1.4.1.b (TODO maybe add item (iii), which is easy,
and item (iv), which holds when `N` is `ℝ^n` and `LP.cone` is the positive ortant) -/
theorem ConeProgram.min_max (LP : ConeProgram R V W M N)

Check warning on line 65 in Mathlib/LinearAlgebra/LinearProgramming.lean

View workflow job for this annotation

GitHub Actions / Build

declaration uses 'sorry'
{c : M} (hc : c ∈ LP.primal) {d : N →ᵃ[R] R} (hd : d ∈ LP.dual) (hs : LP.cone.FG) :
-- TODO maybe `hs` is not needed
(∀ x ∈ LP.primal, LP.objective x ≤ LP.objective c) ∧ (∀ g ∈ LP.dual, d LP.upper ≤ g LP.upper) ↔
LP.objective c = d LP.upper :=
sorry

/-- Theorem 1.4.1.c(1) -/
theorem ConeProgram.empty_dual (LP : ConeProgram R V W M N)

Check warning on line 73 in Mathlib/LinearAlgebra/LinearProgramming.lean

View workflow job for this annotation

GitHub Actions / Build

declaration uses 'sorry'
(hC : LP.primal.Nonempty) (hD : LP.dual = ∅) :
∀ r : R, ∃ d ∈ LP.dual, d LP.upper < r :=
sorry

/-- Theorem 1.4.1.c(2) -/
theorem ConeProgram.empty_primal (LP : ConeProgram R V W M N)

Check warning on line 79 in Mathlib/LinearAlgebra/LinearProgramming.lean

View workflow job for this annotation

GitHub Actions / Build

declaration uses 'sorry'
(hC : LP.primal = ∅) (hD : LP.dual.Nonempty) :
∀ r : R, ∃ c ∈ LP.primal, r < LP.objective c :=
sorry