|
Prev
| Next
|
|
|
|
|
|
simplex_method.hpp |
Headings |
@(@\newcommand{\W}[1]{ \; #1 \; }
\newcommand{\R}[1]{ {\rm #1} }
\newcommand{\B}[1]{ {\bf #1} }
\newcommand{\D}[2]{ \frac{\partial #1}{\partial #2} }
\newcommand{\DD}[3]{ \frac{\partial^2 #1}{\partial #2 \partial #3} }
\newcommand{\Dpow}[2]{ \frac{\partial^{#1}}{\partial {#2}^{#1}} }
\newcommand{\dpow}[2]{ \frac{ {\rm d}^{#1}}{{\rm d}\, {#2}^{#1}} }@)@This is cppad-20221105 documentation. Here is a link to its
current documentation
.
simplex_method Source Code
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
// BEGIN PROTOTYPE
template <class Vector>
bool simplex_method(
size_t level ,
const Vector& A ,
const Vector& b ,
const Vector& c ,
size_t maxitr ,
Vector& xout )
// END PROTOTYPE
{ // number of equations
size_t ne = b.size();
// number of x variables
size_t nx = c.size();
CPPAD_ASSERT_UNKNOWN( size_t(A.size()) == ne * nx );
CPPAD_ASSERT_UNKNOWN( level <= 2 );
//
if( level > 0 )
{ std::cout << "start simplex_method\n";
CppAD::abs_print_mat("A", ne, nx, A);
CppAD::abs_print_mat("b", ne, 1, b);
CppAD::abs_print_mat("c", nx, 1, c);
}
//
// variables (columns) in the Tableau:
// x: the original primary variables with size n
// s: slack variables, one for each equation
// a: auxillary variables, one for each negative right hand size
// r: right hand size for equations
//
// Determine number of auxillary variables
size_t na = 0;
for(size_t i = 0; i < ne; i++)
{ if( b[i] > 0.0 )
++na;
}
// size of columns in the Tableau
size_t nc = nx + ne + na + 1;
// number of rows in Tableau, the equations plust two objectives
size_t nr = ne + 2;
// Initilize Tableau as zero
Vector T(nr * nc);
for(size_t i = 0; i < nr * nc; i++)
T[i] = 0.0;
// initialize basic variable flag as false
CppAD::vector<size_t> basic(nc);
for(size_t j = 0; j < nc; j++)
basic[j] = false;
// For i = 0 , ... , m-1, place the Equations
// sum_j A_{i,j} * x_j + b_i <= 0 in Tableau
na = 0; // use as index of next auxillary variable
for(size_t i = 0; i < ne; i++)
{ if( b[i] > 0.0)
{ // convert to - sum_j A_{i,j} x_j - b_i >= 0
for(size_t j = 0; j < nx; j++)
T[i * nc + j] = - A[i * nx + j];
// slack variable has negative coefficient
T[i * nc + (nx + i)] = -1.0;
// auxillary variable is basic for this constraint
T[i * nc + (nx + ne + na)] = 1.0;
basic[nx + ne + na] = true;
// right hand side
T[i * nc + (nc - 1)] = b[i];
//
++na;
}
else
{ // sum_j A_{i,j} x_j + b_i <= 0
for(size_t j = 0; j < nx; j++)
T[i * nc + j] = A[i * nx + j];
// slack variable is also basic
T[ i * nc + (nx + i) ] = 1.0;
basic[nx + i] = true;
// right hand side for equations
T[ i * nc + (nc - 1) ] = - b[i];
}
}
// na is back to its original value
CPPAD_ASSERT_UNKNOWN( nc == nx + ne + na + 1 );
//
// place the equation objective equation in Tablueau
// row ne corresponds to the equation z - sum_j c_j x_j = 0
// column index for z is nx + ne + na
for(size_t j = 0; j < nx; j++)
T[ne * nc + j] = - c[j];
//
// row ne+1 corresponds to the equation w - a_0 - ... - a_{na-1} = 0
// column index for w is nx + ne + na +1
for(size_t j = 0; j < na; j++)
T[(ne + 1) * nc + (nx + ne + j)] = -1.0;
//
// fix auxillary objective so coefficients in w
// for auxillary variables are zero
for(size_t k = 0; k < na; k++)
{ size_t ja = nx + ne + k;
size_t ia = ne;
for(size_t i = 0; i < ne; i++)
{ if( T[i * nc + ja] != 0.0 )
{ CPPAD_ASSERT_UNKNOWN( T[i * nc + ja] == 1.0 );
CPPAD_ASSERT_UNKNOWN( T[(ne + 1) * nc + ja] == -1.0 )
CPPAD_ASSERT_UNKNOWN( ia == ne );
ia = i;
}
}
CPPAD_ASSERT_UNKNOWN( ia < ne );
for(size_t j = 0; j < nc; j++)
T[(ne + 1) * nc + j] += T[ia * nc + j];
// The result in column ja is zero, avoid roundoff
T[(ne + 1) * nc + ja] = 0.0;
}
//
// index of current objective
size_t iobj = ne; // original objective z
if( na > 0 )
iobj = ne + 1; // auxillary objective w
//
// simplex interations
for(size_t itr = 0; itr < maxitr; itr++)
{ // current value for xout
for(size_t j = 0; j < nx; j++)
{ xout[j] = 0.0;
if( basic[j] )
{ // determine which row of column j is non-zero
xout[j] = std::numeric_limits<double>::quiet_NaN();
for(size_t i = 0; i < ne; i++)
{ double T_ij = T[i * nc + j];
CPPAD_ASSERT_UNKNOWN( T_ij == 0.0 || T_ij == 1.0 );
if( T_ij == 1.0 )
{ // corresponding value in right hand side
xout[j] = T[ i * nc + (nc-1) ];
}
}
}
}
if( level > 1 )
CppAD::abs_print_mat("T", nr, nc, T);
if( level > 0 )
{ CppAD::abs_print_mat("x", nx, 1, xout);
std::cout << "itr = " << itr;
if( iobj > ne )
std::cout << ", auxillary objective w = ";
else
std::cout << ", objective z = ";
std::cout << T[iobj * nc + (nc - 1)] << "\n";
}
//
// number of variables depends on objective
size_t nv = nx + ne; // (x, s)
if( iobj == ne + 1 )
{ // check if we have solved the auxillary problem
bool done = true;
for(size_t k = 0; k < na; k++)
if( basic[nx + ne + k] )
done = false;
if( done )
{ // switch to optimizing the original objective
iobj = ne;
}
else
nv = nx + ne + na; // (x, s, a)
}
//
// determine variable with maximuim coefficient in objective row
double cmax = 0.0;
size_t jmax = nv;
for(size_t j = 0; j < nv; j++)
{ if( T[iobj * nc + j] > cmax )
{ CPPAD_ASSERT_UNKNOWN( ! basic[j] );
cmax = T[ iobj * nc + j];
jmax = j;
}
}
// check for solution
if( jmax == nv )
{ if( iobj == ne )
{ if( level > 0 )
std::cout << "end simplex_method\n";
return true;
}
if( level > 0 )
std::cout << "end_simples_method: no feasible solution\n";
return false;
}
//
// We will increase the j-th variable.
// Determine which row will be the pivot row.
double rmin = std::numeric_limits<double>::infinity();
size_t imin = ne;
for(size_t i = 0; i < ne; i++)
{ if( T[i * nc + jmax] > 0.0 )
{ double r = T[i * nc + (nc-1) ] / T[i * nc + jmax];
if( r < rmin )
{ rmin = r;
imin = i;
}
}
}
if( imin == ne )
{ // not auxillary objective
CPPAD_ASSERT_UNKNOWN( iobj == ne );
if( level > 0 ) std::cout
<< "end simplex_method: objective is unbounded below\n";
return false;
}
double pivot = T[imin * nc + jmax];
//
// Which variable is changing from basic to non-basic.
// Initilaize as not yet determined.
size_t basic2not = nc;
//
// Divide row imin by pivot element
for(size_t j = 0; j < nc; j++)
{ if( basic[j] && T[imin * nc + j] == 1.0 )
{ CPPAD_ASSERT_UNKNOWN( basic2not == nc );
basic2not = j;
}
T[imin * nc + j] /= pivot;
}
// The result in column jmax is one, avoid roundoff
T[imin * nc + jmax ] = 1.0;
//
// Check that we found the variable going from basic to non-basic
CPPAD_ASSERT_UNKNOWN( basic2not < nv && basic2not != jmax );
//
// convert variable for column jmax to basic
// and for column basic2not to non-basic
for(size_t i = 0; i < nr; i++) if( i != imin )
{ double r = T[i * nc + jmax ] / T[imin * nc + jmax];
// row_i = row_i - r * row_imin
for(size_t j = 0; j < nc; j++)
T[i * nc + j] -= r * T[imin * nc + j];
// The result in column jmax is zero, avoid roundoff
T[i * nc + jmax] = 0.0;
}
// update flag for basic variables
basic[ basic2not ] = false;
basic[ jmax ] = true;
}
if( level > 0 ) std::cout
<< "end simplex_method: maximum # iterations without solution\n";
return false;
}
} // END_CPPAD_NAMESPACE
Input File: example/abs_normal/simplex_method.omh