coin-Bcp
KS.hpp
Go to the documentation of this file.
1 // Copyright (C) 2005, International Business Machines
2 // Corporation and others. All Rights Reserved.
3 #ifndef _KS_HPP
4 #define _KS_HPP
5 
6 #include <utility>
7 #include <algorithm>
8 #include <cfloat>
9 
10 using std::fill;
11 
12 // A goto-less implementation of the Horowitz-Sahni exact solution
13 // procedure for solving knapsack problem.
14 //
15 // Reference: Martello and Toth, Knapsack Problems, Wiley, 1990, p30-31.
16 //
17 // ToDo: Implement a dynamic programming approach for case
18 // of knapsacks with integral coefficients
19 //-------------------------------------------------------------------
20 
21 // The knapsack problem is to find:
22 
23 // max {sum(j=1,n) p_j*x_j st. sum (j=1,n)w_j*x_j <= c, x binary}
24 
25 // Notation:
26 // xhat : current solution vector
27 // zhat : current solution value = sum (j=1,n) p_j*xhat_j
28 // chat : current residual capacity = c - sum (j=1,n) w_j*xhat_j
29 // x : best solution so far, n-vector.
30 // z : value of the best solution so far = sum (j=1,n) p_j*x_j
31 
32 // Input: n, the number of variables;
33 // c, the rhs;
34 // p, n-vector of objective func. coefficients;
35 // w, n-vector of the row coeff.
36 
37 // Output: z, the optimal objective function value;
38 // x, the optimal (binary) solution n-vector;
39 
40 struct triplet {
41  double c;
42  double w;
43  int i;
44 };
45 
46 inline bool
47 ratioComp(const triplet& t0, const triplet& t1) {
48  return (t0.c/t0.w > t1.c/t1.w ?
49  true : (t0.c/t0.w < t1.c/t1.w ? false : (t0.i > t1.i)));
50 }
51 
52 class Knapsack {
53 private:
54  inline void
55  sortItems(const double* c, const double* w) {
56  delete perm_;
57  double* ww = new double[n_+1];
58  double* cc = new double[n_+1];
59  perm_ = new int[n_];
60  triplet* items = new triplet[n_];
61  for (int i = n_ - 1; i >= 0; --i) {
62  items[i].c = c[i];
63  items[i].w = w[i];
64  items[i].i = i;
65  }
66  std::sort(items, items+n_, ratioComp);
67  for (int i = n_ - 1; i >= 0; --i) {
68  cc[i] = items[i].c;
69  ww[i] = items[i].w;
70  perm_[i] = items[i].i;
71  }
72  delete[] items;
73  delete[] weight_;
74  delete[] cost_;
75  ww[n_] = DBL_MAX;
76  cc[n_] = 0.0;
77  weight_ = ww;
78  cost_ = cc;
79  }
80 
82  double cap_;
84  int n_;
87  int* perm_;
90  const double* cost_;
93  const double* weight_;
94 
96  int* x;
98  double z;
99 
100 public:
101  Knapsack(int n, double cap, const double* c, const double* w) :
102  cap_(cap), n_(n), perm_(0), cost_(0), weight_(0), x(new int[n])
103  {
104  sortItems(c, w);
105  }
107  delete[] perm_;
108  delete[] x;
109  delete[] weight_;
110  delete[] cost_;
111  }
112 
113  void setCosts(const double* c) {
114  sortItems(c, weight_);
115  }
116  void setCapacity(double cap) { cap_ = cap; }
117 
119  void optimize(double lb = 0.0, double minimp = 1e-6);
120 
121  const int* getBestSol() const { return x; }
122  const double getBestVal() const { return z; }
123 };
124 
125 //#############################################################################
126 
127 void
128 Knapsack::optimize(double lb, double minimp)
129 {
130  z = lb;
131  fill(x, x+n_, 0);
132  int * xhat = new int[n_+1];
133  fill(xhat, xhat+(n_+1), 0);
134  int j;
135 
136  // set up: adding the extra element and
137  // accounting for the FORTRAN vs C difference in indexing arrays.
138  double * p = new double[n_+2];
139  double * w = new double[n_+2];
140  int ii;
141  for (ii = 1; ii < n_+1; ii++){
142  p[ii]=cost_[ii-1];
143  w[ii]=weight_[ii-1];
144  }
145 
146  // 1. initialize
147  double zhat = 0.0;
148  z = 0.0;
149  double caphat = cap_;
150  p[n_+1] = 0.0;
151  w[n_+1] = DBL_MAX;
152  j = 1;
153 
154  while (true) {
155  // 2. compute upper bound u
156  // "find r = min {i: sum k=j,i w_k>chat};"
157  ii = j;
158  double wSemiSum = w[j];
159  double pSemiSum = p[j];
160  while (wSemiSum <= caphat && ii < n_+2){
161  ii++;
162  wSemiSum += w[ii];
163  pSemiSum += p[ii];
164  }
165  if (ii == n_+2) {
166  printf("Exceeded iterator limit. Aborting...\n");
167  abort();
168  }
169  // r = ii at this point
170  wSemiSum -= w[ii];
171  pSemiSum -= p[ii];
172  // *FIXME* : why floor
173  // double u = pSemiSum + floor((caphat - wSemiSum)*p[ii]/w[ii]);
174  double u = pSemiSum + (caphat - wSemiSum)*p[ii]/w[ii];
175 
176  // "if (z >= zhat + u) goto 5: backtrack;"
177  if (z + minimp < zhat + u) {
178  do {
179  // 3. perform a forward step
180  while (w[j] <= caphat){
181  caphat = caphat - w[j];
182  zhat = zhat + p[j];
183  xhat[j] = 1;
184  ++j;
185  }
186  if (j <= n_) {
187  xhat[j] = 0;
188  ++j;
189  }
190  } while (j == n_);
191 
192  // "if (j<n) goto 2: compute_ub;"
193  if (j < n_)
194  continue;
195 
196  // 4. up date the best solution so far
197  if (zhat > z) {
198  z = zhat;
199  int k;
200  for (k = 0; k < n_; ++k){
201  x[perm_[k]] = xhat[k+1];
202  }
203  }
204  j = n_;
205  if (xhat[n_] == 1){
206  caphat = caphat + w[n_];
207  zhat = zhat - p[n_];
208  xhat[n_] = 0;
209  }
210  }
211  // 5. backtrack
212  // "find i=max{k<j:xhat[k]=1};"
213  int i = j-1;
214  while (!(xhat[i]==1) && i>0) {
215  i--;
216  }
217 
218  // "if (no such i exists) return;"
219  if (i == 0) {
220  delete [] p;
221  delete [] w;
222  delete [] xhat;
223  break;
224  }
225 
226  caphat = caphat + w[i];
227  zhat = zhat - p[i];
228  xhat[i] = 0;
229  j = i+1;
230  // "goto 2: compute_ub;"
231  }
232 }
233 
234 #endif
double w
Definition: KS.hpp:42
const int * getBestSol() const
Definition: KS.hpp:121
Definition: KS.hpp:40
const double * weight_
The weight of the items (the order is after doing the cost/weight ordering)
Definition: KS.hpp:93
Knapsack(int n, double cap, const double *c, const double *w)
Definition: KS.hpp:101
const double getBestVal() const
Definition: KS.hpp:122
void sortItems(const double *c, const double *w)
Definition: KS.hpp:55
double cap_
The capacity of the knapsack.
Definition: KS.hpp:82
double z
The optimal solution value.
Definition: KS.hpp:98
void setCapacity(double cap)
Definition: KS.hpp:116
bool ratioComp(const triplet &t0, const triplet &t1)
Definition: KS.hpp:47
const double * cost_
The cost of each item (the order is after doing the cost/weight ordering)
Definition: KS.hpp:90
Definition: KS.hpp:52
~Knapsack()
Definition: KS.hpp:106
void optimize(double lb=0.0, double minimp=1e-6)
Return true/false depending on whether the problem is feasible.
Definition: KS.hpp:128
double c
Definition: KS.hpp:41
void setCosts(const double *c)
Definition: KS.hpp:113
int * x
The optimal solution in terms of the input order.
Definition: KS.hpp:96
int * perm_
The permutation corresponding to the ordering (element perm[i] is the i-th in the original order...
Definition: KS.hpp:87
int n_
The number of items.
Definition: KS.hpp:84
int i
Definition: KS.hpp:43