ECF 1.5
knapsack.cpp
1/* knapsack.c
2 *
3 * (C) 2018 Eva Tuba <etuba@ieee.org> and Carlos M. Fonseca <cmfonsec@dei.uc.pt>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or (at
8 * your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include "knapsack.h"
24
25
26/**********************************/
27/* ----- Utility functions ----- */
28/**********************************/
29
30#if 1
31/*
32 * Random integer x such that 0 <= x <= n_max
33 * Status: FINAL
34 */
35static int randint(int n_max) {
36 int x;
37 div_t y;
38 if (n_max < 1)
39 return 0;
40 y = div(-RAND_MAX-1, -n_max-1);
41 do
42 x = rand();
43 while (x > RAND_MAX + y.rem);
44 return x / y.quot;
45}
46#else
47#include <gsl/gsl_rng.h>
48extern gsl_rng *rng; /* The single rng instance used by the whole code */
49
50static int randint(int n_max) {
51 return gsl_rng_uniform_int(rng, n_max+1);
52}
53#endif
54
55/**********************************************/
56/* ----- Problem-specific instantiation ----- */
57/**********************************************/
58
59/*
60 * Knapsack instantiation
61 * Status: TENTATIVE
62 * Notes:
63 * Needs better error checking
64 */
65struct problem *newProblem(const char *filename) {
66 struct problem *p = NULL;
67 FILE *infile;
68 int i, n=-1, capacity=-1;
69 infile = fopen(filename, "r");
70 if (infile) {
71 fscanf(infile, "%d", &n);
72 fscanf(infile, "%d", &capacity);
73 if (n > 0 && capacity > 0) {
74 p = (problem*) malloc(sizeof (struct problem));
75 p->weight = (int *) malloc(n * sizeof (int));
76 p->profit = (int *) malloc(n * sizeof (int));
77 for (i = 0; i < n; i++)
78 fscanf(infile, "%d %d", p->profit+i, p->weight+i);
79 p->n = n;
80 p->capacity = capacity;
81 } else
82 fprintf(stderr, "Invalid knapsack instance %s\n", filename);
83 fclose(infile);
84 } else
85 fprintf(stderr, "Cannot open file %s\n", filename);
86 return p;
87}
88
89/*****************************/
90/* ----- API functions ----- */
91/*****************************/
92
93/* Memory management */
94
95/*
96 * Allocate memory for a solution
97 * Status: TENTATIVE
98 */
99struct solution *allocSolution(struct problem *p) {
100 struct solution *s = (solution*) malloc(sizeof (struct solution));
101 s->prob = p;
102 s->data = (char*) malloc(p->n * sizeof (char));
103 s->n = p->n;
104 return s;
105}
106
107struct move *allocMove(struct problem *p) {
108 struct move *v = (struct move*) malloc(sizeof (struct move));
109 v->prob = p;
110 return v;
111}
112
113struct pathState *allocPathState(struct problem *p) {
114 struct pathState *ps = (pathState*) malloc(sizeof (struct pathState));
115 ps->pos = (int*) malloc(p->n * sizeof (int));
116 ps->prob = p;
117 ps->n = p->n;
118 return ps;
119}
120
121void freeProblem(struct problem *p) {
122 free(p->weight);
123 free(p->profit);
124 free(p);
125}
126
127void freeSolution(struct solution *s) {
128 free(s->data);
129 free(s);
130}
131
132void freeMove(struct move *v) {
133 free(v);
134}
135
136void freePathState(struct pathState *ps) {
137 free(ps->pos);
138 free(ps);
139}
140
141/* I/O */
142
143/*
144 * Print problem instance data
145 * Status: INTERIM
146 * Notes:
147 * There should also be a way of printing the problem in the format read
148 * by newProblem().
149 */
150void printProblem(struct problem *p) {
151 int i;
152 printf("Knapsack problem instance\n");
153 printf(" Number of items: %d\n", p->n);
154 printf(" Capacity: %d\n", p->capacity);
155 printf(" Weights:");
156 for (i = 0; i < p->n; i++)
157 printf(" %d", p->weight[i]);
158 printf("\n");
159 printf(" Profits:");
160 for (i = 0; i < p->n; i++)
161 printf(" %d", p->profit[i]);
162 printf("\n");
163}
164
165void printSolution(struct solution *s) {
166 int i;
167 int n = s->n;
168 printf("Knapsack solution\n x:");
169 for (i = 0; i < n; i++)
170 printf(" %c", s->data[i]+'0');
171 printf("\n");
172}
173
174void printMove(struct move *v) {
175 printf("Knapsack move\n Flip x[%d]\n", v->data);
176}
177
178void printPathState(struct pathState *ps) {
179 int i;
180 printf("Path state\n");
181 printf(" Path length: %d\n Positions:", ps->distance);
182 for (i = 0; i < ps->distance; i++)
183 printf(" %d", ps->pos[i]);
184 printf("\n");
185}
186
187/* Solution generation */
188
189/*
190 * Generate solutions uniformly at random
191 * Status: TENTATIVE, NEEDS_TESTING
192 * Note:
193 * Evaluation of the random solution is done in this function
194 */
195struct solution *randomSolution(struct solution *s) {
196 /* solution s must have been allocated with allocSolution() */
197 struct problem *p = s->prob;
198 int i, n = s->n;
199 /* Generate */
200 for (i = 0; i < n; i++)
201 s->data[i] = randint(1);
202 /* Evaluate */
203 s->profit = 0, s->weight = 0;
204 for (i = 0; i < n; i++)
205 if (s->data[i]) {
206 s->profit += p->profit[i];
207 s->weight += p->weight[i];
208 }
209 s->objvalue = s->weight - p->capacity;
210 if (s->objvalue <= 0)
211 s->objvalue = -s->profit;
212 return s;
213}
214
215/* Solution inspection */
216
217double getObjectiveValue(struct solution *s) {
218 return (double)s->objvalue;
219}
220
221/* Move generation */
222
223/*
224 * Generate moves uniformly at random
225 * Status: FINAL
226 */
227struct move *randomMove(struct move *v, const struct solution *s) {
228 v->data = randint(s->n-1);
229 return v;
230}
231
232/* Operations on solutions*/
233
234struct solution *copySolution(struct solution *dest, const struct solution *src) {
235 dest->prob = src->prob;
236 dest->n = src->n;
237 dest->profit = src->profit;
238 dest->weight = src->weight;
239 memcpy(dest->data, src->data, src->n * sizeof (char));
240 dest->objvalue = src->objvalue;
241 return dest;
242}
243
244/*
245 * Apply a move to a solution
246 * Status: TENTATIVE, NEEDS_TESTING
247 */
248struct solution *applyMove(struct solution *s, const struct move *v) {
249 struct problem *p = s->prob;
250 int i = v->data;
251 if (i < 0 || i >= s->n) /* null move, do nothing */
252 return s;
253 if (s->data[i] == 0) {
254 s->data[i] = 1;
255 s->weight += p->weight[i];
256 s->profit += p->profit[i];
257 } else {
258 s->data[i] = 0;
259 s->weight -= p->weight[i];
260 s->profit -= p->profit[i];
261 }
262 s->objvalue = s->weight - p->capacity;
263 if (s->objvalue <= 0)
264 s->objvalue = -s->profit;
265 return s;
266}
267
268/* Path generation */
269
270/*
271 * Set up a path from one solution to another
272 * Status: TENTATIVE, NEEDS_TESTING
273 */
274struct pathState *initPathTo(struct pathState *ps, const struct solution *s1, const struct solution *s2) {
275 int i, k, n = s1->n;
276 /* Indices of the bits in which the solutions differ */
277 for (i = 0, k = 0; i < n; i++)
278 if (s1->data[i] != s2->data[i])
279 ps->pos[k++] = i;
280 ps->distance = k;
281 return ps;
282}
283
284/*
285 * Set up a path away from a solution
286 * Status: TENTATIVE, NEEDS_TESTING
287 * Notes:
288 */
289struct pathState *initPathAwayFrom(struct pathState *ps, const struct solution *s) {
290 int i, n = ps->n;
291 for (i = 0; i < n; i++)
292 ps->pos[i] = i;
293 ps->distance = n;
294 return ps;
295}
296
297/*
298 * Generate the next random move in a path towards a solution
299 * Status: TENTATIVE, NEEDS_TESTING
300 * Notes:
301 * A null move does nothing when applied to a solution. This is handled
302 * by applyMove().
303 */
304struct move *nextRandomMove(struct move *v, struct pathState *ps) {
305 int r;
306 if (ps->distance == 0) { /* end of path has been reached, no move is possible */
307 v->data = -1; /* null move */
308 return v;
309 }
310 /* Draw an index at random */
311 r = randint(--ps->distance);
312 v->data = ps->pos[r];
313 /* Update pathState - remember which moves are still available (and only those) */
314 ps->pos[r] = ps->pos[ps->distance];
315 return v;
316}
317
318/* Path inspection */
319
320/*
321 * Current length of path
322 * Status: FINAL
323 */
324int getPathLength(const struct pathState *ps) {
325 return ps->distance;
326}
Definition: flowshop.h:78