Skip to content

Commit 269cb5c

Browse files
committed
Colors and new pivoting
1 parent 71d29f5 commit 269cb5c

File tree

7 files changed

+78
-106
lines changed

7 files changed

+78
-106
lines changed

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
name = "SimplexTableaux"
22
uuid = "b49aa546-d643-4829-bb91-bc1e5e539d80"
33
authors = ["Ed Scheinerman <ers@jhu.edu>"]
4-
version = "0.0.4"
4+
version = "0.0.5"
55

66
[deps]
77
ChooseOptimizer = "858a232f-1959-5553-8cfc-91e1fd5304e2"
88
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
9+
Crayons = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
910
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
1011
LatexPrint = "d2208f48-c256-5759-9089-c25ed2a93924"
1112
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
@@ -16,6 +17,7 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1617
[compat]
1718
ChooseOptimizer = "0.3"
1819
Combinatorics = "1"
20+
Crayons = "4"
1921
JuMP = "1"
2022
LatexPrint = "1"
2123
LinearAlgebra = "1"

src/LPsolve.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ function lp_solve(T::Tableau, verbose::Bool=true)
2626
println("Optimum value = $obj_val\n")
2727
end
2828

29-
@show x
30-
3129
xval = JuMP.value.(x)
3230

3331
return xval

src/Pivoting.jl

Lines changed: 51 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ _not_row_one = "May not modify the header row of the Tableau"
22
_not_col_one = "May not modify the z column of the Tableau"
33

44
"""
5-
pivot!(T::Tableau, i::Int, j::Int)
5+
old_pivot!(T::Tableau, i::Int, j::Int)
66
77
Modify `T` by doing a pivot operation at contraint `i`
88
and variable x_`j`.
99
"""
10-
function pivot!(T::Tableau, i::Int, j::Int)
10+
function old_pivot!(T::Tableau, i::Int, j::Int)
1111
M = T.M # for easier access
1212

1313
i += 1
@@ -29,108 +29,76 @@ function pivot!(T::Tableau, i::Int, j::Int)
2929
end
3030

3131
"""
32-
pivot(T::Tableau, i::Int, j::Int)
32+
set_basis!(T::Tableau, vars::Vector{Int})
3333
34-
Non-modifying version of `pivot!`.
34+
Pivot `T` so that the variables specified in `vars`
35+
are the basic variables.
3536
"""
36-
function pivot(T::Tableau, i::Int, j::Int)
37-
TT = deepcopy(T)
38-
return pivot!(TT, i, j)
39-
end
37+
function set_basis!(T::Tableau, vars::Vector{Int})
38+
n = T.n_vars
39+
m = T.n_cons
4040

41-
"""
42-
scale!(T::Tableau, r::Int, s::_Exact)
41+
vars = sort(unique(vars))
4342

44-
Multiply row `r` of `T` by `s` (which must be nonzero).
45-
"""
46-
function scale!(T::Tableau, r::Int, s::_Exact)
47-
r += 1
48-
if r==1
49-
error(_not_row_one)
50-
end
51-
if s == 0
52-
error("May not scale by 0")
43+
if (length(vars) m) || !(vars collect(1:n))
44+
error("Invalid basis: $vars")
5345
end
54-
T.M[r, :] *= s
55-
return T
56-
end
5746

58-
"""
59-
scale(T::Tableau, r::Int, s::_Exact)
47+
# bop up indices by 1 and make a list
48+
idx = [j+1 for j in vars]
49+
idx = vcat(1, idx)
6050

61-
Non-modifying version of
62-
"""
63-
function scale(T::Tableau, r::Int, s::_Exact)
64-
TT = deepcopy(T)
65-
scale!(TT, r, s)
66-
return TT
51+
B = T.M[:, idx]
52+
BB = invx(B) # will fail if B is not invertible
53+
T.M = BB*T.M
54+
T.B = vars
55+
return T
6756
end
6857

6958
"""
70-
swap!(T::Tableau, i::Int, j::Int)
59+
get_basis(T::Tableau)
7160
72-
Swap constraints `i` and `j` of the Tableau.
61+
Return the current basis (indices of basic variables).
7362
"""
74-
function swap!(T::Tableau, i::Int, j::Int)
75-
i += 1
76-
j += 1
77-
if i<2 || j<2
78-
error(_not_row_one)
79-
end
80-
81-
if i==j
82-
return T
83-
end
84-
85-
row_i = T.M[i, :]
86-
row_j = T.M[j, :]
63+
get_basis(T::Tableau) = copy(T.B)
8764

88-
T.M[j, :] = row_i
89-
T.M[i, :] = row_j
90-
91-
T
92-
end
9365
"""
94-
swap(T::Tableau, i::Int, j::Int)
66+
pivot!(T::Tableau, leave::Int, enter::Int)
9567
96-
Non-modifying version of `swap!`.
68+
Remove element `leave` from the basis and include element `enter`.
9769
"""
98-
function swap(T::Tableau, i::Int, j::Int)
99-
TT = deepcopy(T)
100-
swap!(TT, i, j)
101-
end
70+
function pivot!(T::Tableau, leave::Int, enter::Int)
71+
B = Set(get_basis(T))
10272

