APPFS
Advanced practical programming for scientists
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
ex4_enum.c
Go to the documentation of this file.
1 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <assert.h>
20 #include <stdbool.h>
21 #include <time.h>
22 
23 #include "mshell.h" // or by allocate?
24 #include "sid.h"
25 #include "allocate.h"
26 
27 #define BIP_SID 0x42495078
28 #define BIP_COLS 32
29 #define BIP_ROWS 32
30 
32 {
33  SID
34  int rows;
35  int cols;
36  double a[BIP_ROWS][BIP_COLS];
37  double b[BIP_ROWS];
38 };
39 
40 typedef struct binary_program BIP;
41 
42 #define MAX_LINE_LEN 512
43 
44 #define MAX_COEF_VAL 1e20
45 
46 #define GET_SEC(a, b) ((b - a) / (double)CLOCKS_PER_SEC)
47 
49 
53 bool bip_is_valid(const BIP* bip)
54 {
55  if (NULL == bip || !SID_ok(bip, BIP_SID))
56  return false;
57 
58  if (bip->rows < 1 || bip->rows > BIP_ROWS)
59  return false;
60  if (bip->cols < 1 || bip->cols > BIP_COLS)
61  return false;
62 
63  for(int r = 0; r < bip->rows; r++)
64  {
65  for(int c = 0; c < bip->cols; c++)
66  if (bip->a[r][c] < -MAX_COEF_VAL || bip->a[r][c] > MAX_COEF_VAL)
67  return false;
68 
69  if (bip->b[r] < -MAX_COEF_VAL || bip->b[r] > MAX_COEF_VAL)
70  return false;
71  }
72  return true;
73 }
74 
77 void bip_free(BIP* bip)
78 {
79  assert(bip_is_valid(bip));
80 
81  SID_del(bip);
82 
83  mem_check(bip);
84 
85  deallocate(bip);
86 }
87 
102 BIP* bip_read(const char* filename)
103 {
104  assert(NULL != filename);
105  assert(0 < strlen(filename));
106 
107 #ifdef USE_SCANF
108  char input[] = "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf";
109 #endif
110 
111  char buf[MAX_LINE_LEN];
112  char* s;
113  FILE* fp;
114  BIP* bip = allocate(1, sizeof(*bip));
115  int lines = 0;
116  int rows = 0;
117  int cols;
118  LINE_MODE mode = READ_COLS;
119 
120  if (NULL == (fp = fopen(filename, "r")))
121  {
122  fprintf(stderr, "Can't open file %s\n", filename);
123  goto read_error;
124  }
125  printf("Reading %s\n", filename);
126 
127  while(NULL != (s = fgets(buf, sizeof(buf), fp)))
128  {
129  char* t = strpbrk(s, "#\n\r");
130 
131  lines++;
132 
133  if (NULL != t) /* else line is not terminated or too long */
134  *t = '\0'; /* clip comment or newline */
135 
136 /* Skip over leading space
137  */
138  while(isspace(*s))
139  s++;
140 
141  /* Skip over empty lines
142  */
143  if (!*s) /* <=> (*s == '\0') */
144  continue;
145 
146 #ifdef USE_SCANF
147  double v[33];
148  int nums;
149 
150  nums = sscanf(s, input,
151  &v[ 0], &v[ 1], &v[ 2], &v[ 3], &v[ 4], &v[ 5], &v[ 6], &v[ 7],
152  &v[ 8], &v[ 9], &v[10], &v[11], &v[12], &v[13], &v[14], &v[15],
153  &v[16], &v[17], &v[18], &v[19], &v[20], &v[21], &v[22], &v[23],
154  &v[24], &v[25], &v[26], &v[27], &v[28], &v[29], &v[30], &v[31]);
155 
156  if (nums < 1)
157  {
158  fprintf(stderr, "Error line %d: Expected number, got \"%s\"\n", lines, s);
159  goto read_error;
160  }
161 
162  /* do processing here:
163  * mode tells which kind of line is next.
164  */
165  switch(mode)
166  {
167  case READ_COLS :
168  bip->cols = (int)v[0];
169 
170  if (bip->cols < 1 || bip->cols > BIP_COLS)
171  {
172 fprintf(stderr, "Error line %d: 1 <= cols=%d <= %d\n", lines, bip->cols, BIP_COLS);
173 goto read_error;
174  }
175  /* Insert <= into the input string
176  */
177  strncpy(input + bip->cols * 4, "<= ", 3);
178 
179  mode = READ_ROWS;
180  break;
181  case READ_ROWS :
182  bip->rows = (int)v[0];
183 
184  if (bip->rows < 1 || bip->rows > BIP_ROWS)
185  {
186 fprintf(stderr, "Error line %d: 1 <= rows <= %d\n", lines, BIP_ROWS);
187  goto read_error;
188  }
189  mode = READ_COEF;
190  break;
191  case READ_COEF :
192  if (rows >= bip->rows)
193  {
194  fprintf(stderr, "Error line=%d too many rows (expetced %d)\n",
195  lines, bip->rows);
196  goto read_error;
197  }
198  if (nums != bip->cols + 1)
199  {
200  fprintf(stderr, "Error line=%d Expected %d cols, got %d\n",
201  lines, bip->cols, nums);
202  goto read_error;
203  }
204  for(cols = 0; cols < bip->cols; cols++)
205  bip->a[rows][cols] = v[cols];
206 
207  bip->b[rows] = v[cols];
208 
209  rows++;
210  break;
211  default :
212  abort();
213  }
214 #else
215  /* do processing here:
216  * mode tells which kind of line is next.
217  */
218  switch(mode)
219  {
220  case READ_COLS :
221  bip->cols = atoi(s);
222 
223  if (bip->cols < 1 || bip->cols > BIP_COLS)
224  {
225  fprintf(stderr, "Error line %d: 1 <= cols=%d <= %d\n", lines, bip->cols, BIP_COLS);
226  goto read_error;
227  }
228  mode = READ_ROWS;
229  break;
230  case READ_ROWS :
231  bip->rows = atoi(s);
232 
233  if (bip->rows < 1 || bip->rows > BIP_ROWS)
234  {
235  fprintf(stderr, "Error line %d: 1 <= rows <= %d\n", lines, BIP_ROWS);
236  goto read_error;
237  }
238  mode = READ_COEF;
239  break;
240  case READ_COEF :
241  if (rows >= bip->rows)
242  {
243  fprintf(stderr, "Error line=%d too many rows (expetced %d)\n",
244  lines, bip->rows);
245  goto read_error;
246  }
247 #ifdef USE_STRTOK // not thread safe, rarely a problem in reading
248  const char* delim = " \t";
249  cols = 0;
250 
251  for(s = strtok(s, delim); s != NULL; s = strtok(NULL, delim)) /* not thread safe */
252  {
253  if (cols == bip->cols && strcmp(s, "<="))
254  bip->b[rows] = atof(s);
255  else if (cols < bip->cols)
256  {
257  bip->a[rows][cols] = atof(s);
258  cols++;
259  }
260  }
261 #else
262  for(cols = 0; cols < bip->cols; cols++)
263  {
264  bip->a[rows][cols] = (double)strtol(s, &t, 10);
265 
266  if (s == t)
267  {
268  fprintf(stderr, "Error line=%d Expected %d cols, got %d\n",
269  lines, bip->cols, cols);
270  goto read_error;
271  }
272  s = t;
273  }
274  while(isspace(*s))
275  s++;
276 
277  if (strncmp(s, "<=", 2))
278  {
279  fprintf(stderr, "Error line=%d Expected <= , got \"%s\"\n",
280  lines, s);
281  goto read_error;
282  }
283  s += 2;
284  bip->b[rows] = (double)strtol(s, &t, 10);
285 
286  if (s == t)
287  {
288  fprintf(stderr, "Error line=%d Expected rhs\n", lines);
289  goto read_error;
290  }
291 #endif // !USE_STRTOK
292  rows++;
293  break;
294  default :
295  abort();
296  }
297 #endif // !USE_SCANF
298  }
299  fclose(fp);
300 
301  if (rows != bip->rows)
302  {
303  fprintf(stderr, "Error line=%d Expetced %d rows, got %d\n",
304  lines, bip->rows, rows);
305  goto read_error;
306  }
307 
308  SID_set(bip, BIP_SID);
309 
310  assert(bip_is_valid(bip));
311 
312  printf("Read %d rows, %d cols\n", bip->rows, bip->cols);
313 
314  return bip;
315 
316  read_error:
317  deallocate(bip);
318  return NULL;
319 }
320 
323 void bip_print(FILE* fp, const BIP* bip)
324 {
325  assert(NULL != fp);
326  assert(bip_is_valid(bip));
327 
328  for(int r = 0; r < bip->rows; r++)
329  {
330  for(int c = 0; c < bip->cols; c++)
331  fprintf(fp, "%5g ", bip->a[r][c]);
332  fprintf(fp, "<= %5g\n", bip->b[r]);
333  }
334 }
335 
339  FILE* fp,
340  int vars,
341  const double* x)
342 {
343  assert(NULL != fp);
344  assert(vars >= 0);
345  assert(vars < BIP_COLS);
346  assert(NULL != x);
347 
348  for(int r = 0; r < vars; r++)
349  fprintf(fp, "%2g ", x[r]);
350  fputc('\n', fp);
351 }
352 
356 bool bip_is_feasible(const BIP* bip, const double* x)
357 {
358  assert(bip_is_valid(bip));
359 
360  int r;
361 
362  for(r = 0; r < bip->rows; r++)
363  {
364  double lhs = 0.0;
365 
366  for(int c = 0; c < bip->cols; c++)
367  {
368  assert(x[c] == 0.0 || x[c] == 1.0);
369 
370  lhs += bip->a[r][c] * x[c];
371  }
372  if (lhs > bip->b[r])
373  break;
374  }
375  return r == bip->rows;
376 }
377 
382 int bip_enumerate(const BIP* bip, bool with_output)
383 {
384  assert(bip_is_valid(bip));
385 
386  clock_t start = clock();
387  int solus = 0;
388  int count = 0;
389 
390  /* generate all permutation
391  */
392  for(unsigned long long bitvec = 0; bitvec < (1uL << bip->cols); bitvec++)
393  {
394  unsigned long long mask = 1; // long long because long is 32 bit on 32 bit computers
395  double x[BIP_COLS];
396 
397  assert(sizeof(bitvec) * 8 > BIP_COLS); //lint !e506
398 
399  /* construct solution vector
400  */
401  for(int j = 0; j < bip->cols; j++, mask <<= 1)
402  x[j] = (bitvec & mask) ? 1.0 : 0.0;
403 
404  if (bip_is_feasible(bip, &x[0])) //lint !e772
405  {
406  if (with_output)
407  print_solu(stdout, bip->rows, &x[0]);
408 
409  solus++;
410  }
411  count++;
412  }
413  assert((unsigned)count == (1u << bip->cols));
414 
415  double elapsed = GET_SEC(start, clock());
416 
417  printf("Checked %d vectors in %.3f s = %.3f kvecs/s\n",
418  count, elapsed, count / elapsed / 1000.0);
419 
420  return solus;
421 }
422 
425 int main(int argc, const char** argv)
426 {
427  if (argc < 2)
428  {
429  fprintf(stderr, "usage: %s filename", argv[0]);
430  return EXIT_FAILURE;
431  }
432  BIP* bip = bip_read(argv[1]);
433 
434  if (NULL == bip)
435  return EXIT_FAILURE;
436 
437  bip_print(stdout, bip);
438 
439  printf("%d solutions\n", bip_enumerate(bip, true));
440 
441  bip_free(bip);
442 
443  mem_maximum(stdout);
444 
445  return EXIT_SUCCESS;
446 }
#define MAX_LINE_LEN
Maximum input line length.
Definition: ex4_enum.c:42
int main(int argc, const char **argv)
Usage: ex4_enum bip_file.
Definition: ex4_enum.c:425
#define BIP_ROWS
Definition: ex4_enum.c:29
LINE_MODE
Definition: ex4_enum.c:48
#define MAX_COEF_VAL
Maximum absolute value of a coefficient.
Definition: ex4_enum.c:44
char c
Definition: ex4_struct.c:4
double a[BIP_ROWS][BIP_COLS]
coefficient matrix
Definition: ex4_enum.c:36
void print_solu(FILE *fp, int vars, const double *x)
Print solution vector.
Definition: ex4_enum.c:338
#define SID
Definition: sid.h:6
char x
Definition: ex4_struct.c:4
void deallocate(void *p)
Free allocated memory.
Definition: allocate.c:47
SID int rows
number of rows (constraints)
Definition: ex4_enum.c:34
Wrapper for malloc.
int cols
number of columns (variables)
Definition: ex4_enum.c:35
#define SID_ok(p, id)
Definition: sid.h:9
BIP * bip_read(const char *filename)
Read a bip file.
Definition: ex4_enum.c:102
void bip_print(FILE *fp, const BIP *bip)
Print Binary Program from BIP.
Definition: ex4_enum.c:323
void * allocate(int elems, int size)
Allocate memory.
Definition: allocate.c:23
void bip_free(BIP *bip)
Deallocate BIP data structure.
Definition: ex4_enum.c:77
void mem_maximum(FILE *fp)
Definition: mshell.c:373
#define BIP_SID
Definition: ex4_enum.c:27
#define SID_set(p, id)
Definition: sid.h:7
#define GET_SEC(a, b)
Definition: ex4_enum.c:46
#define mem_check(a)
Definition: mshell.h:71
int bip_enumerate(const BIP *bip, bool with_output)
Enumerate all possible solution of a BIP.
Definition: ex4_enum.c:382
bool bip_is_feasible(const BIP *bip, const double *x)
Check whether a particular vector is a feasible solution to a BIP.
Definition: ex4_enum.c:356
#define BIP_COLS
Definition: ex4_enum.c:28
double b[BIP_ROWS]
right hand side
Definition: ex4_enum.c:37
#define SID_del(p)
Definition: sid.h:8
bool bip_is_valid(const BIP *bip)
Check whether BIP data structure is consistent.
Definition: ex4_enum.c:53