| Prev | Next |  |  |  |  |  | simplex_method.hpp | Headings

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