Example #1
0
void MILPSolverCPX::getRow(const int & i, vector<pair<int,double> > & entries)
{
    const int colCount = getNumCols();
    
    IloRange & currRow = (modelcon->data)[i];
    
    IloNumExprArg ne = currRow.getExpr();
    
    for(IloExpr::LinearIterator itr = static_cast<IloExpr>(ne).getLinearIterator(); itr.ok(); ++itr) {
        const int colID = itr.getVar().getId();
        for (int c = 0; c < colCount; ++c) {
            if ((*modelvar)[c].getId() == colID) {
                entries.push_back(make_pair(c, itr.getCoef()));
                break;
            }
        }        
    }    
    
}
Example #2
0
// Test KKT conditions on the solution.
// The function returns true if the tested KKT conditions are satisfied
// and false otherwise.
// The function assumes that the model currently extracted to CPLEX is fully
// described by obj, vars and rngs.
static bool
checkkkt (IloCplex& cplex, IloObjective const& obj, IloNumVarArray const& vars,
          IloRangeArray const& rngs, IloIntArray const& cone, double tol)
{
   IloEnv env = cplex.getEnv();
   IloModel model = cplex.getModel();
   IloNumArray x(env), dslack(env);
   IloNumArray pi(env, rngs.getSize()), slack(env);

   // Read primal and dual solution information.
   cplex.getValues(x, vars);
   cplex.getSlacks(slack, rngs);

   // pi for second order cone constraints.
   getsocpconstrmultipliers(cplex, vars, rngs, pi, dslack);

   // pi for linear constraints.
   for (IloInt i = 0; i < rngs.getSize(); ++i) {
      IloRange r = rngs[i];
      if ( !r.getQuadIterator().ok() )
         pi[idx(r)] = cplex.getDual(r);
   }

   // Print out the data we just fetched.
   streamsize oprec = env.out().precision(3);
   ios_base::fmtflags oflags = env.out().setf(ios::fixed | ios::showpos);
   env.out() << "x      = [";
   for (IloInt i = 0; i < x.getSize(); ++i)
      env.out() << " " << x[i];
   env.out() << " ]" << endl;
   env.out() << "dslack = [";
   for (IloInt i = 0; i < dslack.getSize(); ++i)
      env.out() << " " << dslack[i];
   env.out() << " ]" << endl;
   env.out() << "pi     = [";
   for (IloInt i = 0; i < rngs.getSize(); ++i)
      env.out() << " " << pi[i];
   env.out() << " ]" << endl;
   env.out() << "slack  = [";
   for (IloInt i = 0; i < rngs.getSize(); ++i)
      env.out() << " " << slack[i];
   env.out() << " ]" << endl;
   env.out().precision(oprec);
   env.out().flags(oflags);

   // Test primal feasibility.
   // This example illustrates the use of dual vectors returned by CPLEX
   // to verify dual feasibility, so we do not test primal feasibility
   // here.

   // Test dual feasibility.
   // We must have
   // - for all <= constraints the respective pi value is non-negative,
   // - for all >= constraints the respective pi value is non-positive,
   // - the dslack value for all non-cone variables must be non-negative.
   // Note that we do not support ranged constraints here.
   for (IloInt i = 0; i < vars.getSize(); ++i) {
      IloNumVar v = vars[i];
      if ( cone[i] == NOT_IN_CONE && dslack[i] < -tol ) {
         env.error() << "Dual multiplier for " << v << " is not feasible: "
                     << dslack[i] << endl;
         return false;
      }
   }
   for (IloInt i = 0; i < rngs.getSize(); ++i) {
      IloRange r = rngs[i];
      if ( fabs (r.getLB() - r.getUB()) <= tol ) {
         // Nothing to check for equality constraints.
      }
      else if ( r.getLB() > -IloInfinity && pi[i] > tol ) {
         env.error() << "Dual multiplier " << pi[i] << " for >= constraint"
                     << endl << r << endl
                     << "not feasible"
                     << endl;
         return false;
      }
      else if ( r.getUB() < IloInfinity && pi[i] < -tol ) {
         env.error() << "Dual multiplier " << pi[i] << " for <= constraint"
                     << endl << r << endl
                     << "not feasible"
                     << endl;
         return false;
      }
   }

   // Test complementary slackness.
   // For each constraint either the constraint must have zero slack or
   // the dual multiplier for the constraint must be 0. We must also
   // consider the special case in which a variable is not explicitly
   // contained in a second order cone constraint.
   for (IloInt i = 0; i < vars.getSize(); ++i) {
      if ( cone[i] == NOT_IN_CONE ) {
         if ( fabs(x[i]) > tol && dslack[i] > tol ) {
            env.error() << "Invalid complementary slackness for " << vars[i]
                        << ":" << endl
                        << " " << x[i] << " and " << dslack[i]
                        << endl;
            return false;
         }
      }
   }
   for (IloInt i = 0; i < rngs.getSize(); ++i) {
      if ( fabs(slack[i]) > tol && fabs(pi[i]) > tol ) {
         env.error() << "Invalid complementary slackness for "
                     << endl << rngs[i] << ":" << endl
                     << " " << slack[i] << " and " << pi[i]
                     << endl;
         return false;
      }
   }

   // Test stationarity.
   // We must have
   //  c - g[i]'(X)*pi[i] = 0
   // where c is the objective function, g[i] is the i-th constraint of the
   // problem, g[i]'(x) is the derivate of g[i] with respect to x and X is the
   // optimal solution.
   // We need to distinguish the following cases:
   // - linear constraints g(x) = ax - b. The derivative of such a
   //   constraint is g'(x) = a.
   // - second order constraints g(x[1],...,x[n]) = -x[1] + |(x[2],...,x[n])|
   //   the derivative of such a constraint is
   //     g'(x) = (-1, x[2]/|(x[2],...,x[n])|, ..., x[n]/|(x[2],...,x[n])|
   //   (here |.| denotes the Euclidean norm).
   // - bound constraints g(x) = -x for variables that are not explicitly
   //   contained in any second order cone constraint. The derivative for
   //   such a constraint is g'(x) = -1.
   // Note that it may happen that the derivative of a second order cone
   // constraint is not defined at the optimal solution X (this happens if
   // X=0). In this case we just skip the stationarity test.
   IloNumArray sum(env, vars.getSize());
   for (IloExpr::LinearIterator it = obj.getLinearIterator(); it.ok(); ++it)
      sum[idx(it.getVar())] = it.getCoef();

   for (IloInt i = 0; i < vars.getSize(); ++i) {
      IloNumVar v = vars[i];
      if ( cone[i] == NOT_IN_CONE )
         sum[i] -= dslack[i];
   }
   for (IloInt i = 0; i < rngs.getSize(); ++i) {
      IloRange r = rngs[i];
      if ( r.getQuadIterator().ok() ) {
         // Quadratic (second order cone) constraint.
         IloNum norm = 0.0;
         for (IloExpr::QuadIterator q = r.getQuadIterator(); q.ok(); ++q) {
            if ( q.getCoef() > 0 )
               norm += x[idx(q.getVar1())] * x[idx(q.getVar1())];
         }
         norm = sqrt(norm);
         if ( fabs(norm) <= tol ) {
            // Derivative is not defined. Skip test.
            env.warning() << "Cannot test stationarity at non-differentiable point."
                          << endl;
            return true;
         }
         else {
            for (IloExpr::QuadIterator q = r.getQuadIterator(); q.ok(); ++q) {
               if ( q.getCoef() < 0 )
                  sum[idx(q.getVar1())] -= pi[i];
               else
                  sum[idx(q.getVar1())] += pi[i] * x[idx(q.getVar1())] / norm;
            }
         }
      }
      else {
         // Linear constraint.
         for (IloExpr::LinearIterator l = r.getLinearIterator(); l.ok(); ++l)
            sum[idx(l.getVar())] -= pi[i] * l.getCoef();
      }
   }

   // Now test that all elements in sum[] are 0.
   for (IloInt i = 0; i < vars.getSize(); ++i) {
      if ( fabs(sum[i]) > tol ) {
         env.error() << "Invalid stationarity " << sum[i] << " for "
                     << vars[i] << endl;
         return false;
      }
   }

   return true;   
}
Example #3
0
/** Create the dual of a linear program.
 * The function can only dualize programs of the form
 * <code>Ax <= b, x >= 0</code>. The data in <code>primalVars</code> and
 * <code>dualRows</code> as well as in <code>primalRows</code> and
 * <code>dualVars</code> is in 1-to-1-correspondence.
 * @param primalObj  Objective function of primal problem.
 * @param primalVars Variables in primal problem.
 * @param primalRows Rows in primal problem.
 * @param dualObj    Objective function of dual will be stored here.
 * @param dualVars   All dual variables will be stored here.
 * @param dualRows   All dual rows will be stored here.
 */
