Example #1
0
void* problem_convert_to_osi(Problem *p)
{
    int i;
    double rowLb, rowUb;
    OsiSolverInterface *solver = new OsiClpSolverInterface();
    CoinBuild cb;

    solver->setIntParam(OsiNameDiscipline, 2);
    solver->messageHandler()->setLogLevel(0);
    solver->setHintParam(OsiDoReducePrint,true,OsiHintTry);

    for(i = 0; i < p->numCols; i++)
    {
        solver->addCol(0, NULL, NULL, p->colLb[i], p->colUb[i], p->objCoef[i]);
        solver->setColName(i, p->colName[i]);
        
        if(p->colType[i] == CONTINUOUS)
            solver->setContinuous(i);
        else 
            solver->setInteger(i);
    }

    for(i = 0; i < p->numRows; i++)
    {
        switch(p->rowSense[i])
        {
            case 'E':
                rowLb = p->rhs[i];
                rowUb = p->rhs[i];
            break;

            case 'L':
                rowLb = -p->infty;
                rowUb = p->rhs[i];
            break;

            case 'G':
                rowLb = p->rhs[i];
                rowUb = p->infty;
            break;

            default:
                fprintf(stderr, "Error: invalid type of constraint!\n");
                exit(EXIT_FAILURE);
        }

        cb.addRow(p->rowNElements[i], p->idxsByRow[i], p->coefsByRow[i], rowLb, rowUb);
    }

    solver->addRows(cb);
    
    for(i = 0; i < p->numRows; i++)
        solver->setRowName(i, p->rowName[i]);

    return solver;
}
Example #2
0
//-----------------------------------------------------------------------------
// Generate Lift-and-Project cuts
//------------------------------------------------------------------- 
void CglLiftAndProject::generateCuts(const OsiSolverInterface& si, OsiCuts& cs,
				     const CglTreeInfo /*info*/)
{
  // Assumes the mixed 0-1 problem 
  //
  //   min {cx: <Atilde,x> >= btilde} 
  //
  // is in canonical form with all bounds,
  // including x_t>=0, -x_t>=-1 for x_t binary,
  // explicitly stated in the constraint matrix. 
  // See ~/COIN/Examples/Cgl2/cgl2.cpp 
  // for a general purpose "convert" function. 

  // Reference [BCC]: Balas, Ceria, and Corneujols,
  // "A lift-and-project cutting plane algorithm
  // for mixed 0-1 program", Math Prog 58, (1993) 
  // 295-324.

  // This implementation uses Normalization 1.

  // Given canonical problem and
  // the lp-relaxation solution, x,
  // the LAP cut generator attempts to construct
  // a cut for every x_j such that 0<x_j<1
  // [BCC:307]
 

  // x_j is the strictly fractional binary variable
  // the cut is generated from
  int j = 0; 

  // Get basic problem information
  // let Atilde be an m by n matrix
  const int m = si.getNumRows(); 
  const int n = si.getNumCols(); 
  const double * x = si.getColSolution();

  // Remember - Atildes may have gaps..
  const CoinPackedMatrix * Atilde = si.getMatrixByRow();
  const double * AtildeElements =  Atilde->getElements();
  const int * AtildeIndices =  Atilde->getIndices();
  const CoinBigIndex * AtildeStarts = Atilde->getVectorStarts();
  const int * AtildeLengths = Atilde->getVectorLengths();  
  const int AtildeFullSize = AtildeStarts[m];
  const double * btilde = si.getRowLower();

  // Set up memory for system (10) [BCC:307]
  // (the problem over the norm intersected 
  //  with the polar cone)
  // 
  // min <<x^T,Atilde^T>,u> + x_ju_0
  // s.t.
  //     <B,w> = (0,...,0,beta_,beta)^T
  //        w  is nonneg for all but the
  //           last two entries, which are free.
  // where 
  // w = (u,v,v_0,u_0)in BCC notation 
  //      u and v are m-vectors; u,v >=0
  //      v_0 and u_0 are free-scalars, and
  //  
  // B = Atilde^T  -Atilde^T  -e_j e_j
  //     btilde^T   e_0^T      0   0
  //     e_0^T      btilde^T   1   0

  // ^T indicates Transpose
  // e_0 is a (AtildeNCols x 1) vector of all zeros 
  // e_j is e_0 with a 1 in the jth position

  // Storing B in column order. B is a (n+2 x 2m+2) matrix 
  // But need to allow for possible gaps in Atilde.
  // At each iteration, only need to change 2 cols and objfunc
  // Sane design of OsiSolverInterface does not permit mucking
  // with matrix.
  // Because we must delete and add cols to alter matrix,
  // and we can only add columns on the end of the matrix
  // put the v_0 and u_0 columns on the end.
  // rather than as described in [BCC]
 
  // Initially allocating B with space for v_0 and u_O cols
  // but not populating, for efficiency.

  // B without u_0 and v_0 is a (n+2 x 2m) size matrix.

  int twoM = 2*m;
  int BNumRows = n+2;
  int BNumCols = twoM+2;
  int BFullSize = 2*AtildeFullSize+twoM+3;
  double * BElements = new double[BFullSize];
  int * BIndices = new int[BFullSize];
  CoinBigIndex * BStarts = new CoinBigIndex [BNumCols+1];
  int * BLengths = new int[BNumCols];


  int i, ij, k=0;
  int nPlus1=n+1;
  int offset = AtildeStarts[m]+m;
  for (i=0; i<m; i++){
    for (ij=AtildeStarts[i];ij<AtildeStarts[i]+AtildeLengths[i];ij++){
      BElements[k]=AtildeElements[ij];
      BElements[k+offset]=-AtildeElements[ij];
      BIndices[k]= AtildeIndices[ij];
      BIndices[k+offset]= AtildeIndices[ij];

      k++;
    }
    BElements[k]=btilde[i];
    BElements[k+offset]=btilde[i];
    BIndices[k]=n;
    BIndices[k+offset]=nPlus1;
    BStarts[i]= AtildeStarts[i]+i;
    BStarts[i+m]=offset+BStarts[i];// = AtildeStarts[m]+m+AtildeStarts[i]+i
    BLengths[i]= AtildeLengths[i]+1;
    BLengths[i+m]= AtildeLengths[i]+1;
    k++;
  }

  BStarts[twoM]=BStarts[twoM-1]+BLengths[twoM-1];

  // Cols that will be deleted each iteration
  int BNumColsLessOne=BNumCols-1;
  int BNumColsLessTwo=BNumCols-2;
  const int delCols[2] = {BNumColsLessOne, BNumColsLessTwo};

  // Set lower bound on u and v
  // u_0, v_0 will be reset as free
  const double solverINFINITY = si.getInfinity();
  double * BColLowers = new double[BNumCols];
  double * BColUppers = new double[BNumCols];
  CoinFillN(BColLowers,BNumCols,0.0);  
  CoinFillN(BColUppers,BNumCols,solverINFINITY); 

  // Set row lowers and uppers.
  // The rhs is zero, for but the last two rows.
  // For these the rhs is beta_
  double * BRowLowers = new double[BNumRows];
  double * BRowUppers = new double[BNumRows];
  CoinFillN(BRowLowers,BNumRows,0.0);  
  CoinFillN(BRowUppers,BNumRows,0.0);
  BRowLowers[BNumRows-2]=beta_;
  BRowUppers[BNumRows-2]=beta_;
  BRowLowers[BNumRows-1]=beta_;
  BRowUppers[BNumRows-1]=beta_;


  // Calculate base objective <<x^T,Atilde^T>,u>
  // Note: at each iteration coefficient u_0
  //       changes to <x^T,e_j>
  //       w=(u,v,beta,v_0,u_0) size 2m+3
  //       So, BOjective[2m+2]=x[j]
  double * BObjective= new double[BNumCols];
  double * Atildex = new double[m];
  CoinFillN(BObjective,BNumCols,0.0);
  Atilde->times(x,Atildex); // Atildex is size m, x is size n
  CoinDisjointCopyN(Atildex,m,BObjective); 

  // Number of cols and size of Elements vector
  // in B without the v_0 and u_0 cols
  int BFullSizeLessThree = BFullSize-3;

  // Load B matrix into a column orders CoinPackedMatrix
  CoinPackedMatrix * BMatrix = new CoinPackedMatrix(true, BNumRows,
						  BNumColsLessTwo, 
						  BFullSizeLessThree,
						  BElements,BIndices, 
						  BStarts,BLengths);
  // Assign problem into a solver interface 
  // Note: coneSi will cleanup the memory itself
  OsiSolverInterface * coneSi = si.clone(false);
  coneSi->assignProblem (BMatrix, BColLowers, BColUppers, 
		      BObjective,
		      BRowLowers, BRowUppers);

  // Problem sense should default to "min" by default, 
  // but just to be virtuous...
  coneSi->setObjSense(1.0);

  // The plot outline from here on down:
  // coneSi has been assigned B without the u_0 and v_0 columns
  // Calculate base objective <<x^T,Atilde^T>,u>
  // bool haveWarmStart = false;
  // For (j=0; j<n, j++)
  //   if (!isBinary(x_j) || x_j<=0 || x_j>=1) continue;
  //   // IMPROVEME: if(haveWarmStart) check if j attractive
  //   add {-e_j,0,-1} matrix column for v_0
  //   add {e_j,0,0} matrix column for u_0
  //   objective coefficient for u_0 is  x_j 
  //   if (haveWarmStart) 
  //      set warmstart info
  //   solve min{objw:Bw=0; w>=0,except v_0, u_0 free}
  //   if (bounded)
  //      get warmstart info
  //      haveWarmStart=true;
  //      ustar = optimal u solution
  //      ustar_0 = optimal u_0 solution
  //      alpha^T= <ustar^T,Atilde> -ustar_0e_j^T
  //      (double check <alpha^T,x> >= beta_ should be violated)
  //      add <alpha^T,x> >= beta_ to cutset 
  //   endif
  //   delete column for u_0 // this deletes all column info.
  //   delete column for v_0
  // endFor
  // clean up memory
  // return 0;

  int * nVectorIndices = new int[n];
  CoinIotaN(nVectorIndices, n, 0);

  bool haveWarmStart = false;
  bool equalObj1, equalObj2;
  CoinRelFltEq eq;

  double v_0Elements[2] = {-1,1};
  double u_0Elements[1] = {1};

  CoinWarmStart * warmStart = 0;

  double * ustar = new double[m];
  CoinFillN(ustar, m, 0.0);

  double* alpha = new double[n];
  CoinFillN(alpha, n, 0.0);

  for (j=0;j<n;j++){
    if (!si.isBinary(j)) continue; // Better to ask coneSi? No! 
                                   // coneSi has no binInfo.
    equalObj1=eq(x[j],0);
    equalObj2=eq(x[j],1);
    if (equalObj1 || equalObj2) continue;
    // IMPROVEME: if (haveWarmStart) check if j attractive;

    // AskLL:wanted to declare u_0 and v_0 packedVec outside loop
    // and setIndices, but didn't see a method to do that(?)
    // (Could "insert". Seems inefficient)
    int v_0Indices[2]={j,nPlus1};
    int u_0Indices[1]={j};
    // 
    CoinPackedVector  v_0(2,v_0Indices,v_0Elements,false);
    CoinPackedVector  u_0(1,u_0Indices,u_0Elements,false);

#if CGL_DEBUG
    const CoinPackedMatrix *see1 = coneSi->getMatrixByRow();
#endif

    coneSi->addCol(v_0,-solverINFINITY,solverINFINITY,0);
    coneSi->addCol(u_0,-solverINFINITY,solverINFINITY,x[j]);
    if(haveWarmStart) {
      coneSi->setWarmStart(warmStart);
      coneSi->resolve();
    }
    else {

#if CGL_DEBUG
      const CoinPackedMatrix *see2 = coneSi->getMatrixByRow();
#endif

      coneSi->initialSolve();
    }
    if(coneSi->isProvenOptimal()){
      warmStart = coneSi->getWarmStart();
      haveWarmStart=true;
      const double * wstar = coneSi->getColSolution();
      CoinDisjointCopyN(wstar, m, ustar);
      Atilde->transposeTimes(ustar,alpha);
      alpha[j]+=wstar[BNumCols-1]; 
      
#if debug
      int p;
      double sum;
      for(p=0;p<n;p++)sum+=alpha[p]*x[p];
      if (sum<=beta_){
	throw CoinError("Cut not violated",
			"cutGeneration",
			"CglLiftAndProject");
      }
#endif

      // add <alpha^T,x> >= beta_ to cutset
      OsiRowCut rc;
      rc.setRow(n,nVectorIndices,alpha);
      rc.setLb(beta_);
      rc.setUb(solverINFINITY);
      cs.insert(rc);
    }
    // delete col for u_o and v_0
    coneSi->deleteCols(2,delCols);

    // clean up memory
  }
  // clean up
  delete [] alpha;
  delete [] ustar;
  delete [] nVectorIndices;
  // BMatrix, BColLowers,BColUppers, BObjective, BRowLowers, BRowUppers
  // are all freed by OsiSolverInterface destructor (?)
  delete [] BLengths;
  delete [] BStarts;
  delete [] BIndices;
  delete [] BElements;
}
Example #3
0
int main (int argc, const char *argv[])
{

  /* Define your favorite OsiSolver.

     CbcModel clones the solver so use solver1 up to the time you pass it
     to CbcModel then use a pointer to cloned solver (model.solver())
  */
  
  OsiClpSolverInterface solver1;
  /* From now on we can build model in a solver independent way.
     You can add rows one at a time but for large problems this is slow so
     this example uses CoinBuild or CoinModel
  */
  OsiSolverInterface * solver = &solver1;
  // Data (is exmip1.mps in Mps/Sample
  // Objective 
  double objValue[]={1.0,2.0,0.0,0.0,0.0,0.0,0.0,-1.0};
  // Lower bounds for columns
  double columnLower[]={2.5,0.0,0.0,0.0,0.5,0.0,0.0,0.0};
  // Upper bounds for columns
  double columnUpper[]={COIN_DBL_MAX,4.1,1.0,1.0,4.0,
                  COIN_DBL_MAX,COIN_DBL_MAX,4.3};
  // Lower bounds for row activities
  double rowLower[]={2.5,-COIN_DBL_MAX,-COIN_DBL_MAX,1.8,3.0};
  // Upper bounds for row activities
  double rowUpper[]={COIN_DBL_MAX,2.1,4.0,5.0,15.0};
  // Matrix stored packed
  int column[] = {0,1,3,4,7,
                  1,2,
                  2,5,
                  3,6,
                  4,7};
  double element[] = {3.0,1.0,-2.0,-1.0,-1.0,
                      2.0,1.1,
                      1.0,1.0,
                      2.8,-1.2,
                      1.0,1.9};
  int starts[]={0,5,7,9,11,13};
  // Integer variables (note upper bound already 1.0)
  int whichInt[]={2,3};
  int numberRows=(int) (sizeof(rowLower)/sizeof(double));
  int numberColumns=(int) (sizeof(columnLower)/sizeof(double));
#define BUILD 2
#if BUILD==1
  // Using CoinBuild 
  // First do columns (objective and bounds)
  int i;
  // We are not adding elements 
  for (i=0;i<numberColumns;i++) {
    solver->addCol(0,NULL,NULL,columnLower[i],columnUpper[i],
                    objValue[i]);
  }
  // mark as integer
  for (i=0;i<(int) (sizeof(whichInt)/sizeof(int));i++)
    solver->setInteger(whichInt[i]);
  // Now build rows
  CoinBuild build;
  for (i=0;i<numberRows;i++) {
    int startRow = starts[i];
    int numberInRow = starts[i+1]-starts[i];
    build.addRow(numberInRow,column+startRow,element+startRow,
                 rowLower[i],rowUpper[i]);
  }  
  // add rows into solver
  solver->addRows(build);
#else
  /* using CoinModel - more flexible but still beta.
     Can do exactly same way but can mix and match much more.
     Also all operations are on building object
  */
  CoinModel build;
  // First do columns (objective and bounds)
  int i;
  for (i=0;i<numberColumns;i++) {
    build.setColumnBounds(i,columnLower[i],columnUpper[i]);
    build.setObjective(i,objValue[i]);
  }
  // mark as integer
  for (i=0;i<(int) (sizeof(whichInt)/sizeof(int));i++)
    build.setInteger(whichInt[i]);
  // Now build rows
  for (i=0;i<numberRows;i++) {
    int startRow = starts[i];
    int numberInRow = starts[i+1]-starts[i];
    build.addRow(numberInRow,column+startRow,element+startRow,
                 rowLower[i],rowUpper[i]);
  }  
  // add rows into solver
  solver->loadFromCoinModel(build);
#endif

  // Pass to solver
  CbcModel model(*solver);
  model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry);


  // Set up some cut generators and defaults
  // Probing first as gets tight bounds on continuous

  CglProbing generator1;
  generator1.setUsingObjective(true);
  generator1.setMaxPass(3);
  generator1.setMaxProbe(100);
  generator1.setMaxLook(50);
  generator1.setRowCuts(3);
  //  generator1.snapshot(*model.solver());
  //generator1.createCliques(*model.solver(),2,1000,true);
  //generator1.setMode(0);

  CglGomory generator2;
  // try larger limit
  generator2.setLimit(300);

  CglKnapsackCover generator3;

  CglOddHole generator4;
  generator4.setMinimumViolation(0.005);
  generator4.setMinimumViolationPer(0.00002);
  // try larger limit
  generator4.setMaximumEntries(200);

  CglClique generator5;
  generator5.setStarCliqueReport(false);
  generator5.setRowCliqueReport(false);

  CglMixedIntegerRounding mixedGen;
  CglFlowCover flowGen;
  
  // Add in generators
  model.addCutGenerator(&generator1,-1,"Probing");
  model.addCutGenerator(&generator2,-1,"Gomory");
  model.addCutGenerator(&generator3,-1,"Knapsack");
  model.addCutGenerator(&generator4,-1,"OddHole");
  model.addCutGenerator(&generator5,-1,"Clique");
  model.addCutGenerator(&flowGen,-1,"FlowCover");
  model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding");

  OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver());
  // go faster stripes
  if (osiclp->getNumRows()<300&&osiclp->getNumCols()<500) {
    osiclp->setupForRepeatedUse(2,0);
    printf("trying slightly less reliable but faster version (? Gomory cuts okay?)\n");
    printf("may not be safe if doing cuts in tree which need accuracy (level 2 anyway)\n");
  }

  // Allow rounding heuristic

  CbcRounding heuristic1(model);
  model.addHeuristic(&heuristic1);

  // And local search when new solution found

  CbcHeuristicLocal heuristic2(model);
  model.addHeuristic(&heuristic2);

  // Redundant definition of default branching (as Default == User)
  CbcBranchUserDecision branch;
  model.setBranchingMethod(&branch);

  // Definition of node choice
  CbcCompareUser compare;
  model.setNodeComparison(compare);

  // Do initial solve to continuous
  model.initialSolve();

  // Could tune more
  model.setMinimumDrop(CoinMin(1.0,
			     fabs(model.getMinimizationObjValue())*1.0e-3+1.0e-4));

  if (model.getNumCols()<500)
    model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible
  else if (model.getNumCols()<5000)
    model.setMaximumCutPassesAtRoot(100); // use minimum drop
  else
    model.setMaximumCutPassesAtRoot(20);
  //model.setMaximumCutPasses(5);

  // Switch off strong branching if wanted
  // model.setNumberStrong(0);
  // Do more strong branching if small
  if (model.getNumCols()<5000)
    model.setNumberStrong(10);

  model.solver()->setIntParam(OsiMaxNumIterationHotStart,100);

  // If time is given then stop after that number of minutes
  if (argc>2) {
    int minutes = atoi(argv[2]);
    std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl;
    assert (minutes>=0);
    model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes);
  }
  // Switch off most output
  if (model.getNumCols()<3000) {
    model.messageHandler()->setLogLevel(1);
    //model.solver()->messageHandler()->setLogLevel(0);
  } else {
    model.messageHandler()->setLogLevel(2);
    model.solver()->messageHandler()->setLogLevel(1);
  }
  double time1 = CoinCpuTime();

  // Do complete search
  
  model.branchAndBound();

  std::cout<<" Branch and cut took "<<CoinCpuTime()-time1<<" seconds, "
	   <<model.getNodeCount()<<" nodes with objective "
	   <<model.getObjValue()
	   <<(!model.status() ? " Finished" : " Not finished")
	   <<std::endl;

  // Print more statistics
  std::cout<<"Cuts at root node changed objective from "<<model.getContinuousObjective()
	   <<" to "<<model.rootObjectiveAfterCuts()<<std::endl;

  int numberGenerators = model.numberCutGenerators();
  for (int iGenerator=0;iGenerator<numberGenerators;iGenerator++) {
    CbcCutGenerator * generator = model.cutGenerator(iGenerator);
    std::cout<<generator->cutGeneratorName()<<" was tried "
	     <<generator->numberTimesEntered()<<" times and created "
	     <<generator->numberCutsInTotal()<<" cuts of which "
	     <<generator->numberCutsActive()<<" were active after adding rounds of cuts"
	     <<std::endl;
  }
  // Print solution if any - we can't get names from Osi!

  if (model.getMinimizationObjValue()<1.0e50) {
    int numberColumns = model.solver()->getNumCols();
    
    const double * solution = model.solver()->getColSolution();
    
    int iColumn;
    std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14);
    
    std::cout<<"--------------------------------------"<<std::endl;
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      double value=solution[iColumn];
      if (fabs(value)>1.0e-7&&model.solver()->isInteger(iColumn)) 
	std::cout<<std::setw(6)<<iColumn<<" "<<value<<std::endl;
    }
    std::cout<<"--------------------------------------"<<std::endl;
  
    std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific);
  }
  return 0;
}    
Example #4
0
OsiSolverInterface* cpropagation_preprocess(CPropagation *cp, int nindexes[])
{
    if(cp->varsToFix == 0)
    {
        /* printf("There are no variables to remove from the problem!\n"); */
        return NULL; /* returns a pointer to original solver */
    }

    const double *colLb = problem_vars_lower_bound(cp->problem), *colUb = problem_vars_upper_bound(cp->problem);
    const double *objCoef = problem_vars_obj_coefs(cp->problem);
    const char *ctype = problem_vars_type(cp->problem);

    double sumFixedObj = 0.0; /* stores the sum of objective coefficients of all variables fixed to 1 */

    OsiSolverInterface *preProcSolver = new OsiClpSolverInterface();
    preProcSolver->setIntParam(OsiNameDiscipline, 2);
    preProcSolver->messageHandler()->setLogLevel(0);
    preProcSolver->setHintParam(OsiDoReducePrint,true,OsiHintTry);
    //preProcSolver->setObjName(cp->solver->getObjName());

    for(int i = 0, j = 0; i < problem_num_cols(cp->problem); i++)
    {
        nindexes[i] = -1;
        if(cp->isToFix[i] == UNFIXED)
        {
            preProcSolver->addCol(0, NULL, NULL, colLb[i], colUb[i], objCoef[i]);
            preProcSolver->setColName(j, problem_var_name(cp->problem, i));
            if(problem_var_type(cp->problem, i) == CONTINUOUS)
                preProcSolver->setContinuous(j);
            else 
                preProcSolver->setInteger(j);
            nindexes[i] = j++;
        }
        else if(cp->isToFix[i] == ACTIVATE)
            sumFixedObj += objCoef[i];
    }

    if(fabs(sumFixedObj) > EPS)
    {
        /* adding a variable with cost equals to the sum of all coefficients of variables fixed to 1 */
        preProcSolver->addCol(0, NULL, NULL, 1.0, 1.0, sumFixedObj);
        preProcSolver->setColName(preProcSolver->getNumCols()-1, "sumFixedObj");
        preProcSolver->setInteger(preProcSolver->getNumCols()-1);
    }

    for(int idxRow = 0; idxRow < problem_num_rows(cp->problem); idxRow++)
    {
        const int nElements = problem_row_size(cp->problem, idxRow);
        const int *idxs = problem_row_idxs(cp->problem, idxRow);
        const double *coefs = problem_row_coefs(cp->problem, idxRow);
        vector< int > vidx; vidx.reserve(problem_num_cols(cp->problem));
        vector< double > vcoef; vcoef.reserve(problem_num_cols(cp->problem));
        double activeCoefs = 0.0;

        for(int i = 0; i < nElements; i++)
        {
            if(cp->isToFix[idxs[i]] == UNFIXED)
            {
                assert(nindexes[idxs[i]] >= 0 && nindexes[idxs[i]] < problem_num_cols(cp->problem));
                vidx.push_back(nindexes[idxs[i]]);
                vcoef.push_back(coefs[i]);
            }
            else if(cp->isToFix[idxs[i]] == ACTIVATE)
            	activeCoefs += coefs[i];
        }

        if(!vidx.empty())
        {
        	double rlb, rub;
        	const char sense = problem_row_sense(cp->problem, idxRow);
        	
        	if(sense == 'E')
            {
                rlb = problem_row_rhs(cp->problem, idxRow) - activeCoefs;
                rub = problem_row_rhs(cp->problem, idxRow) - activeCoefs;
            }
        	else if(sense == 'L')
            {
                rlb = preProcSolver->getInfinity();
                rub = problem_row_rhs(cp->problem, idxRow) - activeCoefs;
            }
        	else if(sense == 'G')
            {
                rlb = problem_row_rhs(cp->problem, idxRow) - activeCoefs;
                rub = preProcSolver->getInfinity();
            }
        	else
        	{
        		fprintf(stderr, "Error: invalid type of constraint!\n");
        		exit(EXIT_FAILURE);
        	}

        	preProcSolver->addRow((int)vcoef.size(), &vidx[0], &vcoef[0], rlb, rub);
            preProcSolver->setRowName(idxRow, problem_row_name(cp->problem, idxRow));
        }
	}

    return preProcSolver;
}