103-
"""
104-
basis_pivot!(T::Tableau, vars)
73+
# check for validity
74+
if 0 B
75+
error("No basis has been established for this tableau")
76+
end
10577

106-
Pivot `T` so that the variables specified in `vars`
107-
are the basic variables.
108-
"""
109-
function basis_pivot!(T::Tableau, vars)
110-
# bop up indices by 1 and make a list
111-
idx = [j+1 for j in vars]
112-
idx = vcat(1, idx)
78+
n = T.n_vars
79+
if !(1 leave n)
80+
error("Invalid variable index: $leave")
81+
end
11382

114-
B = T.M[:, idx]
115-
BB = invx(B) # will fail if B is not invertible
116-
new_M = BB*T.M
83+
if !(1 enter n)
84+
error("Invalid variable index: $enter")
85+
end
11786

118-
r, c = size(T.M)
119-
for i in 1:r
120-
for j in 1:c
121-
T.M[i, j] = new_M[i, j]
122-
end
87+
if leave == enter
88+
@warn "No pivot: enter = leave = $enter"
89+
return nothing
12390
end
124-
return T
125-
end
12691

127-
"""
128-
basis_pivot(T::Tableau, vars)
92+
# form new basis
93+
B = Set(get_basis(T))
94+
if leave B
95+
error("Element $leave is not in the basis; cannot remove it")
96+
end
97+
if enter B
98+
error("Element $enter is already in the basis; cannot add it")
99+
end
129100

130-
Non-modifying version of `basis_pivot!`.
131-
"""
132-
function basis_pivot(T::Tableau, vars)
133-
TT = deepcopy(T)
134-
basis_pivot!(TT, vars)
135-
return TT
101+
delete!(B, leave)
102+
push!(B, enter)
103+
set_basis!(T, collect(B))
136104
end

src/Pretty.jl

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# output Tableau using PrettyTables
22

3+
const _yellow = Crayon(; foreground=:yellow)
4+
const _green = Crayon(; foreground=:green, bold=true)
5+
const _blue = Crayon(; foreground=:blue)
6+
37
function _pretty_string(x::_Exact)::String
48
if x isa Integer
59
return string(x)
@@ -53,8 +57,18 @@ function _left_column(T::Tableau)
5357
return result
5458
end
5559

60+
function _header_colors(T::Tableau)
61+
result = [Crayon(), Crayon()]
62+
for k in 1:T.n_vars
63+
col = k T.B ? _green : Crayon()
64+
push!(result, col)
65+
end
66+
push!(result, Crayon())
67+
return result
68+
end
69+
5670
function show(io::IO, T::Tableau)
5771
MM = _pretty_string.(T.M[2:end, :])
5872
MM = hcat(_left_column(T), MM)
59-
pretty_table(MM; header=_header(T))
73+
pretty_table(MM; header=_header(T), header_crayon=_header_colors(T))
6074
end

src/SimplexTableaux.jl

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,7 @@ import Base: show
1717
include("Exact.jl")
1818

1919
export Tableau,
20-
basis_pivot,
21-
basis_pivot!,
22-
get_Abc,
23-
is_feasible,
24-
lp_solve,
25-
pivot,
26-
pivot!,
27-
restore,
28-
restore!,
29-
scale,
30-
scale!,
31-
swap,
32-
swap!,
33-
value
34-
20+
set_basis!, get_Abc, get_basis, is_feasible, lp_solve, old_pivot!, restore!, value
3521

3622
include("Tableau.jl")
3723
include("Pivoting.jl")

src/Solver.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function pivot_solve!(T::Tableau, verbose::Bool=true)
1717
break
1818
end
1919
verbose && println("\nPivot at ($i,$j)\n")
20-
pivot!(T, i, j)
20+
old_pivot!(T, i, j)
2121

2222
count += 1
2323
if count > max_pivots

src/Tableau.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ Create a `Tableau` data structure for the linear program minimize `c' * x` subje
1212
1313
If matrix and vectors are already in standard form, then use `Tableau(A, b, c, false)`.
1414
"""
15-
struct Tableau
15+
mutable struct Tableau
1616
M::Matrix{_Exact} # place to hold the entire Tableau
1717
A::Matrix # (original) A matrix
1818
b::Vector # (original) RHS, b vector
1919
c::Vector # (original) objective coefficients, c vector
2020
n_vars::Int # number of variables in the LP
2121
n_cons::Int # number of constraints in the LP
22+
B::Vector{Int} # current basis (column indices)
2223

2324
function Tableau(A::AbstractMatrix, b::Vector, c::Vector, is_cannonical::Bool=true)
2425
m, n = size(A)
@@ -40,7 +41,9 @@ struct Tableau
4041
@warn("Rank difficient Tableau")
4142
end
4243
43-
return new(M, A, b, c, n, m)
44+
B = zeros(Int, m) # basis is all 0s to start
45+
46+
return new(M, A, b, c, n, m, B)
4447
end
4548
end
4649
@@ -97,6 +100,7 @@ function restore!(T::Tableau)
97100
T.M[i, j] = TT.M[i, j]
98101
end
99102
end
103+
T.B = zeros(Int, T.n_cons)
100104
return T
101105
end
102106
@@ -107,4 +111,4 @@ Return the value of the LP in `T` at the point `x`.
107111
"""
108112
function value(T::Tableau, x::Vector)
109113
return T.c' * x
110-
end
114+
end

0 commit comments

Comments
 (0)