void BendersOpt::makeDual(IloObjective const &primalObj,
                          IloNumVarArray const &primalVars,
                          IloRangeArray const &primalRows,
                          IloObjective *dualObj,
                          IloNumVarArray *dualVars,
                          IloRangeArray *dualRows)
{
   // To keep the code simple we only support problems
   // of the form Ax <= b, b >= 0 here. We leave it as a reader's
   // exercise to extend the function to something that can handle
   // any kind of linear model.
   for (IloInt j = 0; j < primalVars.getSize(); ++j)
      if ( primalVars[j].getLB() != 0 ||
           primalVars[j].getUB() < IloInfinity )
      {
         std::stringstream s;
         s << "Cannot dualize variable " << primalVars[j];
         throw s.str();
      }
   for (IloInt i = 0; i < primalRows.getSize(); ++i)
      if ( primalRows[i].getLB() > -IloInfinity ||
           primalRows[i].getUB() >= IloInfinity )
      {
         std::stringstream s;
         s << "Cannot dualize constraint " << primalRows[i];
         std::cerr << s.str() << std::endl;
         throw s.str();
      }

   // The dual of
   //   min/max c^T x
   //       Ax <= b
   //        x >= 0
   // is
   //   max/min y^T b
   //       y^T A <= c
   //           y <= 0
   // We scale y by -1 to get >= 0

   IloEnv env = primalVars.getEnv();
   IloObjective obj(env, 0.0,
                    primalObj.getSense() == IloObjective::Minimize ?
                    IloObjective::Maximize : IloObjective::Minimize);
   IloRangeArray rows(env);
   IloNumVarArray y(env);
   std::map<IloNumVar,IloInt,ExtractableLess<IloNumVar> > v2i;
   for (IloInt j = 0; j < primalVars.getSize(); ++j) {
      IloNumVar x = primalVars[j];
      v2i.insert(std::map<IloNumVar,IloInt,ExtractableLess<IloNumVar> >::value_type(x, j));
      rows.add(IloRange(env, -IloInfinity, 0, x.getName()));
   }
   for (IloExpr::LinearIterator it = primalObj.getLinearIterator(); it.ok(); ++it)
      rows[v2i[it.getVar()]].setUB(it.getCoef());

   for (IloInt i = 0; i < primalRows.getSize(); ++i) {
      IloRange r = primalRows[i];
      IloNumColumn col(env);
      col += obj(-r.getUB());
      for (IloExpr::LinearIterator it = r.getLinearIterator(); it.ok(); ++it)
         col += rows[v2i[it.getVar()]](-it.getCoef());
      y.add(IloNumVar(col, 0, IloInfinity, IloNumVar::Float, r.getName()));
   }

   *dualObj = obj;
   *dualVars = y;
   *dualRows = rows;
}
Example #4
0
/** Extract the master block from <code>problem</code>.
 * The constructor also sets up the solver for the newly created master
 * block. The master block can only be extracted if all sub-blocks have
 * already been extracted.
 * @param problem The problem from which to extract the master.
 * @param blocks  The sub blocks that have already been extracted.
 */
