Scippy

SCIP

Solving Constraint Integer Programs

reader_lp.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-2014 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 email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file reader_lp.c
17  * @brief LP file reader
18  * @author Tobias Achterberg
19  * @author Marc Pfetsch
20  * @author Stefan Heinz
21  * @author Stefan Vigerske
22  * @author Michael Winkler
23  * @author Lars Schewe
24  *
25  * @todo write fixed (non-active) variables, e.g., for transformed problem
26  */
27 
28 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
29 
30 #include <stdlib.h>
31 #include <assert.h>
32 #include <string.h>
33 #if defined(_WIN32) || defined(_WIN64)
34 #else
35 #include <strings.h> /*lint --e{766}*/ /* needed for strncasecmp() */
36 #endif
37 #include <ctype.h>
38 
39 #include "scip/reader_lp.h"
40 #include "scip/cons_knapsack.h"
41 #include "scip/cons_linear.h"
42 #include "scip/cons_logicor.h"
43 #include "scip/cons_setppc.h"
44 #include "scip/cons_varbound.h"
45 #include "scip/cons_and.h"
46 #include "scip/cons_sos1.h"
47 #include "scip/cons_sos2.h"
48 #include "scip/cons_indicator.h"
49 #include "scip/cons_quadratic.h"
50 #include "scip/cons_soc.h"
52 #include "scip/pub_misc.h"
53 
54 #define READER_NAME "lpreader"
55 #define READER_DESC "file reader for MIPs in IBM CPLEX's LP file format"
56 #define READER_EXTENSION "lp"
57 
58 #define DEFAULT_LINEARIZE_ANDS TRUE /**< Should possible \"and\"-constraints be linearized when writing the lp file? */
59 #define DEFAULT_AGGRLINEARIZATION_ANDS TRUE /**< Should an aggregated linearization for and constraints be used? */
60 
61 /*
62  * Data structures
63  */
64 
65 #define LP_MAX_LINELEN 65536
66 #define LP_MAX_PUSHEDTOKENS 2
67 #define LP_INIT_COEFSSIZE 8192
68 #define LP_INIT_QUADCOEFSSIZE 16
69 #define LP_MAX_PRINTLEN 561 /**< the maximum length of any line is 560 + '\\0' = 561*/
70 #define LP_MAX_NAMELEN 256 /**< the maximum length for any name is 255 + '\\0' = 256 */
71 #define LP_PRINTLEN 100
72 
73 
74 /** LP reading data */
75 struct SCIP_ReaderData
76 {
77  SCIP_Bool linearizeands;
78  SCIP_Bool aggrlinearizationands;
79 };
80 
81 
82 /** Section in LP File */
84 {
86 };
87 typedef enum LpSection LPSECTION;
88 
90 {
92 };
93 typedef enum LpExpType LPEXPTYPE;
94 
95 enum LpSense
96 {
98 };
99 typedef enum LpSense LPSENSE;
100 
101 /** LP reading data */
102 struct LpInput
103 {
104  SCIP_FILE* file;
105  char linebuf[LP_MAX_LINELEN+1];
106  char probname[LP_MAX_LINELEN];
107  char objname[LP_MAX_LINELEN];
108  char* token;
109  char* tokenbuf;
110  char* pushedtokens[LP_MAX_PUSHEDTOKENS];
111  int npushedtokens;
112  int linenumber;
113  int linepos;
114  LPSECTION section;
115  SCIP_OBJSENSE objsense;
116  SCIP_Bool inlazyconstraints; /**< whether we are currently reading the section for lazy constraints */
117  SCIP_Bool inusercuts; /**< whether we are currently reading the section for user cuts */
118  SCIP_Bool initialconss; /**< should model constraints be marked as initial? */
119  SCIP_Bool dynamicconss; /**< should model constraints be subject to aging? */
120  SCIP_Bool dynamiccols; /**< should columns be added and removed dynamically to the LP? */
121  SCIP_Bool dynamicrows; /**< should rows be added and removed dynamically to the LP? */
122  SCIP_Bool haserror;
123  SCIP_Bool comment;
124  SCIP_Bool endline;
125 };
126 typedef struct LpInput LPINPUT;
127 
128 static const char commentchars[] = "\\";
129 
130 
131 /*
132  * Local methods (for reading)
133  */
134 
135 /** issues an error message and marks the LP data to have errors */
136 static
138  SCIP* scip, /**< SCIP data structure */
139  LPINPUT* lpinput, /**< LP reading data */
140  const char* msg /**< error message */
141  )
142 {
143  char formatstr[256];
144 
145  assert(lpinput != NULL);
146 
147  SCIPerrorMessage("Syntax error in line %d ('%s'): %s \n", lpinput->linenumber, lpinput->token, msg);
148  if( lpinput->linebuf[strlen(lpinput->linebuf)-1] == '\n' )
149  {
150  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, " input: %s", lpinput->linebuf);
151  }
152  else
153  {
154  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, " input: %s\n", lpinput->linebuf);
155  }
156  (void) SCIPsnprintf(formatstr, 256, " %%%ds\n", lpinput->linepos);
157  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, (const char*)formatstr, "^");
158  lpinput->section = LP_END;
159  lpinput->haserror = TRUE;
160 }
161 
162 /** returns whether a syntax error was detected */
163 static
165  LPINPUT* lpinput /**< LP reading data */
166  )
167 {
168  assert(lpinput != NULL);
169 
170  return lpinput->haserror;
171 }
172 
173 /** returns whether the given character is a token delimiter */
174 static
176  char c /**< input character */
177  )
178 {
179  switch (c)
180  {
181  case ' ':
182  case '\f':
183  case '\n':
184  case '\r':
185  case '\t':
186  case '\v':
187  case '\0':
188  return TRUE;
189  default:
190  return FALSE;
191  }
192 }
193 
194 /** returns whether the given character is a single token */
195 static
197  char c /**< input character */
198  )
199 {
200  switch (c)
201  {
202  case '-':
203  case '+':
204  case ':':
205  case '<':
206  case '>':
207  case '=':
208  case '[':
209  case ']':
210  case '*':
211  case '^':
212  return TRUE;
213  default:
214  return FALSE;
215  }
216 }
217 
218 /** returns whether the current character is member of a value string */
219 static
221  char c, /**< input character */
222  char nextc, /**< next input character */
223  SCIP_Bool firstchar, /**< is the given character the first char of the token? */
224  SCIP_Bool* hasdot, /**< pointer to update the dot flag */
225  LPEXPTYPE* exptype /**< pointer to update the exponent type */
226  )
227 {
228  assert(hasdot != NULL);
229  assert(exptype != NULL);
230 
231  if( isdigit((unsigned char)c) )
232  return TRUE;
233  else if( (*exptype == LP_EXP_NONE) && !(*hasdot) && (c == '.') && isdigit((unsigned char)nextc) )
234  {
235  *hasdot = TRUE;
236  return TRUE;
237  }
238  else if( !firstchar && (*exptype == LP_EXP_NONE) && (c == 'e' || c == 'E') )
239  {
240  if( nextc == '+' || nextc == '-' )
241  {
242  *exptype = LP_EXP_SIGNED;
243  return TRUE;
244  }
245  else if( isdigit((unsigned char)nextc) )
246  {
247  *exptype = LP_EXP_UNSIGNED;
248  return TRUE;
249  }
250  }
251  else if( (*exptype == LP_EXP_SIGNED) && (c == '+' || c == '-') )
252  {
253  *exptype = LP_EXP_UNSIGNED;
254  return TRUE;
255  }
256 
257  return FALSE;
258 }
259 
260 /** reads the next line from the input file into the line buffer; skips comments;
261  * returns whether a line could be read
262  */
263 static
265  SCIP* scip, /**< SCIP data structure */
266  LPINPUT* lpinput /**< LP reading data */
267  )
268 {
269  int i;
270 
271  assert(lpinput != NULL);
272 
273  /* if we previously detected a comment we have to parse the remaining line away if there is something left */
274  if( !lpinput->endline && lpinput->comment )
275  {
276  SCIPdebugMessage("Throwing rest of comment away.\n");
277 
278  do
279  {
280  lpinput->linebuf[LP_MAX_LINELEN-2] = '\0';
281  (void)SCIPfgets(lpinput->linebuf, (int) sizeof(lpinput->linebuf), lpinput->file);
282  }
283  while( lpinput->linebuf[LP_MAX_LINELEN-2] != '\0' );
284 
285  lpinput->comment = FALSE;
286  lpinput->endline = TRUE;
287  }
288 
289  /* read next line */
290  lpinput->linepos = 0;
291  lpinput->linebuf[LP_MAX_LINELEN-2] = '\0';
292 
293  if( SCIPfgets(lpinput->linebuf, (int) sizeof(lpinput->linebuf), lpinput->file) == NULL )
294  {
295  /* clear the line, this is really necessary here! */
296  BMSclearMemoryArray(lpinput->linebuf, LP_MAX_LINELEN);
297 
298  return FALSE;
299  }
300 
301  lpinput->linenumber++;
302 
303  /* if line is too long for our buffer correct the buffer and correct position in file */
304  if( lpinput->linebuf[LP_MAX_LINELEN-2] != '\0' )
305  {
306  char* last;
307 
308  /* buffer is full; erase last token since it might be incomplete */
309  lpinput->endline = FALSE;
310  last = strrchr(lpinput->linebuf, ' ');
311 
312  if( last == NULL )
313  {
314  SCIPwarningMessage(scip, "we read %d characters from the file; this might indicate a corrupted input file!",
315  LP_MAX_LINELEN - 2);
316  lpinput->linebuf[LP_MAX_LINELEN-2] = '\0';
317  SCIPdebugMessage("the buffer might be corrupted\n");
318  }
319  else
320  {
321  SCIPfseek(lpinput->file, -(long) strlen(last), SEEK_CUR);
322  SCIPdebugMessage("correct buffer, reread the last %ld characters\n", (long) strlen(last));
323  *last = '\0';
324  }
325  }
326  else
327  {
328  /* found end of line */
329  lpinput->endline = TRUE;
330  }
331  lpinput->linebuf[LP_MAX_LINELEN-1] = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */
332  lpinput->comment = FALSE;
333 
334  /* skip characters after comment symbol */
335  for( i = 0; commentchars[i] != '\0'; ++i )
336  {
337  char* commentstart;
338 
339  commentstart = strchr(lpinput->linebuf, commentchars[i]);
340  if( commentstart != NULL )
341  {
342  *commentstart = '\0';
343  *(commentstart+1) = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */
344 
345  lpinput->comment = TRUE;
346  break;
347  }
348  }
349 
350  return TRUE;
351 }
352 
353 /** swaps the addresses of two pointers */
354 static
356  char** pointer1, /**< first pointer */
357  char** pointer2 /**< second pointer */
358  )
359 {
360  char* tmp;
361 
362  tmp = *pointer1;
363  *pointer1 = *pointer2;
364  *pointer2 = tmp;
365 }
366 
367 /** reads the next token from the input file into the token buffer; returns whether a token was read */
368 static
370  SCIP* scip, /**< SCIP data structure */
371  LPINPUT* lpinput /**< LP reading data */
372  )
373 {
374  SCIP_Bool hasdot;
375  LPEXPTYPE exptype;
376  char* buf;
377  int tokenlen;
378 
379  assert(lpinput != NULL);
380  assert(lpinput->linepos < LP_MAX_LINELEN);
381 
382  /* check the token stack */
383  if( lpinput->npushedtokens > 0 )
384  {
385  swapPointers(&lpinput->token, &lpinput->pushedtokens[lpinput->npushedtokens-1]);
386  lpinput->npushedtokens--;
387 
388  SCIPdebugMessage("(line %d) read token again: '%s'\n", lpinput->linenumber, lpinput->token);
389  return TRUE;
390  }
391 
392  /* skip delimiters */
393  buf = lpinput->linebuf;
394  while( isDelimChar(buf[lpinput->linepos]) )
395  {
396  if( buf[lpinput->linepos] == '\0' )
397  {
398  if( !getNextLine(scip, lpinput) )
399  {
400  lpinput->section = LP_END;
401  SCIPdebugMessage("(line %d) end of file\n", lpinput->linenumber);
402  return FALSE;
403  }
404  assert(lpinput->linepos == 0);
405  }
406  else
407  lpinput->linepos++;
408  }
409  assert(lpinput->linepos < LP_MAX_LINELEN);
410  assert(!isDelimChar(buf[lpinput->linepos]));
411 
412  /* check if the token is a value */
413  hasdot = FALSE;
414  exptype = LP_EXP_NONE;
415  if( isValueChar(buf[lpinput->linepos], buf[lpinput->linepos+1], TRUE, &hasdot, &exptype) )
416  {
417  /* read value token */
418  tokenlen = 0;
419  do
420  {
421  assert(tokenlen < LP_MAX_LINELEN);
422  assert(!isDelimChar(buf[lpinput->linepos]));
423  lpinput->token[tokenlen] = buf[lpinput->linepos];
424  tokenlen++;
425  lpinput->linepos++;
426  }
427  while( isValueChar(buf[lpinput->linepos], buf[lpinput->linepos+1], FALSE, &hasdot, &exptype) );
428  }
429  else
430  {
431  /* read non-value token */
432  tokenlen = 0;
433  do
434  {
435  assert(tokenlen < LP_MAX_LINELEN);
436  lpinput->token[tokenlen] = buf[lpinput->linepos];
437  tokenlen++;
438  lpinput->linepos++;
439  if( tokenlen == 1 && isTokenChar(lpinput->token[0]) )
440  break;
441  }
442  while( !isDelimChar(buf[lpinput->linepos]) && !isTokenChar(buf[lpinput->linepos]) );
443 
444  /* if the token is a power sign '^', skip a following '2'
445  * if the token is an equation sense '<', '>', or '=', skip a following '='
446  * if the token is an equality token '=' and the next character is a '<' or '>', replace the token by the inequality sense
447  */
448  if( tokenlen >= 1 && lpinput->token[tokenlen-1] == '^' && buf[lpinput->linepos] == '2' )
449  {
450  lpinput->linepos++;
451  }
452  if( tokenlen >= 1
453  && (lpinput->token[tokenlen-1] == '<' || lpinput->token[tokenlen-1] == '>' || lpinput->token[tokenlen-1] == '=')
454  && buf[lpinput->linepos] == '=' )
455  {
456  lpinput->linepos++;
457  }
458  else if( lpinput->token[tokenlen-1] == '=' && (buf[lpinput->linepos] == '<' || buf[lpinput->linepos] == '>') )
459  {
460  lpinput->token[tokenlen-1] = buf[lpinput->linepos];
461  lpinput->linepos++;
462  }
463  }
464  assert(tokenlen < LP_MAX_LINELEN);
465  lpinput->token[tokenlen] = '\0';
466 
467  SCIPdebugMessage("(line %d) read token: '%s'\n", lpinput->linenumber, lpinput->token);
468 
469  return TRUE;
470 }
471 
472 /** puts the current token on the token stack, such that it is read at the next call to getNextToken() */
473 static
475  LPINPUT* lpinput /**< LP reading data */
476  )
477 {
478  assert(lpinput != NULL);
479  assert(lpinput->npushedtokens < LP_MAX_PUSHEDTOKENS);
480 
481  swapPointers(&lpinput->pushedtokens[lpinput->npushedtokens], &lpinput->token);
482  lpinput->npushedtokens++;
483 }
484 
485 /** puts the buffered token on the token stack, such that it is read at the next call to getNextToken() */
486 static
488  LPINPUT* lpinput /**< LP reading data */
489  )
490 {
491  assert(lpinput != NULL);
492  assert(lpinput->npushedtokens < LP_MAX_PUSHEDTOKENS);
493 
494  swapPointers(&lpinput->pushedtokens[lpinput->npushedtokens], &lpinput->tokenbuf);
495  lpinput->npushedtokens++;
496 }
497 
498 /** swaps the current token with the token buffer */
499 static
501  LPINPUT* lpinput /**< LP reading data */
502  )
503 {
504  assert(lpinput != NULL);
505 
506  swapPointers(&lpinput->token, &lpinput->tokenbuf);
507 }
508 
509 /** checks whether the current token is a section identifier, and if yes, switches to the corresponding section */
510 static
512  SCIP* scip, /**< SCIP data structure */
513  LPINPUT* lpinput /**< LP reading data */
514  )
515 {
516  SCIP_Bool iscolon;
517  size_t len;
518 
519  assert(lpinput != NULL);
520 
521  /* remember first token by swapping the token buffer */
522  swapTokenBuffer(lpinput);
523 
524  /* look at next token: if this is a ':', the first token is a name and no section keyword */
525  iscolon = FALSE;
526  if( getNextToken(scip, lpinput) )
527  {
528  iscolon = (*lpinput->token == ':');
529  pushToken(lpinput);
530  }
531 
532  /* reinstall the previous token by swapping back the token buffer */
533  swapTokenBuffer(lpinput);
534 
535  /* check for ':' */
536  if( iscolon )
537  return FALSE;
538 
539  len = strlen(lpinput->token);
540  assert(len < LP_MAX_LINELEN);
541 
542  /* the section keywords are at least 2 characters up to 8 or exactly 15 characters long */
543  if( len > 1 && (len < 9 || len == 15) )
544  {
545  char token[16];
546  int c = 0;
547 
548  while( lpinput->token[c] != '\0' )
549  {
550  token[c] = toupper(lpinput->token[c]); /*lint !e734*/
551  ++c;
552  assert(c < 16);
553  }
554  token[c] = '\0';
555 
556  if( (len == 3 && strcmp(token, "MIN") == 0)
557  || (len == 7 && strcmp(token, "MINIMUM") == 0)
558  || (len == 8 && strcmp(token, "MINIMIZE") == 0) )
559  {
560  SCIPdebugMessage("(line %d) new section: OBJECTIVE\n", lpinput->linenumber);
561  lpinput->section = LP_OBJECTIVE;
562  lpinput->objsense = SCIP_OBJSENSE_MINIMIZE;
563  return TRUE;
564  }
565 
566  if( (len == 3 && strcmp(token, "MAX") == 0)
567  || (len == 7 && strcmp(token, "MAXIMUM") == 0)
568  || (len == 8 && strcmp(token, "MAXIMIZE") == 0) )
569  {
570  SCIPdebugMessage("(line %d) new section: OBJECTIVE\n", lpinput->linenumber);
571  lpinput->section = LP_OBJECTIVE;
572  lpinput->objsense = SCIP_OBJSENSE_MAXIMIZE;
573  return TRUE;
574  }
575 
576  if( len == 7 && strcmp(token, "SUBJECT") == 0 )
577  {
578  /* check if the next token is 'TO' */
579  swapTokenBuffer(lpinput);
580  if( getNextToken(scip, lpinput) )
581  {
582  if( strcasecmp(lpinput->token, "TO") == 0 )
583  {
584  SCIPdebugMessage("(line %d) new section: CONSTRAINTS\n", lpinput->linenumber);
585  lpinput->section = LP_CONSTRAINTS;
586  lpinput->inlazyconstraints = FALSE;
587  lpinput->inusercuts = FALSE;
588  return TRUE;
589  }
590  else
591  pushToken(lpinput);
592  }
593  swapTokenBuffer(lpinput);
594  }
595 
596  if( len == 4 && strcmp(token, "SUCH") == 0 )
597  {
598  /* check if the next token is 'THAT' */
599  swapTokenBuffer(lpinput);
600  if( getNextToken(scip, lpinput) )
601  {
602  if( strcasecmp(lpinput->token, "THAT") == 0 )
603  {
604  SCIPdebugMessage("(line %d) new section: CONSTRAINTS\n", lpinput->linenumber);
605  lpinput->section = LP_CONSTRAINTS;
606  lpinput->inlazyconstraints = FALSE;
607  lpinput->inusercuts = FALSE;
608  return TRUE;
609  }
610  else
611  pushToken(lpinput);
612  }
613  swapTokenBuffer(lpinput);
614  }
615 
616  if( (len == 2 && strcmp(token, "ST") == 0)
617  || (len == 3 && strcmp(token, "ST.") == 0)
618  || (len == 4 && strcmp(token, "S.T.") == 0) )
619  {
620  SCIPdebugMessage("(line %d) new section: CONSTRAINTS\n", lpinput->linenumber);
621  lpinput->section = LP_CONSTRAINTS;
622  lpinput->inlazyconstraints = FALSE;
623  lpinput->inusercuts = FALSE;
624  return TRUE;
625  }
626 
627  if( len == 4 && strcmp(token, "LAZY") == 0 )
628  {
629  /* check if the next token is 'CONSTRAINTS' */
630  swapTokenBuffer(lpinput);
631  if( getNextToken(scip, lpinput) )
632  {
633  if( strcasecmp(lpinput->token, "CONSTRAINTS") == 0 )
634  {
635  SCIPdebugMessage("(line %d) new section: CONSTRAINTS (lazy)\n", lpinput->linenumber);
636  lpinput->section = LP_CONSTRAINTS;
637  lpinput->inlazyconstraints = TRUE;
638  lpinput->inusercuts = FALSE;
639  return TRUE;
640  }
641  else
642  pushToken(lpinput);
643  }
644  swapTokenBuffer(lpinput);
645  }
646 
647  if( len == 4 && strcmp(token, "USER") == 0 )
648  {
649  /* check if the next token is 'CUTS' */
650  swapTokenBuffer(lpinput);
651  if( getNextToken(scip, lpinput) )
652  {
653  if( strcasecmp(lpinput->token, "CUTS") == 0 )
654  {
655  SCIPdebugMessage("(line %d) new section: CONSTRAINTS (user cuts)\n", lpinput->linenumber);
656  lpinput->section = LP_CONSTRAINTS;
657  lpinput->inlazyconstraints = FALSE;
658  lpinput->inusercuts = TRUE;
659  return TRUE;
660  }
661  else
662  pushToken(lpinput);
663  }
664  swapTokenBuffer(lpinput);
665  }
666 
667  if( (len == 5 && strcmp(token, "BOUND") == 0)
668  || (len == 6 && strcmp(token, "BOUNDS") == 0) )
669  {
670  SCIPdebugMessage("(line %d) new section: BOUNDS\n", lpinput->linenumber);
671  lpinput->section = LP_BOUNDS;
672  return TRUE;
673  }
674 
675  if( (len == 3 && (strcmp(token, "GEN") == 0 || strcmp(token, "INT") == 0))
676  || (len == 7 && (strcmp(token, "GENERAL") == 0 || strcmp(token, "INTEGER") == 0))
677  || (len == 8 && (strcmp(token, "GENERALS") == 0 || strcmp(token, "INTEGERS") == 0)) )
678  {
679  SCIPdebugMessage("(line %d) new section: GENERALS\n", lpinput->linenumber);
680  lpinput->section = LP_GENERALS;
681  return TRUE;
682  }
683 
684  if( (len == 3 && strcmp(token, "BIN") == 0)
685  || (len == 6 && strcmp(token, "BINARY") == 0)
686  || (len == 8 && strcmp(token, "BINARIES") == 0) )
687  {
688  SCIPdebugMessage("(line %d) new section: BINARIES\n", lpinput->linenumber);
689  lpinput->section = LP_BINARIES;
690  return TRUE;
691  }
692 
693  if( (len == 4 && strcmp(token, "SEMI") == 0)
694  || (len == 5 && strcmp(token, "SEMIS") == 0)
695  || (len == 15 && strcmp(token, "SEMI-CONTINUOUS") == 0) )
696  {
697  SCIPdebugMessage("(line %d) new section: SEMICONTINUOUS\n", lpinput->linenumber);
698  lpinput->section = LP_SEMICONTINUOUS;
699  return TRUE;
700  }
701 
702  if( len == 3 && strcmp(token, "SOS") == 0 )
703  {
704  SCIPdebugMessage("(line %d) new section: SOS\n", lpinput->linenumber);
705  lpinput->section = LP_SOS;
706  return TRUE;
707  }
708 
709  if( len == 3 && strcmp(token, "END") == 0 )
710  {
711  SCIPdebugMessage("(line %d) new section: END\n", lpinput->linenumber);
712  lpinput->section = LP_END;
713  return TRUE;
714  }
715  }
716 
717  return FALSE;
718 }
719 
720 /** returns whether the current token is a sign */
721 static
723  LPINPUT* lpinput, /**< LP reading data */
724  int* sign /**< pointer to update the sign */
725  )
726 {
727  assert(lpinput != NULL);
728  assert(sign != NULL);
729  assert(*sign == +1 || *sign == -1);
730 
731  if( lpinput->token[1] == '\0' )
732  {
733  if( *lpinput->token == '+' )
734  return TRUE;
735  else if( *lpinput->token == '-' )
736  {
737  *sign *= -1;
738  return TRUE;
739  }
740  }
741 
742  return FALSE;
743 }
744 
745 /** returns whether the current token is a value */
746 static
748  SCIP* scip, /**< SCIP data structure */
749  LPINPUT* lpinput, /**< LP reading data */
750  SCIP_Real* value /**< pointer to store the value (unchanged, if token is no value) */
751  )
752 {
753  assert(lpinput != NULL);
754  assert(value != NULL);
755 
756  if( strcasecmp(lpinput->token, "INFINITY") == 0 || strcasecmp(lpinput->token, "INF") == 0 )
757  {
758  *value = SCIPinfinity(scip);
759  return TRUE;
760  }
761  else
762  {
763  double val;
764  char* endptr;
765 
766  val = strtod(lpinput->token, &endptr);
767  if( endptr != lpinput->token && *endptr == '\0' )
768  {
769  *value = val;
770  return TRUE;
771  }
772  }
773 
774  return FALSE;
775 }
776 
777 /** returns whether the current token is an equation sense */
778 static
780  LPINPUT* lpinput, /**< LP reading data */
781  LPSENSE* sense /**< pointer to store the equation sense, or NULL */
782  )
783 {
784  assert(lpinput != NULL);
785 
786  if( strcmp(lpinput->token, "<") == 0 )
787  {
788  if( sense != NULL )
789  *sense = LP_SENSE_LE;
790  return TRUE;
791  }
792  else if( strcmp(lpinput->token, ">") == 0 )
793  {
794  if( sense != NULL )
795  *sense = LP_SENSE_GE;
796  return TRUE;
797  }
798  else if( strcmp(lpinput->token, "=") == 0 )
799  {
800  if( sense != NULL )
801  *sense = LP_SENSE_EQ;
802  return TRUE;
803  }
804 
805  return FALSE;
806 }
807 
808 /** returns the variable with the given name, or creates a new variable if it does not exist */
809 static
811  SCIP* scip, /**< SCIP data structure */
812  char* name, /**< name of the variable */
813  SCIP_VAR** var, /**< pointer to store the variable */
814  SCIP_Bool* created /**< pointer to store whether a new variable was created, or NULL */
815  )
816 {
817  assert(name != NULL);
818  assert(var != NULL);
819 
820  *var = SCIPfindVar(scip, name);
821  if( *var == NULL )
822  {
823  SCIP_VAR* newvar;
824  SCIP_Bool dynamiccols;
825  SCIP_Bool initial;
826  SCIP_Bool removable;
827 
828  SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &dynamiccols) );
829  initial = !dynamiccols;
830  removable = dynamiccols;
831 
832  /* create new variable of the given name */
833  SCIPdebugMessage("creating new variable: <%s>\n", name);
834  SCIP_CALL( SCIPcreateVar(scip, &newvar, name, 0.0, SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS,
835  initial, removable, NULL, NULL, NULL, NULL, NULL) );
836  SCIP_CALL( SCIPaddVar(scip, newvar) );
837  *var = newvar;
838 
839  /* because the variable was added to the problem, it is captured by SCIP and we can safely release it right now
840  * without making the returned *var invalid
841  */
842  SCIP_CALL( SCIPreleaseVar(scip, &newvar) );
843 
844  if( created != NULL )
845  *created = TRUE;
846  }
847  else if( created != NULL )
848  *created = FALSE;
849 
850  return SCIP_OKAY;
851 }
852 
853 /** reads the header of the file */
854 static
856  SCIP* scip, /**< SCIP data structure */
857  LPINPUT* lpinput /**< LP reading data */
858  )
859 {
860  assert(lpinput != NULL);
861 
862  /* everything before first section is treated as comment */
863  do
864  {
865  /* get token */
866  if( !getNextToken(scip, lpinput) )
867  return SCIP_OKAY;
868  }
869  while( !isNewSection(scip, lpinput) );
870 
871  return SCIP_OKAY;
872 }
873 
874 /** reads an objective or constraint with name and coefficients */
875 static
877  SCIP* scip, /**< SCIP data structure */
878  LPINPUT* lpinput, /**< LP reading data */
879  SCIP_Bool isobjective, /**< indicates whether we are currently reading the coefficients of the objective */
880  char* name, /**< pointer to store the name of the line; must be at least of size
881  * LP_MAX_LINELEN */
882  SCIP_VAR*** vars, /**< pointer to store the array with variables (must be freed by caller) */
883  SCIP_Real** coefs, /**< pointer to store the array with coefficients (must be freed by caller) */
884  int* ncoefs, /**< pointer to store the number of coefficients */
885  SCIP_VAR*** quadvars1, /**< pointer to store the array with first variables in quadratic terms (must be freed by caller) */
886  SCIP_VAR*** quadvars2, /**< pointer to store the array with second variables in quadratic terms (must be freed by caller) */
887  SCIP_Real** quadcoefs, /**< pointer to store the array with coefficients in quadratic terms (must be freed by caller) */
888  int* nquadcoefs, /**< pointer to store the number of quadratic coefficients */
889  SCIP_Bool* newsection /**< pointer to store whether a new section was encountered */
890  )
891 {
892  SCIP_Bool havesign;
893  SCIP_Bool havevalue;
894  SCIP_Real coef;
895  int coefsign;
896  int coefssize;
897  SCIP_Bool inquadpart;
898  int quadcoefssize;
899  SCIP_VAR* firstquadvar;
900 
901  assert(lpinput != NULL);
902  assert(name != NULL);
903  assert(vars != NULL);
904  assert(coefs != NULL);
905  assert(ncoefs != NULL);
906  assert(quadvars1 != NULL);
907  assert(quadvars2 != NULL);
908  assert(quadcoefs != NULL);
909  assert(nquadcoefs != NULL);
910  assert(newsection != NULL);
911 
912  *vars = NULL;
913  *coefs = NULL;
914  *quadvars1 = NULL;
915  *quadvars2 = NULL;
916  *quadcoefs = NULL;
917  *name = '\0';
918  *ncoefs = 0;
919  *nquadcoefs = 0;
920  *newsection = FALSE;
921  inquadpart = FALSE;
922 
923  /* read the first token, which may be the name of the line */
924  if( getNextToken(scip, lpinput) )
925  {
926  /* check if we reached a new section */
927  if( isNewSection(scip, lpinput) )
928  {
929  *newsection = TRUE;
930  return SCIP_OKAY;
931  }
932 
933  /* remember the token in the token buffer */
934  swapTokenBuffer(lpinput);
935 
936  /* get the next token and check, whether it is a colon */
937  if( getNextToken(scip, lpinput) )
938  {
939  if( strcmp(lpinput->token, ":") == 0 )
940  {
941  /* the second token was a colon: the first token is the line name */
942  (void)SCIPmemccpy(name, lpinput->tokenbuf, '\0', LP_MAX_LINELEN);
943 
944  name[LP_MAX_LINELEN - 1] = '\0';
945  SCIPdebugMessage("(line %d) read constraint name: '%s'\n", lpinput->linenumber, name);
946  }
947  else
948  {
949  /* the second token was no colon: push the tokens back onto the token stack and parse them as coefficients */
950  pushToken(lpinput);
951  pushBufferToken(lpinput);
952  }
953  }
954  else
955  {
956  /* there was only one token left: push it back onto the token stack and parse it as coefficient */
957  pushBufferToken(lpinput);
958  }
959  }
960 
961  /* initialize buffers for storing the coefficients */
962  coefssize = LP_INIT_COEFSSIZE;
963  SCIP_CALL( SCIPallocMemoryArray(scip, vars, coefssize) );
964  SCIP_CALL( SCIPallocMemoryArray(scip, coefs, coefssize) );
965 
966  quadcoefssize = LP_INIT_QUADCOEFSSIZE;
967  SCIP_CALL( SCIPallocMemoryArray(scip, quadvars1, quadcoefssize) );
968  SCIP_CALL( SCIPallocMemoryArray(scip, quadvars2, quadcoefssize) );
969  SCIP_CALL( SCIPallocMemoryArray(scip, quadcoefs, quadcoefssize) );
970 
971  /* read the coefficients */
972  coefsign = +1;
973  coef = 1.0;
974  havesign = FALSE;
975  havevalue = FALSE;
976  firstquadvar = NULL;
977  *ncoefs = 0;
978  *nquadcoefs = 0;
979  while( getNextToken(scip, lpinput) )
980  {
981  SCIP_VAR* var;
982 
983  /* check if we read a sign */
984  if( isSign(lpinput, &coefsign) )
985  {
986  SCIPdebugMessage("(line %d) read coefficient sign: %+d\n", lpinput->linenumber, coefsign);
987  havesign = TRUE;
988  continue;
989  }
990 
991  /* check if we read a value */
992  if( isValue(scip, lpinput, &coef) )
993  {
994  SCIPdebugMessage("(line %d) read coefficient value: %g with sign %+d\n", lpinput->linenumber, coef, coefsign);
995  if( havevalue )
996  {
997  syntaxError(scip, lpinput, "two consecutive values.");
998  return SCIP_OKAY;
999  }
1000  havevalue = TRUE;
1001  continue;
1002  }
1003 
1004  /* check if we reached an equation sense */
1005  if( isSense(lpinput, NULL) )
1006  {
1007  if( isobjective )
1008  {
1009  syntaxError(scip, lpinput, "no sense allowed in objective");
1010  return SCIP_OKAY;
1011  }
1012 
1013  /* put the sense back onto the token stack */
1014  pushToken(lpinput);
1015  break;
1016  }
1017 
1018  /* check if we reached a new section, that will be only allowed when having no current sign and value and if we
1019  * are not in the qudratic part
1020  */
1021  if( (isobjective || (!havevalue && !havesign)) && !inquadpart && isNewSection(scip, lpinput) )
1022  {
1023  if( havesign && !havevalue )
1024  {
1025  SCIPwarningMessage(scip, "skipped single sign %c without value or variable in objective\n", coefsign == 1 ? '+' : '-');
1026  }
1027  else if( isobjective && havevalue && !SCIPisZero(scip, coef) )
1028  {
1029  SCIPwarningMessage(scip, "constant term %+g in objective is skipped\n", coef * coefsign);
1030  }
1031 
1032  *newsection = TRUE;
1033  return SCIP_OKAY;
1034  }
1035 
1036  /* check if we start a quadratic part */
1037  if( *lpinput->token == '[' )
1038  {
1039  if( inquadpart )
1040  {
1041  syntaxError(scip, lpinput, "cannot start quadratic part while already in quadratic part.");
1042  return SCIP_OKAY;
1043  }
1044  if( havesign && coefsign != +1 )
1045  {
1046  syntaxError(scip, lpinput, "cannot have '-' in front of quadratic part.");
1047  return SCIP_OKAY;
1048  }
1049  if( havevalue )
1050  {
1051  syntaxError(scip, lpinput, "cannot have value in front of quadratic part.");
1052  return SCIP_OKAY;
1053  }
1054 
1055  SCIPdebugMessage("(line %d) start quadratic part\n", lpinput->linenumber);
1056  inquadpart = TRUE;
1057  continue;
1058  }
1059 
1060  /* check if we end a quadratic part */
1061  if( *lpinput->token == ']' )
1062  {
1063  if( !inquadpart )
1064  {
1065  syntaxError(scip, lpinput, "cannot end quadratic part before starting one.");
1066  return SCIP_OKAY;
1067  }
1068  if( havesign || havevalue || firstquadvar != NULL )
1069  {
1070  if( firstquadvar == NULL )
1071  {
1072  syntaxError(scip, lpinput, "expected value or first quadratic variable.");
1073  }
1074  else
1075  {
1076  syntaxError(scip, lpinput, "expected second quadratic variable.");
1077  }
1078  return SCIP_OKAY;
1079  }
1080 
1081  SCIPdebugMessage("(line %d) end quadratic part\n", lpinput->linenumber);
1082  inquadpart = FALSE;
1083 
1084  if( isobjective )
1085  {
1086  /* quadratic part in objective has to end with '/2' */
1087  if( !getNextToken(scip, lpinput) )
1088  {
1089  syntaxError(scip, lpinput, "expected '/2' after end of quadratic part in objective.");
1090  return SCIP_OKAY;
1091  }
1092  if( strcmp(lpinput->token, "/2") == 0 )
1093  {
1094  SCIPdebugMessage("(line %d) saw '/2' after quadratic part in objective\n", lpinput->linenumber);
1095  }
1096  else if( *lpinput->token == '/' )
1097  {
1098  /* maybe it says '/ 2' */
1099  if( !getNextToken(scip, lpinput) || *lpinput->token == '2' )
1100  {
1101  syntaxError(scip, lpinput, "expected '/2' after end of quadratic part in objective.");
1102  return SCIP_OKAY;
1103  }
1104  SCIPdebugMessage("(line %d) saw '/ 2' after quadratic part in objective\n", lpinput->linenumber);
1105  }
1106  else
1107  {
1108  syntaxError(scip, lpinput, "expected '/2' after end of quadratic part in objective.");
1109  return SCIP_OKAY;
1110  }
1111  }
1112 
1113  continue;
1114  }
1115 
1116  /* check if we are in between two quadratic variables */
1117  if( *lpinput->token == '*' )
1118  {
1119  if( !inquadpart )
1120  {
1121  syntaxError(scip, lpinput, "cannot have '*' outside of quadratic part.");
1122  return SCIP_OKAY;
1123  }
1124  if( firstquadvar == NULL )
1125  {
1126  syntaxError(scip, lpinput, "cannot have '*' before first variable in quadratic term.");
1127  return SCIP_OKAY;
1128  }
1129 
1130  continue;
1131  }
1132 
1133  /* all but the first coefficient need a sign */
1134  if( !inquadpart && *ncoefs > 0 && !havesign )
1135  {
1136  syntaxError(scip, lpinput, "expected sign ('+' or '-') or sense ('<' or '>').");
1137  return SCIP_OKAY;
1138  }
1139  if( inquadpart && *nquadcoefs > 0 && !havesign )
1140  {
1141  syntaxError(scip, lpinput, "expected sign ('+' or '-').");
1142  return SCIP_OKAY;
1143  }
1144 
1145  /* check if the last variable should be squared */
1146  if( *lpinput->token == '^' )
1147  {
1148  if( !inquadpart )
1149  {
1150  syntaxError(scip, lpinput, "cannot have squares ('^2') outside of quadratic part.");
1151  return SCIP_OKAY;
1152  }
1153  if( firstquadvar == NULL )
1154  {
1155  syntaxError(scip, lpinput, "cannot have square '^2' before variable.");
1156  return SCIP_OKAY;
1157  }
1158 
1159  var = firstquadvar;
1160  }
1161  else
1162  {
1163  /* the token is a variable name: get the corresponding variable (or create a new one) */
1164  SCIP_CALL( getVariable(scip, lpinput->token, &var, NULL) );
1165  }
1166 
1167  if( !inquadpart )
1168  {
1169  /* insert the linear coefficient */
1170  SCIPdebugMessage("(line %d) read linear coefficient: %+g<%s>\n", lpinput->linenumber, coefsign * coef, SCIPvarGetName(var));
1171  if( !SCIPisZero(scip, coef) )
1172  {
1173  /* resize the vars and coefs array if needed */
1174  if( *ncoefs >= coefssize )
1175  {
1176  coefssize *= 2;
1177  coefssize = MAX(coefssize, (*ncoefs)+1);
1178  SCIP_CALL( SCIPreallocMemoryArray(scip, vars, coefssize) );
1179  SCIP_CALL( SCIPreallocMemoryArray(scip, coefs, coefssize) );
1180  }
1181  assert(*ncoefs < coefssize);
1182 
1183  /* add coefficient */
1184  (*vars)[*ncoefs] = var;
1185  (*coefs)[*ncoefs] = coefsign * coef;
1186  (*ncoefs)++;
1187  }
1188  }
1189  else
1190  {
1191  if( firstquadvar == NULL )
1192  {
1193  /* if first quadratic variable read, store it and continue; expect second one in next round */
1194  firstquadvar = var;
1195  continue;
1196  }
1197 
1198  /* insert the quadratic coefficient */
1199  SCIPdebugMessage("(line %d) read quadratic coefficient: %+g<%s><%s>\n", lpinput->linenumber, (isobjective ? 0.5 : 1) * coefsign * coef, SCIPvarGetName(firstquadvar), SCIPvarGetName(var));
1200  if( !SCIPisZero(scip, coef) )
1201  {
1202  /* resize the vars and coefs array if needed */
1203  if( *nquadcoefs >= quadcoefssize )
1204  {
1205  quadcoefssize *= 2;
1206  quadcoefssize = MAX(quadcoefssize, (*nquadcoefs)+1);
1207  SCIP_CALL( SCIPreallocMemoryArray(scip, quadvars1, quadcoefssize) );
1208  SCIP_CALL( SCIPreallocMemoryArray(scip, quadvars2, quadcoefssize) );
1209  SCIP_CALL( SCIPreallocMemoryArray(scip, quadcoefs, quadcoefssize) );
1210  }
1211  assert(*nquadcoefs < quadcoefssize);
1212 
1213  /* add coefficient */
1214  (*quadvars1)[*nquadcoefs] = firstquadvar;
1215  (*quadvars2)[*nquadcoefs] = var;
1216  (*quadcoefs)[*nquadcoefs] = coefsign * coef;
1217  if( isobjective )
1218  (*quadcoefs)[*nquadcoefs] /= 2.0;
1219  (*nquadcoefs)++;
1220  }
1221  }
1222 
1223  /* reset the flags and coefficient value for the next coefficient */
1224  coefsign = +1;
1225  coef = 1.0;
1226  havesign = FALSE;
1227  havevalue = FALSE;
1228  firstquadvar = NULL;
1229  }
1230 
1231  return SCIP_OKAY;
1232 }
1233 
1234 /** reads the objective section */
1235 static
1237  SCIP* scip, /**< SCIP data structure */
1238  LPINPUT* lpinput /**< LP reading data */
1239  )
1240 {
1241  char name[LP_MAX_LINELEN];
1242  SCIP_VAR** vars;
1243  SCIP_Real* coefs;
1244  int ncoefs;
1245  SCIP_VAR** quadvars1;
1246  SCIP_VAR** quadvars2;
1247  SCIP_Real* quadcoefs;
1248  int nquadcoefs;
1249  SCIP_Bool newsection;
1250 
1251  assert(lpinput != NULL);
1252 
1253  /* read the objective coefficients */
1254  SCIP_CALL( readCoefficients(scip, lpinput, TRUE, name, &vars, &coefs, &ncoefs, &quadvars1, &quadvars2, &quadcoefs, &nquadcoefs, &newsection) );
1255  if( !hasError(lpinput) )
1256  {
1257  int i;
1258 
1259  /* set the linear objective values */
1260  for( i = 0; i < ncoefs; ++i )
1261  {
1262  SCIP_CALL( SCIPchgVarObj(scip, vars[i], SCIPvarGetObj(vars[i]) + coefs[i]) );
1263  }
1264 
1265  /* insert dummy variable and constraint to represent quadratic part of objective; note that
1266  * reading/{initialconss,dynamicconss,dynamicrows,dynamiccols} apply only to model constraints and variables, not
1267  * to an auxiliary objective constraint (otherwise it can happen that an auxiliary objective variable is loose
1268  * with infinite best bound, triggering the problem that an LP that is unbounded because of loose variables with
1269  * infinite best bound cannot be solved)
1270  */
1271  if( nquadcoefs > 0 )
1272  {
1273  SCIP_VAR* quadobjvar;
1274  SCIP_CONS* quadobjcons;
1275  SCIP_Real lhs;
1276  SCIP_Real rhs;
1277  SCIP_Real minusone;
1278 
1279  SCIP_CALL( SCIPcreateVar(scip, &quadobjvar, "quadobjvar", -SCIPinfinity(scip), SCIPinfinity(scip), 1.0,
1281  SCIP_CALL( SCIPaddVar(scip, quadobjvar) );
1282 
1283  if( lpinput->objsense == SCIP_OBJSENSE_MINIMIZE )
1284  {
1285  lhs = -SCIPinfinity(scip);
1286  rhs = 0.0;
1287  }
1288  else
1289  {
1290  lhs = 0.0;
1291  rhs = SCIPinfinity(scip);
1292  }
1293 
1294  minusone = -1.0;
1295  SCIP_CALL( SCIPcreateConsQuadratic(scip, &quadobjcons, "quadobj", 1, &quadobjvar, &minusone, nquadcoefs, quadvars1, quadvars2, quadcoefs, lhs, rhs,
1296  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
1297 
1298  SCIP_CALL( SCIPaddCons(scip, quadobjcons) );
1299  SCIPdebugMessage("(line %d) added constraint <%s> to represent quadratic objective: ", lpinput->linenumber, SCIPconsGetName(quadobjcons));
1300  SCIPdebugPrintCons(scip, quadobjcons, NULL);
1301 
1302  SCIP_CALL( SCIPreleaseCons(scip, &quadobjcons) );
1303  SCIP_CALL( SCIPreleaseVar(scip, &quadobjvar) );
1304  }
1305  }
1306 
1307  /* free memory */
1308  SCIPfreeMemoryArrayNull(scip, &vars);
1309  SCIPfreeMemoryArrayNull(scip, &coefs);
1310  SCIPfreeMemoryArrayNull(scip, &quadvars1);
1311  SCIPfreeMemoryArrayNull(scip, &quadvars2);
1312  SCIPfreeMemoryArrayNull(scip, &quadcoefs);
1313 
1314  return SCIP_OKAY;
1315 }
1316 
1317 /** create indicator constraint */
1318 static
1320  SCIP* scip, /**< SCIP data structure */
1321  LPINPUT* lpinput, /**< LP reading data */
1322  const char* name, /**< name of indicator constraint */
1323  SCIP_VAR* binvar, /**< binary indicator variable */
1324  SCIP_Real binvalue /**< value of indicator part (0/1) */
1325  )
1326 {
1327  char name2[LP_MAX_LINELEN];
1328  SCIP_VAR** linvars;
1329  SCIP_Real* lincoefs;
1330  int nlincoefs;
1331  SCIP_VAR** quadvars1;
1332  SCIP_VAR** quadvars2;
1333  SCIP_Real* quadcoefs;
1334  int nquadcoefs;
1335  SCIP_Bool newsection;
1336  LPSENSE linsense;
1337  SCIP_Real linsidevalue;
1338  int linsidesign;
1339  SCIP_CONS* cons;
1340  SCIP_Real linrhs;
1341  int j;
1342  SCIP_Bool linConsEQ;
1343 
1344  SCIP_Bool initial;
1345  SCIP_Bool separate;
1346  SCIP_Bool enforce;
1347  SCIP_Bool check;
1348  SCIP_Bool propagate;
1349  SCIP_Bool local;
1350  SCIP_Bool dynamic;
1351  SCIP_Bool removable;
1352 
1353  assert( lpinput != NULL );
1354  assert( binvar != NULL );
1355 
1356  /* check that binvalue is 0 or 1 */
1357  if( !SCIPisFeasEQ(scip, binvalue, 0.0) && !SCIPisFeasEQ(scip, binvalue, 1.0) )
1358  {
1359  syntaxError(scip, lpinput, "value for binary variable must be '0' or '1'.");
1360  return SCIP_OKAY;
1361  }
1362 
1363  if( SCIPisFeasEQ(scip, binvalue, 0.0) )
1364  {
1365  SCIP_VAR* negbinvar;
1366  SCIP_Bool infeasible;
1367 
1368  /* At this point we force the variable binvar to be binary, since we need the negated variable. We have to check
1369  * later whether the type of the variable specified in the file agrees with this specification.
1370  */
1371  /* check whether bounds are correct - might already been set if variable is used in another indicator constraint */
1372  if( SCIPvarGetLbGlobal(binvar) < 0.0 )
1373  SCIP_CALL( SCIPchgVarLb(scip, binvar, 0.0) );
1374  if( SCIPvarGetUbGlobal(binvar) > 1.0 )
1375  SCIP_CALL( SCIPchgVarUb(scip, binvar, 1.0) );
1376  SCIP_CALL( SCIPchgVarType(scip, binvar, SCIP_VARTYPE_BINARY, &infeasible) );
1377  /* don't assert feasibility here because the presolver will and should detect a infeasibility */
1378 
1379  SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &negbinvar) );
1380  binvar = negbinvar;
1381  assert( binvar != NULL );
1382  }
1383 
1384  /* read linear constraint */
1385  SCIP_CALL( readCoefficients(scip, lpinput, FALSE, name2, &linvars, &lincoefs, &nlincoefs, &quadvars1, &quadvars2, &quadcoefs, &nquadcoefs, &newsection) );
1386  if( hasError(lpinput) )
1387  goto TERMINATE;
1388  if( newsection )
1389  {
1390  syntaxError(scip, lpinput, "expected constraint.");
1391  goto TERMINATE;
1392  }
1393  if( nquadcoefs > 0 )
1394  {
1395  /* @todo could introduce auxiliary variable and move quadratic part into quadratic constraint? */
1396  syntaxError(scip, lpinput, "quadratic indicator constraints not supported.");
1397  goto TERMINATE;
1398  }
1399  if( name2[0] != '\0' )
1400  {
1401  syntaxError(scip, lpinput, "did not expect name for linear constraint.");
1402  goto TERMINATE;
1403  }
1404 
1405  /* read the constraint sense */
1406  if( !getNextToken(scip, lpinput) || !isSense(lpinput, &linsense) )
1407  {
1408  syntaxError(scip, lpinput, "expected constraint sense '<=', '=', or '>='.");
1409  goto TERMINATE;
1410  }
1411 
1412  /* read the right hand side */
1413  linsidesign = +1;
1414  if( !getNextToken(scip, lpinput) )
1415  {
1416  syntaxError(scip, lpinput, "missing right hand side.");
1417  goto TERMINATE;
1418  }
1419  if( isSign(lpinput, &linsidesign) )
1420  {
1421  if( !getNextToken(scip, lpinput) )
1422  {
1423  syntaxError(scip, lpinput, "missing value of right hand side.");
1424  goto TERMINATE;
1425  }
1426  }
1427  if( !isValue(scip, lpinput, &linsidevalue) )
1428  {
1429  syntaxError(scip, lpinput, "expected value for right hand side.");
1430  goto TERMINATE;
1431  }
1432  linsidevalue *= linsidesign;
1433 
1434  /* assign the left and right hand side, depending on the constraint sense */
1435  linConsEQ = FALSE;
1436  switch( linsense )
1437  {
1438  case LP_SENSE_GE:
1439  linrhs = linsidevalue;
1440  for( j = 0; j < nlincoefs; ++j )
1441  lincoefs[j] *= -1;
1442  break;
1443  case LP_SENSE_LE:
1444  linrhs = linsidevalue;
1445  break;
1446  case LP_SENSE_EQ:
1447  linConsEQ = TRUE;
1448  linrhs = linsidevalue;
1449  break;
1450  case LP_SENSE_NOTHING:
1451  default:
1452  SCIPerrorMessage("invalid constraint sense <%d>\n", linsense);
1453  return SCIP_INVALIDDATA;
1454  }
1455 
1456  /* create and add the indicator constraint */
1457  initial = lpinput->initialconss && !lpinput->inlazyconstraints && !lpinput->inusercuts;
1458  separate = TRUE;
1459  enforce = !lpinput->inusercuts;
1460  check = !lpinput->inusercuts;
1461  propagate = TRUE;
1462  local = FALSE;
1463  dynamic = lpinput->dynamicconss;
1464  removable = lpinput->dynamicrows || lpinput->inusercuts;
1465 
1466  SCIP_CALL( SCIPcreateConsIndicator(scip, &cons, name, binvar, nlincoefs, linvars, lincoefs, linrhs,
1467  initial, separate, enforce, check, propagate, local, dynamic, removable, FALSE) );
1468  SCIP_CALL( SCIPaddCons(scip, cons) );
1469  SCIPdebugMessage("(line %d) created constraint%s: ", lpinput->linenumber,
1470  lpinput->inlazyconstraints ? " (lazy)" : (lpinput->inusercuts ? " (user cut)" : ""));
1471  SCIPdebugPrintCons(scip, cons, NULL);
1472  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1473 
1474  /* create second constraint if it was an equation */
1475  if( linConsEQ )
1476  {
1477  for( j = 0; j < nlincoefs; ++j )
1478  lincoefs[j] *= -1;
1479  linrhs *= -1;
1480  SCIP_CALL( SCIPcreateConsIndicator(scip, &cons, name, binvar, nlincoefs, linvars, lincoefs, linrhs,
1481  initial, separate, enforce, check, propagate, local, dynamic, removable, FALSE) );
1482  SCIP_CALL( SCIPaddCons(scip, cons) );
1483  SCIPdebugMessage("(line %d) created constraint%s: ", lpinput->linenumber,
1484  lpinput->inlazyconstraints ? " (lazy)" : (lpinput->inusercuts ? " (user cut)" : ""));
1485  SCIPdebugPrintCons(scip, cons, NULL);
1486  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1487  }
1488 
1489  TERMINATE:
1490  /* free memory */
1491  SCIPfreeMemoryArrayNull(scip, &linvars);
1492  SCIPfreeMemoryArrayNull(scip, &lincoefs);
1493  SCIPfreeMemoryArrayNull(scip, &quadvars1);
1494  SCIPfreeMemoryArrayNull(scip, &quadvars2);
1495  SCIPfreeMemoryArrayNull(scip, &quadcoefs);
1496 
1497  return SCIP_OKAY;
1498 }
1499 
1500 /** reads the constraints section
1501  *
1502  * Read linear and indicator constraints.
1503  *
1504  * The CPLEX manual says that indicator constraints are of the following form:
1505  *
1506  * [constraintname:] binaryvariable = value -> linear constraint
1507  *
1508  * We also accept "<->".
1509  */
1510 static
1512  SCIP* scip, /**< SCIP data structure */
1513  LPINPUT* lpinput /**< LP reading data */
1514  )
1515 {
1516  char name[LP_MAX_LINELEN];
1517  SCIP_CONS* cons;
1518  SCIP_VAR** vars;
1519  SCIP_Real* coefs;
1520  SCIP_VAR** quadvars1;
1521  SCIP_VAR** quadvars2;
1522  SCIP_Real* quadcoefs;
1523  SCIP_Bool newsection;
1524  LPSENSE sense;
1525  SCIP_Real sidevalue;
1526  SCIP_Real lhs;
1527  SCIP_Real rhs;
1528  SCIP_Bool initial;
1529  SCIP_Bool separate;
1530  SCIP_Bool enforce;
1531  SCIP_Bool check;
1532  SCIP_Bool propagate;
1533  SCIP_Bool local;
1534  SCIP_Bool modifiable;
1535  SCIP_Bool dynamic;
1536  SCIP_Bool removable;
1537  int ncoefs;
1538  int nquadcoefs;
1539  int sidesign;
1540  SCIP_Bool isIndicatorCons;
1541 
1542  assert(lpinput != NULL);
1543 
1544  /* read coefficients */
1545  SCIP_CALL( readCoefficients(scip, lpinput, FALSE, name, &vars, &coefs, &ncoefs, &quadvars1, &quadvars2, &quadcoefs, &nquadcoefs, &newsection) );
1546  if( hasError(lpinput) )
1547  goto TERMINATE;
1548  if( newsection )
1549  {
1550  if( ncoefs > 0 || nquadcoefs > 0 )
1551  syntaxError(scip, lpinput, "expected constraint sense '<=', '=', or '>='.");
1552  goto TERMINATE;
1553  }
1554 
1555  /* read the constraint sense */
1556  if( !getNextToken(scip, lpinput) || !isSense(lpinput, &sense) )
1557  {
1558  syntaxError(scip, lpinput, "expected constraint sense '<=', '=', or '>='.");
1559  goto TERMINATE;
1560  }
1561 
1562  /* read the right hand side */
1563  sidesign = +1;
1564  if( !getNextToken(scip, lpinput) )
1565  {
1566  syntaxError(scip, lpinput, "missing right hand side.");
1567  goto TERMINATE;
1568  }
1569  if( isSign(lpinput, &sidesign) )
1570  {
1571  if( !getNextToken(scip, lpinput) )
1572  {
1573  syntaxError(scip, lpinput, "missing value of right hand side.");
1574  goto TERMINATE;
1575  }
1576  }
1577  if( !isValue(scip, lpinput, &sidevalue) )
1578  {
1579  syntaxError(scip, lpinput, "expected value as right hand side.");
1580  goto TERMINATE;
1581  }
1582  sidevalue *= sidesign;
1583 
1584  /* assign the left and right hand side, depending on the constraint sense */
1585  switch( sense )
1586  {
1587  case LP_SENSE_GE:
1588  lhs = sidevalue;
1589  rhs = SCIPinfinity(scip);
1590  break;
1591  case LP_SENSE_LE:
1592  lhs = -SCIPinfinity(scip);
1593  rhs = sidevalue;
1594  break;
1595  case LP_SENSE_EQ:
1596  lhs = sidevalue;
1597  rhs = sidevalue;
1598  break;
1599  case LP_SENSE_NOTHING:
1600  default:
1601  SCIPerrorMessage("invalid constraint sense <%d>.\n", sense);
1602  return SCIP_INVALIDDATA;
1603  }
1604 
1605  /* check whether we read the first part of an indicator constraint */
1606  isIndicatorCons = FALSE;
1607  if ( getNextToken(scip, lpinput) && !isNewSection(scip, lpinput) )
1608  {
1609  /* check whether we have '<' from a "<->" string */
1610  if ( *lpinput->token == '<' )
1611  {
1612  SCIP_Bool haveequiv = FALSE;
1613  int linepos = lpinput->linepos-1;
1614 
1615  /* check next token - cannot be a new section */
1616  if ( getNextToken(scip, lpinput) )
1617  {
1618  /* check for "<-" */
1619  if ( *lpinput->token == '-' )
1620  {
1621  /* check next token - cannot be a new section */
1622  if ( getNextToken(scip, lpinput) )
1623  {
1624  /* check for "<->" */
1625  if ( *lpinput->token == '>' )
1626  {
1627  lpinput->linepos = linepos;
1628  strcpy(lpinput->token, "<");
1629  syntaxError(scip, lpinput,
1630  "SCIP does not support equivalence (<->) indicator constraints; consider using the \"->\" form.");
1631  haveequiv = TRUE;
1632  }
1633  }
1634  }
1635  }
1636  if ( ! haveequiv )
1637  {
1638  lpinput->linepos = linepos;
1639  strcpy(lpinput->token, "<");
1640  syntaxError(scip, lpinput, "unexpected \"<\".");
1641  }
1642  goto TERMINATE;
1643  }
1644 
1645  /* check for "->" */
1646  if ( *lpinput->token == '-' )
1647  {
1648  /* remember '-' in token buffer */
1649  swapTokenBuffer(lpinput);
1650 
1651  /* check next token - cannot be a new section */
1652  if( getNextToken(scip, lpinput) )
1653  {
1654  /* check for "->" */
1655  if ( *lpinput->token == '>' )
1656  isIndicatorCons = TRUE;
1657  else
1658  {
1659  /* push back last token and '-' */
1660  pushToken(lpinput);
1661  pushBufferToken(lpinput);
1662  }
1663  }
1664  else
1665  pushBufferToken(lpinput);
1666  }
1667  else
1668  pushToken(lpinput);
1669  }
1670 
1671  if( !isIndicatorCons )
1672  {
1673  /* create and add the linear constraint */
1674  initial = lpinput->initialconss && !lpinput->inlazyconstraints && !lpinput->inusercuts;
1675  separate = TRUE;
1676  enforce = !lpinput->inusercuts;
1677  check = !lpinput->inusercuts;
1678  propagate = TRUE;
1679  local = FALSE;
1680  modifiable = FALSE;
1681  dynamic = lpinput->dynamicconss;
1682  removable = lpinput->dynamicrows || lpinput->inusercuts;
1683  if( nquadcoefs == 0 )
1684  {
1685  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, ncoefs, vars, coefs, lhs, rhs,
1686  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, FALSE) );
1687  }
1688  else
1689  {
1690  SCIP_CALL( SCIPcreateConsQuadratic(scip, &cons, name, ncoefs, vars, coefs,
1691  nquadcoefs, quadvars1, quadvars2, quadcoefs, lhs, rhs,
1692  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
1693  }
1694  SCIP_CALL( SCIPaddCons(scip, cons) );
1695  SCIPdebugMessage("(line %d) created constraint%s: ", lpinput->linenumber,
1696  lpinput->inlazyconstraints ? " (lazy)" : (lpinput->inusercuts ? " (user cut)" : ""));
1697  SCIPdebugPrintCons(scip, cons, NULL);
1698  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1699  }
1700  else
1701  {
1702  /* now we should have an indicator constraint */
1703  if( ncoefs != 1 || nquadcoefs > 0 )
1704  {
1705  syntaxError(scip, lpinput, "Indicator part can only consist of one binary variable.");
1706  goto TERMINATE;
1707  }
1708  if( !SCIPisEQ(scip, coefs[0], 1.0) )
1709  {
1710  syntaxError(scip, lpinput, "There cannot be a coefficient before the binary indicator variable.");
1711  goto TERMINATE;
1712  }
1713  if( sense != LP_SENSE_EQ )
1714  {
1715  syntaxError(scip, lpinput, "Indicator part cannot handle equations.");
1716  goto TERMINATE;
1717  }
1718 
1719  SCIP_CALL( createIndicatorConstraint(scip, lpinput, name, vars[0], lhs) );
1720  }
1721 
1722  TERMINATE:
1723  /* free memory */
1724  SCIPfreeMemoryArrayNull(scip, &vars);
1725  SCIPfreeMemoryArrayNull(scip, &coefs);
1726  SCIPfreeMemoryArrayNull(scip, &quadvars1);
1727  SCIPfreeMemoryArrayNull(scip, &quadvars2);
1728  SCIPfreeMemoryArrayNull(scip, &quadcoefs);
1729 
1730  return SCIP_OKAY;
1731 }
1732 
1733 /** reads the bounds section */
1734 static
1736  SCIP* scip, /**< SCIP data structure */
1737  LPINPUT* lpinput /**< LP reading data */
1738  )
1739 {
1740  assert(lpinput != NULL);
1741 
1742  while( getNextToken(scip, lpinput) )
1743  {
1744  SCIP_VAR* var;
1745  SCIP_Real value;
1746  SCIP_Real lb;
1747  SCIP_Real ub;
1748  int sign;
1749  SCIP_Bool hassign;
1750  LPSENSE leftsense;
1751 
1752  /* check if we reached a new section */
1753  if( isNewSection(scip, lpinput) )
1754  return SCIP_OKAY;
1755 
1756  /* default bounds are [0,+inf] */
1757  lb = 0.0;
1758  ub = SCIPinfinity(scip);
1759  leftsense = LP_SENSE_NOTHING;
1760 
1761  /* check if the first token is a sign */
1762  sign = +1;
1763  hassign = isSign(lpinput, &sign);
1764  if( hassign && !getNextToken(scip, lpinput) )
1765  {
1766  syntaxError(scip, lpinput, "expected value.");
1767  return SCIP_OKAY;
1768  }
1769 
1770  /* the first token must be either a value or a variable name */
1771  if( isValue(scip, lpinput, &value) )
1772  {
1773  /* first token is a value: the second token must be a sense */
1774  if( !getNextToken(scip, lpinput) || !isSense(lpinput, &leftsense) )
1775  {
1776  syntaxError(scip, lpinput, "expected bound sense '<=', '=', or '>='.");
1777  return SCIP_OKAY;
1778  }
1779 
1780  /* update the bound corresponding to the sense */
1781  switch( leftsense )
1782  {
1783  case LP_SENSE_GE:
1784  ub = sign * value;
1785  break;
1786  case LP_SENSE_LE:
1787  lb = sign * value;
1788  break;
1789  case LP_SENSE_EQ:
1790  lb = sign * value;
1791  ub = sign * value;
1792  break;
1793  case LP_SENSE_NOTHING:
1794  default:
1795  SCIPerrorMessage("invalid bound sense <%d>\n", leftsense);
1796  return SCIP_INVALIDDATA;
1797  }
1798  }
1799  else if( hassign )
1800  {
1801  syntaxError(scip, lpinput, "expected value.");
1802  return SCIP_OKAY;
1803  }
1804  else
1805  pushToken(lpinput);
1806 
1807  /* the next token must be a variable name */
1808  if( !getNextToken(scip, lpinput) )
1809  {
1810  syntaxError(scip, lpinput, "expected variable name.");
1811  return SCIP_OKAY;
1812  }
1813  SCIP_CALL( getVariable(scip, lpinput->token, &var, NULL) );
1814 
1815  /* the next token might be another sense, or the word "free" */
1816  if( getNextToken(scip, lpinput) )
1817  {
1818  LPSENSE rightsense;
1819 
1820  if( isSense(lpinput, &rightsense) )
1821  {
1822  /* check, if the senses fit */
1823  if( leftsense == LP_SENSE_NOTHING
1824  || (leftsense == LP_SENSE_LE && rightsense == LP_SENSE_LE)
1825  || (leftsense == LP_SENSE_GE && rightsense == LP_SENSE_GE) )
1826  {
1827  if( !getNextToken(scip, lpinput) )
1828  {
1829  syntaxError(scip, lpinput, "expected value or sign.");
1830  return SCIP_OKAY;
1831  }
1832 
1833  /* check if the next token is a sign */
1834  sign = +1;
1835  hassign = isSign(lpinput, &sign);
1836  if( hassign && !getNextToken(scip, lpinput) )
1837  {
1838  syntaxError(scip, lpinput, "expected value.");
1839  return SCIP_OKAY;
1840  }
1841 
1842  /* the next token must be a value */
1843  if( !isValue(scip, lpinput, &value) )
1844  {
1845  syntaxError(scip, lpinput, "expected value.");
1846  return SCIP_OKAY;
1847  }
1848 
1849  /* update the bound corresponding to the sense */
1850  switch( rightsense )
1851  {
1852  case LP_SENSE_GE:
1853  lb = sign * value;
1854  break;
1855  case LP_SENSE_LE:
1856  ub = sign * value;
1857  break;
1858  case LP_SENSE_EQ:
1859  lb = sign * value;
1860  ub = sign * value;
1861  break;
1862  case LP_SENSE_NOTHING:
1863  default:
1864  SCIPerrorMessage("invalid bound sense <%d>\n", leftsense);
1865  return SCIP_INVALIDDATA;
1866  }
1867  }
1868  else
1869  {
1870  syntaxError(scip, lpinput, "the two bound senses do not fit.");
1871  return SCIP_OKAY;
1872  }
1873  }
1874  else if( strcasecmp(lpinput->token, "FREE") == 0 )
1875  {
1876  if( leftsense != LP_SENSE_NOTHING )
1877  {
1878  syntaxError(scip, lpinput, "variable with bound is marked as 'free'.");
1879  return SCIP_OKAY;
1880  }
1881  lb = -SCIPinfinity(scip);
1882  ub = SCIPinfinity(scip);
1883  }
1884  else
1885  {
1886  /* the token was no sense: push it back to the token stack */
1887  pushToken(lpinput);
1888  }
1889  }
1890 
1891  /* change the bounds of the variable if bounds have been given (do not destroy earlier specification of bounds) */
1892  if( lb != 0.0 )
1893  SCIP_CALL( SCIPchgVarLb(scip, var, lb) );
1894  /*lint --e{777}*/
1895  if( ub != SCIPinfinity(scip) )
1896  SCIP_CALL( SCIPchgVarUb(scip, var, ub) );
1897  SCIPdebugMessage("(line %d) new bounds: <%s>[%g,%g]\n", lpinput->linenumber, SCIPvarGetName(var),
1899  }
1900 
1901  return SCIP_OKAY;
1902 }
1903 
1904 /** reads the generals section */
1905 static
1907  SCIP* scip, /**< SCIP data structure */
1908  LPINPUT* lpinput /**< LP reading data */
1909  )
1910 {
1911  assert(lpinput != NULL);
1912 
1913  while( getNextToken(scip, lpinput) )
1914  {
1915  SCIP_VAR* var;
1916  SCIP_Real lb;
1917  SCIP_Real ub;
1918  SCIP_Bool created;
1919  SCIP_Bool infeasible;
1920 
1921  /* check if we reached a new section */
1922  if( isNewSection(scip, lpinput) )
1923  return SCIP_OKAY;
1924 
1925  /* the token must be the name of an existing variable */
1926  SCIP_CALL( getVariable(scip, lpinput->token, &var, &created) );
1927  if( created )
1928  {
1929  syntaxError(scip, lpinput, "unknown variable in generals section.");
1930  return SCIP_OKAY;
1931  }
1932 
1933  lb = SCIPvarGetLbGlobal(var);
1934  ub = SCIPvarGetUbGlobal(var);
1935 
1936  if( !SCIPisFeasIntegral(scip, lb) || !SCIPisFeasIntegral(scip, ub) )
1937  {
1938  SCIPwarningMessage(scip, "variable <%s> declared as integer has non-integral bounds[%.14g, %.14g] -> if feasible, bounds will be adjusted\n", SCIPvarGetName(var), lb, ub);
1939  }
1940 
1941  /* mark the variable to be integral */
1942  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_INTEGER, &infeasible) );
1943  /* don't assert feasibility here because the presolver will and should detect a infeasibility */
1944  }
1945 
1946  return SCIP_OKAY;
1947 }
1948 
1949 /** reads the binaries section */
1950 static
1952  SCIP* scip, /**< SCIP data structure */
1953  LPINPUT* lpinput /**< LP reading data */
1954  )
1955 {
1956  assert(lpinput != NULL);
1957 
1958  while( getNextToken(scip, lpinput) )
1959  {
1960  SCIP_VAR* var;
1961  SCIP_Real lb;
1962  SCIP_Real ub;
1963  SCIP_Bool created;
1964  SCIP_Bool infeasible;
1965 
1966  /* check if we reached a new section */
1967  if( isNewSection(scip, lpinput) )
1968  return SCIP_OKAY;
1969 
1970  /* the token must be the name of an existing variable */
1971  SCIP_CALL( getVariable(scip, lpinput->token, &var, &created) );
1972  if( created )
1973  {
1974  syntaxError(scip, lpinput, "unknown variable in binaries section.");
1975  return SCIP_OKAY;
1976  }
1977 
1978  lb = SCIPvarGetLbGlobal(var);
1979  ub = SCIPvarGetUbGlobal(var);
1980 
1981  if( (!SCIPisFeasZero(scip, lb) && !SCIPisFeasEQ(scip, lb, 1.0)) ||
1982  (!SCIPisFeasZero(scip, ub) && !SCIPisFeasEQ(scip, ub, 1.0) && !SCIPisInfinity(scip, ub)) )
1983  {
1984  SCIPwarningMessage(scip, "variable <%s> declared as binary has non-binary bounds[%.14g, %.14g] -> if feasible, bounds will be adjusted\n", SCIPvarGetName(var), lb, ub);
1985  }
1986 
1987  /* mark the variable to be binary and change its bounds appropriately */
1988  if( SCIPvarGetLbGlobal(var) < 0.0 )
1989  {
1990  SCIP_CALL( SCIPchgVarLb(scip, var, 0.0) );
1991  }
1992  if( SCIPvarGetUbGlobal(var) > 1.0 )
1993  {
1994  SCIP_CALL( SCIPchgVarUb(scip, var, 1.0) );
1995  }
1996  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
1997  /* don't assert feasibility here because the presolver will and should detect a infeasibility */
1998  }
1999 
2000  return SCIP_OKAY;
2001 }
2002 
2003 /** reads the semi-continuous section */
2004 static
2006  SCIP* scip, /**< SCIP data structure */
2007  LPINPUT* lpinput /**< LP reading data */
2008  )
2009 {
2010  SCIP_Real oldlb;
2011  char name[SCIP_MAXSTRLEN];
2012  SCIP_CONS* cons;
2013  SCIP_VAR* var;
2014  SCIP_Bool created;
2015 
2016  SCIP_VAR* vars[2];
2017  SCIP_BOUNDTYPE boundtypes[2];
2018  SCIP_Real bounds[2];
2019 
2020  assert(lpinput != NULL);
2021 
2022  /* if section is titles "semi-continuous", then the parser breaks this into parts */
2023  if( strcasecmp(lpinput->token, "SEMI") == 0 )
2024  {
2025  if( !getNextToken(scip, lpinput) )
2026  {
2027  syntaxError(scip, lpinput, "unexpected end.");
2028  return SCIP_OKAY;
2029  }
2030 
2031  if( strcasecmp(lpinput->token, "-") == 0 )
2032  {
2033  if( !getNextToken(scip, lpinput) || strcasecmp(lpinput->token, "CONTINUOUS") != 0 )
2034  {
2035  syntaxError(scip, lpinput, "expected 'CONTINUOUS' after 'SEMI-'.");
2036  return SCIP_OKAY;
2037  }
2038  }
2039  else
2040  {
2041  pushToken(lpinput);
2042  }
2043  }
2044 
2045  while( getNextToken(scip, lpinput) )
2046  {
2047  /* check if we reached a new section */
2048  if( isNewSection(scip, lpinput) )
2049  return SCIP_OKAY;
2050 
2051  /* the token must be the name of an existing variable */
2052  SCIP_CALL( getVariable(scip, lpinput->token, &var, &created) );
2053  if( created )
2054  {
2055  syntaxError(scip, lpinput, "unknown variable in semi-continuous section.");
2056  return SCIP_OKAY;
2057  }
2058 
2059  if( SCIPvarGetLbGlobal(var) <= 0.0 )
2060  {
2061  SCIPdebugMessage("ignore semi-continuity of variable <%s> with negative lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbGlobal(var));
2062  continue;
2063  }
2064 
2065  oldlb = SCIPvarGetLbGlobal(var);
2066 
2067  /* change the lower bound to 0.0 */
2068  SCIP_CALL( SCIPchgVarLb(scip, var, 0.0) );
2069 
2070  /* add a bound disjunction constraint to say var <= 0.0 or var >= oldlb */
2071  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "semicont_%s", SCIPvarGetName(var));
2072 
2073  vars[0] = var;
2074  vars[1] = var;
2075  boundtypes[0] = SCIP_BOUNDTYPE_UPPER;
2076  boundtypes[1] = SCIP_BOUNDTYPE_LOWER;
2077  bounds[0] = 0.0;
2078  bounds[1] = oldlb;
2079 
2080  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vars, boundtypes, bounds,
2081  !(lpinput->dynamiccols), TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, lpinput->dynamicconss, lpinput->dynamiccols, FALSE) );
2082  SCIP_CALL( SCIPaddCons(scip, cons) );
2083 
2084  SCIPdebugMessage("add bound disjunction constraint for semi-continuity of <%s>:\n\t", SCIPvarGetName(var));
2085  SCIPdebugPrintCons(scip, cons, NULL);
2086 
2087  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2088  }
2089 
2090  return SCIP_OKAY;
2091 }
2092 
2093 /** reads the sos section
2094  *
2095  * The format is as follows:
2096  *
2097  * SOS
2098  * <constraint name>: [S1|S2]:: {<variable name>:<weight>}
2099  * ...
2100  * <constraint name>: [S1|S2]:: {<variable name>:<weight>}
2101  * */
2102 static
2104  SCIP* scip, /**< SCIP data structure */
2105  LPINPUT* lpinput /**< LP reading data */
2106  )
2107 {
2108  SCIP_Bool initial, separate, enforce, check, propagate;
2109  SCIP_Bool local, modifiable, dynamic, removable;
2110  char name[SCIP_MAXSTRLEN];
2111  int cnt = 0;
2112 
2113  assert(lpinput != NULL);
2114 
2115  /* standard settings for SOS constraints: */
2116  initial = lpinput->initialconss;
2117  separate = FALSE;
2118  enforce = TRUE;
2119  check = TRUE;
2120  propagate = TRUE;
2121  local = FALSE;
2122  modifiable = FALSE;
2123  dynamic = lpinput->dynamicconss;
2124  removable = lpinput->dynamicrows;
2125 
2126  while( getNextToken(scip, lpinput) )
2127  {
2128  int type = -1;
2129  SCIP_CONS* cons;
2130 
2131  /* check if we reached a new section */
2132  if( isNewSection(scip, lpinput) )
2133  return SCIP_OKAY;
2134 
2135  /* check for an SOS constraint name */
2136  *name = '\0';
2137 
2138  /* remember the token in the token buffer */
2139  swapTokenBuffer(lpinput);
2140 
2141  /* get the next token and check, whether it is a colon */
2142  if( getNextToken(scip, lpinput) )
2143  {
2144  if( strcmp(lpinput->token, ":") == 0 )
2145  {
2146  /* the second token was a colon: the first token is the constraint name */
2147  (void)SCIPmemccpy(name, lpinput->tokenbuf, '\0', SCIP_MAXSTRLEN);
2148 
2149  name[SCIP_MAXSTRLEN-1] = '\0';
2150  }
2151  else
2152  {
2153  /* the second token was no colon: push the tokens back onto the token stack and parse it next */
2154  pushToken(lpinput);
2155  pushBufferToken(lpinput);
2156  }
2157  }
2158  else
2159  {
2160  /* there was only one token left: push it back onto the token stack and parse it next */
2161  pushBufferToken(lpinput);
2162  }
2163 
2164  /* get type */
2165  if( !getNextToken(scip, lpinput) )
2166  {
2167  syntaxError(scip, lpinput, "expected SOS type: 'S1::' or 'S2::'.");
2168  return SCIP_OKAY;
2169  }
2170  /* check whether constraint name was left out */
2171  if( strcmp(lpinput->token, ":") == 0 )
2172  {
2173  /* we have to push twice ':' and once the type: */
2174  pushToken(lpinput);
2175  lpinput->token[0] = ':';
2176  lpinput->token[1] = '\0';
2177  pushToken(lpinput);
2178  swapTokenBuffer(lpinput);
2179 
2180  /* set artificial name */
2181  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "SOS%d", ++cnt);
2182  }
2183 
2184  /* check whether it is type 1 or type 2 */
2185  if( strcmp(lpinput->token, "S1") == 0 )
2186  {
2187  type = 1;
2188  SCIP_CALL( SCIPcreateConsSOS1(scip, &cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate,
2189  local, modifiable, dynamic, removable) );
2190  }
2191  else if( strcmp(lpinput->token, "S2") == 0 )
2192  {
2193  type = 2;
2194  SCIP_CALL( SCIPcreateConsSOS2(scip, &cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate,
2195  local, modifiable, dynamic, removable) );
2196  }
2197  else
2198  {
2199  syntaxError(scip, lpinput, "SOS constraint type other than 1 or 2 appeared.");
2200  return SCIP_OKAY;
2201  }
2202  assert( type == 1 || type == 2 );
2203 
2204  SCIPdebugMessage("created SOS%d constraint <%s>\n", type, name);
2205 
2206  /* make sure that a colons follows */
2207  if( !getNextToken(scip, lpinput) || strcmp(lpinput->token, ":") != 0 )
2208  {
2209  syntaxError(scip, lpinput, "SOS constraint type has to be followed by two colons.");
2210  return SCIP_OKAY;
2211  }
2212 
2213  /* make sure that another colons follows */
2214  if( !getNextToken(scip, lpinput) || strcmp(lpinput->token, ":") != 0 )
2215  {
2216  syntaxError(scip, lpinput, "SOS constraint type has to be followed by two colons.");
2217  return SCIP_OKAY;
2218  }
2219 
2220  /* parse elements of SOS constraint */
2221  while( getNextToken(scip, lpinput) )
2222  {
2223  SCIP_VAR* var;
2224  SCIP_Real weight;
2225 
2226  /* check if we reached a new section */
2227  if( isNewSection(scip, lpinput) )
2228  break;
2229 
2230  /* remember the token in the token buffer */
2231  swapTokenBuffer(lpinput);
2232 
2233  /* get variable and colon */
2234  var = SCIPfindVar(scip, lpinput->tokenbuf);
2235 
2236  /* if token is a variable name */
2237  if( var == NULL )
2238  {
2239  pushBufferToken(lpinput);
2240  break;
2241  }
2242  else
2243  {
2244  SCIPdebugMessage("found variable <%s>\n", SCIPvarGetName(var));
2245  if( !getNextToken(scip, lpinput) || strcmp(lpinput->token, ":") != 0 )
2246  {
2247  syntaxError(scip, lpinput, "expected colon and weight.");
2248  return SCIP_OKAY;
2249  }
2250  /* check next token */
2251  if( !getNextToken(scip, lpinput) )
2252  {
2253  /* push back token, since it could be the name of a new constraint */
2254  pushToken(lpinput);
2255  pushBufferToken(lpinput);
2256  break;
2257  }
2258  else
2259  {
2260  /* get weight */
2261  if( !isValue(scip, lpinput, &weight) )
2262  {
2263  /* push back token, since it could be the name of a new constraint */
2264  pushToken(lpinput);
2265  pushBufferToken(lpinput);
2266  break;
2267  }
2268  else
2269  {
2270  /* we now know that we have a variable/weight pair -> add variable*/
2271  switch( type )
2272  {
2273  case 1:
2274  SCIP_CALL( SCIPaddVarSOS1(scip, cons, var, weight) );
2275  break;
2276  case 2:
2277  SCIP_CALL( SCIPaddVarSOS2(scip, cons, var, weight) );
2278  break;
2279  default:
2280  SCIPerrorMessage("unknown SOS type: <%d>\n", type); /* should not happen */
2281  SCIPABORT();
2282  return SCIP_INVALIDDATA; /*lint !e527*/
2283  }
2284  SCIPdebugMessage("added variable <%s> with weight %g.\n", SCIPvarGetName(var), weight);
2285  }
2286  }
2287  }
2288  }
2289 
2290  /* add the SOS constraint */
2291  SCIP_CALL( SCIPaddCons(scip, cons) );
2292  SCIPdebugMessage("(line %d) added constraint <%s>: ", lpinput->linenumber, SCIPconsGetName(cons));
2293  SCIPdebugPrintCons(scip, cons, NULL);
2294  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2295  }
2296 
2297  return SCIP_OKAY;
2298 }
2299 
2300 /** reads an LP file
2301  *
2302  * @todo check whether variables forced to be binary for the creation of indicator constraints are
2303  * really specified to be binary (or general with 0/1 bounds) in the file.
2304  */
2305 static
2307  SCIP* scip, /**< SCIP data structure */
2308  LPINPUT* lpinput, /**< LP reading data */
2309  const char* filename /**< name of the input file */
2310  )
2311 {
2312  assert(lpinput != NULL);
2313 
2314  /* open file */
2315  lpinput->file = SCIPfopen(filename, "r");
2316  if( lpinput->file == NULL )
2317  {
2318  SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
2319  SCIPprintSysError(filename);
2320  return SCIP_NOFILE;
2321  }
2322 
2323  /* create problem */
2324  SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
2325 
2326  /* parse the file */
2327  lpinput->section = LP_START;
2328  while( lpinput->section != LP_END && !hasError(lpinput) )
2329  {
2330  switch( lpinput->section )
2331  {
2332  case LP_START:
2333  SCIP_CALL( readStart(scip, lpinput) );
2334  break;
2335 
2336  case LP_OBJECTIVE:
2337  SCIP_CALL( readObjective(scip, lpinput) );
2338  break;
2339 
2340  case LP_CONSTRAINTS:
2341  SCIP_CALL( readConstraints(scip, lpinput) );
2342  break;
2343 
2344  case LP_BOUNDS:
2345  SCIP_CALL( readBounds(scip, lpinput) );
2346  break;
2347 
2348  case LP_GENERALS:
2349  SCIP_CALL( readGenerals(scip, lpinput) );
2350  break;
2351 
2352  case LP_BINARIES:
2353  SCIP_CALL( readBinaries(scip, lpinput) );
2354  break;
2355 
2356  case LP_SEMICONTINUOUS:
2357  SCIP_CALL( readSemicontinuous(scip, lpinput) );
2358  break;
2359 
2360  case LP_SOS:
2361  SCIP_CALL( readSos(scip, lpinput) );
2362  break;
2363 
2364  case LP_END: /* this is already handled in the while() loop */
2365  default:
2366  SCIPerrorMessage("invalid LP file section <%d>\n", lpinput->section);
2367  return SCIP_INVALIDDATA;
2368  }
2369  }
2370 
2371  /* close file */
2372  SCIPfclose(lpinput->file);
2373 
2374  return SCIP_OKAY;
2375 }
2376 
2377 
2378 /*
2379  * Local methods (for writing)
2380  */
2381 
2382 /** hash key retrieval function for variables */
2383 static
2384 SCIP_DECL_HASHGETKEY(hashGetKeyVar)
2385 { /*lint --e{715}*/
2386  return elem;
2387 }
2388 
2389 /** returns TRUE iff the indices of both variables are equal */
2390 static
2391 SCIP_DECL_HASHKEYEQ(hashKeyEqVar)
2392 { /*lint --e{715}*/
2393  if( key1 == key2 )
2394  return TRUE;
2395  return FALSE;
2396 }
2397 
2398 /** returns the hash value of the key */
2399 static
2400 SCIP_DECL_HASHKEYVAL(hashKeyValVar)
2401 { /*lint --e{715}*/
2402  assert( SCIPvarGetIndex((SCIP_VAR*) key) >= 0 );
2403  return (unsigned int) SCIPvarGetIndex((SCIP_VAR*) key);
2404 }
2405 
2406 
2407 #if 0
2408 /* prints variable name LP format conform; always use this method to stay consistent
2409  *
2410  * 1) variable names should not start with a digit
2411  * 2) avoid variable name starting with an 'e' or 'E' since this notation is reserved for exponential entries
2412  */
2413 static
2414 void printVarName(
2415  SCIP* scip, /**< SCIP data structure */
2416  FILE* file, /**< output file (or NULL for standard output) */
2417  SCIP_VAR* var, /**< variable */
2418  SCIP_Bool genericnames /**< use generic variable names? */
2419  )
2420 {
2421  const char* name;
2422 
2423  assert( scip != NULL );
2424  assert( var != NULL );
2425 
2426  name = SCIPvarGetName(var);
2427  assert( name != NULL );
2428 
2429  if( genericnames || name[0] == '\0' )
2430  SCIPinfoMessage(scip, file, "x%d", SCIPvarGetProbindex(var) + 1);
2431  else
2432  {
2433  if( isdigit((unsigned char)name[0]) || name[0] == 'e' || name[0] == 'E' )
2434  SCIPinfoMessage(scip, file, "_%s", name);
2435  else
2436  SCIPinfoMessage(scip, file, "%s", name);
2437  }
2438 }
2439 #endif
2440 
2441 /** transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant */
2442 static
2444  SCIP* scip, /**< SCIP data structure */
2445  SCIP_VAR*** vars, /**< pointer to vars array to get active variables for */
2446  SCIP_Real** scalars, /**< pointer to scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
2447  int* nvars, /**< pointer to number of variables and values in vars and vals array */
2448  SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */
2449  SCIP_Bool transformed /**< transformed constraint? */
2450  )
2451 {
2452  int requiredsize;
2453  int v;
2454 
2455  assert(scip != NULL);
2456  assert(vars != NULL);
2457  assert(scalars != NULL);
2458  assert(*vars != NULL);
2459  assert(*scalars != NULL);
2460  assert(nvars != NULL);
2461  assert(constant != NULL);
2462 
2463  if( transformed )
2464  {
2465  SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) );
2466 
2467  if( requiredsize > *nvars )
2468  {
2469  SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) );
2470  SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) );
2471 
2472  SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) );
2473  assert( requiredsize <= *nvars );
2474  }
2475  }
2476  else
2477  {
2478  for( v = 0; v < *nvars; ++v )
2479  {
2480  SCIP_CALL( SCIPvarGetOrigvarSum(&(*vars)[v], &(*scalars)[v], constant) );
2481  }
2482  }
2483  return SCIP_OKAY;
2484 }
2485 
2486 /** clears the given line buffer */
2487 static
2489  char* linebuffer, /**< line */
2490  int* linecnt /**< number of characters in line */
2491  )
2492 {
2493  assert( linebuffer != NULL );
2494  assert( linecnt != NULL );
2495 
2496  (*linecnt) = 0;
2497  linebuffer[0] = '\0';
2498 }
2499 
2500 /** ends the given line with '\\0' and prints it to the given file stream */
2501 static
2502 void endLine(
2503  SCIP* scip, /**< SCIP data structure */
2504  FILE* file, /**< output file (or NULL for standard output) */
2505  char* linebuffer, /**< line */
2506  int* linecnt /**< number of characters in line */
2507  )
2508 {
2509  assert( scip != NULL );
2510  assert( linebuffer != NULL );
2511  assert( linecnt != NULL );
2512 
2513  if( (*linecnt) > 0 )
2514  {
2515  linebuffer[(*linecnt)] = '\0';
2516  SCIPinfoMessage(scip, file, "%s\n", linebuffer);
2517  clearLine(linebuffer, linecnt);
2518  }
2519 }
2520 
2521 /** appends extension to line and prints it to the give file stream if the
2522  * line exceeded the length given in the define LP_PRINTLEN */
2523 static
2525  SCIP* scip, /**< SCIP data structure */
2526  FILE* file, /**< output file (or NULL for standard output) */
2527  char* linebuffer, /**< line */
2528  int* linecnt, /**< number of characters in line */
2529  const char* extension /**< string to extent the line */
2530  )
2531 {
2532  assert( scip != NULL );
2533  assert( linebuffer != NULL );
2534  assert( linecnt != NULL );
2535  assert( extension != NULL );
2536  assert( strlen(linebuffer) + strlen(extension) < LP_MAX_PRINTLEN );
2537 
2538  /* NOTE: avoid
2539  * sprintf(linebuffer, "%s%s", linebuffer, extension);
2540  * because of overlapping memory areas in memcpy used in sprintf.
2541  */
2542  strncat(linebuffer, extension, LP_MAX_PRINTLEN - strlen(linebuffer));
2543 
2544  (*linecnt) += (int) strlen(extension);
2545 
2546  SCIPdebugMessage("linebuffer <%s>, length = %lu\n", linebuffer, (unsigned long)strlen(linebuffer));
2547 
2548  if( (*linecnt) > LP_PRINTLEN )
2549  endLine(scip, file, linebuffer, linecnt);
2550 }
2551 
2552 
2553 /* print row in LP format to file stream */
2554 static
2556  SCIP* scip, /**< SCIP data structure */
2557  FILE* file, /**< output file (or NULL for standard output) */
2558  const char* rowname, /**< row name */
2559  const char* rownameextension, /**< row name extension */
2560  const char* type, /**< row type ("=", "<=", or ">=") */
2561  SCIP_VAR** linvars, /**< array of linear variables */
2562  SCIP_Real* linvals, /**< array of linear coefficient values */
2563  int nlinvars, /**< number of linear variables */
2564  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
2565  int nquadvarterms, /**< number of quadratic variable terms */
2566  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
2567  int nbilinterms, /**< number of bilinear terms */
2568  SCIP_Real rhs /**< right hand side */
2569  )
2570 {
2571  int v;
2572  char linebuffer[LP_MAX_PRINTLEN] = { '\0' };
2573  int linecnt;
2574 
2575  SCIP_VAR* var;
2576  char varname[LP_MAX_NAMELEN];
2577  char varname2[LP_MAX_NAMELEN];
2578  char consname[LP_MAX_NAMELEN + 1]; /* an extra character for ':' */
2579  char buffer[LP_MAX_PRINTLEN];
2580 
2581  assert( scip != NULL );
2582  assert( strcmp(type, "=") == 0 || strcmp(type, "<=") == 0 || strcmp(type, ">=") == 0 );
2583  assert( nlinvars == 0 || (linvars != NULL && linvals != NULL) );
2584  assert( nquadvarterms == 0 || quadvarterms != NULL );
2585 
2586  /* if there is a bilinear term, then there need to be at least two quadratic variables */
2587  assert( nbilinterms == 0 || (bilinterms != NULL && nquadvarterms >= 2) );
2588 
2589  clearLine(linebuffer, &linecnt);
2590 
2591  /* start each line with a space */
2592  appendLine(scip, file, linebuffer, &linecnt, " ");
2593 
2594  /* print row name */
2595  if( strlen(rowname) > 0 || strlen(rownameextension) > 0 )
2596  {
2597  (void) SCIPsnprintf(consname, LP_MAX_NAMELEN + 1, "%s%s:", rowname, rownameextension);
2598  appendLine(scip, file, linebuffer, &linecnt, consname);
2599  }
2600 
2601  /* print coefficients */
2602  for( v = 0; v < nlinvars; ++v )
2603  {
2604  var = linvars[v];
2605  assert( var != NULL );
2606 
2607  /* we start a new line; therefore we tab this line */
2608  if( linecnt == 0 )
2609  appendLine(scip, file, linebuffer, &linecnt, " ");
2610 
2611  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var));
2612  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %+.15g %s", linvals[v], varname);
2613 
2614  appendLine(scip, file, linebuffer, &linecnt, buffer);
2615  }
2616 
2617  /* print quadratic part */
2618  if( nquadvarterms > 0 )
2619  {
2620  /* print linear coefficients of quadratic variables */
2621  for( v = 0; v < nquadvarterms; ++v )
2622  {
2623  if( quadvarterms[v].lincoef == 0.0 )
2624  continue;
2625 
2626  /* we start a new line; therefore we tab this line */
2627  if( linecnt == 0 )
2628  appendLine(scip, file, linebuffer, &linecnt, " ");
2629 
2630  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(quadvarterms[v].var));
2631  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %+.15g %s", quadvarterms[v].lincoef, varname);
2632 
2633  appendLine(scip, file, linebuffer, &linecnt, buffer);
2634  }
2635 
2636  /* start quadratic part */
2637  appendLine(scip, file, linebuffer, &linecnt, " + [");
2638 
2639  /* print square terms */
2640  for( v = 0; v < nquadvarterms; ++v )
2641  {
2642  if( quadvarterms[v].sqrcoef == 0.0 )
2643  continue;
2644 
2645  /* we start a new line; therefore we tab this line */
2646  if( linecnt == 0 )
2647  appendLine(scip, file, linebuffer, &linecnt, " ");
2648 
2649  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(quadvarterms[v].var));
2650  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %+.15g %s^2", quadvarterms[v].sqrcoef, varname);
2651 
2652  appendLine(scip, file, linebuffer, &linecnt, buffer);
2653  }
2654 
2655  /* print bilinear terms */
2656  for( v = 0; v < nbilinterms; ++v )
2657  {
2658  /* we start a new line; therefore we tab this line */
2659  if( linecnt == 0 )
2660  appendLine(scip, file, linebuffer, &linecnt, " ");
2661 
2662  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(bilinterms[v].var1));
2663  (void) SCIPsnprintf(varname2, LP_MAX_NAMELEN, "%s", SCIPvarGetName(bilinterms[v].var2));
2664  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %+.15g %s * %s", bilinterms[v].coef, varname, varname2);
2665 
2666  appendLine(scip, file, linebuffer, &linecnt, buffer);
2667  }
2668 
2669  /* end quadratic part */
2670  appendLine(scip, file, linebuffer, &linecnt, " ]");
2671  }
2672 
2673  /* print left hand side */
2674  if( SCIPisZero(scip, rhs) )
2675  rhs = 0.0;
2676 
2677  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %s %+.15g", type, rhs);
2678 
2679  /* we start a new line; therefore we tab this line */
2680  if( linecnt == 0 )
2681  appendLine(scip, file, linebuffer, &linecnt, " ");
2682  appendLine(scip, file, linebuffer, &linecnt, buffer);
2683 
2684  endLine(scip, file, linebuffer, &linecnt);
2685 }
2686 
2687 
2688 /** prints given (linear or) quadratic constraint information in LP format to file stream */
2689 static
2691  SCIP* scip, /**< SCIP data structure */
2692  FILE* file, /**< output file (or NULL for standard output) */
2693  const char* rowname, /**< name of the row */
2694  SCIP_VAR** linvars, /**< array of linear variables */
2695  SCIP_Real* linvals, /**< array of linear coefficients values (or NULL if all linear coefficient values are 1) */
2696  int nlinvars, /**< number of linear variables */
2697  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
2698  int nquadvarterms, /**< number of quadratic variable terms */
2699  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
2700  int nbilinterms, /**< number of bilinear terms */
2701  SCIP_Real lhs, /**< left hand side */
2702  SCIP_Real rhs, /**< right hand side */
2703  SCIP_Bool transformed /**< transformed constraint? */
2704  )
2705 {
2706  int v;
2707  SCIP_VAR** activevars = NULL;
2708  SCIP_Real* activevals = NULL;
2709  int nactivevars;
2710  SCIP_Real activeconstant = 0.0;
2711 
2712  assert( scip != NULL );
2713  assert( rowname != NULL );
2714 
2715  /* The LP format does not forbid that the variable array is empty */
2716  assert( nlinvars == 0 || linvars != NULL );
2717  assert( nquadvarterms == 0 || quadvarterms != NULL );
2718  assert( nbilinterms == 0 || bilinterms != NULL );
2719 
2720  assert( lhs <= rhs );
2721 
2722  if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
2723  return SCIP_OKAY;
2724 
2725  nactivevars = nlinvars;
2726  if( nlinvars > 0 )
2727  {
2728  /* duplicate variable and value array */
2729  SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, linvars, nactivevars ) );
2730  if( linvals != NULL )
2731  {
2732  SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, linvals, nactivevars ) );
2733  }
2734  else
2735  {
2736  SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) );
2737 
2738  for( v = 0; v < nactivevars; ++v )
2739  activevals[v] = 1.0;
2740  }
2741 
2742  /* retransform given variables to active variables */
2743  SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activeconstant, transformed) );
2744  }
2745 
2746  /* print row(s) in LP format */
2747  if( SCIPisEQ(scip, lhs, rhs) )
2748  {
2749  assert( !SCIPisInfinity(scip, rhs) );
2750 
2751  /* equal constraint */
2752  printRow(scip, file, rowname, "", "=", activevars, activevals, nactivevars,
2753  quadvarterms, nquadvarterms, bilinterms, nbilinterms,
2754  rhs - activeconstant);
2755  }
2756  else
2757  {
2758  if( !SCIPisInfinity(scip, -lhs) )
2759  {
2760  /* print inequality ">=" */
2761  printRow(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", ">=",
2762  activevars, activevals, nactivevars,
2763  quadvarterms, nquadvarterms, bilinterms, nbilinterms,
2764  lhs - activeconstant);
2765  }
2766  if( !SCIPisInfinity(scip, rhs) )
2767  {
2768  /* print inequality "<=" */
2769  printRow(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "<=",
2770  activevars, activevals, nactivevars,
2771  quadvarterms, nquadvarterms, bilinterms, nbilinterms,
2772  rhs - activeconstant);
2773  }
2774  }
2775 
2776  if( nlinvars > 0 )
2777  {
2778  /* free buffer arrays */
2779  SCIPfreeBufferArray(scip, &activevars);
2780  SCIPfreeBufferArray(scip, &activevals);
2781  }
2782 
2783  return SCIP_OKAY;
2784 }
2785 
2786 
2787 /** prints given SOS constraint information in LP format to file stream */
2788 static
2790  SCIP* scip, /**< SCIP data structure */
2791  FILE* file, /**< output file (or NULL for standard output) */
2792  const char* rowname, /**< name of the row */
2793  SCIP_VAR** vars, /**< array of variables */
2794  SCIP_Real* weights, /**< array of weight values (or NULL) */
2795  int nvars, /**< number of variables */
2796  int type /**< SOS type (SOS1 or SOS2) */
2797  )
2798 {
2799  int v;
2800 
2801  char linebuffer[LP_MAX_PRINTLEN];
2802  int linecnt;
2803  char buffer[LP_MAX_PRINTLEN];
2804  char varname[LP_MAX_NAMELEN];
2805 
2806  assert( scip != NULL );
2807  assert( file != NULL );
2808  assert( type == 1 || type == 2 );
2809 
2810  clearLine(linebuffer, &linecnt);
2811 
2812  /* start each line with a space */
2813  appendLine(scip, file, linebuffer, &linecnt, " ");
2814  assert( strlen(rowname) < LP_MAX_NAMELEN );
2815 
2816  if( strlen(rowname) > 0 )
2817  {
2818  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, "%s:", rowname);
2819  appendLine(scip, file, linebuffer, &linecnt, buffer);
2820  }
2821 
2822  /* SOS type */
2823  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " S%d::", type);
2824  appendLine(scip, file, linebuffer, &linecnt, buffer);
2825 
2826  for( v = 0; v < nvars; ++v )
2827  {
2828  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(vars[v]));
2829 
2830  if( weights != NULL )
2831  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %s:%.15g", varname, weights[v]);
2832  else
2833  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %s:%d", varname, v);
2834 
2835  if(linecnt == 0 )
2836  {
2837  /* we start a new line; therefore we tab this line */
2838  appendLine(scip, file, linebuffer, &linecnt, " ");
2839  }
2840  appendLine(scip, file, linebuffer, &linecnt, buffer);
2841  }
2842 
2843  endLine(scip, file, linebuffer, &linecnt);
2844 }
2845 
2846 /** prints given soc constraint in LP format to file stream */
2847 static
2849  SCIP* scip, /**< SCIP data structure */
2850  FILE* file, /**< output file (or NULL for standard output) */
2851  const char* rowname, /**< name of the row */
2852  SCIP_CONS* cons /**< second order cone constraint */
2853  )
2854 {
2855  int v;
2856  char linebuffer[LP_MAX_PRINTLEN] = { '\0' };
2857  int linecnt;
2858  SCIP_VAR* var;
2859  SCIP_Real coef;
2860  SCIP_Real offset;
2861  char varname[LP_MAX_NAMELEN];
2862  char consname[LP_MAX_NAMELEN + 1]; /* an extra character for ':' */
2863  char buffer[LP_MAX_PRINTLEN];
2864 
2865  SCIP_Real rhs;
2866 
2867  assert( scip != NULL );
2868  assert( rowname != NULL );
2869  assert( cons != NULL );
2870 
2871  /* print constraint in LP format
2872  * the SOC constraint is given as
2873  * sqrt(constant + sum_i (lhscoef_i(lhsvar_i+lhsoffset_i))^2) <= rhscoef(rhsvar+rhsoffset)
2874  * and is printed as
2875  * sum_i (2*lhscoef_i^2 lhs_offset_i) lhsvar_i - (2 * rhscoef^2 * rhsoffset) rhsvar
2876  * + [ sum_i lhscoef_i^2 lhsvar_i^2 - rhscoef^2 rhsvar^2 ]
2877  * <=
2878  * - sum_i lhscoef_i^2 lhs_offset_i^2 - constant + rhscoef^2 rhsoffset^2
2879  */
2880 
2881  clearLine(linebuffer, &linecnt);
2882 
2883  /* start each line with a space */
2884  appendLine(scip, file, linebuffer, &linecnt, " ");
2885 
2886  /* print row name */
2887  if( strlen(rowname) > 0 )
2888  {
2889  (void) SCIPsnprintf(consname, LP_MAX_NAMELEN + 1, "%s:", rowname);
2890  appendLine(scip, file, linebuffer, &linecnt, consname);
2891  }
2892 
2893  rhs = -SCIPgetLhsConstantSOC(scip, cons);
2894 
2895  /* print linear part of left hand side and add constant parts to rhs */
2896  for( v = 0; v < SCIPgetNLhsVarsSOC(scip, cons); ++v )
2897  {
2898  var = SCIPgetLhsVarsSOC(scip, cons)[v];
2899  assert( var != NULL );
2900  offset = SCIPgetLhsOffsetsSOC(scip, cons)[v];
2901  coef = SCIPgetLhsCoefsSOC(scip, cons)[v];
2902 
2903  rhs -= coef * coef * offset * offset;
2904 
2905  if( offset == 0.0 || coef == 0.0 )
2906  continue;
2907 
2908  /* we start a new line; therefore we tab this line */
2909  if( linecnt == 0 )
2910  appendLine(scip, file, linebuffer, &linecnt, " ");
2911 
2912  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var));
2913  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %+.15g %s", 2*offset*coef*coef, varname);
2914 
2915  appendLine(scip, file, linebuffer, &linecnt, buffer);
2916  }
2917 
2918  /* print linear part from right hand side and add constant part to rhs */
2919  offset = SCIPgetRhsOffsetSOC(scip, cons);
2920  coef = SCIPgetRhsCoefSOC(scip, cons);
2921  if( offset != 0.0 && coef != 0.0 )
2922  {
2923  var = SCIPgetRhsVarSOC(scip, cons);
2924  assert( var != NULL );
2925 
2926  rhs += coef * coef * offset * offset;
2927 
2928  if( linecnt == 0 )
2929  appendLine(scip, file, linebuffer, &linecnt, " ");
2930 
2931  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var));
2932  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %+.15g %s", -2*offset*coef*coef, varname);
2933 
2934  appendLine(scip, file, linebuffer, &linecnt, buffer);
2935  }
2936 
2937  /* start quadratic part */
2938  appendLine(scip, file, linebuffer, &linecnt, " + [");
2939 
2940  /* print quadratic part of left hand side */
2941  for( v = 0; v < SCIPgetNLhsVarsSOC(scip, cons); ++v )
2942  {
2943  var = SCIPgetLhsVarsSOC(scip, cons)[v];
2944  assert( var != NULL );
2945  coef = SCIPgetLhsCoefsSOC(scip, cons)[v];
2946 
2947  if( coef == 0.0 )
2948  continue;
2949 
2950  /* we start a new line; therefore we tab this line */
2951  if( linecnt == 0 )
2952  appendLine(scip, file, linebuffer, &linecnt, " ");
2953 
2954  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var));
2955  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %+.15g %s^2", coef*coef, varname);
2956 
2957  appendLine(scip, file, linebuffer, &linecnt, buffer);
2958  }
2959 
2960  /* print quadratic part of right hand side */
2961  coef = SCIPgetRhsCoefSOC(scip, cons);
2962  if( coef != 0.0 )
2963  {
2964  var = SCIPgetRhsVarSOC(scip, cons);
2965  assert( var != NULL );
2966 
2967  /* we start a new line; therefore we tab this line */
2968  if( linecnt == 0 )
2969  appendLine(scip, file, linebuffer, &linecnt, " ");
2970 
2971  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var));
2972  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %+.15g %s^2", -coef*coef, varname);
2973 
2974  appendLine(scip, file, linebuffer, &linecnt, buffer);
2975  }
2976 
2977  /* end quadratic part */
2978  appendLine(scip, file, linebuffer, &linecnt, " ]");
2979 
2980  /* print right hand side */
2981  if( SCIPisZero(scip, rhs) )
2982  rhs = 0.0;
2983 
2984  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " <= %+.15g", rhs);
2985 
2986  /* we start a new line; therefore we tab this line */
2987  if( linecnt == 0 )
2988  appendLine(scip, file, linebuffer, &linecnt, " ");
2989  appendLine(scip, file, linebuffer, &linecnt, buffer);
2990 
2991  endLine(scip, file, linebuffer, &linecnt);
2992 
2993  return SCIP_OKAY;
2994 }
2995 
2996 /** prints a linearization of an and-constraint into the given file */
2997 static
2999  SCIP* scip, /**< SCIP data structure */
3000  FILE* file, /**< output file (or NULL for standard output) */
3001  const char* consname, /**< name of the constraint */
3002  SCIP_CONS* cons, /**< and constraint */
3003  SCIP_Bool aggrlinearizationands,/**< print weak or strong realaxation */
3004  SCIP_Bool transformed /**< transformed constraint? */
3005  )
3006 {
3007  SCIP_VAR** vars;
3008  SCIP_VAR** operands;
3009  SCIP_VAR* resultant;
3010  SCIP_Real* vals;
3011  char rowname[LP_MAX_NAMELEN];
3012  int nvars;
3013  int v;
3014 
3015  assert(scip != NULL);
3016  assert(consname != NULL);
3017  assert(cons != NULL);
3018 
3019  nvars = SCIPgetNVarsAnd(scip, cons);
3020  operands = SCIPgetVarsAnd(scip, cons);
3021  resultant = SCIPgetResultantAnd(scip, cons);
3022 
3023  /* allocate buffer array */
3024  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars + 1) );
3025  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars + 1) );
3026 
3027  /* the tight relaxtion, number of and-constraint operands rows */
3028  if( !aggrlinearizationands )
3029  {
3030  vars[0] = resultant;
3031  vals[0] = 1.0;
3032  vals[1] = -1.0;
3033 
3034  /* print operator rows */
3035  for( v = 0; v < nvars; ++v )
3036  {
3037  (void) SCIPsnprintf(rowname, LP_MAX_NAMELEN, "%s_%d", consname, v);
3038  vars[1] = operands[v];
3039 
3040  /* print for each operator a row */
3041  SCIP_CALL( printQuadraticCons(scip, file, rowname,
3042  vars, vals, 2, NULL, 0, NULL, 0, -SCIPinfinity(scip), 0.0, transformed) );
3043  }
3044  }
3045 
3046  /* prepare for next row */
3047  for( v = nvars - 1; v >= 0; --v )
3048  {
3049  vars[v] = operands[v];
3050  vals[v] = -1.0;
3051  }
3052 
3053  vars[nvars] = resultant;
3054 
3055  /* the weak relaxtion, only one constraint */
3056  if( aggrlinearizationands )
3057  {
3058  /* adjust rowname of constraint */
3059  (void) SCIPsnprintf(rowname, LP_MAX_NAMELEN, "%s_operators", consname);
3060 
3061  vals[nvars] = (SCIP_Real) nvars;
3062 
3063  /* print aggregated operator row */
3064  SCIP_CALL( printQuadraticCons(scip, file, rowname,
3065  vars, vals, nvars + 1, NULL, 0, NULL, 0, -SCIPinfinity(scip), 0.0, transformed) );
3066  }
3067 
3068  /* create additional linear constraint */
3069  (void) SCIPsnprintf(rowname, LP_MAX_NAMELEN, "%s_add", consname);
3070 
3071  vals[nvars] = 1.0;
3072 
3073  SCIP_CALL( printQuadraticCons(scip, file, rowname,
3074  vars, vals, nvars + 1, NULL, 0, NULL, 0, -nvars + 1.0, SCIPinfinity(scip), transformed) );
3075 
3076  /* free buffer array */
3077  SCIPfreeBufferArray(scip, &vals);
3078  SCIPfreeBufferArray(scip, &vars);
3079 
3080  return SCIP_OKAY;
3081 }
3082 
3083 /** check whether given variables are aggregated and put them into an array without duplication */
3084 static
3086  SCIP* scip, /**< SCIP data structure */
3087  SCIP_VAR** vars, /**< variable array */
3088  int nvars, /**< number of active variables in the problem */
3089  SCIP_VAR*** aggvars, /**< pointer to array storing the aggregated variables on output */
3090  int* naggvars, /**< pointer to number of aggregated variables on output */
3091  int* saggvars, /**< pointer to number of slots in aggvars array */
3092  SCIP_HASHTABLE* varAggregated /**< hashtable for checking duplicates */
3093  )
3094 {
3095  int v;
3096 
3097  assert( scip != NULL );
3098  assert( aggvars != NULL );
3099  assert( naggvars != NULL );
3100  assert( saggvars != NULL );
3101 
3102  /* check variables */
3103  for( v = 0; v < nvars; ++v )
3104  {
3105  SCIP_VARSTATUS status;
3106  SCIP_VAR* var;
3107 
3108  var = vars[v];
3109  status = SCIPvarGetStatus(var);
3110 
3111  /* collect aggregated variables in a list */
3112  if( status >= SCIP_VARSTATUS_AGGREGATED )
3113  {
3114  assert( status == SCIP_VARSTATUS_AGGREGATED || status == SCIP_VARSTATUS_MULTAGGR || status == SCIP_VARSTATUS_NEGATED );
3115  assert( varAggregated != NULL );
3116 
3117  if( ! SCIPhashtableExists(varAggregated, (void*) var) )
3118  {
3119  /* possibly enlarge array */
3120  if ( *saggvars <= *naggvars )
3121  {
3122  int newsize;
3123  newsize = SCIPcalcMemGrowSize(scip, *naggvars + 1);
3124  assert( newsize > *saggvars );
3125  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggvars, *saggvars, newsize) );
3126  *saggvars = newsize;
3127  }
3128 
3129  (*aggvars)[*naggvars] = var;
3130  (*naggvars)++;
3131  SCIP_CALL( SCIPhashtableInsert(varAggregated, (void*) var) );
3132  assert( *naggvars <= *saggvars );
3133  }
3134  }
3135  }
3136  return SCIP_OKAY;
3137 }
3138 
3139 /** print aggregated variable-constraints */
3140 static
3142  SCIP* scip, /**< SCIP data structure */
3143  FILE* file, /**< output file (or NULL for standard output) */
3144  SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */
3145  int nvars, /**< number of active variables in the problem */
3146  int nAggregatedVars, /**< number of aggregated variables */
3147  SCIP_VAR** aggregatedVars /**< array storing the aggregated variables */
3148  )
3149 {
3150  int j;
3151 
3152  SCIP_VAR** activevars;
3153  SCIP_Real* activevals;
3154  int nactivevars;
3155  SCIP_Real activeconstant = 0.0;
3156  char consname[LP_MAX_NAMELEN];
3157 
3158  assert( scip != NULL );
3159 
3160  /* write aggregation constraints */
3161  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nvars) );
3162  SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nvars) );
3163 
3164  for( j = 0; j < nAggregatedVars; ++j )
3165  {
3166  /* set up list to obtain substitution variables */
3167  nactivevars = 1;
3168 
3169  activevars[0] = aggregatedVars[j];
3170  activevals[0] = 1.0;
3171  activeconstant = 0.0;
3172 
3173  /* retransform given variables to active variables */
3174  SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activeconstant, transformed) );
3175 
3176  activevals[nactivevars] = -1.0;
3177  activevars[nactivevars] = aggregatedVars[j];
3178  ++nactivevars;
3179 
3180  /* output constraint */
3181  (void) SCIPsnprintf(consname, LP_MAX_NAMELEN, "aggr_%s", SCIPvarGetName(aggregatedVars[j]));
3182  printRow(scip, file, consname, "", "=", activevars, activevals, nactivevars, NULL, 0, NULL, 0, - activeconstant);
3183  }
3184 
3185  /* free buffer arrays */
3186  SCIPfreeBufferArray(scip, &activevars);
3187  SCIPfreeBufferArray(scip, &activevals);
3188 
3189  return SCIP_OKAY;
3190 }
3191 
3192 /** method check if the variable names are not longer than LP_MAX_NAMELEN */
3193 static
3195  SCIP* scip, /**< SCIP data structure */
3196  SCIP_VAR** vars, /**< array of variables */
3197  int nvars /**< number of variables */
3198  )
3199 {
3200  int v;
3201 
3202  assert(scip != NULL);
3203  assert(vars != NULL || nvars == 0);
3204 
3205  /* check if the variable names are not to long */
3206  for( v = 0; v < nvars; ++v )
3207  {
3208  if( strlen(SCIPvarGetName(vars[v])) > LP_MAX_NAMELEN ) /*lint !e613*/
3209  {
3210  SCIPwarningMessage(scip, "there is a variable name which has to be cut down to %d characters; LP might be corrupted\n",
3211  LP_MAX_NAMELEN - 1);
3212  return;
3213  }
3214  }
3215 }
3216 
3217 /** method check if the constraint names are not longer than LP_MAX_NAMELEN */
3218 static
3220  SCIP* scip, /**< SCIP data structure */
3221  SCIP_CONS** conss, /**< array of constraints */
3222  int nconss, /**< number of constraints */
3223  SCIP_Bool transformed /**< TRUE iff problem is the transformed problem */
3224  )
3225 {
3226  int c;
3227  SCIP_CONS* cons;
3228  SCIP_CONSHDLR* conshdlr;
3229  const char* conshdlrname;
3230 
3231  assert( scip != NULL );
3232  assert( conss != NULL );
3233 
3234  for( c = 0; c < nconss; ++c )
3235  {
3236  cons = conss[c];
3237  assert(cons != NULL );
3238 
3239  /* in case the transformed is written only constraints are posted which are enabled in the current node */
3240  assert(!transformed || SCIPconsIsEnabled(cons));
3241 
3242  conshdlr = SCIPconsGetHdlr(cons);
3243  assert( conshdlr != NULL );
3244 
3245  conshdlrname = SCIPconshdlrGetName(conshdlr);
3246  assert( transformed == SCIPconsIsTransformed(cons) );
3247 
3248  if( strcmp(conshdlrname, "linear") == 0 )
3249  {
3250  SCIP_Real lhs = SCIPgetLhsLinear(scip, cons);
3251  SCIP_Real rhs = SCIPgetLhsLinear(scip, cons);
3252 
3253  if( (SCIPisEQ(scip, lhs, rhs) && strlen(SCIPconsGetName(conss[c])) > LP_MAX_NAMELEN)
3254  || ( !SCIPisEQ(scip, lhs, rhs) && strlen(SCIPconsGetName(conss[c])) > LP_MAX_NAMELEN - 4) )
3255  {
3256  SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n",
3257  LP_MAX_NAMELEN - 1);
3258  return;
3259  }
3260  }
3261  else if( strlen(SCIPconsGetName(conss[c])) > LP_MAX_NAMELEN )
3262  {
3263  SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n",
3264  LP_MAX_NAMELEN - 1);
3265  return;
3266  }
3267  }
3268 }
3269 
3270 /*
3271  * Callback methods of reader
3272  */
3273 
3274 /** copy method for reader plugins (called when SCIP copies plugins) */
3275 static
3277 { /*lint --e{715}*/
3278  assert(scip != NULL);
3279  assert(reader != NULL);
3280  assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
3281 
3282  /* call inclusion method of reader */
3283  SCIP_CALL( SCIPincludeReaderLp(scip) );
3284 
3285  return SCIP_OKAY;
3286 }
3287 
3288 /** destructor of reader to free user data (called when SCIP is exiting) */
3289 static
3291 {
3292  SCIP_READERDATA* readerdata;
3293 
3294  assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
3295  readerdata = SCIPreaderGetData(reader);
3296  assert(readerdata != NULL);
3297  SCIPfreeMemory(scip, &readerdata);
3298 
3299  return SCIP_OKAY;
3300 }
3301 
3302 /** problem reading method of reader */
3303 static
3305 { /*lint --e{715}*/
3306 
3307  SCIP_CALL( SCIPreadLp(scip, reader, filename, result) );
3308 
3309  return SCIP_OKAY;
3310 }
3311 
3312 
3313 /** problem writing method of reader */
3314 static
3316 { /*lint --e{715}*/
3317  assert(reader != NULL);
3318  assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
3319 
3320  SCIP_CALL( SCIPwriteLp(scip, file, name, transformed, objsense, objscale, objoffset, vars,
3321  nvars, nbinvars, nintvars, nimplvars, ncontvars, conss, nconss, result) );
3322 
3323  return SCIP_OKAY;
3324 }
3325 
3326 
3327 /*
3328  * reader specific interface methods
3329  */
3330 
3331 /** includes the lp file reader in SCIP */
3333  SCIP* scip /**< SCIP data structure */
3334  )
3335 {
3336  SCIP_READERDATA* readerdata;
3337  SCIP_READER* reader;
3338 
3339  /* create reader data */
3340  SCIP_CALL( SCIPallocMemory(scip, &readerdata) );
3341 
3342  /* include reader */
3343  SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, readerdata) );
3344 
3345  /* set non fundamental callbacks via setter functions */
3346  SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyLp) );
3347  SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeLp) );
3348  SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadLp) );
3349  SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteLp) );
3350 
3351  /* add lp-reader parameters */
3353  "reading/"READER_NAME"/linearize-and-constraints",
3354  "should possible \"and\" constraint be linearized when writing the lp file?",
3355  &readerdata->linearizeands, TRUE, DEFAULT_LINEARIZE_ANDS, NULL, NULL) );
3357  "reading/"READER_NAME"/aggrlinearization-ands",
3358  "should an aggregated linearization for and constraints be used?",
3359  &readerdata->aggrlinearizationands, TRUE, DEFAULT_AGGRLINEARIZATION_ANDS, NULL, NULL) );
3360 
3361  return SCIP_OKAY;
3362 }
3363 
3364 
3365 /** reads problem from file */
3367  SCIP* scip, /**< SCIP data structure */
3368  SCIP_READER* reader, /**< the file reader itself */
3369  const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */
3370  SCIP_RESULT* result /**< pointer to store the result of the file reading call */
3371  )
3372 { /*lint --e{715}*/
3373  SCIP_RETCODE retcode;
3374  LPINPUT lpinput;
3375  int i;
3376 
3377  /* initialize LP input data */
3378  lpinput.file = NULL;
3379  lpinput.linebuf[0] = '\0';
3380  lpinput.probname[0] = '\0';
3381  lpinput.objname[0] = '\0';
3382  SCIP_CALL( SCIPallocMemoryArray(scip, &lpinput.token, LP_MAX_LINELEN) ); /*lint !e506*/
3383  lpinput.token[0] = '\0';
3384  SCIP_CALL( SCIPallocMemoryArray(scip, &lpinput.tokenbuf, LP_MAX_LINELEN) ); /*lint !e506*/
3385  lpinput.tokenbuf[0] = '\0';
3386  for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i )
3387  {
3388  SCIP_CALL( SCIPallocMemoryArray(scip, &(lpinput.pushedtokens[i]), LP_MAX_LINELEN) ); /*lint !e866 !e506*/
3389  }
3390 
3391  lpinput.npushedtokens = 0;
3392  lpinput.linenumber = 0;
3393  lpinput.linepos = 0;
3394  lpinput.section = LP_START;
3395  lpinput.objsense = SCIP_OBJSENSE_MINIMIZE;
3396  lpinput.inlazyconstraints = FALSE;
3397  lpinput.inusercuts = FALSE;
3398  lpinput.haserror = FALSE;
3399  lpinput.comment = FALSE;
3400  lpinput.endline = FALSE;
3401  SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &(lpinput.initialconss)) );
3402  SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &(lpinput.dynamicconss)) );
3403  SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &(lpinput.dynamiccols)) );
3404  SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &(lpinput.dynamicrows)) );
3405 
3406  /* read the file */
3407  retcode = readLPFile(scip, &lpinput, filename);
3408 
3409  /* free dynamically allocated memory */
3410  SCIPfreeMemoryArray(scip, &lpinput.token);
3411  SCIPfreeMemoryArray(scip, &lpinput.tokenbuf);
3412  for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i )
3413  {
3414  SCIPfreeMemoryArray(scip, &lpinput.pushedtokens[i]);
3415  }
3416 
3417  /* check for correct return value */
3418  SCIP_CALL( retcode );
3419 
3420  /* evaluate the result */
3421  if( lpinput.haserror )
3422  return SCIP_READERROR;
3423  else
3424  {
3425  /* set objective sense */
3426  SCIP_CALL( SCIPsetObjsense(scip, lpinput.objsense) );
3427  *result = SCIP_SUCCESS;
3428  }
3429 
3430  return SCIP_OKAY;
3431 }
3432 
3433 
3434 /** writes problem to file */
3436  SCIP* scip, /**< SCIP data structure */
3437  FILE* file, /**< output file, or NULL if standard output should be used */
3438  const char* name, /**< problem name */
3439  SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */
3440  SCIP_OBJSENSE objsense, /**< objective sense */
3441  SCIP_Real objscale, /**< scalar applied to objective function; external objective value is
3442  * extobj = objsense * objscale * (intobj + objoffset) */
3443  SCIP_Real objoffset, /**< objective offset from bound shifting and fixing */
3444  SCIP_VAR** vars, /**< array with active variables ordered binary, integer, implicit, continuous */
3445  int nvars, /**< number of active variables in the problem */
3446  int nbinvars, /**< number of binary variables */
3447  int nintvars, /**< number of general integer variables */
3448  int nimplvars, /**< number of implicit integer variables */
3449  int ncontvars, /**< number of continuous variables */
3450  SCIP_CONS** conss, /**< array with constraints of the problem */
3451  int nconss, /**< number of constraints in the problem */
3452  SCIP_RESULT* result /**< pointer to store the result of the file writing call */
3453  )
3454 {
3455  SCIP_READER* reader;
3456  SCIP_READERDATA* readerdata;
3457  SCIP_Bool linearizeands;
3458  SCIP_Bool aggrlinearizationands;
3459  int c;
3460  int v;
3461 
3462  int linecnt;
3463  char linebuffer[LP_MAX_PRINTLEN];
3464 
3465  char varname[LP_MAX_NAMELEN];
3466  char buffer[LP_MAX_PRINTLEN];
3467 
3468  SCIP_CONSHDLR* conshdlr;
3469  SCIP_CONSHDLR* conshdlrInd;
3470  const char* conshdlrname;
3471  SCIP_CONS* cons;
3472  SCIP_CONS** consSOS1;
3473  SCIP_CONS** consSOS2;
3474  SCIP_CONS** consQuadratic;
3475  SCIP_CONS** consSOC;
3476  SCIP_CONS** consIndicator;
3477  int nConsSOS1 = 0;
3478  int nConsSOS2 = 0;
3479  int nConsQuadratic = 0;
3480  int nConsSOC = 0;
3481  int nConsIndicator = 0;
3482  char consname[LP_MAX_NAMELEN];
3483 
3484  SCIP_VAR** aggvars;
3485  int naggvars = 0;
3486  int saggvars;
3487  SCIP_HASHTABLE* varAggregated;
3488  SCIP_HASHMAP* consHidden;
3489 
3490  SCIP_VAR** consvars;
3491  SCIP_Real* consvals;
3492  int nconsvars;
3493 
3494  SCIP_VAR* var;
3495  SCIP_Real lb;
3496  SCIP_Real ub;
3497 
3498  assert(scip != NULL);
3499 
3500  /* find indicator constraint handler */
3501  conshdlrInd = SCIPfindConshdlr(scip, "indicator");
3502  consHidden = NULL;
3503 
3504  /* if indicator constraint handler is present */
3505  if( conshdlrInd != NULL )
3506  {
3507  /* create hashtable storing linear constraints that should not be output */
3508  SCIP_CALL( SCIPhashmapCreate(&consHidden, SCIPblkmem(scip), SCIPcalcHashtableSize(1000)) );
3509 
3510  /* loop through indicator constraints (works only in transformed problem) */
3511  if( transformed )
3512  {
3513  SCIP_CONS** consInd;
3514  int nConsInd;
3515 
3516  consInd = SCIPconshdlrGetConss(conshdlrInd);
3517  nConsInd = SCIPconshdlrGetNConss(conshdlrInd);
3518  SCIPdebugMessage("Number of indicator constraints: %d\n", nConsInd);
3519 
3520  for( c = 0; c < nConsInd; ++c )
3521  {
3522  assert( consInd[c] != NULL );
3523  cons = SCIPgetLinearConsIndicator(consInd[c]);
3524 
3525  assert( !SCIPhashmapExists(consHidden, (void*) cons) );
3526  SCIP_CALL( SCIPhashmapSetImage(consHidden, (void*) cons, (void*) TRUE) );
3527  SCIPdebugMessage("Marked linear constraint <%s> as hidden.\n", SCIPconsGetName(cons));
3528  }
3529  }
3530  else
3531  {
3532  /* otherwise we have to pass through all constraints */
3533  for( c = 0; c < nconss; ++c )
3534  {
3535  cons = conss[c];
3536  assert( cons != NULL);
3537 
3538  conshdlr = SCIPconsGetHdlr(cons);
3539  assert( conshdlr != NULL );
3540  conshdlrname = SCIPconshdlrGetName(conshdlr);
3541 
3542  if( strcmp(conshdlrname, "indicator") == 0 )
3543  {
3544  SCIP_CONS* lincons;
3545 
3546  lincons = SCIPgetLinearConsIndicator(cons);
3547  assert( lincons != NULL );
3548 
3549  assert( !SCIPhashmapExists(consHidden, (void*) lincons) );
3550  SCIP_CALL( SCIPhashmapSetImage(consHidden, (void*) lincons, (void*) TRUE) );
3551  SCIPdebugMessage("Marked linear constraint <%s> as hidden.\n", SCIPconsGetName(lincons));
3552  }
3553  }
3554  }
3555  }
3556 
3557  /* check if the variable names are not to long */
3558  checkVarnames(scip, vars, nvars);
3559  /* check if the constraint names are to long */
3560  checkConsnames(scip, conss, nconss, transformed);
3561 
3562  /* print statistics as comment to file */
3563  SCIPinfoMessage(scip, file, "\\ SCIP STATISTICS\n");
3564  SCIPinfoMessage(scip, file, "\\ Problem name : %s\n", name);
3565  SCIPinfoMessage(scip, file, "\\ Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n",
3566  nvars, nbinvars, nintvars, nimplvars, ncontvars);
3567  SCIPinfoMessage(scip, file, "\\ Constraints : %d\n", nconss);
3568  SCIPinfoMessage(scip, file, "\\ Obj. scale : %.15g\n", objscale);
3569  SCIPinfoMessage(scip, file, "\\ Obj. offset : %.15g\n", objoffset);
3570 
3571  /* print objective sense */
3572  SCIPinfoMessage(scip, file, "%s\n", objsense == SCIP_OBJSENSE_MINIMIZE ? "Minimize" : "Maximize");
3573 
3574  clearLine(linebuffer, &linecnt);
3575  appendLine(scip, file, linebuffer, &linecnt, " Obj:");
3576 
3577  for( v = 0; v < nvars; ++v )
3578  {
3579  var = vars[v];
3580 
3581 #ifndef NDEBUG
3582  /* in case the original problem has to be written, the variables have to be either "original" or "negated" */
3583  if( ! transformed )
3585 #endif
3586 
3587  if( SCIPisZero(scip, SCIPvarGetObj(var)) )
3588  continue;
3589 
3590  /* we start a new line; therefore we tab this line */
3591  if( linecnt == 0 )
3592  appendLine(scip, file, linebuffer, &linecnt, " ");
3593 
3594  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var));
3595  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %+.15g %s", SCIPvarGetObj(var), varname );
3596 
3597  appendLine(scip, file, linebuffer, &linecnt, buffer);
3598  }
3599 
3600  endLine(scip, file, linebuffer, &linecnt);
3601 
3602  /* print "Subject to" section */
3603  SCIPinfoMessage(scip, file, "Subject to\n");
3604 
3605  reader = SCIPfindReader(scip, READER_NAME);
3606  if( reader != NULL )
3607  {
3608  readerdata = SCIPreaderGetData(reader);
3609  assert(readerdata != NULL);
3610 
3611  linearizeands = readerdata->linearizeands;
3612  aggrlinearizationands = readerdata->aggrlinearizationands;
3613  }
3614  else
3615  {
3616  linearizeands = DEFAULT_LINEARIZE_ANDS;
3617  aggrlinearizationands = DEFAULT_AGGRLINEARIZATION_ANDS;
3618  }
3619 
3620  /* collect SOS, quadratic, and SOC constraints in array for later output */
3621  SCIP_CALL( SCIPallocBufferArray(scip, &consSOS1, nconss) );
3622  SCIP_CALL( SCIPallocBufferArray(scip, &consSOS2, nconss) );
3623  SCIP_CALL( SCIPallocBufferArray(scip, &consQuadratic, nconss) );
3624  SCIP_CALL( SCIPallocBufferArray(scip, &consSOC, nconss) );
3625  SCIP_CALL( SCIPallocBufferArray(scip, &consIndicator, nconss) );
3626 
3627  for( c = 0; c < nconss; ++c )
3628  {
3629  cons = conss[c];
3630  assert( cons != NULL);
3631 
3632  /* in case the transformed is written only constraints are posted which are enabled in the current node */
3633  assert(!transformed || SCIPconsIsEnabled(cons));
3634 
3635  /* skip marked constraints in connection with indicator constraints */
3636  if( conshdlrInd != NULL && SCIPhashmapExists(consHidden, (void*) cons) )
3637  {
3638  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0 );
3639  continue;
3640  }
3641 
3642  conshdlr = SCIPconsGetHdlr(cons);
3643  assert( conshdlr != NULL );
3644 
3645  (void) SCIPsnprintf(consname, LP_MAX_NAMELEN, "%s", SCIPconsGetName(cons));
3646  conshdlrname = SCIPconshdlrGetName(conshdlr);
3647  assert( transformed == SCIPconsIsTransformed(cons) );
3648 
3649  if( strcmp(conshdlrname, "linear") == 0 )
3650  {
3651  SCIP_CALL( printQuadraticCons(scip, file, consname,
3652  SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons), SCIPgetNVarsLinear(scip, cons),
3653  NULL, 0, NULL, 0, SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons), transformed) );
3654  }
3655  else if( strcmp(conshdlrname, "setppc") == 0 )
3656  {
3657  consvars = SCIPgetVarsSetppc(scip, cons);
3658  nconsvars = SCIPgetNVarsSetppc(scip, cons);
3659 
3660  switch( SCIPgetTypeSetppc(scip, cons) )
3661  {
3663  SCIP_CALL( printQuadraticCons(scip, file, consname,
3664  consvars, NULL, nconsvars, NULL, 0, NULL, 0, 1.0, 1.0, transformed) );
3665  break;
3667  SCIP_CALL( printQuadraticCons(scip, file, consname,
3668  consvars, NULL, nconsvars, NULL, 0, NULL, 0, -SCIPinfinity(scip), 1.0, transformed) );
3669  break;
3671  SCIP_CALL( printQuadraticCons(scip, file, consname,
3672  consvars, NULL, nconsvars, NULL, 0, NULL, 0, 1.0, SCIPinfinity(scip), transformed) );
3673  break;
3674  }
3675  }
3676  else if( strcmp(conshdlrname, "logicor") == 0 )
3677  {
3678  SCIP_CALL( printQuadraticCons(scip, file, consname,
3679  SCIPgetVarsLogicor(scip, cons), NULL, SCIPgetNVarsLogicor(scip, cons),
3680  NULL, 0, NULL, 0, 1.0, SCIPinfinity(scip), transformed) );
3681  }
3682  else if( strcmp(conshdlrname, "knapsack") == 0 )
3683  {
3684  SCIP_Longint* weights;
3685 
3686  consvars = SCIPgetVarsKnapsack(scip, cons);
3687  nconsvars = SCIPgetNVarsKnapsack(scip, cons);
3688 
3689  /* copy Longint array to SCIP_Real array */
3690  weights = SCIPgetWeightsKnapsack(scip, cons);
3691  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) );
3692  for( v = 0; v < nconsvars; ++v )
3693  consvals[v] = (SCIP_Real)weights[v];
3694 
3695  SCIP_CALL( printQuadraticCons(scip, file, consname, consvars, consvals, nconsvars,
3696  NULL, 0, NULL, 0, -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), transformed) );
3697 
3698  SCIPfreeBufferArray(scip, &consvals);
3699  }
3700  else if( strcmp(conshdlrname, "varbound") == 0 )
3701  {
3702  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) );
3703  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) );
3704 
3705  consvars[0] = SCIPgetVarVarbound(scip, cons);
3706  consvars[1] = SCIPgetVbdvarVarbound(scip, cons);
3707 
3708  consvals[0] = 1.0;
3709  consvals[1] = SCIPgetVbdcoefVarbound(scip, cons);
3710 
3711  SCIP_CALL( printQuadraticCons(scip, file, consname, consvars, consvals, 2, NULL, 0, NULL, 0,
3712  SCIPgetLhsVarbound(scip, cons), SCIPgetRhsVarbound(scip, cons), transformed) );
3713 
3714  SCIPfreeBufferArray(scip, &consvars);
3715  SCIPfreeBufferArray(scip, &consvals);
3716  }
3717  else if( strcmp(conshdlrname, "SOS1") == 0 )
3718  {
3719  /* store constraint */
3720  consSOS1[nConsSOS1++] = cons;
3721  }
3722  else if( strcmp(conshdlrname, "SOS2") == 0 )
3723  {
3724  /* store constraint */
3725  consSOS2[nConsSOS2++] = cons;
3726  }
3727  else if( strcmp(conshdlrname, "indicator") == 0 )
3728  {
3729  SCIP_CONS* lincons;
3730  SCIP_VAR* binvar;
3731  SCIP_VAR* slackvar;
3732  SCIP_VAR** linvars;
3733  SCIP_Real* linvals;
3734  int nlinvars;
3735  int cnt;
3736  int rhs;
3737 
3738  assert( conshdlrInd != NULL );
3739 
3740  lincons = SCIPgetLinearConsIndicator(cons);
3741  binvar = SCIPgetBinaryVarIndicator(cons);
3742  slackvar = SCIPgetSlackVarIndicator(cons);
3743 
3744  assert( lincons != NULL );
3745  assert( binvar != NULL );
3746  assert( slackvar != NULL );
3747 
3748  rhs = 1;
3749  if ( SCIPvarIsNegated(binvar) )
3750  {
3751  rhs = 0;
3752  binvar = SCIPvarGetNegatedVar(binvar);
3753  }
3754 
3755  /* collect linear constraint information (remove slack variable) */
3756  linvars = SCIPgetVarsLinear(scip, lincons);
3757  linvals = SCIPgetValsLinear(scip, lincons);
3758  nlinvars = SCIPgetNVarsLinear(scip, lincons);
3759  assert( linvars != NULL );
3760  assert( linvals != NULL );
3761 
3762  /* linvars always contains slack variable, thus nlinvars >= 1 */
3763  if( nlinvars > 1 && !SCIPconsIsDeleted(lincons) )
3764  {
3765  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(binvar) );
3766  if( strlen(consname) > 0 )
3767  SCIPinfoMessage(scip, file, " %s: %s = %d ->", consname, varname, rhs);
3768  else
3769  SCIPinfoMessage(scip, file, " %s = %d ->", varname, rhs);
3770 
3771  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nlinvars-1) );
3772  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nlinvars-1) );
3773 
3774  cnt = 0;
3775  for( v = 0; v < nlinvars; ++v )
3776  {
3777  var = linvars[v];
3778  if( var != slackvar )
3779  {
3780  consvars[cnt] = var;
3781  consvals[cnt++] = linvals[v];
3782  }
3783  }
3784  /* if slackvariable is fixed, it might have been removed from constraint */
3785  assert( nlinvars == 0 || cnt == nlinvars-1 || SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(slackvar), SCIPvarGetUbGlobal(slackvar)) );
3786 
3787  SCIP_CALL( printQuadraticCons(scip, file, "", consvars, consvals, cnt, NULL, 0, NULL, 0,
3788  SCIPgetLhsLinear(scip, lincons), SCIPgetRhsLinear(scip, lincons), transformed) );
3789 
3790  SCIPfreeBufferArray(scip, &consvars);
3791  SCIPfreeBufferArray(scip, &consvals);
3792  }
3793 
3794  /* store constraint */
3795  consIndicator[nConsIndicator++] = cons;
3796  }
3797  else if( strcmp(conshdlrname, "quadratic") == 0 )
3798  {
3799  SCIP_CALL( printQuadraticCons(scip, file, consname,
3803  SCIPgetNBilinTermsQuadratic(scip, cons), SCIPgetLhsQuadratic(scip, cons),
3804  SCIPgetRhsQuadratic(scip, cons), transformed) );
3805 
3806  consQuadratic[nConsQuadratic++] = cons;
3807  }
3808  else if( strcmp(conshdlrname, "soc") == 0 )
3809  {
3810  SCIP_CALL( printSOCCons(scip, file, consname, cons) );
3811 
3812  consSOC[nConsSOC++] = cons;
3813  }
3814  else if( strcmp(conshdlrname, "and") == 0 )
3815  {
3816  if( linearizeands )
3817  {
3818  SCIP_CALL( printAndCons(scip, file, consname, cons, aggrlinearizationands, transformed) );
3819  }
3820  else
3821  {
3822  SCIPwarningMessage(scip, "change parameter \"reading/"READER_NAME"/linearize-and-constraints\" to TRUE to print and-constraints\n");
3823  SCIPinfoMessage(scip, file, "\\ ");
3824  SCIP_CALL( SCIPprintCons(scip, cons, file) );
3825  SCIPinfoMessage(scip, file, ";\n");
3826  }
3827  }
3828  else
3829  {
3830  SCIPwarningMessage(scip, "constraint handler <%s> cannot print requested format\n", conshdlrname );
3831  SCIPinfoMessage(scip, file, "\\ ");
3832  SCIP_CALL( SCIPprintCons(scip, cons, file) );
3833  SCIPinfoMessage(scip, file, ";\n");
3834  }
3835  }
3836 
3837  /* allocate array for storing aggregated and negated variables (dynamically adjusted) */
3838  saggvars = MAX(10, nvars);
3839  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &aggvars, saggvars) );
3840 
3841  /* create hashtable for storing aggregated variables */
3842  SCIP_CALL( SCIPhashtableCreate(&varAggregated, SCIPblkmem(scip), 10 * saggvars, hashGetKeyVar, hashKeyEqVar, hashKeyValVar, NULL) );
3843 
3844  /* check for aggregated variables in SOS1 constraints and output aggregations as linear constraints */
3845  for( c = 0; c < nConsSOS1; ++c )
3846  {
3847  cons = consSOS1[c];
3848  consvars = SCIPgetVarsSOS1(scip, cons);
3849  nconsvars = SCIPgetNVarsSOS1(scip, cons);
3850 
3851  SCIP_CALL( collectAggregatedVars(scip, consvars, nconsvars, &aggvars, &naggvars, &saggvars, varAggregated) );
3852  }
3853 
3854  /* check for aggregated variables in SOS2 constraints and output aggregations as linear constraints */
3855  for( c = 0; c < nConsSOS2; ++c )
3856  {
3857  cons = consSOS2[c];
3858  consvars = SCIPgetVarsSOS2(scip, cons);
3859  nconsvars = SCIPgetNVarsSOS2(scip, cons);
3860 
3861  SCIP_CALL( collectAggregatedVars(scip, consvars, nconsvars, &aggvars, &naggvars, &saggvars, varAggregated) );
3862  }
3863 
3864  /* check for aggregated variables in quadratic parts of quadratic constraints and output aggregations as linear constraints */
3865  for( c = 0; c < nConsQuadratic; ++c )
3866  {
3867  cons = consQuadratic[c];
3868  for( v = 0; v < SCIPgetNQuadVarTermsQuadratic(scip, cons); ++v )
3869  {
3870  SCIP_CALL( collectAggregatedVars(scip, &SCIPgetQuadVarTermsQuadratic(scip, cons)[v].var, 1, &aggvars, &naggvars, &saggvars, varAggregated) );
3871  }
3872  }
3873 
3874  /* check for aggregated variables in second order cone constraints and output aggregations as linear constraints */
3875  for( c = 0; c < nConsSOC; ++c )
3876  {
3877  cons = consSOC[c];
3878 
3879  SCIP_CALL( collectAggregatedVars(scip, SCIPgetLhsVarsSOC(scip, cons), SCIPgetNLhsVarsSOC(scip, cons), &aggvars, &naggvars, &saggvars, varAggregated) );
3880  var = SCIPgetRhsVarSOC(scip, cons);
3881  SCIP_CALL( collectAggregatedVars(scip, &var, 1, &aggvars, &naggvars, &saggvars, varAggregated) );
3882  }
3883 
3884  /* check for aggregated variables in indicator constraints and output aggregations as linear constraints */
3885  for( c = 0; c < nConsIndicator; ++c )
3886  {
3887  SCIP_VAR* binvar;
3888 
3889  cons = consIndicator[c];
3890  binvar = SCIPgetBinaryVarIndicator(cons);
3891  if ( ! SCIPvarIsNegated(binvar) )
3892  {
3893  /* we take care of negated variables above, but not of aggregated variables */
3894  SCIP_CALL( collectAggregatedVars(scip, &binvar, 1, &aggvars, &naggvars, &saggvars, varAggregated) );
3895  }
3896  }
3897 
3898  /* print aggregation constraints */
3899  SCIP_CALL( printAggregatedCons(scip, file, transformed, nvars, naggvars, aggvars) );
3900 
3901  /* print "Bounds" section */
3902  SCIPinfoMessage(scip, file, "Bounds\n");
3903  for( v = 0; v < nvars; ++v )
3904  {
3905  var = vars[v];
3906  assert( var != NULL );
3907  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var) );
3908 
3909  if( transformed )
3910  {
3911  /* in case the transformed is written only local bounds are posted which are valid in the current node */
3912  lb = SCIPvarGetLbLocal(var);
3913  ub = SCIPvarGetUbLocal(var);
3914  }
3915  else
3916  {
3917  lb = SCIPvarGetLbOriginal(var);
3918  ub = SCIPvarGetUbOriginal(var);
3919  }
3920 
3921  if( SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub) )
3922  SCIPinfoMessage(scip, file, " %s free\n", varname);
3923  else
3924  {
3925  /* print lower bound */
3926  if( SCIPisInfinity(scip, -lb) )
3927  SCIPinfoMessage(scip, file, " -inf <= ");
3928  else
3929  {
3930  if( SCIPisZero(scip, lb) )
3931  {
3932  /* variables are nonnegative by default - so we skip these variables */
3933  if( SCIPisInfinity(scip, ub) )
3934  continue;
3935  lb = 0.0;
3936  }
3937 
3938  SCIPinfoMessage(scip, file, " %.15g <= ", lb);
3939  }
3940  /* print variable name */
3941  SCIPinfoMessage(scip, file, "%s", varname);
3942 
3943  /* print upper bound as far this one is not infinity */
3944  if( !SCIPisInfinity(scip, ub) )
3945  SCIPinfoMessage(scip, file, " <= %.15g", ub);
3946 
3947  SCIPinfoMessage(scip, file, "\n");
3948  }
3949  }
3950 
3951  /* output aggregated variables as 'free' */
3952  for( v = 0; v < naggvars; ++v )
3953  {
3954  var = aggvars[v];
3955  assert( var != NULL );
3956  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var) );
3957 
3958  SCIPinfoMessage(scip, file, " %s free\n", varname);
3959  }
3960 
3961  /* print binaries section */
3962  if( nbinvars > 0 )
3963  {
3964  SCIPinfoMessage(scip, file, "Binaries\n");
3965 
3966  clearLine(linebuffer, &linecnt);
3967 
3968  /* output active variables */
3969  for( v = 0; v < nvars; ++v )
3970  {
3971  var = vars[v];
3972  assert( var != NULL );
3973 
3974  if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
3975  {
3976  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var) );
3977  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %s", varname);
3978  appendLine(scip, file, linebuffer, &linecnt, buffer);
3979  }
3980  }
3981 
3982  /* possibly output aggregated variables */
3983  for( v = 0; v < naggvars; ++v )
3984  {
3985  var = aggvars[v];
3986  assert( var != NULL );
3987 
3988  if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
3989  {
3990  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var) );
3991  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %s", varname);
3992  appendLine(scip, file, linebuffer, &linecnt, buffer);
3993  }
3994  }
3995 
3996  endLine(scip, file, linebuffer, &linecnt);
3997  }
3998 
3999  /* print generals section */
4000  if( nintvars > 0 )
4001  {
4002  SCIPinfoMessage(scip, file, "Generals\n");
4003 
4004  /* output active variables */
4005  for( v = 0; v < nvars; ++v )
4006  {
4007  var = vars[v];
4008  assert( var != NULL );
4009 
4010  if( SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER )
4011  {
4012  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var) );
4013  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %s", varname);
4014  appendLine(scip, file, linebuffer, &linecnt, buffer);
4015  }
4016  }
4017 
4018  /* possibly output aggregated variables */
4019  for( v = 0; v < naggvars; ++v )
4020  {
4021  var = aggvars[v];
4022  assert( var != NULL );
4023 
4024  if( SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER )
4025  {
4026  (void) SCIPsnprintf(varname, LP_MAX_NAMELEN, "%s", SCIPvarGetName(var) );
4027  (void) SCIPsnprintf(buffer, LP_MAX_PRINTLEN, " %s", varname);
4028  appendLine(scip, file, linebuffer, &linecnt, buffer);
4029  }
4030  }
4031 
4032  endLine(scip, file, linebuffer, &linecnt);
4033  }
4034 
4035  /* free space */
4036  SCIPfreeBlockMemoryArray(scip, &aggvars, saggvars);
4037  SCIPhashtableFree(&varAggregated);
4038  if( conshdlrInd != NULL )
4039  SCIPhashmapFree(&consHidden);
4040 
4041  /* print SOS section */
4042  if( nConsSOS1 > 0 || nConsSOS2 > 0 )
4043  {
4044  SCIP_Real* weights;
4045  SCIPinfoMessage(scip, file, "SOS\n");
4046 
4047  /* first output SOS1 constraints */
4048  for( c = 0; c < nConsSOS1; ++c )
4049  {
4050  cons = consSOS1[c];
4051  consvars = SCIPgetVarsSOS1(scip, cons);
4052  nconsvars = SCIPgetNVarsSOS1(scip, cons);
4053  weights = SCIPgetWeightsSOS1(scip, cons);
4054 
4055  (void) SCIPsnprintf(consname, LP_MAX_NAMELEN, "%s", SCIPconsGetName(cons) );
4056  printSosCons(scip, file, consname, consvars, weights, nconsvars, 1);
4057  }
4058 
4059  /* next output SOS2 constraints */
4060  for( c = 0; c < nConsSOS2; ++c )
4061  {
4062  cons = consSOS2[c];
4063  consvars = SCIPgetVarsSOS2(scip, cons);
4064  nconsvars = SCIPgetNVarsSOS2(scip, cons);
4065  weights = SCIPgetWeightsSOS2(scip, cons);
4066 
4067  (void) SCIPsnprintf(consname, LP_MAX_NAMELEN, "%s", SCIPconsGetName(cons) );
4068  printSosCons(scip, file, consname, consvars, weights, nconsvars, 2);
4069  }
4070  }
4071 
4072  /* free space */
4073  SCIPfreeBufferArray(scip, &consIndicator);
4074  SCIPfreeBufferArray(scip, &consSOC);
4075  SCIPfreeBufferArray(scip, &consQuadratic);
4076  SCIPfreeBufferArray(scip, &consSOS2);
4077  SCIPfreeBufferArray(scip, &consSOS1);
4078 
4079  /* end of lp format */
4080  SCIPinfoMessage(scip, file, "%s\n", "End");
4081 
4082  *result = SCIP_SUCCESS;
4083 
4084  return SCIP_OKAY;
4085 }
4086