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