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