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  assert(buf[lpinput->linepos] != '\0'); /* '\0' is a delim-char, so this assert is redundant, but it helps to suppress a scan-build warning */
379 
380  /* check if the token is a value */
381  hasdot = FALSE;
382  exptype = LP_EXP_NONE;
383  if( isValueChar(buf[lpinput->linepos], buf[lpinput->linepos+1], TRUE, &hasdot, &exptype) )
384  {
385  /* read value token */
386  tokenlen = 0;
387  do
388  {
389  assert(tokenlen < LP_MAX_LINELEN);
390  assert(!isDelimChar(buf[lpinput->linepos]));
391  lpinput->token[tokenlen] = buf[lpinput->linepos];
392  tokenlen++;
393  lpinput->linepos++;
394  }
395  while( isValueChar(buf[lpinput->linepos], buf[lpinput->linepos+1], FALSE, &hasdot, &exptype) );
396  }
397  else
398  {
399  /* read non-value token */
400  tokenlen = 0;
401  do
402  {
403  assert(tokenlen < LP_MAX_LINELEN);
404  lpinput->token[tokenlen] = buf[lpinput->linepos];
405  tokenlen++;
406  lpinput->linepos++;
407  if( tokenlen == 1 && isTokenChar(lpinput->token[0]) )
408  break;
409  }
410  while( !isDelimChar(buf[lpinput->linepos]) && !isTokenChar(buf[lpinput->linepos]) );
411 
412  /* if the token is a power sign '^', skip a following '2'
413  * if the token is an equation sense '<', '>', or '=', skip a following '='
414  * if the token is an equality token '=' and the next character is a '<' or '>', replace the token by the inequality sense
415  */
416  if( tokenlen >= 1 && lpinput->token[tokenlen-1] == '^' && buf[lpinput->linepos] == '2' )
417  {
418  lpinput->linepos++;
419  }
420  if( tokenlen >= 1
421  && (lpinput->token[tokenlen-1] == '<' || lpinput->token[tokenlen-1] == '>' || lpinput->token[tokenlen-1] == '=')
422  && buf[lpinput->linepos] == '=' )
423  {
424  lpinput->linepos++;
425  }
426  else if( lpinput->token[tokenlen-1] == '=' && (buf[lpinput->linepos] == '<' || buf[lpinput->linepos] == '>') )
427  {
428  lpinput->token[tokenlen-1] = buf[lpinput->linepos];
429  lpinput->linepos++;
430  }
431  }
432  assert(tokenlen < LP_MAX_LINELEN);
433  lpinput->token[tokenlen] = '\0';
434 
435  SCIPdebugMsg(scip, "(line %d) read token: '%s'\n", lpinput->linenumber, lpinput->token);
436 
437  return TRUE;
438 }
439 
440 /** puts the current token on the token stack, such that it is read at the next call to getNextToken() */
441 static
443  LPINPUT* lpinput /**< LP reading data */
444  )
445 {
446  assert(lpinput != NULL);
447  assert(lpinput->npushedtokens < LP_MAX_PUSHEDTOKENS);
448 
449  swapPointers(&lpinput->pushedtokens[lpinput->npushedtokens], &lpinput->token);
450  lpinput->npushedtokens++;
451 }
452 
453 /** puts the buffered token on the token stack, such that it is read at the next call to getNextToken() */
454 static
456  LPINPUT* lpinput /**< LP reading data */
457  )
458 {
459  assert(lpinput != NULL);
460  assert(lpinput->npushedtokens < LP_MAX_PUSHEDTOKENS);
461 
462  swapPointers(&lpinput->pushedtokens[lpinput->npushedtokens], &lpinput->tokenbuf);
463  lpinput->npushedtokens++;
464 }
465 
466 /** swaps the current token with the token buffer */
467 static
469  LPINPUT* lpinput /**< LP reading data */
470  )
471 {
472  assert(lpinput != NULL);
473 
474  swapPointers(&lpinput->token, &lpinput->tokenbuf);
475 }
476 
477 /** checks whether the current token is a section identifier, and if yes, switches to the corresponding section */
478 static
480  SCIP* scip, /**< SCIP data structure */
481  LPINPUT* lpinput /**< LP reading data */
482  )
483 {
484  SCIP_Bool iscolon;
485  size_t len;
486 
487  assert(lpinput != NULL);
488 
489  /* remember first token by swapping the token buffer */
490  swapTokenBuffer(lpinput);
491 
492  /* look at next token: if this is a ':', the first token is a name and no section keyword */
493  iscolon = FALSE;
494  if( getNextToken(scip, lpinput) )
495  {
496  iscolon = (*lpinput->token == ':');
497  pushToken(lpinput);
498  }
499 
500  /* reinstall the previous token by swapping back the token buffer */
501  swapTokenBuffer(lpinput);
502 
503  /* check for ':' */
504  if( iscolon )
505  return FALSE;
506 
507  len = strlen(lpinput->token);
508  assert(len < LP_MAX_LINELEN);
509 
510  /* the section keywords are at least 2 characters up to 8 or exactly 15 characters long */
511  if( len > 1 && (len < 9 || len == 15) )
512  {
513  char token[16];
514  int c = 0;
515 
516  while( lpinput->token[c] != '\0' )
517  {
518  token[c] = toupper(lpinput->token[c]); /*lint !e734*/
519  ++c;
520  assert(c < 16);
521  }
522  token[c] = '\0';
523 
524  if( (len == 3 && strcmp(token, "MIN") == 0)
525  || (len == 7 && strcmp(token, "MINIMUM") == 0)
526  || (len == 8 && strcmp(token, "MINIMIZE") == 0) )
527  {
528  SCIPdebugMsg(scip, "(line %d) new section: OBJECTIVE\n", lpinput->linenumber);
529  lpinput->section = LP_OBJECTIVE;
530  lpinput->objsense = SCIP_OBJSENSE_MINIMIZE;
531  return TRUE;
532  }
533 
534  if( (len == 3 && strcmp(token, "MAX") == 0)
535  || (len == 7 && strcmp(token, "MAXIMUM") == 0)
536  || (len == 8 && strcmp(token, "MAXIMIZE") == 0) )
537  {
538  SCIPdebugMsg(scip, "(line %d) new section: OBJECTIVE\n", lpinput->linenumber);
539  lpinput->section = LP_OBJECTIVE;
540  lpinput->objsense = SCIP_OBJSENSE_MAXIMIZE;
541  return TRUE;
542  }
543 
544  if( len == 3 && strcmp(token, "END") == 0 )
545  {
546  SCIPdebugMsg(scip, "(line %d) new section: END\n", lpinput->linenumber);
547  lpinput->section = LP_END;
548  return TRUE;
549  }
550  }
551 
552  return FALSE;
553 }
554 
555 /** returns whether the current token is a sign */
556 static
558  LPINPUT* lpinput, /**< LP reading data */
559  int* sign /**< pointer to update the sign */
560  )
561 {
562  assert(lpinput != NULL);
563  assert(sign != NULL);
564  assert(*sign == +1 || *sign == -1);
565 
566  if( lpinput->token[1] == '\0' )
567  {
568  if( *lpinput->token == '+' )
569  return TRUE;
570  else if( *lpinput->token == '-' )
571  {
572  *sign *= -1;
573  return TRUE;
574  }
575  }
576 
577  return FALSE;
578 }
579 
580 /** returns whether the current token is a value */
581 static
583  SCIP* scip, /**< SCIP data structure */
584  LPINPUT* lpinput, /**< LP reading data */
585  SCIP_Real* value /**< pointer to store the value (unchanged, if token is no value) */
586  )
587 {
588  assert(lpinput != NULL);
589  assert(value != NULL);
590 
591  if( strcasecmp(lpinput->token, "INFINITY") == 0 || strcasecmp(lpinput->token, "INF") == 0 )
592  {
593  *value = SCIPinfinity(scip);
594  return TRUE;
595  }
596  else
597  {
598  double val;
599  char* endptr;
600 
601  val = strtod(lpinput->token, &endptr);
602  if( endptr != lpinput->token && *endptr == '\0' )
603  {
604  *value = val;
605  return TRUE;
606  }
607  }
608 
609  return FALSE;
610 }
611 
612 /** returns whether the current token is an equation sense */
613 static
615  LPINPUT* lpinput, /**< LP reading data */
616  LPSENSE* sense /**< pointer to store the equation sense, or NULL */
617  )
618 {
619  assert(lpinput != NULL);
620 
621  if( strcmp(lpinput->token, "<") == 0 )
622  {
623  if( sense != NULL )
624  *sense = LP_SENSE_LE;
625  return TRUE;
626  }
627  else if( strcmp(lpinput->token, ">") == 0 )
628  {
629  if( sense != NULL )
630  *sense = LP_SENSE_GE;
631  return TRUE;
632  }
633  else if( strcmp(lpinput->token, "=") == 0 )
634  {
635  if( sense != NULL )
636  *sense = LP_SENSE_EQ;
637  return TRUE;
638  }
639 
640  return FALSE;
641 }
642 
643 /** returns the variable with the given name, or creates a new variable if it does not exist */
644 static
646  SCIP* scip, /**< SCIP data structure */
647  char* name, /**< name of the variable */
648  SCIP_VAR** var /**< pointer to store the variable */
649  )
650 {
651  assert(name != NULL);
652  assert(var != NULL);
653 
654  *var = SCIPfindVar(scip, name);
655 
656  if( *var == NULL )
657  return SCIP_READERROR;
658 
659  return SCIP_OKAY;
660 }
661 
662 /** reads the header of the file */
663 static
665  SCIP* scip, /**< SCIP data structure */
666  LPINPUT* lpinput /**< LP reading data */
667  )
668 {
669  assert(lpinput != NULL);
670 
671  /* everything before first section is treated as comment */
672  do
673  {
674  /* get token */
675  if( !getNextToken(scip, lpinput) )
676  return SCIP_OKAY;
677  }
678  while( !isNewSection(scip, lpinput) );
679 
680  return SCIP_OKAY;
681 }
682 
683 /** reads an objective or constraint with name and coefficients */
684 static
686  SCIP* scip, /**< SCIP data structure */
687  LPINPUT* lpinput, /**< LP reading data */
688  SCIP_Bool isobjective, /**< indicates whether we are currently reading the coefficients of the objective */
689  char* name, /**< pointer to store the name of the line; must be at least of size
690  * LP_MAX_LINELEN */
691  int* coefssize, /**< size of vars and coefs arrays */
692  SCIP_VAR*** vars, /**< pointer to store the array with variables (must be freed by caller) */
693  SCIP_Real** coefs, /**< pointer to store the array with coefficients (must be freed by caller) */
694  int* ncoefs, /**< pointer to store the number of coefficients */
695  SCIP_Bool* newsection /**< pointer to store whether a new section was encountered */
696  )
697 {
698  SCIP_Bool havesign;
699  SCIP_Bool havevalue;
700  SCIP_Real coef;
701  int coefsign;
702 
703  assert(lpinput != NULL);
704  assert(name != NULL);
705  assert(coefssize != NULL);
706  assert(vars != NULL);
707  assert(coefs != NULL);
708  assert(ncoefs != NULL);
709  assert(newsection != NULL);
710 
711  *coefssize = 0;
712  *vars = NULL;
713  *coefs = NULL;
714  *name = '\0';
715  *ncoefs = 0;
716  *newsection = FALSE;
717 
718  /* read the first token, which may be the name of the line */
719  if( getNextToken(scip, lpinput) )
720  {
721  /* check if we reached a new section */
722  if( isNewSection(scip, lpinput) )
723  {
724  *newsection = TRUE;
725  return SCIP_OKAY;
726  }
727 
728  /* remember the token in the token buffer */
729  swapTokenBuffer(lpinput);
730 
731  /* get the next token and check, whether it is a colon */
732  if( getNextToken(scip, lpinput) )
733  {
734  if( strcmp(lpinput->token, ":") == 0 )
735  {
736  /* the second token was a colon: the first token is the line name */
737  (void)SCIPmemccpy(name, lpinput->tokenbuf, '\0', LP_MAX_LINELEN);
738 
739  name[LP_MAX_LINELEN - 1] = '\0';
740  SCIPdebugMsg(scip, "(line %d) read constraint name: '%s'\n", lpinput->linenumber, name);
741  }
742  else
743  {
744  /* the second token was no colon: push the tokens back onto the token stack and parse them as coefficients */
745  pushToken(lpinput);
746  pushBufferToken(lpinput);
747  }
748  }
749  else
750  {
751  /* there was only one token left: push it back onto the token stack and parse it as coefficient */
752  pushBufferToken(lpinput);
753  }
754  }
755 
756  /* initialize buffers for storing the coefficients */
757  *coefssize = LP_INIT_COEFSSIZE;
758  SCIP_CALL( SCIPallocBlockMemoryArray(scip, vars, *coefssize) );
759  SCIP_CALL( SCIPallocBlockMemoryArray(scip, coefs, *coefssize) );
760 
761  /* read the coefficients */
762  coefsign = +1;
763  coef = 1.0;
764  havesign = FALSE;
765  havevalue = FALSE;
766  *ncoefs = 0;
767  while( getNextToken(scip, lpinput) )
768  {
769  SCIP_VAR* var;
770 
771  /* check if we read a sign */
772  if( isSign(lpinput, &coefsign) )
773  {
774  SCIPdebugMsg(scip, "(line %d) read coefficient sign: %+d\n", lpinput->linenumber, coefsign);
775  havesign = TRUE;
776  continue;
777  }
778 
779  /* check if we read a value */
780  if( isValue(scip, lpinput, &coef) )
781  {
782  SCIPdebugMsg(scip, "(line %d) read coefficient value: %g with sign %+d\n", lpinput->linenumber, coef, coefsign);
783  if( havevalue )
784  {
785  syntaxError(scip, lpinput, "two consecutive values.");
786  return SCIP_OKAY;
787  }
788  havevalue = TRUE;
789  continue;
790  }
791 
792  /* check if we reached an equation sense */
793  if( isSense(lpinput, NULL) )
794  {
795  if( isobjective )
796  {
797  syntaxError(scip, lpinput, "no sense allowed in objective");
798  return SCIP_OKAY;
799  }
800 
801  /* put the sense back onto the token stack */
802  pushToken(lpinput);
803  break;
804  }
805 
806  /* check if we reached a new section, that will be only allowed when having no current sign and value and if we
807  * are not in the quadratic part
808  */
809  if( (isobjective || (!havevalue && !havesign)) && isNewSection(scip, lpinput) )
810  {
811  if( havesign && !havevalue )
812  {
813  SCIPwarningMessage(scip, "skipped single sign %c without value or variable in objective\n", coefsign == 1 ? '+' : '-');
814  }
815  else if( isobjective && havevalue && !SCIPisZero(scip, coef) )
816  {
817  SCIPwarningMessage(scip, "constant term %+g in objective is skipped\n", coef * coefsign);
818  }
819 
820  *newsection = TRUE;
821  return SCIP_OKAY;
822  }
823 
824  /* check if we start a quadratic part */
825  if( *lpinput->token == '[' )
826  {
827  syntaxError(scip, lpinput, "diff reader does not support quadratic objective function.");
828  return SCIP_READERROR;
829  }
830 
831  /* all but the first coefficient need a sign */
832  if( *ncoefs > 0 && !havesign )
833  {
834  syntaxError(scip, lpinput, "expected sign ('+' or '-') or sense ('<' or '>').");
835  return SCIP_OKAY;
836  }
837 
838  /* check if the last variable should be squared */
839  if( *lpinput->token == '^' )
840  {
841  syntaxError(scip, lpinput, "diff reader does not support quadratic objective function.");
842  return SCIP_READERROR;
843  }
844  else
845  {
846  /* the token is a variable name: get the corresponding variable */
847  SCIP_CALL( getVariable(scip, lpinput->token, &var) );
848  }
849 
850  /* insert the linear coefficient */
851  SCIPdebugMsg(scip, "(line %d) read linear coefficient: %+g<%s>\n", lpinput->linenumber, coefsign * coef, SCIPvarGetName(var));
852  if( !SCIPisZero(scip, coef) )
853  {
854  /* resize the vars and coefs array if needed */
855  if( *ncoefs >= *coefssize )
856  {
857  int oldcoefssize;
858 
859  oldcoefssize = *coefssize;
860  *coefssize *= 2;
861  *coefssize = MAX(*coefssize, (*ncoefs)+1);
862  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, vars, oldcoefssize, *coefssize) );
863  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, coefs, oldcoefssize, *coefssize) );
864  }
865  assert(*ncoefs < *coefssize);
866 
867  /* add coefficient */
868  (*vars)[*ncoefs] = var;
869  (*coefs)[*ncoefs] = coefsign * coef;
870  (*ncoefs)++;
871  }
872 
873  /* reset the flags and coefficient value for the next coefficient */
874  coefsign = +1;
875  coef = 1.0;
876  havesign = FALSE;
877  havevalue = FALSE;
878  }
879 
880  return SCIP_OKAY;
881 }
882 
883 /** reads the objective section */
884 static
886  SCIP* scip, /**< SCIP data structure */
887  LPINPUT* lpinput /**< LP reading data */
888  )
889 {
890  char name[LP_MAX_LINELEN];
891  SCIP_VAR** vars;
892  SCIP_Real* coefs;
893  SCIP_Bool newsection;
894  int coefssize;
895  int ncoefs;
896 
897  assert(lpinput != NULL);
898 
899  /* read the objective coefficients */
900  SCIP_CALL( readCoefficients(scip, lpinput, TRUE, name, &coefssize, &vars, &coefs, &ncoefs, &newsection) );
901 
902  /* change the objective function */
903  SCIP_CALL( SCIPchgReoptObjective(scip, lpinput->objsense, vars, coefs, ncoefs) );
904 
905  /* free memory */
906  SCIPfreeBlockMemoryArrayNull(scip, &coefs, coefssize);
907  SCIPfreeBlockMemoryArrayNull(scip, &vars, coefssize);
908 
909  return SCIP_OKAY;
910 }
911 
912 /** reads a diff file */
913 static
915  SCIP* scip, /**< SCIP data structure */
916  LPINPUT* lpinput, /**< LP reading data */
917  const char* filename /**< name of the input file */
918  )
919 {
920  assert(lpinput != NULL);
921 
922  /* open file */
923  lpinput->file = SCIPfopen(filename, "r");
924  if( lpinput->file == NULL )
925  {
926  SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
927  SCIPprintSysError(filename);
928  return SCIP_NOFILE;
929  }
930 
931  /* free transformed problem */
932  if( SCIPisReoptEnabled(scip) && SCIPgetStage(scip) > SCIP_STAGE_PROBLEM )
933  {
934  SCIP_CALL( SCIPfreeReoptSolve(scip) );
935  }
936  else
937  {
938  SCIP_CALL( SCIPfreeTransform(scip) );
939  }
940 
941  /* parse the file */
942  lpinput->section = LP_START;
943  while( lpinput->section != LP_END && !hasError(lpinput) )
944  {
945  switch( lpinput->section )
946  {
947  case LP_START:
948  SCIP_CALL( readStart(scip, lpinput) );
949  break;
950 
951  case LP_OBJECTIVE:
952  SCIP_CALL( readObjective(scip, lpinput) );
953  break;
954 
955  case LP_END: /* this is already handled in the while() loop */
956  default:
957  SCIPerrorMessage("invalid Diff file section <%d>\n", lpinput->section);
958  return SCIP_INVALIDDATA;
959  }
960  }
961 
962  /* close file */
963  SCIPfclose(lpinput->file);
964 
965  return SCIP_OKAY;
966 }
967 
968 /*
969  * Callback methods of reader
970  */
971 
972 /** copy method for reader plugins (called when SCIP copies plugins) */
973 static
974 SCIP_DECL_READERCOPY(readerCopyDiff)
975 { /*lint --e{715}*/
976  assert(scip != NULL);
977  assert(reader != NULL);
978  assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
979 
980  /* call inclusion method of reader */
982 
983  return SCIP_OKAY;
984 }
985 
986 /** destructor of reader to free user data (called when SCIP is exiting) */
987 static
988 SCIP_DECL_READERFREE(readerFreeDiff)
989 { /*lint --e{715}*/
990  return SCIP_OKAY;
991 }
992 
993 /** problem reading method of reader */
994 static
995 SCIP_DECL_READERREAD(readerReadDiff)
996 { /*lint --e{715}*/
997 
998  SCIP_CALL( SCIPreadDiff(scip, reader, filename, result) );
999 
1000  return SCIP_OKAY;
1001 }
1002 
1003 /*
1004  * reader specific interface methods
1005  */
1006 
1007 /** includes the lp file reader in SCIP */
1009  SCIP* scip /**< SCIP data structure */
1010  )
1011 {
1012  SCIP_READER* reader;
1013 
1014  /* include reader */
1016 
1017  /* set non fundamental callbacks via setter functions */
1018  SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyDiff) );
1019  SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeDiff) );
1020  SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadDiff) );
1021 
1022  return SCIP_OKAY;
1023 }
1024 
1025 
1026 /** reads problem from file */
1028  SCIP* scip, /**< SCIP data structure */
1029  SCIP_READER* reader, /**< the file reader itself */
1030  const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */
1031  SCIP_RESULT* result /**< pointer to store the result of the file reading call */
1032  )
1033 { /*lint --e{715}*/
1034  LPINPUT lpinput;
1035  int i;
1036 
1037  /* initialize LP input data */
1038  lpinput.file = NULL;
1039  lpinput.linebuf[0] = '\0';
1040  lpinput.probname[0] = '\0';
1041  lpinput.objname[0] = '\0';
1042  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lpinput.token, LP_MAX_LINELEN) ); /*lint !e506*/
1043  lpinput.token[0] = '\0';
1044  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lpinput.tokenbuf, LP_MAX_LINELEN) ); /*lint !e506*/
1045  lpinput.tokenbuf[0] = '\0';
1046  for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i )
1047  {
1048  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(lpinput.pushedtokens[i]), LP_MAX_LINELEN) ); /*lint !e866 !e506*/
1049  }
1050 
1051  lpinput.npushedtokens = 0;
1052  lpinput.linenumber = 0;
1053  lpinput.linepos = 0;
1054  lpinput.section = LP_START;
1055  lpinput.objsense = SCIP_OBJSENSE_MINIMIZE;
1056  lpinput.haserror = FALSE;
1057  lpinput.comment = FALSE;
1058  lpinput.endline = FALSE;
1059 
1060  /* read the file */
1061  SCIP_CALL( readDiffFile(scip, &lpinput, filename) );
1062 
1063  /* free dynamically allocated memory */
1064  for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i )
1065  {
1066  SCIPfreeBlockMemoryArray(scip, &lpinput.pushedtokens[i], LP_MAX_LINELEN);
1067  }
1068  SCIPfreeBlockMemoryArray(scip, &lpinput.tokenbuf, LP_MAX_LINELEN);
1069  SCIPfreeBlockMemoryArray(scip, &lpinput.token, LP_MAX_LINELEN);
1070 
1071  /* evaluate the result */
1072  if( lpinput.haserror )
1073  return SCIP_READERROR;
1074 
1075  *result = SCIP_SUCCESS;
1076 
1077  return SCIP_OKAY;
1078 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
static SCIP_DECL_READERCOPY(readerCopyDiff)
Definition: reader_diff.c:974
SCIP_EXPORT const char * SCIPreaderGetName(SCIP_READER *reader)
Definition: reader.c:547
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:86
#define NULL
Definition: def.h:253
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:80
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
static SCIP_RETCODE readDiffFile(SCIP *scip, LPINPUT *lpinput, const char *filename)
Definition: reader_diff.c:914
SCIP_Bool SCIPisReoptEnabled(SCIP *scip)
Definition: scip_solve.c:3438
static SCIP_Bool getNextToken(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:336
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:122
static void pushToken(LPINPUT *lpinput)
Definition: reader_diff.c:442
static SCIP_Bool isValue(SCIP *scip, LPINPUT *lpinput, SCIP_Real *value)
Definition: reader_diff.c:582
#define READER_NAME
Definition: reader_diff.c:44
public solving methods
diff file reader
#define LP_MAX_PUSHEDTOKENS
Definition: reader_diff.c:52
static SCIP_Bool getNextLine(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:231
SCIP_RETCODE SCIPsetReaderRead(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERREAD((*readerread)))
Definition: scip_reader.c:185
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:215
#define FALSE
Definition: def.h:73
SCIP_RETCODE SCIPsetReaderCopy(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERCOPY((*readercopy)))
Definition: scip_reader.c:137
#define TRUE
Definition: def.h:72
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
SCIP_RETCODE SCIPfreeReoptSolve(SCIP *scip)
Definition: scip_solve.c:3264
static void pushBufferToken(LPINPUT *lpinput)
Definition: reader_diff.c:455
int SCIPfseek(SCIP_FILE *stream, long offset, int whence)
Definition: fileio.c:199
#define SCIPdebugMsg
Definition: scip_message.h:69
static SCIP_Bool isSense(LPINPUT *lpinput, LPSENSE *sense)
Definition: reader_diff.c:614
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:685
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:645
SCIP_EXPORT const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16738
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
char * SCIPfgets(char *s, int size, SCIP_FILE *stream)
Definition: fileio.c:187
SCIPInterval sign(const SCIPInterval &x)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE readStart(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:664
SCIP_RETCODE SCIPsetReaderFree(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERFREE((*readerfree)))
Definition: scip_reader.c:161
#define SCIP_CALL(x)
Definition: def.h:365
#define LP_MAX_LINELEN
Definition: reader_diff.c:51
wrapper functions to map file i/o to standard or zlib file i/o
SCIP_Real SCIPinfinity(SCIP *scip)
public data structures and miscellaneous methods
SCIP_RETCODE SCIPchgReoptObjective(SCIP *scip, SCIP_OBJSENSE objsense, SCIP_VAR **vars, SCIP_Real *coefs, int nvars)
Definition: scip_prob.c:1118
#define SCIP_Bool
Definition: def.h:70
static void syntaxError(SCIP *scip, LPINPUT *lpinput, const char *msg)
Definition: reader_diff.c:104
SCIP_RETCODE SCIPincludeReaderDiff(SCIP *scip)
Definition: reader_diff.c:1008
enum SCIP_Objsense SCIP_OBJSENSE
Definition: type_prob.h:41
enum LpSense LPSENSE
Definition: reader_diff.c:72
SCIP_RETCODE SCIPincludeReaderBasic(SCIP *scip, SCIP_READER **readerptr, const char *name, const char *desc, const char *extension, SCIP_READERDATA *readerdata)
Definition: scip_reader.c:99
static SCIP_Bool hasError(LPINPUT *lpinput)
Definition: reader_diff.c:131
#define READER_DESC
Definition: reader_diff.c:45
static SCIP_DECL_READERREAD(readerReadDiff)
Definition: reader_diff.c:995
SCIP_VAR * SCIPfindVar(SCIP *scip, const char *name)
Definition: scip_prob.c:2680
general public methods
#define MAX(x, y)
Definition: def.h:222
#define READER_EXTENSION
Definition: reader_diff.c:46
public methods for message output
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10263
enum LpExpType LPEXPTYPE
Definition: reader_diff.c:66
#define SCIP_Real
Definition: def.h:164
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:885
static SCIP_DECL_READERFREE(readerFreeDiff)
Definition: reader_diff.c:988
void SCIPprintSysError(const char *message)
Definition: misc.c:10172
LpSense
Definition: reader_diff.c:68
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:98
static void swapTokenBuffer(LPINPUT *lpinput)
Definition: reader_diff.c:468
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:120
int SCIPfclose(SCIP_FILE *fp)
Definition: fileio.c:219
#define LP_INIT_COEFSSIZE
Definition: reader_diff.c:53
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:355
public methods for reader plugins
public methods for global and local (sub)problems
int SCIPmemccpy(char *dest, const char *src, char stop, unsigned int cnt)
Definition: misc.c:10147
static SCIP_Bool isNewSection(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:479
SCIP_RETCODE SCIPreadDiff(SCIP *scip, SCIP_READER *reader, const char *filename, SCIP_RESULT *result)
Definition: reader_diff.c:1027
static SCIP_Bool isSign(LPINPUT *lpinput, int *sign)
Definition: reader_diff.c:557
SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
Definition: scip_solve.c:3327