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