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