Dip  0.92.4
GAP_KnapPisinger.h
Go to the documentation of this file.
1 //===========================================================================//
2 // This file is part of the Decomp Solver Framework. //
3 // //
4 // Decomp is distributed under the Common Public License as part of the //
5 // COIN-OR repository (http://www.coin-or.org). //
6 // //
7 // Authors: Matthew Galati, SAS Institute Inc. (matthew.galati@sas.com) //
8 // Ted Ralphs, Lehigh University (ted@lehigh.edu) //
9 // Jiadong Wang, Lehigh University (jiw408@lehigh.edu) //
10 // //
11 // Copyright (C) 2002-2019, Lehigh University, Matthew Galati, and Ted Ralphs//
12 // All Rights Reserved. //
13 //===========================================================================//
14 
15 #ifndef GAP_KNAP_PISINGER_INCLUDED
16 #define GAP_KNAP_PISINGER_INCLUDED
17 
18 // --------------------------------------------------------------------- //
63 // --------------------------------------------------------------------- //
64 extern "C" {
65 #include "combo.h"
66 }
67 
68 // --------------------------------------------------------------------- //
69 #include "UtilMacros.h"
70 
71 // --------------------------------------------------------------------- //
73 
74 private:
75  int m_nItems; //< number of items (== nTasks)
76  item* m_items; //< array of items for Pisinger solver
77  int m_capacity; //< capacity of knapsack
78  int* m_weight; //< weight of items
79  int* m_profit; //< profit of items
80  double* m_workDbl; //< temp work space
81 
82 private:
83  inline const int getIndexIJ(const int i,
84  const int j) const {
85  return (i * m_nItems) + j;
86  }
87 
88  //1.0e-6 seems to cause overflow
89  int calcScaleFactor(const double* redCost,
90  const double epsTol = 1.0e-4) {
91  //---
92  //--- A very simple function to scale an array of doubles to integers.
93  //--- Note: epstol denotes the preferred accuracy,
94  //--- so, we will scale by 1.0/epstol, unless something smaller works.
95  //--- It returns the scale factor.
96  //---
97  //--- Since the knapsack solver solves the max problem, we will
98  //--- flip the sign of the redCost first (max p == min -p).
99  //---
100  //--- This also means that we can look just at redCost[i] <= 0.
101  //---
102  int i, scaleFactor = 1, n_aFrac = 0, factorToBig = 0;
103  double fractionalPart, rcFlipped;
104  double oneOverEps = 1.0 / epsTol;
105 
106  for (i = 0; i < m_nItems; i++) {
107  if (redCost[i] >= 0) {
108  continue;
109  }
110 
111  rcFlipped = -redCost[i];
112  fractionalPart = UtilFracPart(rcFlipped);
113 
114  if (!UtilIsZero(fractionalPart)) {
115  fractionalPart *= oneOverEps;
116  m_workDbl[n_aFrac++] = (int)fractionalPart * (double)epsTol;
117  }
118  }
119 
120  for (i = 0; i < n_aFrac; i++) {
121  CoinAssertDebug(m_workDbl[i] < (COIN_INT_MAX / scaleFactor));
122  m_workDbl[i] *= scaleFactor;
123 
124  while (!UtilIsZero(UtilFracPart(m_workDbl[i]))) {
125  scaleFactor *= 10;
126 
127  if (scaleFactor >= oneOverEps) {
128  factorToBig = 1;
129  break;
130  }
131 
133  m_workDbl[i] *= 10;
134  CoinAssertDebug(m_workDbl[i] >= 0);
135  }
136 
137  if (factorToBig) {
138  break;
139  }
140  }
141 
142  return scaleFactor;
143  }
144 
145 public:
146  void solve(const int blockB,
147  const double* redCost,
148  const double* origCost,
149  vector<int>& solInd,
150  vector<double>& solEls,
151  double& varRedCost,
152  double& varOrigCost) {
153  //---
154  //--- Since we want to find min redCost, and the constraint is a
155  //--- simple knapsack constraint, we know that if redCost[i] >= 0
156  //--- then we can fix x[i]=0. It makes no sense to select.
157  //---
158  //--- The knapsack solver solves maximization problem, so we also
159  //--- need to fip the sign of the redCost.
160  //---
161  //--- The knapsack solver also expects integers for weight and profit,
162  //--- the weights are already integer, but since the profits are coming
163  //--- from reduced cost, we need to scale them to integers
164  //---
165  int i, j;
166  int nItems = 0;
167  int scaleFactor = calcScaleFactor(redCost);
168  double rcScaled;
169  int weightSum = 0;
170  vector<int> shrunkToOrig;
171 
172  for (i = 0; i < m_nItems; i++) {
173  if (redCost[i] < 0.0) {
174  rcScaled = (-redCost[i]) * scaleFactor;
175  long rcLong = static_cast<long>(floor(rcScaled + 0.5));
176  CoinAssert(rcScaled < COIN_INT_MAX);
177  m_items[nItems].p = rcLong;
178  CoinAssert(m_items[nItems].p >= 0);
179  m_items[nItems].w = m_weight[i];
180  m_items[nItems].i = nItems;
181  m_items[nItems].x = 0;
182  weightSum += m_weight[i];
183  shrunkToOrig.push_back(i);
184  nItems++;
185  }
186  }
187 
188  //---
189  //--- print the current problem
190  //---
191  /*
192  printf("COMBO Knap Max (nItems = %d, cap=%d)\n", nItems, m_capacity);
193  for(i = 0; i < nItems; i++){
194  j = shrunkToOrig[i];
195  printf("[%d->%d] pOrig:%g, p:%ld, w:%ld\n",
196  i, j, -redCost[j], m_items[i].p, m_items[i].w);
197  }
198  */
199 
200  //---
201  //--- solve the knapsack problem
202  //--- first deal with some trivial cases
203  if (nItems == 1) {
204  CoinAssert(m_items[0].w <= m_capacity);
205  m_items[0].x = 1;
206  } else if (weightSum <= m_capacity) {
207  //---
208  //--- then put all items in the knapsack (to max profit)
209  //---
210  for (i = 0; i < nItems; i++) {
211  m_items[i].x = 1;
212  }
213  } else if (nItems == 2) {
214  CoinAssert(m_items[0].w <= m_capacity);
215  CoinAssert(m_items[1].w <= m_capacity);
216  int w0 = m_items[0].w;
217  int w1 = m_items[1].w;
218  int p0 = m_items[0].p;
219  int p1 = m_items[1].p;
220  double bestObj = 0;
221 
222  if ( (w1 <= m_capacity) && (p1 > bestObj) ) {
223  bestObj = p1;
224  m_items[0].x = 0;
225  m_items[1].x = 1;
226  }
227 
228  if ( (w0 <= m_capacity) && (p0 > bestObj) ) {
229  bestObj = p0;
230  m_items[0].x = 1;
231  m_items[1].x = 0;
232  }
233 
234  if ( (w0 + w1 <= m_capacity) && (p0 + p1 > bestObj) ) {
235  bestObj = p0 + p1;
236  m_items[0].x = 1;
237  m_items[1].x = 1;
238  }
239  } else if (nItems > 2) {
240  item* fItem = m_items;
241  item* lItem = m_items + (nItems - 1);
242  long obj = 0;
243  obj = combo(fItem, //first item
244  lItem, //last item
245  m_capacity, //capacity of knapsack
246  -COIN_INT_MAX, //obj lower bound
247  COIN_INT_MAX, //obj upper bound
248  1, //define sol vector
249  0); //do not solve relaxed prob
250  //printf("combo obj = %ld\n", obj);
251  }
252 
253  int origColIndex;
254  /*int wtSum = 0;
255  for(i = 0; i < nItems; i++)
256  printf("m_items[%d].x=%d i=%d p=%ld w=%ld\n",
257  i,
258  m_items[i].i,
259  m_items[i].x,
260  m_items[i].p,
261  m_items[i].w);*/
262 
263  for (i = 0; i < nItems; i++) {
264  if (m_items[i].x == 1) {
265  j = shrunkToOrig[m_items[i].i];
266  origColIndex = getIndexIJ(blockB, j);
267  varRedCost += redCost[j];
268  varOrigCost += origCost[j];
269  solInd.push_back(origColIndex);
270  solEls.push_back(1.0);
271  }
272  }
273  }
274 
275 public:
276  GAP_KnapPisinger(const int nItems,
277  const int capacity,
278  const int* weight,
279  const int* profit) :
280  m_nItems (nItems),
281  m_items (0),
282  m_capacity (capacity),
283  m_weight (0),
284  m_profit (0),
285  m_workDbl (0) {
286  m_items = new item[nItems];
287  m_weight = new int[nItems];
288  m_profit = new int[nItems];
289  m_workDbl = new double[nItems];
291  "Error: Out of Memory");
292  memcpy(m_weight, weight, nItems * sizeof(int));
293  memcpy(m_profit, profit, nItems * sizeof(int));
294  }
300  }
301 };
302 
303 
304 #endif
const int getIndexIJ(const int i, const int j) const
bool UtilIsZero(const double x, const double etol=1.0e-8)
Definition: UtilMacros.h:272
void solve(const int blockB, const double *redCost, const double *origCost, vector< int > &solInd, vector< double > &solEls, double &varRedCost, double &varOrigCost)
#define UTIL_DELARR(x)
Definition: UtilMacros.h:29
#define CoinAssertHint(expression, hint)
Definition: CoinError.hpp:184
const int COIN_INT_MAX
Definition: CoinFinite.hpp:19
int calcScaleFactor(const double *redCost, const double epsTol=1.0e-4)
Types and protos for combo algorithm API:
GAP_KnapPisinger(const int nItems, const int capacity, const int *weight, const int *profit)
#define CoinAssertDebug(expression)
Definition: CoinError.hpp:181
double UtilFracPart(const double x)
Definition: UtilMacros.h:243
#define CoinAssert(expression)
Definition: CoinError.hpp:183