BendersOpt::Block::Block(Problem const *problem, BlockVector const &blocks)
   : env(), number(-1), vars(0), rows(0), cplex(0), cb(0)
{
   IloNumVarArray problemVars = problem->getVariables();
   IloRangeArray problemRanges = problem->getRows();

   IloExpr masterObj(env);
   IloNumVarArray masterVars(env);
   IloRangeArray masterRows(env);

   // Find columns that do not intersect block variables and
   // copy them to the master block.
   IdxMap idxMap;
   RowSet rowSet;
   for (IloInt j = 0; j < problemVars.getSize(); ++j) {
      IloNumVar x = problemVars[j];
      if ( problem->getBlock(x) < 0 ) {
         // Column is not in a block. Copy it to the master.
         IloNumVar v(env, x.getLB(), x.getUB(), x.getType(), x.getName());
         varMap.insert(VarMap::value_type(v, x));
         masterObj += problem->getObjCoef(x) * v;

         idxMap[x] = masterVars.getSize();
         masterVars.add(v);
      }
      else {
         // Column is in a block. Collect all rows that intersect
         // this column.
         RowSet const &intersected = problem->getIntersectedRows(x);
         for (RowSet::const_iterator it = intersected.begin();
              it != intersected.end(); ++it)
            rowSet.insert(*it);
         idxMap[x] = -1;
      }
   }

   // Pick up the rows that we need to copy.
   // These are the rows that are only intersected by master variables,
   // that is, the rows that are not in any block's rowset.
   for (IloInt i = 0; i < problemRanges.getSize(); ++i) {
      IloRange r = problemRanges[i];
      if ( rowSet.find(r) == rowSet.end() ) {
         IloRange masterRow(env, r.getLB(), r.getUB(), r.getName());
         IloExpr lhs(env);
         for (IloExpr::LinearIterator it = r.getLinearIterator(); it.ok(); ++it)
         {
            lhs += it.getCoef() * masterVars[idxMap[it.getVar()]];
         }
         masterRow.setExpr(lhs);
         masterRows.add(masterRow);
      }
   }

   // Adjust variable indices in blocks so that reference to variables
   // in the original problem become references to variables in the master.
   for (BlockVector::const_iterator b = blocks.begin(); b != blocks.end(); ++b) {
      for (std::vector<FixData>::iterator it = (*b)->fixed.begin(); it != (*b)->fixed.end(); ++it)
         it->col = idxMap[problemVars[it->col]];
   }

   // Create the eta variables, one for each block.
   // See the comments at the top of this file for details about the
   // eta variables.
   IloInt const firsteta = masterVars.getSize();
   for (BlockVector::size_type i = 0; i < blocks.size(); ++i) {
      std::stringstream s;
      s << "_eta" << i;
      IloNumVar eta(env, 0.0, IloInfinity, s.str().c_str());
      masterObj += eta;
      masterVars.add(eta);
   }

   // Create model and solver instance
   vars = masterVars;
   rows = masterRows;
   IloModel model(env);
   model.add(obj = IloObjective(env, masterObj, problem->getObjSense()));
   model.add(vars);
   model.add(rows);
   cplex = IloCplex(model);

   cplex.use(cb = new (env) LazyConstraintCallback(env, this, blocks,
                                              firsteta));

   for (IloExpr::LinearIterator it = obj.getLinearIterator(); it.ok(); ++it)
      objMap.insert(ObjMap::value_type(it.getVar(), it.getCoef()));
}
Example #5
0
/** Extract sub block number <code>n</code> from <code>problem</code>.
 * The constructor creates a representation of block number <code>n</code>
 * as described in <code>problem</code>.
 * The constructor will also connect the newly created block to a remote
 * object solver instance.
 * @param problem  The problem from which the block is to be extracted.
 * @param n        Index of the block to be extracted.
 * @param argc     Argument for IloCplex constructor.
 * @param argv     Argument for IloCplex constructor.
 * @param machines List of machines to which to connect. If the code is
 *                 compiled for the TCP/IP transport then the block will
 *                 be connected to <code>machines[n]</code>.
 */
