Let's consider the following integer program:
$\begin{array}{rccccl}\max&&&x_2&&\\&-5x_1&+&3x_2&\leq&0\\&5x_1&+&3x_2&\leq&5\\&x_1,&&x_2&\geq&0\\&x_1,&&x_2&&\text{integer}\end{array}$
{{{id=171|
pts = [];
for i in range(10):
for j in range(10):
pts.append( (i,j) );
P = list_plot( pts );
x = var('x');
P += plot( (5/3)*x, (x, 0, 20) );
P += plot( (-5/3)*x + 5, (x,0,20) );
P.set_axes_range( 0, 5, 0, 4 );
P
///
}}}
{{{id=2|
def Pivot(A, B, x, y):
#print "Pivoting on row %d and column %d." % (x,y);
m = len(A);
n = len(A[0]);
val = A[x][y];
for j in range(n):
A[x][j] = A[x][j] / val;
for i in range(m):
if i != x:
val = A[i][y];
for j in range(n):
A[i][j] = A[i][j] - val * A[x][j];
B[x] = y; # modify basis element
///
}}}
{{{id=141|
def Rebase(A, B):
# make sure the basis is basic
for i in range(1, len(B)):
Pivot(A, B, i, B[i]);
///
}}}
{{{id=170|
def PrimalSimplex(A, B):
for j in range(1,len(A[0])):
if A[0][j] < 0:
# find a pivot point
bestrow=-1;
bestratio = 10000;
for i in range(1, len(A)):
if A[i][j] > 0 and A[i][0] / A[i][j] < bestratio:
bestrow = i;
bestratio = A[i][0] / A[i][j];
if bestrow > 0:
Pivot(A, B, bestrow, j);
return PrimalSimplex(A, B);
else:
return None, None; # unbounded!
return A, B;
///
}}}
{{{id=130|
def DualSimplex(A, B):
for i in range(1,len(A)):
if A[i][0] < 0:
# find a pivot point
bestcol=-1;
bestratio = -10000;
for j in range(1, len(A[i])):
if A[i][j] < 0 and A[0][j] / A[i][j] > bestratio:
bestcol = j;
bestratio = A[0][j] / A[i][j];
if bestcol > 0:
Pivot(A, B, i, bestcol);
return DualSimplex(A, B);
else:
return None, None; # unbounded!
return A, B;
///
}}}
{{{id=3|
def PrintTableau(A,B):
str_length=4;
col_lengths = {};
for j in range(len(A[0])):
col_lengths[j] = 0;
for ii in range(len(A)):
if len(str(A[ii][j])) > col_lengths[j]:
col_lengths[j] = len(str(A[ii][j]));
for i in range(len(A)):
row_str = "[";
for j in range(len(A[i])):
s = str(A[i][j]);
for t in range(col_lengths[j] - len(s)):
row_str += " ";
row_str += s;
if j == 0:
row_str+="|";
else:
row_str+=" ";
print row_str + "]";
print;
///
}}}
{{{id=135|
def PrintActiveTableaus(Active):
for A, B in Active:
print "Current LP Lower Bound: ", -A[0][0], " approx: ", N(-A[0][0]);
PrintTableau(A, B);
print;
///
}}}
{{{id=136|
def BranchOnVariable(T, B, var, x):
# make two deep copies, with extra slack variable column
T1 = [ [ T[i][j] for j in range(len(T[i])) ] + [0] for i in range(len(T)) ];
T2 = [ [ T[i][j] for j in range(len(T[i])) ] + [0] for i in range(len(T)) ];
# make two new constraint rows
C1 = [ 0 ] * len(T[0]) + [1];
C1[0] = floor(x);
C1[var] = 1;
C2 = [ 0 ] * len(T[0]) + [-1];
C2[0] = (floor(x)+1);
C2[var] = 1;
T1.append(C1);
T2.append(C2);
# make two new bases
B1 = [ B[i] for i in range(len(B)) ] + [ len(T[0]) ];
B2 = [ B[i] for i in range(len(B)) ] + [ len(T[0]) ];
#Rebase(T1, B1);
#Rebase(T2, B2);
return (T1,B1), (T2,B2);
///
}}}
{{{id=163|
colors = [ "red", "green", "purple", "orange", "black", "blue" ];
fillcolors = [ (1,0.25,0.25), (0.25, 1, 0.25), (0.25, 0.25, 1), (1,1,0.5), (1,0.5,1), (0.5,1,1), (0.5,0.5,0.5) ];
def PlotActivePoints(OrigP, Active, cindex):
P = OrigP;
for A,B in Active:
inv = [ -1, -1];
for j in range(1,len(B)):
if B[j] == 1:
inv[0] = j;
if B[j] == 2:
inv[1] = j;
P += list_plot( [ (A[inv[0]][0], A[inv[1]][0])], size=50, color=colors[cindex]);
return P;
///
}}}
{{{id=137|
A = [\
[ 0, -1, -4, 0, 0, 0 ],\
[ 0, (5/3), -1, -1, 0, 0],\
[ 5, (5/3), 1, 0, 1, 0]];
B = [ 0, 3, 4 ];
PrintTableau(A,B);
///
[0| -1 -4 0 0 0 ]
[0|5/3 -1 -1 0 0 ]
[5|5/3 1 0 1 0 ]
}}}
{{{id=139|
Rebase(A,B);
PrintTableau(A,B);
PrimalSimplex(A, B);
PrintTableau(A,B);
///
[0| -1 -4 0 0 0 ]
[0|-5/3 1 1 0 0 ]
[5| 5/3 1 0 1 0 ]
[23/2|0 0 17/10 23/10 0 ]
[ 5/2|0 1 1/2 1/2 0 ]
[ 3/2|1 0 -3/10 3/10 0 ]
}}}
{{{id=145|
Active = [ (A,B) ];
PrintActiveTableaus(Active);
///
Current LP Lower Bound: -23/2 approx: -11.5000000000000
[23/2|0 0 17/10 23/10 0 ]
[ 5/2|0 1 1/2 1/2 0 ]
[ 3/2|1 0 -3/10 3/10 0 ]
}}}
{{{id=140|
pts = [];
for i in range(10):
for j in range(10):
pts.append( (i,j) );
P = list_plot( pts );
x = var('x');
P += plot( (5/3)*x, (x, 0, 20) );
P += plot( (-5/3)*x + 5, (x,0,20) );
P = PlotActivePoints(P, Active, 0);
P.set_axes_range( 0, 5, 0, 4 );
P
///
}}}
{{{id=143|
A0, B0 = Active[0];
Active.remove( (A0,B0) );
for X in BranchOnVariable(A0, B0, 1, 1.5):
Active.append(X);
A, B = X;
PrintTableau(A,B);
Rebase(A,B);
DualSimplex(A, B);
PrintActiveTableaus(Active);
///
[23/2|0 0 17/10 23/10 0 0 ]
[ 5/2|0 1 1/2 1/2 0 0 ]
[ 3/2|1 0 -3/10 3/10 0 0 ]
[ 1|1 0 0 0 0 1 ]
[23/2|0 0 17/10 23/10 0 0 ]
[ 5/2|0 1 1/2 1/2 0 0 ]
[ 3/2|1 0 -3/10 3/10 0 0 ]
[ 2|1 0 0 0 0 -1 ]
Current LP Lower Bound: -23/3 approx: -7.66666666666667
[23/3|0 0 4 0 0 23/3 ]
[ 5/3|0 1 1 0 0 5/3 ]
[ 1|1 0 0 0 0 1 ]
[ 5/3|0 0 -1 1 0 -10/3 ]
Current LP Lower Bound: -26/3 approx: -8.66666666666667
[26/3|0 0 0 4 0 17/3 ]
[ 5/3|0 1 0 1 0 5/3 ]
[ 2|1 0 0 0 0 -1 ]
[ 5/3|0 0 1 -1 0 -10/3 ]
}}}
{{{id=152|
P = polygon2d([[1.05,0], [1.95,0], [1.95,6], [1.05,6]], rgbcolor=fillcolors[0], alpha=0.5) + P;
P = PlotActivePoints(P, Active, 1);
P.set_axes_range(0,5,0,4);
P
///
}}}
{{{id=144|
A0, B0 = Active[0];
Active.remove( (A0,B0) );
for X in BranchOnVariable(A0, B0, 2, 1.5):
A, B = X;
PrintTableau(A, B);
Rebase(A,B);
A, B = DualSimplex(A, B);
if A is None:
print "Infeasible (Dual Unbounded)!\n";
else:
Active.append( (A, B) );
PrintActiveTableaus(Active);
///
[23/3|0 0 4 0 0 23/3 0 ]
[ 5/3|0 1 1 0 0 5/3 0 ]
[ 1|1 0 0 0 0 1 0 ]
[ 5/3|0 0 -1 1 0 -10/3 0 ]
[ 1|0 1 0 0 0 0 1 ]
[23/3|0 0 4 0 0 23/3 0 ]
[ 5/3|0 1 1 0 0 5/3 0 ]
[ 1|1 0 0 0 0 1 0 ]
[ 5/3|0 0 -1 1 0 -10/3 0 ]
[ 2|0 1 0 0 0 0 -1 ]
Infeasible (Dual Unbounded)!
Current LP Lower Bound: -26/3 approx: -8.66666666666667
[26/3|0 0 0 4 0 17/3 ]
[ 5/3|0 1 0 1 0 5/3 ]
[ 2|1 0 0 0 0 -1 ]
[ 5/3|0 0 1 -1 0 -10/3 ]
Current LP Lower Bound: -5 approx: -5.00000000000000
[ 5|0 0 0 0 0 1 4 ]
[ 1|0 1 0 0 0 0 1 ]
[ 1|1 0 0 0 0 1 0 ]
[7/3|0 0 0 1 0 -5/3 -1 ]
[2/3|0 0 1 0 0 5/3 -1 ]
}}}
{{{id=153|
P = polygon2d([[0,1.05],[0,1.95], [1.05,1.95], [1.05,1.05]], rgbcolor=(0.5,0.5,0.5), alpha=0.5) + P;
P = PlotActivePoints(P, Active, 2);
P.set_axes_range(0,5,0,4);
P
///
}}}
{{{id=146|
A0, B0 = Active[0];
Active.remove( (A0,B0) );
for X in BranchOnVariable(A0, B0, 2, 1.5):
A, B = X;
Rebase(A,B);
PrintTableau(A, B);
A, B = DualSimplex(A, B);
if A is None:
print "Infeasible (Dual Unbounded)!\n";
else:
Active.append( (A, B) );
PrintActiveTableaus(Active);
///
[26/3|0 0 0 4 0 17/3 0 ]
[ 5/3|0 1 0 1 0 5/3 0 ]
[ 2|1 0 0 0 0 -1 0 ]
[ 5/3|0 0 1 -1 0 -10/3 0 ]
[-2/3|0 0 0 -1 0 -5/3 1 ]
[26/3|0 0 0 4 0 17/3 0 ]
[ 5/3|0 1 0 1 0 5/3 0 ]
[ 2|1 0 0 0 0 -1 0 ]
[ 5/3|0 0 1 -1 0 -10/3 0 ]
[-1/3|0 0 0 1 0 5/3 1 ]
Infeasible (Dual Unbounded)!
Current LP Lower Bound: -5 approx: -5.00000000000000
[ 5|0 0 0 0 0 1 4 ]
[ 1|0 1 0 0 0 0 1 ]
[ 1|1 0 0 0 0 1 0 ]
[7/3|0 0 0 1 0 -5/3 -1 ]
[2/3|0 0 1 0 0 5/3 -1 ]
Current LP Lower Bound: -32/5 approx: -6.40000000000000
[32/5|0 0 0 3/5 0 0 17/5 ]
[ 1|0 1 0 0 0 0 1 ]
[12/5|1 0 0 3/5 0 0 -3/5 ]
[ 3|0 0 1 1 0 0 -2 ]
[ 2/5|0 0 0 3/5 0 1 -3/5 ]
}}}
{{{id=154|
P = polygon2d([[1.95,1.05],[1.95,1.95], [6,1.95], [6,1.05]], rgbcolor=(0.25,1,0.25), alpha=0.5) + P;
P = PlotActivePoints(P, Active, 2);
P.set_axes_range(0,5,0,4);
P
///
}}}
{{{id=147|
A0, B0 = Active[1];
Active.remove( (A0,B0) );
for X in BranchOnVariable(A0, B0, 1, 2.5):
A, B = X;
Rebase(A,B);
PrintTableau(A, B);
A, B = DualSimplex(A, B);
if A is None:
print "Infeasible (Dual Unbounded)!\n";
else:
Active.append( (A, B) );
PrintActiveTableaus(Active);
///
[32/5|0 0 0 3/5 0 0 17/5 0 ]
[ 1|0 1 0 0 0 0 1 0 ]
[12/5|1 0 0 3/5 0 0 -3/5 0 ]
[ 3|0 0 1 1 0 0 -2 0 ]
[ 2/5|0 0 0 3/5 0 1 -3/5 0 ]
[-2/5|0 0 0 -3/5 0 0 3/5 1 ]
[32/5|0 0 0 3/5 0 0 17/5 0 ]
[ 1|0 1 0 0 0 0 1 0 ]
[12/5|1 0 0 3/5 0 0 -3/5 0 ]
[ 3|0 0 1 1 0 0 -2 0 ]
[ 2/5|0 0 0 3/5 0 1 -3/5 0 ]
[-3/5|0 0 0 3/5 0 0 -3/5 1 ]
Current LP Lower Bound: -5 approx: -5.00000000000000
[ 5|0 0 0 0 0 1 4 ]
[ 1|0 1 0 0 0 0 1 ]
[ 1|1 0 0 0 0 1 0 ]
[7/3|0 0 0 1 0 -5/3 -1 ]
[2/3|0 0 1 0 0 5/3 -1 ]
Current LP Lower Bound: -6 approx: -6.00000000000000
[ 6|0 0 0 0 0 0 4 1 ]
[ 1|0 1 0 0 0 0 1 0 ]
[ 2|1 0 0 0 0 0 0 1 ]
[7/3|0 0 1 0 0 0 -1 5/3 ]
[ 0|0 0 0 0 0 1 0 1 ]
[2/3|0 0 0 1 0 0 -1 -5/3 ]
Current LP Lower Bound: -3 approx: -3.00000000000000
[3|0 0 0 4 0 0 0 17/3 ]
[0|0 1 0 1 0 0 0 5/3 ]
[3|1 0 0 0 0 0 0 -1 ]
[5|0 0 1 -1 0 0 0 -10/3 ]
[1|0 0 0 0 0 1 0 -1 ]
[1|0 0 0 -1 0 0 1 -5/3 ]
}}}
{{{id=148|
P = polygon2d([[2.05,0],[2.95,0], [2.95,1.05], [2.05,1.05] ], rgbcolor=(0.25,0.25,1), alpha=0.5) + P;
P = PlotActivePoints(P, Active, 2);
P.set_axes_range(0,5,0,4);
P
///
}}}
{{{id=158|
///
}}}
{{{id=172|
///
}}}