APPFS
Advanced practical programming for scientists
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
bip_enum.c
Go to the documentation of this file.
1 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include <assert.h>
11 #include <stdbool.h>
12 #include <time.h>
13 #include <limits.h>
14 #include <math.h>
15 #include <errno.h>
16 #include <float.h>
17 #include <fenv.h>
18 
19 #include "mshell.h" // or by allocate?
20 #include "splitline.h"
21 #include "bip_enum.h"
22 
23 #if defined(USE_INT)
24 typedef int Numb;
25 #elif defined(USE_LONGLONG)
26 typedef long long Numb;
27 #elif defined(USE_FLOAT)
28 typedef float Numb;
29 #elif defined(USE_DOUBLE)
30 typedef double Numb;
31 #elif defined(USE_LONGDOUBLE)
32 typedef long double Numb;
33 #else
34 #error "No number type defined"
35 #endif
36 
37 #define BIP_MAX_COLS 32
38 #define BIP_MAX_ROWS 32
39 
41 
42 typedef enum { LE = 0, GE = 1, EQ = 2 } Sense;
43 
45 {
46  int rows;
47  int max_rows;
48  int cols;
50  Numb b[BIP_MAX_ROWS];
52 };
53 
54 
55 #define MAX_LINE_LEN 512
56 
57 #define GET_SEC(a, b) ((b - a) / (double)CLOCKS_PER_SEC)
58 
59 static Numb max_coef_val;
60 static Numb min_coef_val;
61 static bool int_coef;
62 
66 static bool bip_is_valid(const BIP* bip)
67 {
68  if (NULL == bip)
69  return false;
70 
71  if (max_coef_val <= min_coef_val) // bip_init not called.
72  return false;
73 
74  if (bip->rows < 1 || bip->rows > BIP_MAX_ROWS)
75  return false;
76  if (bip->cols < 1 || bip->cols > BIP_MAX_COLS)
77  return false;
78 
79  for(int r = 0; r < bip->rows; r++)
80  {
81  for(int c = 0; c < bip->cols; c++)
82  if (bip->a[r][c] < min_coef_val || bip->a[r][c] > max_coef_val) // can only happen with floating point Numb
83  return false;
84 
85  if (bip->b[r] < min_coef_val || bip->b[r] > max_coef_val) // can only happen with floating point Numb
86  return false;
87  }
88  return true;
89 }
90 
91 void bip_init()
92 {
93 #if defined(USE_INT)
94 
95  max_coef_val = INT_MAX;
96  min_coef_val = INT_MIN;
97  int_coef = true;
98 
99 #elif defined(USE_LONGLONG)
100 
101  max_coef_val = LLONG_MAX;
102  min_coef_val = LLONG_MIN;
103  int_coef = true;
104 
105 #elif defined(USE_FLOAT)
106 
107  max_coef_val = powf(10, (float)FLT_DIG);
108  min_coef_val = -powf(10, (float)FLT_DIG);
109  int_coef = false;
110 
111 #elif defined(USE_DOUBLE)
112 
113  max_coef_val = pow(10, (double)DBL_DIG);
114  min_coef_val = -pow(10, (double)DBL_DIG);
115  int_coef = false;
116 
117 #elif defined(USE_LONGDOUBLE)
118 
119  max_coef_val = powl(10, (long double)LDBL_DIG);
120  min_coef_val = -powl(10, (long double)LDBL_DIG);
121  int_coef = false;
122 
123 #else
124 #error "No number type defined"
125 #endif
126 
127  // printf("Min/Max coefficient values [%.0Lf,%.0Lf]\n",
128  // (long double)min_coef_val, (long double)max_coef_val);
129 }
130 
133 void bip_free(BIP* bip)
134 {
135  assert(bip_is_valid(bip));
136 
137  mem_check(bip);
138 
139  free(bip);
140 }
141 
142 static bool bip_can_overflow(const BIP* bip)
143 {
144  assert(bip_is_valid(bip));
145 
146  for(int r = 0; r < bip->rows; r++)
147  {
148  Numb row_max = 0;
149  Numb row_min = 0;
150 
151  for(int c = 0; c < bip->cols; c++)
152  {
153  Numb val = bip->a[r][c];
154 
155  if (val > 0)
156  {
157  if (row_max < max_coef_val - val)
158  row_max += val;
159  else
160  return fprintf(stderr, "Error: row %d numerical overflow\n", r), true;
161  }
162  else if (val < 0)
163  {
164  if (row_min > min_coef_val - val)
165  row_min += val;
166  else
167  return fprintf(stderr, "Error: row %d numerical negative overflow\n", r), true;
168  }
169  else
170  {
171  assert(val == 0);
172  }
173  }
174  }
175  return false;
176 }
177 
178 
179 static LINE_MODE process_line(LINE_MODE mode, const LFS* lfs, const int lines, BIP* bip)
180 {
181  /* If line is not empty
182  */
183  if (lfs_used_fields(lfs) > 0)
184  {
185  long double val;
186  char* t;
187 
188  /* do processing here:
189  * mode tells which kind of line is next.
190  */
191  switch(mode)
192  {
193  case READ_COLS :
194  if (lfs_used_fields(lfs) != 1)
195  return fprintf(stderr, "Error line %d: Got %d fields, expected 1\n",
196  lines, lfs_used_fields(lfs)),
197  READ_ERROR;
198 
199  val = strtold(lfs_get_field(lfs, 0), &t);
200 
201  if (errno == ERANGE || isnan(val) || isinf(val) || rintl(val) != val || val < 1.0 || val > (long double)BIP_MAX_COLS || *t != '\0')
202  return fprintf(stderr, "Error line=%d Number of cols %s=%Lf out of range or not integer %s\n",
203  lines, lfs_get_field(lfs, 0), val, errno ? strerror(errno) : ""),
204  READ_ERROR;
205 
206  bip->cols = (int)val;
207  mode = READ_ROWS;
208  break;
209  case READ_ROWS :
210  if (lfs_used_fields(lfs) != 1)
211  return fprintf(stderr, "Error line %d: Got %d fields, expected 1\n",
212  lines, lfs_used_fields(lfs)),
213  READ_ERROR;
214 
215  val = strtold(lfs_get_field(lfs, 0), &t);
216 
217  if (errno == ERANGE || isnan(val) || isinf(val) || rintl(val) != val || val < 1.0 || val > (long double)BIP_MAX_ROWS || *t != '\0')
218  return fprintf(stderr, "Error line=%d Number of rows %s=%Lf out of range or not integer %s\n",
219  lines, lfs_get_field(lfs, 0), val, errno ? strerror(errno) : ""),
220  READ_ERROR;
221 
222  bip->max_rows = (int)val;
223  mode = READ_COEF;
224  break;
225  case READ_COEF :
226  if (bip->rows >= bip->max_rows)
227  return fprintf(stderr, "Error line=%d Expetced %d rows, got more\n",
228  lines, bip->max_rows),
229  READ_ERROR;
230 
231  if (lfs_used_fields(lfs) != bip->cols + 2)
232  return fprintf(stderr, "Error line %d: Got %d fields, expected %d\n",
233  lines, lfs_used_fields(lfs), bip->cols + 2),
234  READ_ERROR;
235 
236  for(int col = 0; col < bip->cols + 2; col++)
237  {
238  if (col != bip->cols)
239  {
240  val = strtold(lfs_get_field(lfs, col), &t);
241 
242  if (errno == ERANGE || isnan(val) || isinf(val)
243  || (int_coef && rintl(val) != val)
244  || val > (long double)max_coef_val
245  || val < (long double)min_coef_val
246  || *t != '\0')
247  return fprintf(stderr, "Error line=%d Number %s=%Lf out of range %s: %s\n",
248  lines, lfs_get_field(lfs, col), val, int_coef ? "or not integer" : "", errno ? strerror(errno) : ""),
249  READ_ERROR;
250 
251  if (col < bip->cols)
252  bip->a[bip->rows][col] = (Numb)val;
253  else
254  bip->b[bip->rows] = (Numb)val;
255  }
256  else
257  {
258  const char* sense = lfs_get_field(lfs, bip->cols);
259 
260  if (!strcmp(sense, "<="))
261  bip->sense[bip->rows] = LE;
262  else if (!strcmp(sense, ">="))
263  bip->sense[bip->rows] = GE;
264  else if (!strcmp(sense, "=") || !strcmp(sense, "=="))
265  bip->sense[bip->rows] = EQ;
266  else
267  return fprintf(stderr, "Error line=%d Expected <=, >=, ==, got \"%s\"\n",
268  lines, sense),
269  READ_ERROR;
270  }
271  }
272  bip->rows++;
273  break;
274  default :
275  abort();
276  }
277  }
278  return mode;
279 }
280 
281 
296 BIP* bip_read(const char* filename)
297 {
298  assert(NULL != filename);
299  assert(0 < strlen(filename));
300 
301  char buf[MAX_LINE_LEN];
302  char* s;
303  FILE* fp;
304  BIP* bip = calloc(1, sizeof(*bip));
305  LFS* lfs = NULL;
306  int lines = 0;
307  LINE_MODE mode = READ_COLS;
308 
309  if (NULL == (fp = fopen(filename, "r")))
310  {
311  fprintf(stderr, "Can't open file %s\n", filename);
312  free(bip);
313  return NULL;
314  }
315  printf("Reading %s\n", filename);
316 
317  while(mode != READ_ERROR && NULL != (s = fgets(buf, sizeof(buf), fp)))
318  {
319  lines++;
320 
321  lfs = lfs_split_line(lfs, s, "#");
322  mode = process_line(mode, lfs, lines, bip);
323  }
324  fclose(fp);
325 
326  if (NULL != lfs)
327  lfs_free(lfs);
328 
329  if (READ_ERROR == mode)
330  {
331  free(bip);
332 
333  return NULL;
334  }
335  if (bip->cols == 0 || bip->max_rows == 0 || bip->rows < bip->max_rows)
336  {
337  fprintf(stderr, "Error: unexpected EOF\n");
338  free(bip);
339  return NULL;
340  }
341 
342  assert(bip->rows == bip->max_rows);
343 
344  assert(bip_is_valid(bip));
345 
346  printf("Read %d rows, %d cols\n", bip->rows, bip->cols);
347 
348  if (bip_can_overflow(bip))
349  {
350  bip_free(bip);
351 
352  return NULL;
353  }
354  return bip;
355 }
356 
359 void bip_print(const BIP* bip, FILE* fp)
360 {
361  const char* sense[3] = { "<=", ">=", "==" };
362 
363  assert(NULL != fp);
364  assert(bip_is_valid(bip));
365 
366  for(int r = 0; r < bip->rows; r++)
367  {
368  for(int c = 0; c < bip->cols; c++)
369  fprintf(fp, "%Lf ", (long double)bip->a[r][c]);
370  fprintf(fp, "%s %Lf\n", sense[bip->sense[r]], (long double)bip->b[r]);
371  }
372 }
373 
376 static void print_solu(
377  FILE* fp,
378  int vars,
379  const double* x)
380 {
381  assert(NULL != fp);
382  assert(vars >= 0);
383  assert(vars < BIP_MAX_COLS);
384  assert(NULL != x);
385 
386  for(int r = 0; r < vars; r++)
387  fprintf(fp, "%2g ", x[r]);
388  fputc('\n', fp);
389 }
390 
394 static bool bip_is_feasible(const BIP* bip, const double* x)
395 {
396  assert(bip_is_valid(bip));
397 
398  int r;
399 
400  for(r = 0; r < bip->rows; r++)
401  {
402  double lhs = 0.0;
403 
404  for(int c = 0; c < bip->cols; c++)
405  {
406  assert(x[c] == 0.0 || x[c] == 1.0);
407 
408  lhs += bip->a[r][c] * x[c];
409 
410  assert(fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT) == 0);
411  }
412 
413  switch(bip->sense[r])
414  {
415  case LE :
416  if (lhs <= bip->b[r])
417  continue;
418  break;
419  case GE :
420  if (lhs >= bip->b[r])
421  continue;
422  break;
423  case EQ :
424  if (lhs == bip->b[r])
425  continue;
426  break;
427  default :
428  abort();
429  }
430  break;
431  }
432  return r == bip->rows;
433 }
434 
439 int bip_enumerate(const BIP* bip, bool with_output)
440 {
441  assert(bip_is_valid(bip));
442 
443  clock_t start = clock();
444  int solus = 0;
445  int count = 0;
446 
447  /* generate all permutation
448  */
449  for(unsigned long long bitvec = 0; bitvec < (1uL << bip->cols); bitvec++)
450  {
451  unsigned long long mask = 1; // long long because long is 32 bit on 32 bit computers
452  double x[BIP_MAX_COLS]; // having this always double is questionable
453 
454  assert(sizeof(bitvec) * 8 > BIP_MAX_COLS); //lint !e506
455 
456  /* construct solution vector
457  */
458  for(int j = 0; j < bip->cols; j++, mask <<= 1)
459  x[j] = (bitvec & mask) ? 1.0 : 0.0;
460 
461  if (bip_is_feasible(bip, &x[0])) //lint !e772
462  {
463  if (with_output)
464  print_solu(stdout, bip->cols, &x[0]);
465 
466  solus++;
467  }
468  count++;
469  }
470  assert((unsigned)count == (1u << bip->cols));
471 
472  double elapsed = GET_SEC(start, clock());
473 
474  printf("Checked %d vectors in %.3f s = %.3f kvecs/s\n",
475  count, elapsed, count / elapsed / 1000.0);
476 
477  return solus;
478 }
Definition: bip_enum.c:42
#define GET_SEC(a, b)
Definition: bip_enum.c:57
#define MAX_LINE_LEN
Maximum input line length.
Definition: bip_enum.c:55
static bool int_coef
Definition: bip_enum.c:61
static void print_solu(FILE *fp, int vars, const double *x)
Print solution vector.
Definition: bip_enum.c:376
Sense
Definition: bip_enum.c:42
static bool bip_is_feasible(const BIP *bip, const double *x)
Check whether a particular vector is a feasible solution to a BIP.
Definition: bip_enum.c:394
int max_rows
maximum number of rows
Definition: bip_enum.c:47
void bip_print(const BIP *bip, FILE *fp)
Print Binary Program from BIP.
Definition: bip_enum.c:359
void bip_init()
Definition: bip_enum.c:91
int cols
number of columns (variables)
Definition: bip_enum.c:48
Split line into fields Header.
#define BIP_MAX_ROWS
Definition: bip_enum.c:38
Numb a[BIP_MAX_ROWS][BIP_MAX_COLS]
coefficient matrix
Definition: bip_enum.c:49
BIP * bip_read(const char *filename)
Read a bip file.
Definition: bip_enum.c:296
const char * lfs_get_field(const LFS *lfs, int fno)
Definition: splitline.c:116
void bip_free(BIP *bip)
Deallocate BIP data structure.
Definition: bip_enum.c:133
static LINE_MODE process_line(LINE_MODE mode, const LFS *lfs, const int lines, BIP *bip)
Definition: bip_enum.c:179
void lfs_free(LFS *lfs)
Definition: splitline.c:35
static Numb max_coef_val
Definition: bip_enum.c:59
static bool bip_can_overflow(const BIP *bip)
Definition: bip_enum.c:142
int rows
number of rows (constraints)
Definition: bip_enum.c:46
Definition: bip_enum.c:42
#define BIP_MAX_COLS
Definition: bip_enum.c:37
Numb b[BIP_MAX_ROWS]
right hand side
Definition: bip_enum.c:50
int lfs_used_fields(const LFS *lfs)
Definition: splitline.c:109
BIP Enumerator Header.
Definition: bip_enum.c:42
#define mem_check(a)
Definition: mshell.h:71
static Numb min_coef_val
Definition: bip_enum.c:60
LINE_MODE
Definition: bip_enum.c:40
Sense sense[BIP_MAX_ROWS]
equation sense
Definition: bip_enum.c:51
int bip_enumerate(const BIP *bip, bool with_output)
Enumerate all possible solution of a BIP.
Definition: bip_enum.c:439
#define calloc(a, b)
Definition: mshell.h:54
LFS * lfs_split_line(LFS *lfs, const char *line, const char *comment)
Definition: splitline.c:44
static bool bip_is_valid(const BIP *bip)
Check whether BIP data structure is consistent.
Definition: bip_enum.c:66
#define free(a)
Definition: mshell.h:57