BendersOpt::Block::Block(Problem const *problem, IloInt n, int argc, char const *const *argv,
                         std::vector<char const *> const &machines)
   : env(), number(n), vars(0), rows(0), cplex(0), cb(0)
{
   IloNumVarArray problemVars = problem->getVariables();
   IloRangeArray problemRanges = problem->getRows();

   // Create a map that maps variables in the original model to their
   // respective index in problemVars.
   std::map<IloNumVar,IloInt,ExtractableLess<IloNumVar> > origIdxMap;
   for (IloInt j = 0; j < problemVars.getSize(); ++j)
      origIdxMap.insert(std::map<IloNumVar,IloInt,ExtractableLess<IloNumVar> >::value_type(problemVars[j], j));

   // Copy non-fixed variables from original problem into primal problem.
   IloExpr primalObj(env);
   IloNumVarArray primalVars(env);
   IloRangeArray primalRows(env);
   IdxMap idxMap; // Index of original variable in block's primal model
   RowSet rowSet;
   for (IloInt j = 0; j < problemVars.getSize(); ++j) {
      IloNumVar x = problemVars[j];
      if ( problem->getBlock(x) == number ) {
         // Create column in block LP with exactly the same data.
         if ( x.getType() != IloNumVar::Float ) {
            std::stringstream s;
            s << "Cannot create non-continuous block variable " << x;
            std::cerr << s.str() << std::endl;
            throw s.str();
         }
         IloNumVar v(env, x.getLB(), x.getUB(), x.getType(), x.getName());
         // Normalize objective function to 'minimize'
         double coef = problem->getObjCoef(x);
         if ( problem->getObjSense() != IloObjective::Minimize )
            coef *= -1.0;
         primalObj += coef * v;
            
         // Record the index that the copied variable has in the
         // block model.
         idxMap.insert(IdxMap::value_type(x, primalVars.getSize()));
         primalVars.add(v);
            
         // Mark the rows that are intersected by this column
         // so that we can collect them later.
         RowSet const &intersected = problem->getIntersectedRows(x);
         for (RowSet::const_iterator it = intersected.begin();
              it != intersected.end(); ++it)
            rowSet.insert(*it);
      }
      else
         idxMap.insert(IdxMap::value_type(x, -1));
   }

   // Now copy all rows that intersect block variables.
   for (IloInt i = 0; i < problemRanges.getSize(); ++i) {
      IloRange r = problemRanges[i];
      if ( rowSet.find(r) == rowSet.end() )
         continue;

      // Create a copy of the row, normalizing it to '<='
      double factor = 1.0;
      if ( r.getLB() > -IloInfinity )
         factor = -1.0;
      IloRange primalR(env,
                       factor < 0 ? -r.getUB() : r.getLB(),
                       factor < 0 ? -r.getLB() : r.getUB(), r.getName());
      IloExpr lhs(env);
      for (IloExpr::LinearIterator it = r.getLinearIterator(); it.ok(); ++it)
      {
         IloNumVar v = it.getVar();
         double const val = factor * it.getCoef();
         if ( problem->getBlock(v) != number ) {
            // This column is not explicitly in this block. This means
            // that it is a column that will be fixed by the master.
            // We collect all such columns so that we can adjust the
            // dual objective function according to concrete fixings.
            // Store information about variables in this block that
            // will be fixed by master solves.
            fixed.push_back(FixData(primalRows.getSize(), origIdxMap[v], -val));
         }
         else {
            // The column is an ordinary in this block. Just copy it.
            lhs += primalVars[idxMap[v]] * val;
         }
      }
      primalR.setExpr(lhs);
      primalRows.add(primalR);
      lhs.end();
   }

   // Create the dual of the primal model we just created.
   // Note that makeDual _always_ returns a 'maximize' objective.
   IloObjective objective(env, primalObj, IloObjective::Minimize);
      
   makeDual(objective, primalVars, primalRows,
            &obj, &vars, &rows);
   objective.end();
   primalRows.endElements();
   primalRows.end();
   primalVars.endElements();
   primalVars.end();
   primalObj.end();
   // Create a model.
   IloModel model(env);
   model.add(obj);
   model.add(vars);
   model.add(rows);
   for (IloExpr::LinearIterator it = obj.getLinearIterator(); it.ok(); ++it)
      objMap.insert(ObjMap::value_type(it.getVar(), it.getCoef()));

   // Finally create the IloCplex instance that will solve
   // the problems associated with this block.
   char const **transargv = new char const *[argc + 3];
   for (int i = 0; i < argc; ++i)
      transargv[i] = argv[i];
#if defined(USE_MPI)
   char extra[128];
   sprintf (extra, "-remoterank=%d", static_cast<int>(number + 1));
   transargv[argc++] = extra;
   (void)machines;
#elif defined(USE_PROCESS)
   char extra[128];
   sprintf (extra, "-logfile=block%04d.log", static_cast<int>(number));
   transargv[argc++] = extra;
   (void)machines;
#elif defined(USE_TCPIP)
   transargv[argc++] = machines[number];
#endif
   cplex = IloCplex(model, TRANSPORT, argc, transargv);
   delete[] transargv;

   // Suppress output from this block's solver.
   cplex.setOut(env.getNullStream());
   cplex.setWarning(env.getNullStream());
}
Example #6
0
int
main (int argc, char **argv)
{
   int result = 0;
   IloEnv env;

   try {
      static int indices[] = { 0, 1, 2, 3, 4, 5, 6 };
      IloModel model(env);

      /* ***************************************************************** *
       *                                                                   *
       *    S E T U P   P R O B L E M                                      *
       *                                                                   *
       *  The model we setup here is                                       *
       * Minimize                                                          *
       *  obj: 3x1 - x2 + 3x3 + 2x4 + x5 + 2x6 + 4x7                       *
       * Subject To                                                        *
       *  c1: x1 + x2 = 4                                                  *
       *  c2: x1 + x3 >= 3                                                 *
       *  c3: x6 + x7 <= 5                                                 *
       *  c4: -x1 + x7 >= -2                                               *
       *  q1: [ -x1^2 + x2^2 ] <= 0                                        *
       *  q2: [ 4.25x3^2 -2x3*x4 + 4.25x4^2 - 2x4*x5 + 4x5^2  ] + 2 x1 <= 9.0
       *  q3: [ x6^2 - x7^2 ] >= 4                                         *
       * Bounds                                                            *
       *  0 <= x1 <= 3                                                     *
       *  x2 Free                                                          *
       *  0 <= x3 <= 0.5                                                   *
       *  x4 Free                                                          *
       *  x5 Free                                                          *
       *  x7 Free                                                          *
       * End                                                               *
       *                                                                   *
       * ***************************************************************** */

      IloNumVarArray x(env);
      x.add(IloNumVar(env, 0, 3, "x1"));
      x.add(IloNumVar(env, -IloInfinity, IloInfinity, "x2"));
      x.add(IloNumVar(env, 0, 0.5, "x3"));
      x.add(IloNumVar(env, -IloInfinity, IloInfinity, "x4"));
      x.add(IloNumVar(env, -IloInfinity, IloInfinity, "x5"));
      x.add(IloNumVar(env, 0, IloInfinity, "x6"));
      x.add(IloNumVar(env, -IloInfinity, IloInfinity, "x7"));
      for (IloInt i = 0; i < x.getSize(); ++i)
         x[i].setObject(&indices[i]);

      IloObjective obj = IloMinimize(env,
                                     3*x[0] - x[1] + 3*x[2] + 2*x[3] +
                                     x[4] + 2*x[5] + 4*x[6], "obj");
      model.add(obj);

      IloRangeArray linear(env);
      linear.add(IloRange(env, 4.0, x[0] + x[1], 4.0, "c1"));
      linear.add(IloRange(env, 3.0, x[0] + x[2], IloInfinity, "c2"));
      linear.add(IloRange(env, -IloInfinity, x[5] + x[6], 5.0, "c3"));
      linear.add(IloRange(env, -2.0, -x[0] + x[6], IloInfinity, "c4"));
      for (IloInt i = 0; i < linear.getSize(); ++i)
         linear[i].setObject(&indices[i]);
      model.add(linear);

      IloRangeArray quad(env);
      quad.add(IloRange(env, -IloInfinity, -x[0]*x[0] + x[1] * x[1], 0, "q1"));
      quad.add(IloRange(env, -IloInfinity,
                        4.25*x[2]*x[2] - 2*x[2]*x[3] + 4.25*x[3]*x[3] +
                        -2*x[3]*x[4] + 4*x[4]*x[4] + 2*x[0],
                        9.0, "q2"));
      quad.add(IloRange(env, 4.0, x[5]*x[5] - x[6]*x[6], IloInfinity, "q3"));
      for (IloInt i = 0; i < quad.getSize(); ++i)
         quad[i].setObject(&indices[i]);
      model.add(quad);

      /* ***************************************************************** *
       *                                                                   *
       *    O P T I M I Z E   P R O B L E M                                *
       *                                                                   *
       * ***************************************************************** */
      IloCplex cplex(model);
      cplex.setParam(IloCplex::Param::Barrier::QCPConvergeTol, 1e-10);
      cplex.solve();

      /* ***************************************************************** *
       *                                                                   *
       *    Q U E R Y   S O L U T I O N                                    *
       *                                                                   *
       * ***************************************************************** */
      IloNumArray xval(env);
      IloNumArray slack(env);
      IloNumArray qslack(env);
      IloNumArray cpi(env);
      IloNumArray rpi(env);
      IloNumArray qpi;
      cplex.getValues(x, xval);
      cplex.getSlacks(slack, linear);
      cplex.getSlacks(qslack, quad);
      cplex.getReducedCosts(cpi, x);
      cplex.getDuals(rpi, linear);
      qpi = getqconstrmultipliers(cplex, xval, quad);

      
      /* ***************************************************************** *
       *                                                                   *
       *    C H E C K   K K T   C O N D I T I O N S                        *
       *                                                                   *
       *    Here we verify that the optimal solution computed by CPLEX     *
       *    (and the qpi[] values computed above) satisfy the KKT          *
       *    conditions.                                                    *
       *                                                                   *
       * ***************************************************************** */

      // Primal feasibility: This example is about duals so we skip this test.

      // Dual feasibility: We must verify
      // - for <= constraints (linear or quadratic) the dual
      //   multiplier is non-positive.
      // - for >= constraints (linear or quadratic) the dual
      //   multiplier is non-negative.
      for (IloInt i = 0; i < linear.getSize(); ++i) {
         if ( linear[i].getLB() <= -IloInfinity ) {
            // <= constraint
            if ( rpi[i] > ZEROTOL ) {
               cerr << "Dual feasibility test failed for <= row " << i
                    << ": " << rpi[i] << endl;
               result = -1;
            }
         }
         else if ( linear[i].getUB() >= IloInfinity ) {
            // >= constraint
            if ( rpi[i] < -ZEROTOL ) {
               cerr << "Dual feasibility test failed for >= row " << i
                    << ":" << rpi[i] << endl;
               result = -1;
            }
         }
         else {
            // nothing to do for equality constraints
         }
      }
      for (IloInt q = 0; q < quad.getSize(); ++q) {
         if ( quad[q].getLB() <= -IloInfinity ) {
            // <= constraint
            if ( qpi[q] > ZEROTOL ) {
               cerr << "Dual feasibility test failed for <= quad " << q
                    << ": " << qpi[q] << endl;
               result = -1;
            }
         }
         else if ( quad[q].getUB() >= IloInfinity ) {
            // >= constraint
            if ( qpi[q] < -ZEROTOL ) {
               cerr << "Dual feasibility test failed for >= quad " << q
                    << ":" << qpi[q] << endl;
               result = -1;
            }
         }
         else {
            // nothing to do for equality constraints
         }
      }

      // Complementary slackness.
      // For any constraint the product of primal slack and dual multiplier
      // must be 0.
      for (IloInt i = 0; i < linear.getSize(); ++i) {
         if ( fabs (linear[i].getUB() - linear[i].getLB()) > ZEROTOL &&
              fabs (slack[i] * rpi[i]) > ZEROTOL )
         {
            cerr << "Complementary slackness test failed for row " << i
                 << ": " << fabs (slack[i] * rpi[i]) << endl;
            result = -1;
         }
      }
      for (IloInt q = 0; q < quad.getSize(); ++q) {
         if ( fabs (quad[q].getUB() - quad[q].getLB()) > ZEROTOL &&
              fabs (qslack[q] * qpi[q]) > ZEROTOL )
         {
            cerr << "Complementary slackness test failed for quad " << q
                 << ":" << fabs (qslack[q] * qpi[q]) << endl;
            result = -1;
         }
      }
      for (IloInt j = 0; j < x.getSize(); ++j) {
         if ( x[j].getUB() < IloInfinity ) {
            double const slk = x[j].getUB() - xval[j];
            double const dual = cpi[j] < -ZEROTOL ? cpi[j] : 0.0;
            if ( fabs (slk * dual) > ZEROTOL ) {
               cerr << "Complementary slackness test failed for ub " << j
                    << ": " << fabs (slk * dual) << endl;
               result = -1;
            }
         }
         if ( x[j].getLB() > -IloInfinity ) {
            double const slk = xval[j] - x[j].getLB();
            double const dual = cpi[j] > ZEROTOL ? cpi[j] : 0.0;
            if ( fabs (slk * dual) > ZEROTOL ) {
               cerr << "Complementary slackness test failed for lb " << j
                    << ": " << fabs (slk * dual) << endl;
               result = -1;
            }
         }
      }

      // Stationarity.
      // The difference between objective function and gradient at optimal
      // solution multiplied by dual multipliers must be 0, i.e., for the
      // optimal solution x
      // 0 == c
      //      - sum(r in rows)  r'(x)*rpi[r]
      //      - sum(q in quads) q'(x)*qpi[q]
      //      - sum(c in cols)  b'(x)*cpi[c]
      // where r' and q' are the derivatives of a row or quadratic constraint,
      // x is the optimal solution and rpi[r] and qpi[q] are the dual
      // multipliers for row r and quadratic constraint q.
      // b' is the derivative of a bound constraint and cpi[c] the dual bound
      // multiplier for column c.
      IloNumArray kktsum(env, x.getSize());

      // Objective function.
      for (IloExpr::LinearIterator it = obj.getLinearIterator(); it.ok(); ++it)
         kktsum[idx(it.getVar())] = it.getCoef();

      // Linear constraints.
      // The derivative of a linear constraint ax - b (<)= 0 is just a.
      for (IloInt i = 0; i < linear.getSize(); ++i) {
         for (IloExpr::LinearIterator it = linear[i].getLinearIterator();
              it.ok(); ++it)
            kktsum[idx(it.getVar())] -= rpi[i] * it.getCoef();
      }

      // Quadratic constraints.
      // The derivative of a constraint xQx + ax - b <= 0 is
      // Qx + Q'x + a.
      for (IloInt q = 0; q < quad.getSize(); ++q) {
         for (IloExpr::LinearIterator it = quad[q].getLinearIterator();
              it.ok(); ++it)
            kktsum[idx(it.getVar())] -= qpi[q] * it.getCoef();

         for (IloExpr::QuadIterator it = quad[q].getQuadIterator();
              it.ok(); ++it)
         {
            kktsum[idx(it.getVar1())] -= qpi[q] * xval[idx(it.getVar2())] * it.getCoef();
            kktsum[idx(it.getVar2())] -= qpi[q] * xval[idx(it.getVar1())] * it.getCoef();
         }
      }

      // Bounds.
      // The derivative for lower bounds is -1 and that for upper bounds
      // is 1.
      // CPLEX already returns dj with the appropriate sign so there is
      // no need to distinguish between different bound types here.
      for (IloInt j = 0; j < x.getSize(); ++j)
         kktsum[j] -= cpi[j];

      for (IloInt j = 0; j < kktsum.getSize(); ++j) {
         if ( fabs (kktsum[j]) > ZEROTOL ) {
            cerr << "Stationarity test failed at index " << j
                 << ": " << kktsum[j] << endl;
            result = -1;
         }
      }

      if ( result == 0) {
         // KKT conditions satisfied. Dump out the optimal solutions and
         // the dual values.
         streamsize oprec = cout.precision(3);
         ios_base::fmtflags oflags = cout.setf(ios::fixed | ios::showpos);
         cout << "Optimal solution satisfies KKT conditions." << endl;
         cout << "   x[] = " << xval << endl;
         cout << " cpi[] = " << cpi << endl;
         cout << " rpi[] = " << rpi << endl;
         cout << " qpi[] = " << qpi << endl;
         cout.precision(oprec);
         cout.flags(oflags);
      }
   }
   catch (IloException& e) {
      cerr << "Concert exception caught: " << e << endl;
      result = -1;
   }
   catch (...) {
      cerr << "Unknown exception caught" << endl;
      result = -1;
   }

   env.end();

   return result;
}  // END main