// Rational simplex solver written by John C. Bowman and Pouria Ramazi, 2018.
import rational;
bool optimizeTableau=true;
int[] artificialColumn;
void simplexInit(rational[] c, rational[][] A, int[] s=new int[],
rational[] b, int count) {}
void simplexTableau(rational[][] E, int[] Bindices, int I=-1, int J=-1,
int n=E[0].length-1) {}
void simplexPhase1(rational[] c, rational[][] A, rational[] b,
int[] Bindices) {}
void simplexPhase2() {}
void simplexWrite(rational[][] E, int[] Bindices, int, int)
{
int m=E.length-1;
int n=E[0].length-1;
write(E[m][0],tab);
for(int j=1; j <= n; ++j)
write(E[m][j],tab);
write();
for(int i=0; i < m; ++i) {
write(E[i][0],tab);
for(int j=1; j <= n; ++j) {
write(E[i][j],tab);
}
write();
}
write();
};
struct simplex {
static int OPTIMAL=0;
static int UNBOUNDED=1;
static int INFEASIBLE=2;
int case;
rational[] x;
rational[] xStandard;
rational cost;
rational[] d;
bool dual=false;
int m,n;
int J;
// Row reduce based on pivot E[I][J]
void rowreduce(rational[][] E, int N, int I, int J) {
rational[] EI=E[I];
rational v=EI[J];
for(int j=0; j < J; ++j) EI[j] /= v;
EI[J]=1;
for(int j=J+1; j <= N; ++j) EI[j] /= v;
for(int i=0; i < I; ++i) {
rational[] Ei=E[i];
rational EiJ=Ei[J];
for(int j=0; j < J; ++j)
Ei[j] -= EI[j]*EiJ;
Ei[J]=0;
for(int j=J+1; j <= N; ++j)
Ei[j] -= EI[j]*EiJ;
}
for(int i=I+1; i <= m; ++i) {
rational[] Ei=E[i];
rational EiJ=Ei[J];
for(int j=0; j < J; ++j)
Ei[j] -= EI[j]*EiJ;
Ei[J]=0;
for(int j=J+1; j <= N; ++j)
Ei[j] -= EI[j]*EiJ;
}
}
int iterate(rational[][] E, int N, int[] Bindices, bool phase1=false) {
while(true) {
// Bland's rule: first negative entry in reduced cost (bottom) row enters
rational[] Em=E[m];
for(J=1; J <= N; ++J)
if(Em[J] < 0) break;
if(J > N)
break;
int I=-1;
rational t;
for(int i=0; i < m; ++i) {
rational u=E[i][J];
if(u > 0) {
t=E[i][0]/u;
I=i;
break;
}
}
for(int i=I+1; i < m; ++i) {
rational u=E[i][J];
if(u > 0) {
rational r=E[i][0]/u;
if(r <= t && (r < t || Bindices[i] < Bindices[I])) {
t=r; I=i;
} // Bland's rule: exiting variable has smallest minimizing subscript
}
}
if(I == -1)
return UNBOUNDED; // Can only happen in Phase 2.
simplexTableau(E,Bindices,I,J);
// Generate new tableau
Bindices[I]=J;
rowreduce(E,N,I,J);
if(phase1 && Em[0] == 0) break;
}
return OPTIMAL;
}
int iterateDual(rational[][] E, int N, int[] Bindices, bool phase1=false) {
while(true) {
// Bland's rule: negative variable with smallest subscript exits
int I;
for(I=0; I < m; ++I) {
if(E[I][0] < 0) break;
}
if(I == m)
break;
for(int i=I+1; i < m; ++i) {
if(E[i][0] < 0 && Bindices[i] < Bindices[I])
I=i;
}
rational[] Em=E[m];
rational[] EI=E[I];
int J=0;
rational t;
for(int j=1; j <= N; ++j) {
rational u=EI[j];
if(u < 0) {
t=-Em[j]/u;
J=j;
break;
}
}
for(int j=J+1; j <= N; ++j) {
rational u=EI[j];
if(u < 0) {
rational r=-Em[j]/u;
if(r <= t && (r < t || j < J)) {
t=r; J=j;
} // Bland's rule: smallest minimizing subscript enters
}
}
if(J == 0)
return INFEASIBLE; // Can only happen in Phase 2.
simplexTableau(E,Bindices,I,J);
// Generate new tableau
Bindices[I]=J;
rowreduce(E,N,I,J);
}
return OPTIMAL;
}
// Try to find a solution x to Ax=b that minimizes the cost c^T x,
// where A is an m x n matrix, x is a vector of n non-negative numbers,
// b is a vector of length m, and c is a vector of length n.
// Can set phase1=false if the last m columns of A form the identity matrix.
void operator init(rational[] c, rational[][] A, rational[] b,
bool phase1=true) {
// Phase 1
m=A.length;
if(m == 0) {case=INFEASIBLE; return;}
n=A[0].length;
if(n == 0) {case=INFEASIBLE; return;}
rational[][] E=new rational[m+1][n+1];
rational[] Em=E[m];
for(int j=1; j <= n; ++j)
Em[j]=0;
for(int i=0; i < m; ++i) {
rational[] Ai=A[i];
rational[] Ei=E[i];
if(b[i] >= 0 || dual) {
for(int j=1; j <= n; ++j) {
rational Aij=Ai[j-1];
Ei[j]=Aij;
Em[j] -= Aij;
}
} else {
for(int j=1; j <= n; ++j) {
rational Aij=-Ai[j-1];
Ei[j]=Aij;
Em[j] -= Aij;
}
}
}
void basicValues() {
rational sum=0;
for(int i=0; i < m; ++i) {
rational B=dual ? b[i] : abs(b[i]);
E[i][0]=B;
sum -= B;
}
Em[0]=sum;
}
int[] Bindices;
if(phase1) {
Bindices=new int[m];
int k=0;
artificialColumn.delete();
// Check for redundant basis vectors.
for(int p=0; p < m; ++p) {
bool checkBasis(int j) {
for(int i=0; i < m; ++i) {
rational[] Ei=E[i];
if(i != p ? Ei[j] != 0 : Ei[j] <= 0)
return false;
}
return true;
}
int checkTableau() {
if(optimizeTableau)
for(int j=1; j <= n; ++j)
if(checkBasis(j)) return j;
return 0;
}
int j=checkTableau();
Bindices[p]=n+1+p;
if(j == 0) { // Add an artificial variable
artificialColumn.push(p+1);
for(int i=0; i < p; ++i)
E[i].push(0);
E[p].push(1);
for(int i=p+1; i < m; ++i)
E[i].push(0);
E[m].push(0);
++k;
}
}
basicValues();
simplexPhase1(c,A,b,Bindices);
iterate(E,n+k,Bindices,true);
if(Em[0] != 0) {
simplexTableau(E,Bindices);
case=INFEASIBLE;
return;
}
} else {
Bindices=sequence(new int(int x){return x;},m)+n-m+1;
basicValues();
}
rational[] cB=phase1 ? new rational[m] : c[n-m:n];
rational[][] D=phase1 ? new rational[m+1][n+1] : E;
if(phase1) {
// Drive artificial variables out of basis.
for(int i=0; i < m; ++i) {
if(Bindices[i] > n) {
rational[] Ei=E[i];
int j;
for(j=1; j <= n; ++j)
if(Ei[j] != 0) break;
if(j > n) continue;
simplexTableau(E,Bindices,i,j,n);
Bindices[i]=j;
rowreduce(E,n,i,j);
}
}
simplexTableau(E,Bindices,-1,-1,n);
int ip=0; // reduced i
for(int i=0; i < m; ++i) {
int k=Bindices[i];
if(k > n) continue;
Bindices[ip]=k;
cB[ip]=c[k-1];
rational[] Dip=D[ip];
rational[] Ei=E[i];
for(int j=1; j <= n; ++j)
Dip[j]=Ei[j];
Dip[0]=Ei[0];
++ip;
}
rational[] Dip=D[ip];
rational[] Em=E[m];
for(int j=1; j <= n; ++j)
Dip[j]=Em[j];
Dip[0]=Em[0];
if(m > ip) {
Bindices.delete(ip,m-1);
D.delete(ip,m-1);
m=ip;
}
}
rational[] Dm=D[m];
for(int j=1; j <= n; ++j) {
rational sum=0;
for(int k=0; k < m; ++k)
sum += cB[k]*D[k][j];
Dm[j]=c[j-1]-sum;
}
rational sum=0;
for(int k=0; k < m; ++k)
sum += cB[k]*D[k][0];
Dm[0]=-sum;
simplexPhase2();
case=(dual ? iterateDual : iterate)(D,n,Bindices);
simplexTableau(D,Bindices);
if(case != INFEASIBLE) {
x=new rational[n];
for(int j=0; j < n; ++j)
x[j]=0;
for(int k=0; k < m; ++k)
x[Bindices[k]-1]=D[k][0];
xStandard=copy(x);
}
if(case == UNBOUNDED) {
d=new rational[n];
for(int j=0; j < n; ++j)
d[j]=0;
d[J-1]=1;
for(int k=0; k < m; ++k)
d[Bindices[k]-1]=-D[k][J];
}
if(case != OPTIMAL)
return;
cost=-Dm[0];
}
// Try to find a solution x to sgn(Ax-b)=sgn(s) that minimizes the cost
// c^T x, where A is an m x n matrix, x is a vector of n non-negative
// numbers, b is a vector of length m, and c is a vector of length n.
void operator init(rational[] c, rational[][] A, int[] s, rational[] b) {
int m=A.length;
if(m == 0) {case=INFEASIBLE; return;}
int n=A[0].length;
if(n == 0) {case=INFEASIBLE; return;}
int count=0;
for(int i=0; i < m; ++i)
if(s[i] != 0) ++count;
rational[][] a=new rational[m][n+count];
for(int i=0; i < m; ++i) {
rational[] ai=a[i];
rational[] Ai=A[i];
for(int j=0; j < n; ++j) {
ai[j]=Ai[j];
}
}
int k=0;
bool phase1=false;
dual=count == m && all(c >= 0);
for(int i=0; i < m; ++i) {
rational[] ai=a[i];
for(int j=0; j < k; ++j)
ai[n+j]=0;
int si=s[i];
if(k < count)
ai[n+k]=-si;
for(int j=k+1; j < count; ++j)
ai[n+j]=0;
if(si == 0) phase1=true;
else {
++k;
rational bi=b[i];
if(bi == 0) {
if(si == 1) {
s[i]=-1;
for(int j=0; j < n+count; ++j)
ai[j]=-ai[j];
}
} else if(dual && si == 1) {
b[i]=-bi;
s[i]=-1;
for(int j=0; j < n+count; ++j)
ai[j]=-ai[j];
} else if(si*bi > 0)
phase1=true;
}
}
if(dual) phase1=false;
rational[] C=concat(c,array(count,rational(0)));
simplexInit(C,a,b,count);
operator init(C,a,b,phase1);
if(case != INFEASIBLE && count > 0)
x.delete(n,n+count-1);
}
}