Scippy

SCIP

Solving Constraint Integer Programs

reader_diff.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2018 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file reader_diff.c
17  * @brief DIFF file reader
18  * @author Jakob Witzig
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <string.h>
26 #if defined(_WIN32) || defined(_WIN64)
27 #else
28 #include <strings.h> /*lint --e{766}*/ /* needed for strncasecmp() */
29 #endif
30 #include <ctype.h>
31 
32 #include "scip/reader_diff.h"
33 
34 #define READER_NAME "diffreader"
35 #define READER_DESC "file reader for changes in the LP file"
36 #define READER_EXTENSION "diff"
37 
38 /*
39  * Data structures
40  */
41 #define LP_MAX_LINELEN 65536
42 #define LP_MAX_PUSHEDTOKENS 2
43 #define LP_INIT_COEFSSIZE 8192
44 
45 /** Section in LP File */
47 {
49 };
50 typedef enum LpSection LPSECTION;
51 
53 {
55 };
56 typedef enum LpExpType LPEXPTYPE;
57 
58 enum LpSense
59 {
61 };
62 typedef enum LpSense LPSENSE;
63 
64 /** LP reading data */
65 struct LpInput
66 {
67  SCIP_FILE* file;
68  char linebuf[LP_MAX_LINELEN+1];
69  char probname[LP_MAX_LINELEN];
70  char objname[LP_MAX_LINELEN];
71  char* token;
72  char* tokenbuf;
73  char* pushedtokens[LP_MAX_PUSHEDTOKENS];
74  int npushedtokens;
75  int linenumber;
76  int linepos;
77  LPSECTION section;
78  SCIP_OBJSENSE objsense;
79  SCIP_Bool haserror;
80  SCIP_Bool comment;
81  SCIP_Bool endline;
82 };
83 typedef struct LpInput LPINPUT;
84 
85 static const char commentchars[] = "\\";
86 
87 
88 /*
89  * Local methods (for reading)
90  */
91 
92 /** issues an error message and marks the LP data to have errors */
93 static
95  SCIP* scip, /**< SCIP data structure */
96  LPINPUT* lpinput, /**< LP reading data */
97  const char* msg /**< error message */
98  )
99 {
100  char formatstr[256];
101 
102  assert(lpinput != NULL);
103 
104  SCIPerrorMessage("Syntax error in line %d ('%s'): %s \n", lpinput->linenumber, lpinput->token, msg);
105  if( lpinput->linebuf[strlen(lpinput->linebuf)-1] == '\n' )
106  {
107  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, " input: %s", lpinput->linebuf);
108  }
109  else
110  {
111  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, " input: %s\n", lpinput->linebuf);
112  }
113  (void) SCIPsnprintf(formatstr, 256, " %%%ds\n", lpinput->linepos);
114  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, (const char*)formatstr, "^");
115  lpinput->section = LP_END;
116  lpinput->haserror = TRUE;
117 }
118 
119 /** returns whether a syntax error was detected */
120 static
122  LPINPUT* lpinput /**< LP reading data */
123  )
124 {
125  assert(lpinput != NULL);
126 
127  return lpinput->haserror;
128 }
129 
130 /** returns whether the given character is a token delimiter */
131 static
133  char c /**< input character */
134  )
135 {
136  switch (c)
137  {
138  case ' ':
139  case '\f':
140  case '\n':
141  case '\r':
142  case '\t':
143  case '\v':
144  case '\0':
145  return TRUE;
146  default:
147  return FALSE;
148  }
149 }
150 
151 /** returns whether the given character is a single token */
152 static
154  char c /**< input character */
155  )
156 {
157  switch (c)
158  {
159  case '-':
160  case '+':
161  case ':':
162  case '<':
163  case '>':
164  case '=':
165  case '[':
166  case ']':
167  case '*':
168  case '^':
169  return TRUE;
170  default:
171  return FALSE;
172  }
173 }
174 
175 /** returns whether the current character is member of a value string */
176 static
178  char c, /**< input character */
179  char nextc, /**< next input character */
180  SCIP_Bool firstchar, /**< is the given character the first char of the token? */
181  SCIP_Bool* hasdot, /**< pointer to update the dot flag */
182  LPEXPTYPE* exptype /**< pointer to update the exponent type */
183  )
184 {
185  assert(hasdot != NULL);
186  assert(exptype != NULL);
187 
188  if( isdigit((unsigned char)c) )
189  return TRUE;
190  else if( (*exptype == LP_EXP_NONE) && !(*hasdot) && (c == '.') && isdigit((unsigned char)nextc) )
191  {
192  *hasdot = TRUE;
193  return TRUE;
194  }
195  else if( !firstchar && (*exptype == LP_EXP_NONE) && (c == 'e' || c == 'E') )
196  {
197  if( nextc == '+' || nextc == '-' )
198  {
199  *exptype = LP_EXP_SIGNED;
200  return TRUE;
201  }
202  else if( isdigit((unsigned char)nextc) )
203  {
204  *exptype = LP_EXP_UNSIGNED;
205  return TRUE;
206  }
207  }
208  else if( (*exptype == LP_EXP_SIGNED) && (c == '+' || c == '-') )
209  {
210  *exptype = LP_EXP_UNSIGNED;
211  return TRUE;
212  }
213 
214  return FALSE;
215 }
216 
217 /** reads the next line from the input file into the line buffer; skips comments;
218  * returns whether a line could be read
219  */
220 static
222  SCIP* scip, /**< SCIP data structure */
223  LPINPUT* lpinput /**< LP reading data */
224  )
225 {
226  int i;
227 
228  assert(lpinput != NULL);
229 
230  /* if we previously detected a comment we have to parse the remaining line away if there is something left */
231  if( !lpinput->endline && lpinput->comment )
232  {
233  SCIPdebugMsg(scip, "Throwing rest of comment away.\n");
234 
235  do
236  {
237  lpinput->linebuf[LP_MAX_LINELEN-2] = '\0';
238  (void)SCIPfgets(lpinput->linebuf, (int) sizeof(lpinput->linebuf), lpinput->file);
239  }
240  while( lpinput->linebuf[LP_MAX_LINELEN-2] != '\0' );
241 
242  lpinput->comment = FALSE;
243  lpinput->endline = TRUE;
244  }
245 
246  /* read next line */
247  lpinput->linepos = 0;
248  lpinput->linebuf[LP_MAX_LINELEN-2] = '\0';
249 
250  if( SCIPfgets(lpinput->linebuf, (int) sizeof(lpinput->linebuf), lpinput->file) == NULL )
251  {
252  /* clear the line, this is really necessary here! */
253  BMSclearMemoryArray(lpinput->linebuf, LP_MAX_LINELEN);
254 
255  return FALSE;
256  }
257 
258  lpinput->linenumber++;
259 
260  /* if line is too long for our buffer correct the buffer and correct position in file */
261  if( lpinput->linebuf[LP_MAX_LINELEN-2] != '\0' )
262  {
263  char* last;
264 
265  /* buffer is full; erase last token since it might be incomplete */
266  lpinput->endline = FALSE;
267  last = strrchr(lpinput->linebuf, ' ');
268 
269  if( last == NULL )
270  {
271  SCIPwarningMessage(scip, "we read %d characters from the file; this might indicate a corrupted input file!",
272  LP_MAX_LINELEN - 2);
273  lpinput->linebuf[LP_MAX_LINELEN-2] = '\0';
274  SCIPdebugMsg(scip, "the buffer might be corrupted\n");
275  }
276  else
277  {
278  SCIPfseek(lpinput->file, -(long) strlen(last) - 1, SEEK_CUR);
279  SCIPdebugMsg(scip, "correct buffer, reread the last %ld characters\n", (long) strlen(last) + 1);
280  *last = '\0';
281  }
282  }
283  else
284  {
285  /* found end of line */
286  lpinput->endline = TRUE;
287  }
288  lpinput->linebuf[LP_MAX_LINELEN-1] = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */
289  lpinput->comment = FALSE;
290 
291  /* skip characters after comment symbol */
292  for( i = 0; commentchars[i] != '\0'; ++i )
293  {
294  char* commentstart;
295 
296  commentstart = strchr(lpinput->linebuf, commentchars[i]);
297  if( commentstart != NULL )
298  {
299  *commentstart = '\0';
300  *(commentstart+1) = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */
301 
302  lpinput->comment = TRUE;
303  break;
304  }
305  }
306 
307  return TRUE;
308 }
309 
310 /** swaps the addresses of two pointers */
311 static
313  char** pointer1, /**< first pointer */
314  char** pointer2 /**< second pointer */
315  )
316 {
317  char* tmp;
318 
319  tmp = *pointer1;
320  *pointer1 = *pointer2;
321  *pointer2 = tmp;
322 }
323 
324 /** reads the next token from the input file into the token buffer; returns whether a token was read */
325 static
327  SCIP* scip, /**< SCIP data structure */
328  LPINPUT* lpinput /**< LP reading data */
329  )
330 {
331  SCIP_Bool hasdot;
332  LPEXPTYPE exptype;
333  char* buf;
334  int tokenlen;
335 
336  assert(lpinput != NULL);
337  assert(lpinput->linepos < LP_MAX_LINELEN);
338 
339  /* check the token stack */
340  if( lpinput->npushedtokens > 0 )
341  {
342  swapPointers(&lpinput->token, &lpinput->pushedtokens[lpinput->npushedtokens-1]);
343  lpinput->npushedtokens--;
344 
345  SCIPdebugMsg(scip, "(line %d) read token again: '%s'\n", lpinput->linenumber, lpinput->token);
346  return TRUE;
347  }
348 
349  /* skip delimiters */
350  buf = lpinput->linebuf;
351  while( isDelimChar(buf[lpinput->linepos]) )
352  {
353  if( buf[lpinput->linepos] == '\0' )
354  {
355  if( !getNextLine(scip, lpinput) )
356  {
357  lpinput->section = LP_END;
358  SCIPdebugMsg(scip, "(line %d) end of file\n", lpinput->linenumber);
359  return FALSE;
360  }
361  assert(lpinput->linepos == 0);
362  }
363  else
364  lpinput->linepos++;
365  }
366  assert(lpinput->linepos < LP_MAX_LINELEN);
367  assert(!isDelimChar(buf[lpinput->linepos]));
368 
369  /* check if the token is a value */
370  hasdot = FALSE;
371  exptype = LP_EXP_NONE;
372  if( isValueChar(buf[lpinput->linepos], buf[lpinput->linepos+1], TRUE, &hasdot, &exptype) )
373  {
374  /* read value token */
375  tokenlen = 0;
376  do
377  {
378  assert(tokenlen < LP_MAX_LINELEN);
379  assert(!isDelimChar(buf[lpinput->linepos]));
380  lpinput->token[tokenlen] = buf[lpinput->linepos];
381  tokenlen++;
382  lpinput->linepos++;
383  }
384  while( isValueChar(buf[lpinput->linepos], buf[lpinput->linepos+1], FALSE, &hasdot, &exptype) );
385  }
386  else
387  {
388  /* read non-value token */
389  tokenlen = 0;
390  do
391  {
392  assert(tokenlen < LP_MAX_LINELEN);
393  lpinput->token[tokenlen] = buf[lpinput->linepos];
394  tokenlen++;
395  lpinput->linepos++;
396  if( tokenlen == 1 && isTokenChar(lpinput->token[0]) )
397  break;
398  }
399  while( !isDelimChar(buf[lpinput->linepos]) && !isTokenChar(buf[lpinput->linepos]) );
400 
401  /* if the token is a power sign '^', skip a following '2'
402  * if the token is an equation sense '<', '>', or '=', skip a following '='
403  * if the token is an equality token '=' and the next character is a '<' or '>', replace the token by the inequality sense
404  */
405  if( tokenlen >= 1 && lpinput->token[tokenlen-1] == '^' && buf[lpinput->linepos] == '2' )
406  {
407  lpinput->linepos++;
408  }
409  if( tokenlen >= 1
410  && (lpinput->token[tokenlen-1] == '<' || lpinput->token[tokenlen-1] == '>' || lpinput->token[tokenlen-1] == '=')
411  && buf[lpinput->linepos] == '=' )
412  {
413  lpinput->linepos++;
414  }
415  else if( lpinput->token[tokenlen-1] == '=' && (buf[lpinput->linepos] == '<' || buf[lpinput->linepos] == '>') )
416  {
417  lpinput->token[tokenlen-1] = buf[lpinput->linepos];
418  lpinput->linepos++;
419  }
420  }
421  assert(tokenlen < LP_MAX_LINELEN);
422  lpinput->token[tokenlen] = '\0';
423 
424  SCIPdebugMsg(scip, "(line %d) read token: '%s'\n", lpinput->linenumber, lpinput->token);
425 
426  return TRUE;
427 }
428 
429 /** puts the current token on the token stack, such that it is read at the next call to getNextToken() */
430 static
432  LPINPUT* lpinput /**< LP reading data */
433  )
434 {
435  assert(lpinput != NULL);
436  assert(lpinput->npushedtokens < LP_MAX_PUSHEDTOKENS);
437 
438  swapPointers(&lpinput->pushedtokens[lpinput->npushedtokens], &lpinput->token);
439  lpinput->npushedtokens++;
440 }
441 
442 /** puts the buffered token on the token stack, such that it is read at the next call to getNextToken() */
443 static
445  LPINPUT* lpinput /**< LP reading data */
446  )
447 {
448  assert(lpinput != NULL);
449  assert(lpinput->npushedtokens < LP_MAX_PUSHEDTOKENS);
450 
451  swapPointers(&lpinput->pushedtokens[lpinput->npushedtokens], &lpinput->tokenbuf);
452  lpinput->npushedtokens++;
453 }
454 
455 /** swaps the current token with the token buffer */
456 static
458  LPINPUT* lpinput /**< LP reading data */
459  )
460 {
461  assert(lpinput != NULL);
462 
463  swapPointers(&lpinput->token, &lpinput->tokenbuf);
464 }
465 
466 /** checks whether the current token is a section identifier, and if yes, switches to the corresponding section */
467 static
469  SCIP* scip, /**< SCIP data structure */
470  LPINPUT* lpinput /**< LP reading data */
471  )
472 {
473  SCIP_Bool iscolon;
474  size_t len;
475 
476  assert(lpinput != NULL);
477 
478  /* remember first token by swapping the token buffer */
479  swapTokenBuffer(lpinput);
480 
481  /* look at next token: if this is a ':', the first token is a name and no section keyword */
482  iscolon = FALSE;
483  if( getNextToken(scip, lpinput) )
484  {
485  iscolon = (*lpinput->token == ':');
486  pushToken(lpinput);
487  }
488 
489  /* reinstall the previous token by swapping back the token buffer */
490  swapTokenBuffer(lpinput);
491 
492  /* check for ':' */
493  if( iscolon )
494  return FALSE;
495 
496  len = strlen(lpinput->token);
497  assert(len < LP_MAX_LINELEN);
498 
499  /* the section keywords are at least 2 characters up to 8 or exactly 15 characters long */
500  if( len > 1 && (len < 9 || len == 15) )
501  {
502  char token[16];
503  int c = 0;
504 
505  while( lpinput->token[c] != '\0' )
506  {
507  token[c] = toupper(lpinput->token[c]); /*lint !e734*/
508  ++c;
509  assert(c < 16);
510  }
511  token[c] = '\0';
512 
513  if( (len == 3 && strcmp(token, "MIN") == 0)
514  || (len == 7 && strcmp(token, "MINIMUM") == 0)
515  || (len == 8 && strcmp(token, "MINIMIZE") == 0) )
516  {
517  SCIPdebugMsg(scip, "(line %d) new section: OBJECTIVE\n", lpinput->linenumber);
518  lpinput->section = LP_OBJECTIVE;
519  lpinput->objsense = SCIP_OBJSENSE_MINIMIZE;
520  return TRUE;
521  }
522 
523  if( (len == 3 && strcmp(token, "MAX") == 0)
524  || (len == 7 && strcmp(token, "MAXIMUM") == 0)
525  || (len == 8 && strcmp(token, "MAXIMIZE") == 0) )
526  {
527  SCIPdebugMsg(scip, "(line %d) new section: OBJECTIVE\n", lpinput->linenumber);
528  lpinput->section = LP_OBJECTIVE;
529  lpinput->objsense = SCIP_OBJSENSE_MAXIMIZE;
530  return TRUE;
531  }
532 
533  if( len == 3 && strcmp(token, "END") == 0 )
534  {
535  SCIPdebugMsg(scip, "(line %d) new section: END\n", lpinput->linenumber);
536  lpinput->section = LP_END;
537  return TRUE;
538  }
539  }
540 
541  return FALSE;
542 }
543 
544 /** returns whether the current token is a sign */
545 static
547  LPINPUT* lpinput, /**< LP reading data */
548  int* sign /**< pointer to update the sign */
549  )
550 {
551  assert(lpinput != NULL);
552  assert(sign != NULL);
553  assert(*sign == +1 || *sign == -1);
554 
555  if( lpinput->token[1] == '\0' )
556  {
557  if( *lpinput->token == '+' )
558  return TRUE;
559  else if( *lpinput->token == '-' )
560  {
561  *sign *= -1;
562  return TRUE;
563  }
564  }
565 
566  return FALSE;
567 }
568 
569 /** returns whether the current token is a value */
570 static
572  SCIP* scip, /**< SCIP data structure */
573  LPINPUT* lpinput, /**< LP reading data */
574  SCIP_Real* value /**< pointer to store the value (unchanged, if token is no value) */
575  )
576 {
577  assert(lpinput != NULL);
578  assert(value != NULL);
579 
580  if( strcasecmp(lpinput->token, "INFINITY") == 0 || strcasecmp(lpinput->token, "INF") == 0 )
581  {
582  *value = SCIPinfinity(scip);
583  return TRUE;
584  }
585  else
586  {
587  double val;
588  char* endptr;
589 
590  val = strtod(lpinput->token, &endptr);
591  if( endptr != lpinput->token && *endptr == '\0' )
592  {
593  *value = val;
594  return TRUE;
595  }
596  }
597 
598  return FALSE;
599 }
600 
601 /** returns whether the current token is an equation sense */
602 static
604  LPINPUT* lpinput, /**< LP reading data */
605  LPSENSE* sense /**< pointer to store the equation sense, or NULL */
606  )
607 {
608  assert(lpinput != NULL);
609 
610  if( strcmp(lpinput->token, "<") == 0 )
611  {
612  if( sense != NULL )
613  *sense = LP_SENSE_LE;
614  return TRUE;
615  }
616  else if( strcmp(lpinput->token, ">") == 0 )
617  {
618  if( sense != NULL )
619  *sense = LP_SENSE_GE;
620  return TRUE;
621  }
622  else if( strcmp(lpinput->token, "=") == 0 )
623  {
624  if( sense != NULL )
625  *sense = LP_SENSE_EQ;
626  return TRUE;
627  }
628 
629  return FALSE;
630 }
631 
632 /** returns the variable with the given name, or creates a new variable if it does not exist */
633 static
635  SCIP* scip, /**< SCIP data structure */
636  char* name, /**< name of the variable */
637  SCIP_VAR** var /**< pointer to store the variable */
638  )
639 {
640  assert(name != NULL);
641  assert(var != NULL);
642 
643  *var = SCIPfindVar(scip, name);
644 
645  if( *var == NULL )
646  return SCIP_READERROR;
647 
648  return SCIP_OKAY;
649 }
650 
651 /** reads the header of the file */
652 static
654  SCIP* scip, /**< SCIP data structure */
655  LPINPUT* lpinput /**< LP reading data */
656  )
657 {
658  assert(lpinput != NULL);
659 
660  /* everything before first section is treated as comment */
661  do
662  {
663  /* get token */
664  if( !getNextToken(scip, lpinput) )
665  return SCIP_OKAY;
666  }
667  while( !isNewSection(scip, lpinput) );
668 
669  return SCIP_OKAY;
670 }
671 
672 /** reads an objective or constraint with name and coefficients */
673 static
675  SCIP* scip, /**< SCIP data structure */
676  LPINPUT* lpinput, /**< LP reading data */
677  SCIP_Bool isobjective, /**< indicates whether we are currently reading the coefficients of the objective */
678  char* name, /**< pointer to store the name of the line; must be at least of size
679  * LP_MAX_LINELEN */
680  int* coefssize, /**< size of vars and coefs arrays */
681  SCIP_VAR*** vars, /**< pointer to store the array with variables (must be freed by caller) */
682  SCIP_Real** coefs, /**< pointer to store the array with coefficients (must be freed by caller) */
683  int* ncoefs, /**< pointer to store the number of coefficients */
684  SCIP_Bool* newsection /**< pointer to store whether a new section was encountered */
685  )
686 {
687  SCIP_Bool havesign;
688  SCIP_Bool havevalue;
689  SCIP_Real coef;
690  int coefsign;
691 
692  assert(lpinput != NULL);
693  assert(name != NULL);
694  assert(coefssize != NULL);
695  assert(vars != NULL);
696  assert(coefs != NULL);
697  assert(ncoefs != NULL);
698  assert(newsection != NULL);
699 
700  *coefssize = 0;
701  *vars = NULL;
702  *coefs = NULL;
703  *name = '\0';
704  *ncoefs = 0;
705  *newsection = FALSE;
706 
707  /* read the first token, which may be the name of the line */
708  if( getNextToken(scip, lpinput) )
709  {
710  /* check if we reached a new section */
711  if( isNewSection(scip, lpinput) )
712  {
713  *newsection = TRUE;
714  return SCIP_OKAY;
715  }
716 
717  /* remember the token in the token buffer */
718  swapTokenBuffer(lpinput);
719 
720  /* get the next token and check, whether it is a colon */
721  if( getNextToken(scip, lpinput) )
722  {
723  if( strcmp(lpinput->token, ":") == 0 )
724  {
725  /* the second token was a colon: the first token is the line name */
726  (void)SCIPmemccpy(name, lpinput->tokenbuf, '\0', LP_MAX_LINELEN);
727 
728  name[LP_MAX_LINELEN - 1] = '\0';
729  SCIPdebugMsg(scip, "(line %d) read constraint name: '%s'\n", lpinput->linenumber, name);
730  }
731  else
732  {
733  /* the second token was no colon: push the tokens back onto the token stack and parse them as coefficients */
734  pushToken(lpinput);
735  pushBufferToken(lpinput);
736  }
737  }
738  else
739  {
740  /* there was only one token left: push it back onto the token stack and parse it as coefficient */
741  pushBufferToken(lpinput);
742  }
743  }
744 
745  /* initialize buffers for storing the coefficients */
746  *coefssize = LP_INIT_COEFSSIZE;
747  SCIP_CALL( SCIPallocBlockMemoryArray(scip, vars, *coefssize) );
748  SCIP_CALL( SCIPallocBlockMemoryArray(scip, coefs, *coefssize) );
749 
750  /* read the coefficients */
751  coefsign = +1;
752  coef = 1.0;
753  havesign = FALSE;
754  havevalue = FALSE;
755  *ncoefs = 0;
756  while( getNextToken(scip, lpinput) )
757  {
758  SCIP_VAR* var;
759 
760  /* check if we read a sign */
761  if( isSign(lpinput, &coefsign) )
762  {
763  SCIPdebugMsg(scip, "(line %d) read coefficient sign: %+d\n", lpinput->linenumber, coefsign);
764  havesign = TRUE;
765  continue;
766  }
767 
768  /* check if we read a value */
769  if( isValue(scip, lpinput, &coef) )
770  {
771  SCIPdebugMsg(scip, "(line %d) read coefficient value: %g with sign %+d\n", lpinput->linenumber, coef, coefsign);
772  if( havevalue )
773  {
774  syntaxError(scip, lpinput, "two consecutive values.");
775  return SCIP_OKAY;
776  }
777  havevalue = TRUE;
778  continue;
779  }
780 
781  /* check if we reached an equation sense */
782  if( isSense(lpinput, NULL) )
783  {
784  if( isobjective )
785  {
786  syntaxError(scip, lpinput, "no sense allowed in objective");
787  return SCIP_OKAY;
788  }
789 
790  /* put the sense back onto the token stack */
791  pushToken(lpinput);
792  break;
793  }
794 
795  /* check if we reached a new section, that will be only allowed when having no current sign and value and if we
796  * are not in the quadratic part
797  */
798  if( (isobjective || (!havevalue && !havesign)) && isNewSection(scip, lpinput) )
799  {
800  if( havesign && !havevalue )
801  {
802  SCIPwarningMessage(scip, "skipped single sign %c without value or variable in objective\n", coefsign == 1 ? '+' : '-');
803  }
804  else if( isobjective && havevalue && !SCIPisZero(scip, coef) )
805  {
806  SCIPwarningMessage(scip, "constant term %+g in objective is skipped\n", coef * coefsign);
807  }
808 
809  *newsection = TRUE;
810  return SCIP_OKAY;
811  }
812 
813  /* check if we start a quadratic part */
814  if( *lpinput->token == '[' )
815  {
816  syntaxError(scip, lpinput, "diff reader does not support quadratic objective function.");
817  return SCIP_READERROR;
818  }
819 
820  /* all but the first coefficient need a sign */
821  if( *ncoefs > 0 && !havesign )
822  {
823  syntaxError(scip, lpinput, "expected sign ('+' or '-') or sense ('<' or '>').");
824  return SCIP_OKAY;
825  }
826 
827  /* check if the last variable should be squared */
828  if( *lpinput->token == '^' )
829  {
830  syntaxError(scip, lpinput, "diff reader does not support quadratic objective function.");
831  return SCIP_READERROR;
832  }
833  else
834  {
835  /* the token is a variable name: get the corresponding variable */
836  SCIP_CALL( getVariable(scip, lpinput->token, &var) );
837  }
838 
839  /* insert the linear coefficient */
840  SCIPdebugMsg(scip, "(line %d) read linear coefficient: %+g<%s>\n", lpinput->linenumber, coefsign * coef, SCIPvarGetName(var));
841  if( !SCIPisZero(scip, coef) )
842  {
843  /* resize the vars and coefs array if needed */
844  if( *ncoefs >= *coefssize )
845  {
846  int oldcoefssize;
847 
848  oldcoefssize = *coefssize;
849  *coefssize *= 2;
850  *coefssize = MAX(*coefssize, (*ncoefs)+1);
851  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, vars, oldcoefssize, *coefssize) );
852  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, coefs, oldcoefssize, *coefssize) );
853  }
854  assert(*ncoefs < *coefssize);
855 
856  /* add coefficient */
857  (*vars)[*ncoefs] = var;
858  (*coefs)[*ncoefs] = coefsign * coef;
859  (*ncoefs)++;
860  }
861 
862  /* reset the flags and coefficient value for the next coefficient */
863  coefsign = +1;
864  coef = 1.0;
865  havesign = FALSE;
866  havevalue = FALSE;
867  }
868 
869  return SCIP_OKAY;
870 }
871 
872 /** reads the objective section */
873 static
875  SCIP* scip, /**< SCIP data structure */
876  LPINPUT* lpinput /**< LP reading data */
877  )
878 {
879  char name[LP_MAX_LINELEN];
880  SCIP_VAR** vars;
881  SCIP_Real* coefs;
882  SCIP_Bool newsection;
883  int coefssize;
884  int ncoefs;
885 
886  assert(lpinput != NULL);
887 
888  /* read the objective coefficients */
889  SCIP_CALL( readCoefficients(scip, lpinput, TRUE, name, &coefssize, &vars, &coefs, &ncoefs, &newsection) );
890 
891  /* change the objective function */
892  SCIP_CALL( SCIPchgReoptObjective(scip, lpinput->objsense, vars, coefs, ncoefs) );
893 
894  /* free memory */
895  SCIPfreeBlockMemoryArrayNull(scip, &coefs, coefssize);
896  SCIPfreeBlockMemoryArrayNull(scip, &vars, coefssize);
897 
898  return SCIP_OKAY;
899 }
900 
901 /** reads a diff file */
902 static
904  SCIP* scip, /**< SCIP data structure */
905  LPINPUT* lpinput, /**< LP reading data */
906  const char* filename /**< name of the input file */
907  )
908 {
909  assert(lpinput != NULL);
910 
911  /* open file */
912  lpinput->file = SCIPfopen(filename, "r");
913  if( lpinput->file == NULL )
914  {
915  SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
916  SCIPprintSysError(filename);
917  return SCIP_NOFILE;
918  }
919 
920  /* free transformed problem */
921  if( SCIPisReoptEnabled(scip) && SCIPgetStage(scip) > SCIP_STAGE_PROBLEM )
922  {
923  SCIP_CALL( SCIPfreeReoptSolve(scip) );
924  }
925  else
926  {
927  SCIP_CALL( SCIPfreeTransform(scip) );
928  }
929 
930  /* parse the file */
931  lpinput->section = LP_START;
932  while( lpinput->section != LP_END && !hasError(lpinput) )
933  {
934  switch( lpinput->section )
935  {
936  case LP_START:
937  SCIP_CALL( readStart(scip, lpinput) );
938  break;
939 
940  case LP_OBJECTIVE:
941  SCIP_CALL( readObjective(scip, lpinput) );
942  break;
943 
944  case LP_END: /* this is already handled in the while() loop */
945  default:
946  SCIPerrorMessage("invalid Diff file section <%d>\n", lpinput->section);
947  return SCIP_INVALIDDATA;
948  }
949  }
950 
951  /* close file */
952  SCIPfclose(lpinput->file);
953 
954  return SCIP_OKAY;
955 }
956 
957 /*
958  * Callback methods of reader
959  */
960 
961 /** copy method for reader plugins (called when SCIP copies plugins) */
962 static
963 SCIP_DECL_READERCOPY(readerCopyDiff)
964 { /*lint --e{715}*/
965  assert(scip != NULL);
966  assert(reader != NULL);
967  assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
968 
969  /* call inclusion method of reader */
971 
972  return SCIP_OKAY;
973 }
974 
975 /** destructor of reader to free user data (called when SCIP is exiting) */
976 static
977 SCIP_DECL_READERFREE(readerFreeDiff)
978 { /*lint --e{715}*/
979  return SCIP_OKAY;
980 }
981 
982 /** problem reading method of reader */
983 static
984 SCIP_DECL_READERREAD(readerReadDiff)
985 { /*lint --e{715}*/
986 
987  SCIP_CALL( SCIPreadDiff(scip, reader, filename, result) );
988 
989  return SCIP_OKAY;
990 }
991 
992 /*
993  * reader specific interface methods
994  */
995 
996 /** includes the lp file reader in SCIP */
998  SCIP* scip /**< SCIP data structure */
999  )
1000 {
1001  SCIP_READER* reader;
1002 
1003  /* include reader */
1005 
1006  /* set non fundamental callbacks via setter functions */
1007  SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyDiff) );
1008  SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeDiff) );
1009  SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadDiff) );
1010 
1011  return SCIP_OKAY;
1012 }
1013 
1014 
1015 /** reads problem from file */
1017  SCIP* scip, /**< SCIP data structure */
1018  SCIP_READER* reader, /**< the file reader itself */
1019  const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */
1020  SCIP_RESULT* result /**< pointer to store the result of the file reading call */
1021  )
1022 { /*lint --e{715}*/
1023  LPINPUT lpinput;
1024  int i;
1025 
1026  /* initialize LP input data */
1027  lpinput.file = NULL;
1028  lpinput.linebuf[0] = '\0';
1029  lpinput.probname[0] = '\0';
1030  lpinput.objname[0] = '\0';
1031  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lpinput.token, LP_MAX_LINELEN) ); /*lint !e506*/
1032  lpinput.token[0] = '\0';
1033  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lpinput.tokenbuf, LP_MAX_LINELEN) ); /*lint !e506*/
1034  lpinput.tokenbuf[0] = '\0';
1035  for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i )
1036  {
1037  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(lpinput.pushedtokens[i]), LP_MAX_LINELEN) ); /*lint !e866 !e506*/
1038  }
1039 
1040  lpinput.npushedtokens = 0;
1041  lpinput.linenumber = 0;
1042  lpinput.linepos = 0;
1043  lpinput.section = LP_START;
1044  lpinput.objsense = SCIP_OBJSENSE_MINIMIZE;
1045  lpinput.haserror = FALSE;
1046  lpinput.comment = FALSE;
1047  lpinput.endline = FALSE;
1048 
1049  /* read the file */
1050  SCIP_CALL( readDiffFile(scip, &lpinput, filename) );
1051 
1052  /* free dynamically allocated memory */
1053  for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i )
1054  {
1055  SCIPfreeBlockMemoryArray(scip, &lpinput.pushedtokens[i], LP_MAX_LINELEN);
1056  }
1057  SCIPfreeBlockMemoryArray(scip, &lpinput.tokenbuf, LP_MAX_LINELEN);
1058  SCIPfreeBlockMemoryArray(scip, &lpinput.token, LP_MAX_LINELEN);
1059 
1060  /* evaluate the result */
1061  if( lpinput.haserror )
1062  return SCIP_READERROR;
1063 
1064  *result = SCIP_SUCCESS;
1065 
1066  return SCIP_OKAY;
1067 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22604
static SCIP_DECL_READERCOPY(readerCopyDiff)
Definition: reader_diff.c:963
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:22593
int SCIPmemccpy(char *dest, const char *src, char stop, unsigned int cnt)
Definition: misc.c:9895
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22587
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:821
static SCIP_Bool isValueChar(char c, char nextc, SCIP_Bool firstchar, SCIP_Bool *hasdot, LPEXPTYPE *exptype)
Definition: reader_diff.c:177
SCIP_RETCODE SCIPreadDiff(SCIP *scip, SCIP_READER *reader, const char *filename, SCIP_RESULT *result)
Definition: reader_diff.c:1016
static SCIP_RETCODE readDiffFile(SCIP *scip, LPINPUT *lpinput, const char *filename)
Definition: reader_diff.c:903
static SCIP_Bool getNextToken(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:326
static void pushToken(LPINPUT *lpinput)
Definition: reader_diff.c:431
static SCIP_Bool isValue(SCIP *scip, LPINPUT *lpinput, SCIP_Real *value)
Definition: reader_diff.c:571
#define READER_NAME
Definition: reader_diff.c:34
diff file reader
const char * SCIPreaderGetName(SCIP_READER *reader)
Definition: reader.c:515
SCIP_RETCODE SCIPincludeReaderDiff(SCIP *scip)
Definition: reader_diff.c:997
#define LP_MAX_PUSHEDTOKENS
Definition: reader_diff.c:42
static SCIP_Bool getNextLine(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:221
SCIP_RETCODE SCIPchgReoptObjective(SCIP *scip, SCIP_OBJSENSE objsense, SCIP_VAR **vars, SCIP_Real *coefs, int nvars)
Definition: scip.c:10943
#define FALSE
Definition: def.h:64
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:47028
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10011
#define TRUE
Definition: def.h:63
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
LpExpType
Definition: reader_diff.c:52
static SCIP_Bool isTokenChar(char c)
Definition: reader_diff.c:153
static SCIP_Bool isDelimChar(char c)
Definition: reader_diff.c:132
static void pushBufferToken(LPINPUT *lpinput)
Definition: reader_diff.c:444
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1267
int SCIPfseek(SCIP_FILE *stream, long offset, int whence)
Definition: fileio.c:199
#define SCIPdebugMsg
Definition: scip.h:455
static SCIP_Bool isSense(LPINPUT *lpinput, LPSENSE *sense)
Definition: reader_diff.c:603
SCIP_RETCODE SCIPfreeReoptSolve(SCIP *scip)
Definition: scip.c:17189
enum LpSection LPSECTION
Definition: reader_diff.c:50
static SCIP_RETCODE readCoefficients(SCIP *scip, LPINPUT *lpinput, SCIP_Bool isobjective, char *name, int *coefssize, SCIP_VAR ***vars, SCIP_Real **coefs, int *ncoefs, SCIP_Bool *newsection)
Definition: reader_diff.c:674
SCIP_VAR * SCIPfindVar(SCIP *scip, const char *name)
Definition: scip.c:12506
SCIP_FILE * SCIPfopen(const char *path, const char *mode)
Definition: fileio.c:140
struct LpInput LPINPUT
Definition: reader_diff.c:83
static SCIP_RETCODE getVariable(SCIP *scip, char *name, SCIP_VAR **var)
Definition: reader_diff.c:634
static const char commentchars[]
Definition: reader_diff.c:85
#define SCIPerrorMessage
Definition: pub_message.h:45
static void swapPointers(char **pointer1, char **pointer2)
Definition: reader_diff.c:312
struct SCIP_File SCIP_FILE
Definition: pub_fileio.h:34
SCIP_Bool SCIPisReoptEnabled(SCIP *scip)
Definition: scip.c:17363
char * SCIPfgets(char *s, int size, SCIP_FILE *stream)
Definition: fileio.c:187
SCIPInterval sign(const SCIPInterval &x)
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16662
static SCIP_RETCODE readStart(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:653
#define SCIP_CALL(x)
Definition: def.h:350
#define LP_MAX_LINELEN
Definition: reader_diff.c:41
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1360
SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
Definition: scip.c:17252
#define SCIP_Bool
Definition: def.h:61
static void syntaxError(SCIP *scip, LPINPUT *lpinput, const char *msg)
Definition: reader_diff.c:94
SCIP_RETCODE SCIPincludeReaderBasic(SCIP *scip, SCIP_READER **readerptr, const char *name, const char *desc, const char *extension, SCIP_READERDATA *readerdata)
Definition: scip.c:5264
void SCIPprintSysError(const char *message)
Definition: misc.c:9920
enum SCIP_Objsense SCIP_OBJSENSE
Definition: type_prob.h:41
#define MAX(x, y)
Definition: tclique_def.h:75
enum LpSense LPSENSE
Definition: reader_diff.c:62
static SCIP_Bool hasError(LPINPUT *lpinput)
Definition: reader_diff.c:121
#define READER_DESC
Definition: reader_diff.c:35
SCIP_RETCODE SCIPsetReaderCopy(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERCOPY((*readercopy)))
Definition: scip.c:5302
static SCIP_DECL_READERREAD(readerReadDiff)
Definition: reader_diff.c:984
#define READER_EXTENSION
Definition: reader_diff.c:36
enum LpExpType LPEXPTYPE
Definition: reader_diff.c:56
#define SCIP_Real
Definition: def.h:149
LpSection
Definition: reader_diff.c:46
static SCIP_RETCODE readObjective(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:874
static SCIP_DECL_READERFREE(readerFreeDiff)
Definition: reader_diff.c:977
SCIP_RETCODE SCIPsetReaderRead(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERREAD((*readerread)))
Definition: scip.c:5350
LpSense
Definition: reader_diff.c:58
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:47076
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:22605
static void swapTokenBuffer(LPINPUT *lpinput)
Definition: reader_diff.c:457
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
int SCIPfclose(SCIP_FILE *fp)
Definition: fileio.c:219
#define LP_INIT_COEFSSIZE
Definition: reader_diff.c:43
SCIP_RETCODE SCIPsetReaderFree(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERFREE((*readerfree)))
Definition: scip.c:5326
static SCIP_Bool isNewSection(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:468
static SCIP_Bool isSign(LPINPUT *lpinput, int *sign)
Definition: reader_diff.c:546