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