Beispiel #1
0
// --------------------------------------------------------------------- //
int GAP_DecompApp::createModelPartAP(DecompConstraintSet* model)
{
   int             i, j, colIndex;
   int             status     = GAPStatusOk;
   int             nTasks     = m_instance.getNTasks();    //n
   int             nMachines  = m_instance.getNMachines(); //m
   int             nCols      = nTasks * nMachines;
   int             nRows      = nTasks;
   UtilPrintFuncBegin(m_osLog, m_classTag,
                      "createModelPartAP()", m_appParam.LogLevel, 2);
   //---
   //--- Build the core model constraints (AP = assignment problem).
   //---
   //--- m is number of machines (index i)
   //--- n is number of tasks    (index j)
   //---
   //--- sum{i in 1..m} x[i,j] = 1, j in 1..n
   //---
   //--- Example structure: m=3, n=4
   //---  x   x   x     = 1 [j=1]
   //---   x   x   x    = 1 [j=2]
   //---    x   x   x   = 1 [j=3]
   //---     x   x   x  = 1 [j=4]
   //---
   //---
   //--- Allocate an empty row-ordered CoinPackedMatrix. Since we plan
   //---   to add rows, set the column dimension and let the row dimension
   //---   be set dynamically.
   //---
   model->M = new CoinPackedMatrix(false, 0.0, 0.0);
   CoinAssertHint(model->M, "Error: Out of Memory");
   model->M->setDimensions(0, nCols);
   //---
   //--- we know the sizes needed, so reserve space for them (for efficiency)
   //---
   model->reserve(nRows, nCols);

   //---
   //--- create one row per task
   //---   rowNames are not needed, they are used for debugging
   //---
   for (j = 0; j < nTasks; j++) {
      CoinPackedVector row;
      string           rowName = "a(j_" + UtilIntToStr(j) + ")";

      for (i = 0; i < nMachines; i++) {
         colIndex = getIndexIJ(i, j);
         row.insert(colIndex, 1.0);
      }

      model->appendRow(row, 1.0, 1.0, rowName);
   }

   //---
   //--- set the col upper and lower bounds (all in [0,1])
   //---
   UtilFillN(model->colLB, nCols,  0.0);
   UtilFillN(model->colUB, nCols,  1.0);
   //---
   //--- set the indices of the integer variables of model
   //---   (all vars are binary)
   //---
   UtilIotaN(model->integerVars, nCols, 0);
   //---
   //--- set column names for debugging
   //---
   colIndex = 0;

   for (i = 0; i < nMachines; i++) {
      for (j = 0; j < nTasks; j++) {
         string colName = "x("
                          + UtilIntToStr(colIndex) + "_"
                          + UtilIntToStr(i) + "," + UtilIntToStr(j) + ")";
         model->colNames.push_back(colName);
         colIndex++;
      }
   }

   UtilPrintFuncEnd(m_osLog, m_classTag,
                    "createModelPartAP()", m_appParam.LogLevel, 2);
   return status;
}
Beispiel #2
0
// --------------------------------------------------------------------- //
void MMKP_MCKnap::solveTrivialMaxSum(const double * redCost,
				     const double * origCost,
				     vector<int>  & solInd,
				     double       & varRedCost,
				     double       & varOrigCost){
   
   double minRedCost;
   int    i, j, minRedCostInd, ijIndex, minWeight, totalWeight;

   //---
   //--- Pisinger's code breaks on this trivial case.
   //--- 
   //---  In the case where maxwsum <= c, then we can trivially
   //---  pick the max profit / min cost element from each group
   //---   
   //--- We have to be careful here because there might be ties to deal
   //---   with. The max profit might be p* for two different choices
   //---   but only one of those gave a weight that was under capacity.
   //--- So, we have to find the alternative choice with lowest weight.
   //---
   //--- NOTE: this algorithm was added because mcknap algorithm seems
   //---  to crash on this trivial case. It would be better if we could
   //---  get this case fixed. TODO: send test case to Pisinger.
   //---
   varRedCost  = 0.0;
   varOrigCost = 0.0;
   solInd.reserve(m_nGroupRows);
   
   ijIndex     = 0;
   totalWeight = 0;
   for(i = 0; i < m_nGroupRows; i++){
      ijIndex       = getIndexIJ(i, 0);
      minRedCostInd = ijIndex;
      minRedCost    = redCost[ijIndex];
      minWeight     = m_weight[ijIndex];//need if we have ties
#ifdef MMKP_MCKNAP_DEBUG
      printf("i:%d j:%d redCost:%g minRedCost:%g wt:%d minWeight:%d\n",
           i, 0, redCost[ijIndex], minRedCost, m_weight[ijIndex],
           minWeight);
#endif

      ijIndex++;
      for(j = 1; j < m_nGroupCols; j++){
	if((redCost[ijIndex] - minRedCost) < -MCKP_EPSILON){
	  minRedCost    = redCost[ijIndex];
	  minWeight     = m_weight[ijIndex];
	  minRedCostInd = ijIndex;
	}else if( UtilIsZero(redCost[ijIndex] - minRedCost, MCKP_EPSILON) ){
	  //---
	  //--- break ties with element with least weight
	  //---
	  if(minWeight > m_weight[ijIndex]){
	    minWeight     = m_weight[ijIndex];
	    minRedCostInd = ijIndex;
	  }
	}
#ifdef MMKP_MCKNAP_DEBUG
	printf("i:%d j:%d redCost:%g minRedCost:%g wt:%d minWeight:%d\n",
	     i, j, redCost[ijIndex], minRedCost, m_weight[ijIndex],
	     minWeight);
#endif

	ijIndex++;
      }      
      assert((minRedCostInd >= 0) && (minRedCostInd < m_nCols));      
      totalWeight += m_weight[minRedCostInd];
      solInd.push_back(minRedCostInd);
#ifdef MMKP_MCKNAP_DEBUG
      printf("i:%d totalWeight:%d cap:%d mincostInd:%d redCost:%g origCost:%g\n",
             i, totalWeight, m_capacity, minRedCostInd, minRedCost, 
           origCost[minRedCostInd]);fflush(stdout);
#endif
      assert(totalWeight <= m_capacity);
      varRedCost  += minRedCost;
      varOrigCost += origCost[minRedCostInd];
   }
}
Beispiel #3
0
//===========================================================================//
int GAP_DecompApp::createModelPartKP(DecompConstraintSet* model,
                                     vector<int>&          whichKnaps)
{
   int          i, j, b, colIndex;
   int          status     = GAPStatusOk;
   int          nTasks     = m_instance.getNTasks();    //n
   int          nMachines  = m_instance.getNMachines(); //m
   int          nKnaps     = static_cast<int>(whichKnaps.size());
   const int*   weight     = m_instance.getWeight();
   const int*   capacity   = m_instance.getCapacity();
   int          nCols      = nTasks * nMachines;
   int          nRows      = nKnaps;
   UtilPrintFuncBegin(m_osLog, m_classTag,
                      "createModelPartKP()", m_appParam.LogLevel, 2);
   //---
   //--- Build the relax model constraints (KP = assignment problem).
   //---
   //--- m is number of machines (index i)
   //--- n is number of tasks    (index j)
   //---
   //--- sum{j in 1..n} w[i,j] x[i,j] <= b[i], i in 1..m
   //--- x[i,j] in {0,1}, i in 1..m, j in 1..n
   //---
   //--- Example structure: m=3, n=4
   //---  xxxx         <= b[i=1]
   //---      xxxx     <= b[i=2]
   //---          xxxx <= b[i=3]
   //---
   //---
   //--- Allocate an empty row-ordered CoinPackedMatrix. Since we plan
   //---   to add rows, set the column dimension and let the row dimension
   //---   be set dynamically.
   //---
   model->M = new CoinPackedMatrix(false, 0.0, 0.0);
   CoinAssertHint(model->M, "Error: Out of Memory");
   model->M->setDimensions(0, nCols);
   //---
   //--- we know the sizes needed, so reserve space for them (for efficiency)
   //---
   model->reserve(nRows, nCols);
   //---
   //--- create one row per knapsack
   //---   rowNames are not needed, they are used for debugging
   //---
   vector<int>::iterator it;

   for (it = whichKnaps.begin(); it != whichKnaps.end(); ++it) {
      i = *it;
      CoinPackedVector row;
      string           rowName = "k(i_" + UtilIntToStr(i) + ")";

      for (j = 0; j < nTasks; j++) {
         colIndex = getIndexIJ(i, j);
         row.insert(colIndex, weight[colIndex]);
      }

      model->appendRow(row, -m_infinity, capacity[i], rowName);
   }

   //---
   //--- set the col upper and lower bounds (all in [0,1])
   //---
   UtilFillN(model->colLB, nCols,  0.0);
   UtilFillN(model->colUB, nCols,  1.0);
   //---
   //--- set the indices of the integer variables of model
   //---
   UtilIotaN(model->integerVars, nCols, 0);

   //---
   //--- tell the solver which columns are active (in this block)
   //---
   for (it = whichKnaps.begin(); it != whichKnaps.end(); ++it) {
      b = *it;

      for (i = 0; i < nMachines; i++) {
         for (j = 0; j < nTasks; j++) {
            colIndex = getIndexIJ(i, j);

            if (i == b) {
               model->activeColumns.push_back(colIndex);
            }
         }
      }
   }

   //---
   //--- set column names for debugging
   //---
   colIndex = 0;

   for (i = 0; i < nMachines; i++) {
      for (j = 0; j < nTasks; j++) {
         string colName = "x("
                          + UtilIntToStr(colIndex) + "_"
                          + UtilIntToStr(i) + "," + UtilIntToStr(j) + ")";
         model->colNames.push_back(colName);
         colIndex++;
      }
   }

   UtilPrintFuncEnd(m_osLog, m_classTag,
                    "createModelPartKP()", m_appParam.LogLevel, 2);
   return status;
}
Beispiel #4
0
// --------------------------------------------------------------------- //
void MMKP_MCKnap::solveMCKnap(const double   * redCost,
			      const double   * origCost,
			      vector<int>    & solInd,
			      vector<double> & solEls,
			      double         & varRedCost,
			      double         & varOrigCost){
   
   int i, j, colIndex;

   //---
   //--- Pisinger's code (mcknap) solves a max problem. And, it assumes 
   //--- all positive costs/profits and weights.
   //---   
   memcpy(m_costDbl, redCost, m_nCols * sizeof(double));
#ifdef MMKP_MCKNAP_DEBUG
   for(i = 0; i < m_nCols; i++){
      pair<int,int> ij = getIndexInv(i);
      printf("\ncostDbl[%d: %d, %d]: %g",
	     i, ij.first, ij.second, m_costDbl[i]);
   }
#endif

   
   //---
   //--- flip reduced costs (max c == min -c)
   //---
   UtilNegateArr(m_nCols, m_costDbl);

   //---
   //--- add a constant so that all vertex weights are positive, inc alpha
   //---
   double offset = 0.0;
   double minrc  = *min_element(m_costDbl, m_costDbl + m_nCols);
#ifdef MMKP_MCKNAP_DEBUG
   printf("\nminrc   = %g", minrc);
#endif   
   if(minrc <= 0){
      offset = -minrc + 1;
      UtilAddOffsetArr(m_nCols, offset, m_costDbl);
   }

   //---
   //--- now scale the double array to an integer array
   //---
   //TODO: magic number - have to be careful of overflow... 
   m_cscale = UtilScaleDblToIntArr(m_nCols, m_costDbl, m_cost, MCKP_EPSILON);

#ifdef MMKP_MCKNAP_DEBUG
   double diff;
   printf("\noffset   = %g", offset);
   printf("\nm_cscale = %d", m_cscale);
   printf("\nm_wscale = %d", m_wscale);
   printf("\ncapacity = %d", m_capacity);
   for(i = 0; i < m_nCols; i++){
      pair<int,int> ij = getIndexInv(i);
      diff = fabs((m_costDbl[i]*m_cscale) - m_cost[i]);
      printf("\n[%d: %d, %d]: dbl-> %12.5f int-> %8d diff-> %12.5f",
	     i, ij.first, ij.second, m_costDbl[i], m_cost[i], diff);
      assert( diff < 0.99 );
   }
#endif

   //---
   //--- sanity check
   //---  if any cost value becomes negative that
   //---  denotes an overflow happened
   //--- TODO: not sure how to do this scaling safely and
   //---  accurately
   //---
   for(i = 0; i < m_nCols; i++){
      if(m_cost[i] < 0){
         throw UtilException("negative cost value",
                             "solveMCKnap", "MMKP_MCKnap");
      }
   }
      
   //---
   //--- setup the data structures for mcknap
   //---
   itemset * setPtr    = m_setset->fset;
   itemrec * recPtr    = NULL;
   itemrec * recSolPtr = NULL;
   
   //THINK: reset - assume memory is still there
   m_setset->size  = m_nGroupRows;
   setPtr = m_setset->fset;
   for(i = 0; i < m_setset->size; i++){
      setPtr->size = m_nGroupCols;
      recPtr       = setPtr->fset;    
      setPtr->lset = setPtr->fset + setPtr->size - 1;
      setPtr++;
   }
   m_setset->lset = m_setset->fset + m_setset->size - 1;
   

   colIndex            = 0;
   setPtr = m_setset->fset;
   for(i = 0; i < m_setset->size; i++){
      recPtr    = setPtr->fset;
      for(j = 0; j < setPtr->size; j++){
	 recPtr->i = i;
	 recPtr->j = j;
         recPtr->psum = m_cost[colIndex];
         recPtr->wsum = m_weight[colIndex];
#ifdef MMKP_MCKNAP_DEBUG
         printf("\ncolIndex: %d i: %d, j: %d, p: %d, w: %d",
		colIndex, i, j, recPtr->psum, recPtr->wsum);
#endif
         recPtr++;
         colIndex++;
      }
      setPtr++;
   }

   itemrec * solRec = new itemrec[m_setset->size];
   
   double minObj = 99999;
//   long minObj = 99999;
   int status  = minmcknapSolve(m_capacity, m_setset, solRec, &minObj);

   solInd.reserve(m_nGroupRows);
   solEls.reserve(m_nGroupRows);
   UtilFillN<double>(solEls, m_nGroupRows, 1.0);
   varRedCost  = 0.0;
   varOrigCost = 0.0;

   //---
   //--- TODO:
   //--- this is painful to get optimal assignments
   //---    wrote Dr. Pisinger for help (7/4/07)
   //--- NOTE: optsol is NOT reentrant
   //---
   //CoinAssert(optsol.size == 1); //TODO
#ifdef MMKP_MCKNAP_DEBUG
   printf("\nstatus=%d minObj=%g\n", status, minObj);
#endif

   switch(status){
   case MCKNAP_RC_INF:
      assert(status != MCKNAP_RC_INF);
      break;
   case MCKNAP_RC_OK:
      {
	 //---
	 //--- need to unravel:
	 //---    s * ((-x) + offset)
	 //---
	  
	 double solObj = minObj / static_cast<double>(m_cscale);
	 solObj -= (offset * m_setset->size);
	 solObj  = -solObj;
	  
#ifdef MMKP_MCKNAP_DEBUG
	 printf("\nminObj = %g, solObj = %g", minObj, solObj);
#endif
	  
	  
	 int c, i, j, g;
	 for(g = 0; g < m_setset->size; g++){
	    recSolPtr = &solRec[g];
	    i         = recSolPtr->i;//was missing - STOP
	    j         = recSolPtr->j;//was missing
	    c         = getIndexIJ(i, j);
	    solInd.push_back(c);
	    varRedCost  += redCost[c];
	    varOrigCost += origCost[c];
#ifdef MMKP_MCKNAP_DEBUG	     
	    printf("\nc: %d = (%d,%d) redCost: %g cost: %d wt: %d",
		   c, i, j, 
		   redCost[c], m_cost[c], m_weight[c]);
#endif
	    /*for(c = 0; c < m_nCols; c++){
	    //but could have more than one equal in p and w!
	    //this is NOT the right way to get back optimal
	    if((m_cost[c]   == recSolPtr->psum) &&
	    (m_weight[c] == recSolPtr->wsum)){
	    //TODO: why should the user have to calc origCost?
	    //framework should probably do that
	    solInd.push_back(c);
	    varRedCost  += redCost[c];
	    varOrigCost += origCost[c];
	    #ifdef MMKP_MCKNAP_DEBUG
	    pair<int,int> ij = getIndexInv(c);
	    printf("\nc: %d = (%d,%d) redCost: %g cost: %d wt: %d",
	    c,
	    ij.first, ij.second,
	    redCost[c], m_cost[c], m_weight[c]);
	    #endif
	    break;
	    }
	    }*/
	 }
	 //UtilPrintVector<int>(solInd);
	 break;
      }
   case MCKNAP_RC_TRIVIAL_MAXSUM:
     fflush(stdout);
      //maxwsum <= c, so just pick the max elements from each group
      solveTrivialMaxSum(redCost, origCost, solInd, 
			 varRedCost, varOrigCost);
#ifdef MMKP_MCKNAP_DEBUG	     
      printf("trivial sum varRedCost=%g varOrigCost=%g\n",
	     varRedCost, varOrigCost);
#endif
      break;
   default:
      assert(0);
   }
   UTIL_DELARR(solRec);
}