1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file reader_mps.c
17 * @ingroup DEFPLUGINS_READER
18 * @brief (extended) MPS file reader
19 * @author Thorsten Koch
20 * @author Tobias Achterberg
21 * @author Marc Pfetsch
22 * @author Stefan Heinz
23 * @author Stefan Vigerske
24 * @author Michael Winkler
25 *
26 * This reader/writer handles MPS files in extended MPS format, as it
27 * is used by CPLEX. In the extended format the limits on variable
28 * name lengths and coefficients are considerably relaxed. The columns
29 * in the format are then separated by whitespaces.
30 *
31 * @todo Check whether constructing the names for aggregated constraint yields name clashes (aggrXXX).
32 */
33
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35
36 #include "blockmemshell/memory.h"
37 #include <ctype.h>
38 #include "scip/cons_and.h"
39 #include "scip/cons_bounddisjunction.h"
40 #include "scip/cons_indicator.h"
41 #include "scip/cons_knapsack.h"
42 #include "scip/cons_linear.h"
43 #include "scip/cons_logicor.h"
44 #include "scip/cons_quadratic.h"
45 #include "scip/cons_setppc.h"
46 #include "scip/cons_soc.h"
47 #include "scip/cons_sos1.h"
48 #include "scip/cons_sos2.h"
49 #include "scip/cons_varbound.h"
50 #include "scip/pub_cons.h"
51 #include "scip/pub_fileio.h"
52 #include "scip/pub_message.h"
53 #include "scip/pub_misc.h"
54 #include "scip/pub_misc_sort.h"
55 #include "scip/pub_reader.h"
56 #include "scip/pub_var.h"
57 #include "scip/reader_mps.h"
58 #include "scip/scip_cons.h"
59 #include "scip/scip_mem.h"
60 #include "scip/scip_message.h"
61 #include "scip/scip_numerics.h"
62 #include "scip/scip_param.h"
63 #include "scip/scip_prob.h"
64 #include "scip/scip_reader.h"
65 #include "scip/scip_solvingstats.h"
66 #include "scip/scip_var.h"
67 #include <stdlib.h>
68 #include <string.h>
69
70 #define READER_NAME "mpsreader"
71 #define READER_DESC "file reader for MIQPs in IBM's Mathematical Programming System format"
72 #define READER_EXTENSION "mps"
73
74 #define DEFAULT_LINEARIZE_ANDS TRUE /**< should possible \"and\" constraint be linearized when writing the mps file? */
75 #define DEFAULT_AGGRLINEARIZATION_ANDS TRUE /**< should an aggregated linearization for and constraints be used? */
76
77 /*
78 * mps reader internal methods
79 */
80
81 #define MPS_MAX_LINELEN 1024
82 #define MPS_MAX_NAMELEN 256
83 #define MPS_MAX_VALUELEN 26
84 #define MPS_MAX_FIELDLEN 20
85
86 #define PATCH_CHAR '_'
87 #define BLANK ' '
88
89 /** MPS reading data */
90 struct SCIP_ReaderData
91 {
92 SCIP_Bool linearizeands;
93 SCIP_Bool aggrlinearizationands;
94 };
95
96 /** enum containing all mps sections */
97 enum MpsSection
98 {
99 MPS_NAME,
100 MPS_OBJSEN,
101 MPS_OBJNAME,
102 MPS_ROWS,
103 MPS_USERCUTS,
104 MPS_LAZYCONS,
105 MPS_COLUMNS,
106 MPS_RHS,
107 MPS_RANGES,
108 MPS_BOUNDS,
109 MPS_SOS,
110 MPS_QUADOBJ,
111 MPS_QMATRIX,
112 MPS_QCMATRIX,
113 MPS_INDICATORS,
114 MPS_ENDATA
115 };
116 typedef enum MpsSection MPSSECTION;
117
118 /** mps input structure */
119 struct MpsInput
120 {
121 MPSSECTION section;
122 SCIP_FILE* fp;
123 int lineno;
124 SCIP_OBJSENSE objsense;
125 SCIP_Bool haserror;
126 char buf[MPS_MAX_LINELEN];
127 const char* f0;
128 const char* f1;
129 const char* f2;
130 const char* f3;
131 const char* f4;
132 const char* f5;
133 char probname[MPS_MAX_NAMELEN];
134 char objname [MPS_MAX_NAMELEN];
135 SCIP_Bool initialconss; /**< should model constraints be marked as initial? */
136 SCIP_Bool dynamicconss; /**< should model constraints be subject to aging? */
137 SCIP_Bool dynamiccols; /**< should columns be added and removed dynamically to the LP? */
138 SCIP_Bool dynamicrows; /**< should rows be added and removed dynamically to the LP? */
139 SCIP_Bool isinteger;
140 SCIP_Bool isnewformat;
141 };
142 typedef struct MpsInput MPSINPUT;
143
144 /** sparse matrix representation */
145 struct SparseMatrix
146 {
147 SCIP_Real* values; /**< matrix element */
148 SCIP_VAR** columns; /**< corresponding variables */
149 const char** rows; /**< corresponding constraint names */
150 int nentries; /**< number of elements in the arrays */
151 int sentries; /**< number of slots in the arrays */
152 };
153 typedef struct SparseMatrix SPARSEMATRIX;
154
155 /** struct for mapping cons names to numbers */
156 struct ConsNameFreq
157 {
158 const char* consname; /**< name of the constraint */
159 int freq; /**< how often we have seen the name */
160 };
161 typedef struct ConsNameFreq CONSNAMEFREQ;
162
163 /** creates the mps input structure */
164 static
mpsinputCreate(SCIP * scip,MPSINPUT ** mpsi,SCIP_FILE * fp)165 SCIP_RETCODE mpsinputCreate(
166 SCIP* scip, /**< SCIP data structure */
167 MPSINPUT** mpsi, /**< mps input structure */
168 SCIP_FILE* fp /**< file object for the input file */
169 )
170 {
171 assert(mpsi != NULL);
172 assert(fp != NULL);
173
174 SCIP_CALL( SCIPallocBlockMemory(scip, mpsi) );
175
176 (*mpsi)->section = MPS_NAME;
177 (*mpsi)->fp = fp;
178 (*mpsi)->lineno = 0;
179 (*mpsi)->objsense = SCIP_OBJSENSE_MINIMIZE;
180 (*mpsi)->haserror = FALSE;
181 (*mpsi)->isinteger = FALSE;
182 (*mpsi)->isnewformat = FALSE;
183 (*mpsi)->buf [0] = '\0';
184 (*mpsi)->probname[0] = '\0';
185 (*mpsi)->objname [0] = '\0';
186 (*mpsi)->f0 = NULL;
187 (*mpsi)->f1 = NULL;
188 (*mpsi)->f2 = NULL;
189 (*mpsi)->f3 = NULL;
190 (*mpsi)->f4 = NULL;
191 (*mpsi)->f5 = NULL;
192
193 SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &((*mpsi)->initialconss)) );
194 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &((*mpsi)->dynamicconss)) );
195 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &((*mpsi)->dynamiccols)) );
196 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &((*mpsi)->dynamicrows)) );
197
198 return SCIP_OKAY;
199 }
200
201 /** free the mps input structure */
202 static
mpsinputFree(SCIP * scip,MPSINPUT ** mpsi)203 void mpsinputFree(
204 SCIP* scip, /**< SCIP data structure */
205 MPSINPUT** mpsi /**< mps input structure */
206 )
207 {
208 SCIPfreeBlockMemory(scip, mpsi);
209 }
210
211 /** returns the current section */
212 static
mpsinputSection(const MPSINPUT * mpsi)213 MPSSECTION mpsinputSection(
214 const MPSINPUT* mpsi /**< mps input structure */
215 )
216 {
217 assert(mpsi != NULL);
218
219 return mpsi->section;
220 }
221
222 /** return the current value of field 0 */
223 static
mpsinputField0(const MPSINPUT * mpsi)224 const char* mpsinputField0(
225 const MPSINPUT* mpsi /**< mps input structure */
226 )
227 {
228 assert(mpsi != NULL);
229
230 return mpsi->f0;
231 }
232
233 /** return the current value of field 1 */
234 static
mpsinputField1(const MPSINPUT * mpsi)235 const char* mpsinputField1(
236 const MPSINPUT* mpsi /**< mps input structure */
237 )
238 {
239 assert(mpsi != NULL);
240
241 return mpsi->f1;
242 }
243
244 /** return the current value of field 2 */
245 static
mpsinputField2(const MPSINPUT * mpsi)246 const char* mpsinputField2(
247 const MPSINPUT* mpsi /**< mps input structure */
248 )
249 {
250 assert(mpsi != NULL);
251
252 return mpsi->f2;
253 }
254
255 /** return the current value of field 3 */
256 static
mpsinputField3(const MPSINPUT * mpsi)257 const char* mpsinputField3(
258 const MPSINPUT* mpsi /**< mps input structure */
259 )
260 {
261 assert(mpsi != NULL);
262
263 return mpsi->f3;
264 }
265
266 /** return the current value of field 4 */
267 static
mpsinputField4(const MPSINPUT * mpsi)268 const char* mpsinputField4(
269 const MPSINPUT* mpsi /**< mps input structure */
270 )
271 {
272 assert(mpsi != NULL);
273
274 return mpsi->f4;
275 }
276
277 /** return the current value of field 5 */
278 static
mpsinputField5(const MPSINPUT * mpsi)279 const char* mpsinputField5(
280 const MPSINPUT* mpsi /**< mps input structure */
281 )
282 {
283 assert(mpsi != NULL);
284
285 return mpsi->f5;
286 }
287
288 /** returns the objective name */
289 static
mpsinputObjname(const MPSINPUT * mpsi)290 const char* mpsinputObjname(
291 const MPSINPUT* mpsi /**< mps input structure */
292 )
293 {
294 assert(mpsi != NULL);
295
296 return mpsi->objname;
297 }
298
299 /** returns the objective sense */
300 static
mpsinputObjsense(const MPSINPUT * mpsi)301 SCIP_OBJSENSE mpsinputObjsense(
302 const MPSINPUT* mpsi /**< mps input structure */
303 )
304 {
305 assert(mpsi != NULL);
306
307 return mpsi->objsense;
308 }
309
310 /** returns if an error was detected */
311 static
mpsinputHasError(const MPSINPUT * mpsi)312 SCIP_Bool mpsinputHasError(
313 const MPSINPUT* mpsi /**< mps input structure */
314 )
315 {
316 assert(mpsi != NULL);
317
318 return mpsi->haserror;
319 }
320
321 /** returns the value of the Bool "is integer" in the mps input */
322 static
mpsinputIsInteger(const MPSINPUT * mpsi)323 SCIP_Bool mpsinputIsInteger(
324 const MPSINPUT* mpsi /**< mps input structure */
325 )
326 {
327 assert(mpsi != NULL);
328
329 return mpsi->isinteger;
330 }
331
332 /** set the section in the mps input structure to given section */
333 static
mpsinputSetSection(MPSINPUT * mpsi,MPSSECTION section)334 void mpsinputSetSection(
335 MPSINPUT* mpsi, /**< mps input structure */
336 MPSSECTION section /**< section that is set */
337 )
338 {
339 assert(mpsi != NULL);
340
341 mpsi->section = section;
342 }
343
344 /** set the problem name in the mps input structure to given problem name */
345 static
mpsinputSetProbname(MPSINPUT * mpsi,const char * probname)346 void mpsinputSetProbname(
347 MPSINPUT* mpsi, /**< mps input structure */
348 const char* probname /**< name of the problem to set */
349 )
350 {
351 assert(mpsi != NULL);
352 assert(probname != NULL);
353 assert(strlen(probname) < sizeof(mpsi->probname));
354
355 (void)SCIPmemccpy(mpsi->probname, probname, '\0', MPS_MAX_NAMELEN - 1);
356 }
357
358 /** set the objective name in the mps input structure to given objective name */
359 static
mpsinputSetObjname(MPSINPUT * mpsi,const char * objname)360 void mpsinputSetObjname(
361 MPSINPUT* mpsi, /**< mps input structure */
362 const char* objname /**< name of the objective function to set */
363 )
364 {
365 assert(mpsi != NULL);
366 assert(objname != NULL);
367 assert(strlen(objname) < sizeof(mpsi->objname));
368
369 (void)SCIPmemccpy(mpsi->objname, objname, '\0', MPS_MAX_NAMELEN - 1);
370 }
371
372 /** set the objective sense in the mps input structure to given objective sense */
373 static
mpsinputSetObjsense(MPSINPUT * mpsi,SCIP_OBJSENSE sense)374 void mpsinputSetObjsense(
375 MPSINPUT* mpsi, /**< mps input structure */
376 SCIP_OBJSENSE sense /**< sense of the objective function */
377 )
378 {
379 assert(mpsi != NULL);
380
381 mpsi->objsense = sense;
382 }
383
384 static
mpsinputSyntaxerror(MPSINPUT * mpsi)385 void mpsinputSyntaxerror(
386 MPSINPUT* mpsi /**< mps input structure */
387 )
388 {
389 assert(mpsi != NULL);
390
391 SCIPerrorMessage("Syntax error in line %d\n", mpsi->lineno);
392 mpsi->section = MPS_ENDATA;
393 mpsi->haserror = TRUE;
394 }
395
396 /** method post a ignore message */
397 static
mpsinputEntryIgnored(SCIP * scip,MPSINPUT * mpsi,const char * what,const char * what_name,const char * entity,const char * entity_name,SCIP_VERBLEVEL verblevel)398 void mpsinputEntryIgnored(
399 SCIP* scip, /**< SCIP data structure */
400 MPSINPUT* mpsi, /**< mps input structure */
401 const char* what, /**< what get ignored */
402 const char* what_name, /**< name of that object */
403 const char* entity, /**< entity */
404 const char* entity_name, /**< entity name */
405 SCIP_VERBLEVEL verblevel /**< SCIP verblevel for this message */
406 )
407 {
408 assert(mpsi != NULL);
409 assert(what != NULL);
410 assert(what_name != NULL);
411 assert(entity != NULL);
412 assert(entity_name != NULL);
413
414 SCIPverbMessage(scip, verblevel, NULL,
415 "Warning line %d: %s \"%s\" for %s \"%s\" ignored\n", mpsi->lineno, what, what_name, entity, entity_name);
416 }
417
418 /** fill the line from \p pos up to column 80 with blanks. */
419 static
clearFrom(char * buf,unsigned int pos)420 void clearFrom(
421 char* buf, /**< buffer to clear */
422 unsigned int pos /**< position to start the clearing process */
423 )
424 {
425 unsigned int i;
426
427 for(i = pos; i < 80; i++)
428 buf[i] = BLANK;
429 buf[80] = '\0';
430 }
431
432 /** change all blanks inside a field to #PATCH_CHAR. */
433 static
patchField(char * buf,int beg,int end)434 void patchField(
435 char* buf, /**< buffer to patch */
436 int beg, /**< position to begin */
437 int end /**< position to end */
438 )
439 {
440 int i;
441
442 while( (beg <= end) && (buf[end] == BLANK) )
443 end--;
444
445 while( (beg <= end) && (buf[beg] == BLANK) )
446 beg++;
447
448 for( i = beg; i <= end; i++ )
449 if( buf[i] == BLANK )
450 buf[i] = PATCH_CHAR;
451 }
452
453 /** read a mps format data line and parse the fields. */
454 static
mpsinputReadLine(MPSINPUT * mpsi)455 SCIP_Bool mpsinputReadLine(
456 MPSINPUT* mpsi /**< mps input structure */
457 )
458 {
459 unsigned int len;
460 unsigned int i;
461 int space;
462 char* s;
463 SCIP_Bool is_marker;
464 SCIP_Bool is_empty;
465 char* nexttok;
466
467 do
468 {
469 mpsi->f0 = mpsi->f1 = mpsi->f2 = mpsi->f3 = mpsi->f4 = mpsi->f5 = 0;
470 is_marker = FALSE;
471
472 /* Read until we have not a comment line. */
473 do
474 {
475 mpsi->buf[MPS_MAX_LINELEN-1] = '\0';
476 if( NULL == SCIPfgets(mpsi->buf, (int) sizeof(mpsi->buf), mpsi->fp) )
477 return FALSE;
478 mpsi->lineno++;
479 }
480 while( *mpsi->buf == '*' ); /* coverity[a_loop_bound] */
481
482 /* Normalize line */
483 len = (unsigned int) strlen(mpsi->buf);
484
485 for( i = 0; i < len; i++ )
486 if( (mpsi->buf[i] == '\t') || (mpsi->buf[i] == '\n') || (mpsi->buf[i] == '\r') )
487 mpsi->buf[i] = BLANK;
488
489 if( len < 80 )
490 clearFrom(mpsi->buf, len);
491
492 SCIPdebugMessage("line %d: <%s>\n", mpsi->lineno, mpsi->buf);
493
494 assert(strlen(mpsi->buf) >= 80);
495
496 /* Look for new section */
497 if( *mpsi->buf != BLANK )
498 {
499 mpsi->f0 = SCIPstrtok(&mpsi->buf[0], " ", &nexttok);
500
501 assert(mpsi->f0 != 0);
502
503 mpsi->f1 = SCIPstrtok(NULL, " ", &nexttok);
504
505 return TRUE;
506 }
507
508 /* If we decide to use the new format we never revert this decision */
509 if( !mpsi->isnewformat )
510 {
511 /* Test for fixed format comments */
512 if( (mpsi->buf[14] == '$') && (mpsi->buf[13] == ' ') )
513 clearFrom(mpsi->buf, 14);
514 else if( (mpsi->buf[39] == '$') && (mpsi->buf[38] == ' ') )
515 clearFrom(mpsi->buf, 39);
516
517 /* Test for fixed format */
518 space = mpsi->buf[12] | mpsi->buf[13]
519 | mpsi->buf[22] | mpsi->buf[23]
520 | mpsi->buf[36] | mpsi->buf[37] | mpsi->buf[38]
521 | mpsi->buf[47] | mpsi->buf[48]
522 | mpsi->buf[61] | mpsi->buf[62] | mpsi->buf[63];
523
524 if( space == BLANK )
525 {
526 /* Now we have space at the right positions.
527 * But are there also the non space where they
528 * should be ?
529 */
530 SCIP_Bool number;
531
532 number = isdigit((unsigned char)mpsi->buf[24]) || isdigit((unsigned char)mpsi->buf[25])
533 || isdigit((unsigned char)mpsi->buf[26]) || isdigit((unsigned char)mpsi->buf[27])
534 || isdigit((unsigned char)mpsi->buf[28]) || isdigit((unsigned char)mpsi->buf[29])
535 || isdigit((unsigned char)mpsi->buf[30]) || isdigit((unsigned char)mpsi->buf[31])
536 || isdigit((unsigned char)mpsi->buf[32]) || isdigit((unsigned char)mpsi->buf[33])
537 || isdigit((unsigned char)mpsi->buf[34]) || isdigit((unsigned char)mpsi->buf[35]);
538
539 /* len < 14 is handle ROW lines with embedded spaces
540 * in the names correctly
541 */
542 if( number || len < 14 )
543 {
544 /* We assume fixed format, so we patch possible embedded spaces. */
545 patchField(mpsi->buf, 4, 12);
546 patchField(mpsi->buf, 14, 22);
547 patchField(mpsi->buf, 39, 47);
548 }
549 else
550 {
551 if( mpsi->section == MPS_COLUMNS || mpsi->section == MPS_RHS
552 || mpsi->section == MPS_RANGES || mpsi->section == MPS_BOUNDS )
553 mpsi->isnewformat = TRUE;
554 }
555 }
556 else
557 {
558 mpsi->isnewformat = TRUE;
559 }
560 }
561 s = &mpsi->buf[1];
562
563 /* At this point it is not clear if we have a indicator field.
564 * If there is none (e.g. empty) f1 will be the first name field.
565 * If there is one, f2 will be the first name field.
566 *
567 * Initially comment marks '$' are only allowed in the beginning
568 * of the 2nd and 3rd name field. We test all fields but the first.
569 * This makes no difference, since if the $ is at the start of a value
570 * field, the line will be erroneous anyway.
571 */
572 do
573 {
574 if( NULL == (mpsi->f1 = SCIPstrtok(s, " ", &nexttok)) )
575 break;
576
577 if( (NULL == (mpsi->f2 = SCIPstrtok(NULL, " ", &nexttok))) || (*mpsi->f2 == '$') )
578 {
579 mpsi->f2 = 0;
580 break;
581 }
582 if( !strcmp(mpsi->f2, "'MARKER'") )
583 is_marker = TRUE;
584
585 if( (NULL == (mpsi->f3 = SCIPstrtok(NULL, " ", &nexttok))) || (*mpsi->f3 == '$') )
586 {
587 mpsi->f3 = 0;
588 break;
589 }
590 if( is_marker )
591 {
592 if( !strcmp(mpsi->f3, "'INTORG'") )
593 mpsi->isinteger = TRUE;
594 else if( !strcmp(mpsi->f3, "'INTEND'") )
595 mpsi->isinteger = FALSE;
596 else
597 break; /* unknown marker */
598 }
599 if( !strcmp(mpsi->f3, "'MARKER'") )
600 is_marker = TRUE;
601
602 if( (NULL == (mpsi->f4 = SCIPstrtok(NULL, " ", &nexttok))) || (*mpsi->f4 == '$') )
603 {
604 mpsi->f4 = 0;
605 break;
606 }
607 if( is_marker )
608 {
609 if( !strcmp(mpsi->f4, "'INTORG'") )
610 mpsi->isinteger = TRUE;
611 else if( !strcmp(mpsi->f4, "'INTEND'") )
612 mpsi->isinteger = FALSE;
613 else
614 break; /* unknown marker */
615 }
616 if( (NULL == (mpsi->f5 = SCIPstrtok(NULL, " ", &nexttok))) || (*mpsi->f5 == '$') )
617 mpsi->f5 = 0;
618 }
619 while( FALSE );
620
621 /* check for empty lines */
622 is_empty = (mpsi->f0 == NULL && mpsi->f1 == NULL);
623 }
624 while( is_marker || is_empty );
625
626 return TRUE;
627 }
628
629 /** Insert \p str as field 4 and shift all other fields up. */
630 static
mpsinputInsertField4(MPSINPUT * mpsi,const char * str)631 void mpsinputInsertField4(
632 MPSINPUT* mpsi, /**< mps input structure */
633 const char* str /**< str to insert */
634 )
635 {
636 assert(mpsi != NULL);
637 assert(str != NULL);
638
639 mpsi->f5 = mpsi->f4;
640 mpsi->f4 = str;
641 }
642
643 /** Insert \p name as field 1 or 2 and shift all other fields up. */
644 static
mpsinputInsertName(MPSINPUT * mpsi,const char * name,SCIP_Bool second)645 void mpsinputInsertName(
646 MPSINPUT* mpsi, /**< mps input structure */
647 const char* name, /**< name to insert */
648 SCIP_Bool second /**< insert as second field? */
649 )
650 {
651 assert(mpsi != NULL);
652 assert(name != NULL);
653
654 mpsi->f5 = mpsi->f4;
655 mpsi->f4 = mpsi->f3;
656 mpsi->f3 = mpsi->f2;
657
658 if( second )
659 mpsi->f2 = name;
660 else
661 {
662 mpsi->f2 = mpsi->f1;
663 mpsi->f1 = name;
664 }
665 }
666
667 /** Add variable name to storage */
668 static
addVarNameToStorage(SCIP * scip,const char *** varnames,int * varnamessize,int * nvars,const char * colname)669 SCIP_RETCODE addVarNameToStorage(
670 SCIP* scip, /**< SCIP data structure */
671 const char*** varnames, /**< the variable name storage */
672 int* varnamessize, /**< the size of the variable names storage */
673 int* nvars, /**< the number of variables */
674 const char* colname /**< the name of the variable */
675 )
676 {
677 assert(scip != NULL);
678
679 if( varnames != NULL )
680 {
681 SCIP_CALL( SCIPensureBlockMemoryArray(scip, varnames, varnamessize, (*nvars) + 1) );
682 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*varnames)[(*nvars)], colname, strlen(colname) + 1) ); /*lint !e866*/
683 (*nvars)++;
684 }
685
686 return SCIP_OKAY;
687 }
688
689 /** Add constraint name to storage */
690 static
addConsNameToStorage(SCIP * scip,const char *** consnames,int * consnamessize,int * ncons,const char * rowname)691 SCIP_RETCODE addConsNameToStorage(
692 SCIP* scip, /**< SCIP data structure */
693 const char*** consnames, /**< the constraint name storage */
694 int* consnamessize, /**< the size of the constraint names storage */
695 int* ncons, /**< the number of constraint */
696 const char* rowname /**< the name of the constraint */
697 )
698 {
699 assert(scip != NULL);
700
701 if( consnames != NULL )
702 {
703 SCIP_CALL( SCIPensureBlockMemoryArray(scip, consnames, consnamessize, (*ncons) + 1) );
704 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consnames)[(*ncons)], rowname, strlen(rowname) + 1) ); /*lint !e866*/
705 (*ncons)++;
706 }
707
708 return SCIP_OKAY;
709 }
710
711 /** Process NAME section. */
712 static
readName(SCIP * scip,MPSINPUT * mpsi)713 SCIP_RETCODE readName(
714 SCIP* scip, /**< SCIP data structure */
715 MPSINPUT* mpsi /**< mps input structure */
716 )
717 {
718 assert(mpsi != NULL);
719
720 SCIPdebugMsg(scip, "read problem name\n");
721
722 /* This has to be the Line with the NAME section. */
723 if( !mpsinputReadLine(mpsi) || mpsinputField0(mpsi) == NULL || strcmp(mpsinputField0(mpsi), "NAME") )
724 {
725 mpsinputSyntaxerror(mpsi);
726 return SCIP_OKAY;
727 }
728
729 /* Sometimes the name is omitted. */
730 mpsinputSetProbname(mpsi, (mpsinputField1(mpsi) == 0) ? "_MPS_" : mpsinputField1(mpsi));
731
732 /* This hat to be a new section */
733 /* coverity[tainted_data] */
734 if( !mpsinputReadLine(mpsi) || (mpsinputField0(mpsi) == NULL) )
735 {
736 mpsinputSyntaxerror(mpsi);
737 return SCIP_OKAY;
738 }
739
740 if( !strncmp(mpsinputField0(mpsi), "ROWS", 4) )
741 mpsinputSetSection(mpsi, MPS_ROWS);
742 else if( !strncmp(mpsinputField0(mpsi), "USERCUTS", 8) )
743 mpsinputSetSection(mpsi, MPS_USERCUTS);
744 else if( !strncmp(mpsinputField0(mpsi), "LAZYCONS", 8) )
745 mpsinputSetSection(mpsi, MPS_LAZYCONS);
746 else if( !strncmp(mpsinputField0(mpsi), "OBJSEN", 6) )
747 mpsinputSetSection(mpsi, MPS_OBJSEN);
748 else if( !strncmp(mpsinputField0(mpsi), "OBJNAME", 7) )
749 mpsinputSetSection(mpsi, MPS_OBJNAME);
750 else
751 {
752 mpsinputSyntaxerror(mpsi);
753 return SCIP_OKAY;
754 }
755
756 return SCIP_OKAY;
757 }
758
759 /** Process OBJSEN section. This Section is a CPLEX extension. */
760 static
readObjsen(SCIP * scip,MPSINPUT * mpsi)761 SCIP_RETCODE readObjsen(
762 SCIP* scip, /**< SCIP data structure */
763 MPSINPUT* mpsi /**< mps input structure */
764 )
765 {
766 assert(mpsi != NULL);
767
768 SCIPdebugMsg(scip, "read objective sense\n");
769
770 /* This has to be the Line with MIN or MAX. */
771 if( !mpsinputReadLine(mpsi) || (mpsinputField1(mpsi) == NULL) )
772 {
773 mpsinputSyntaxerror(mpsi);
774 return SCIP_OKAY;
775 }
776
777 if( !strncmp(mpsinputField1(mpsi), "MIN", 3) )
778 mpsinputSetObjsense(mpsi, SCIP_OBJSENSE_MINIMIZE);
779 else if( !strncmp(mpsinputField1(mpsi), "MAX", 3) )
780 mpsinputSetObjsense(mpsi, SCIP_OBJSENSE_MAXIMIZE);
781 else
782 {
783 mpsinputSyntaxerror(mpsi);
784 return SCIP_OKAY;
785 }
786
787 /* Look for ROWS, USERCUTS, LAZYCONS, or OBJNAME Section */
788 /* coverity[tainted_data] */
789 if( !mpsinputReadLine(mpsi) || mpsinputField0(mpsi) == NULL )
790 {
791 mpsinputSyntaxerror(mpsi);
792 return SCIP_OKAY;
793 }
794
795 if( !strcmp(mpsinputField0(mpsi), "ROWS") )
796 mpsinputSetSection(mpsi, MPS_ROWS);
797 else if( !strcmp(mpsinputField0(mpsi), "USERCUTS") )
798 mpsinputSetSection(mpsi, MPS_USERCUTS);
799 else if( !strcmp(mpsinputField0(mpsi), "LAZYCONS") )
800 mpsinputSetSection(mpsi, MPS_LAZYCONS);
801 else if( !strcmp(mpsinputField0(mpsi), "OBJNAME") )
802 mpsinputSetSection(mpsi, MPS_OBJNAME);
803 else
804 {
805 mpsinputSyntaxerror(mpsi);
806 return SCIP_OKAY;
807 }
808
809 return SCIP_OKAY;
810 }
811
812 /** Process OBJNAME section. This Section is a CPLEX extension. */
813 static
readObjname(SCIP * scip,MPSINPUT * mpsi)814 SCIP_RETCODE readObjname(
815 SCIP* scip, /**< SCIP data structure */
816 MPSINPUT* mpsi /**< mps input structure */
817 )
818 {
819 assert(mpsi != NULL);
820
821 SCIPdebugMsg(scip, "read objective name\n");
822
823 /* This has to be the Line with the name. */
824 if( !mpsinputReadLine(mpsi) || mpsinputField1(mpsi) == NULL )
825 {
826 mpsinputSyntaxerror(mpsi);
827 return SCIP_OKAY;
828 }
829
830 mpsinputSetObjname(mpsi, mpsinputField1(mpsi));
831
832 /* Look for ROWS, USERCUTS, or LAZYCONS Section */
833 /* coverity[tainted_data] */
834 if( !mpsinputReadLine(mpsi) || mpsinputField0(mpsi) == NULL )
835 {
836 mpsinputSyntaxerror(mpsi);
837 return SCIP_OKAY;
838 }
839 if( !strcmp(mpsinputField0(mpsi), "ROWS") )
840 mpsinputSetSection(mpsi, MPS_ROWS);
841 else if( !strcmp(mpsinputField0(mpsi), "USERCUTS") )
842 mpsinputSetSection(mpsi, MPS_USERCUTS);
843 else if( !strcmp(mpsinputField0(mpsi), "LAZYCONS") )
844 mpsinputSetSection(mpsi, MPS_LAZYCONS);
845 else
846 mpsinputSyntaxerror(mpsi);
847
848 return SCIP_OKAY;
849 }
850
851 /** Process ROWS, USERCUTS, or LAZYCONS section. */
852 static
readRows(MPSINPUT * mpsi,SCIP * scip,const char *** consnames,int * consnamessize,int * nconsnames)853 SCIP_RETCODE readRows(
854 MPSINPUT* mpsi, /**< mps input structure */
855 SCIP* scip, /**< SCIP data structure */
856 const char*** consnames, /**< storage for the constraint names, or NULL */
857 int* consnamessize, /**< the size of the constraint names storage, or NULL */
858 int* nconsnames /**< the number of stored constraint names, or NULL */
859 )
860 {
861 SCIPdebugMsg(scip, "read rows\n");
862
863 /* coverity[tainted_data] */
864 while( mpsinputReadLine(mpsi) )
865 {
866 if( mpsinputField0(mpsi) != NULL )
867 {
868 if( !strcmp(mpsinputField0(mpsi), "ROWS") )
869 mpsinputSetSection(mpsi, MPS_ROWS);
870 else if( !strcmp(mpsinputField0(mpsi), "USERCUTS") )
871 mpsinputSetSection(mpsi, MPS_USERCUTS);
872 else if( !strcmp(mpsinputField0(mpsi), "LAZYCONS") )
873 mpsinputSetSection(mpsi, MPS_LAZYCONS);
874 else if( !strcmp(mpsinputField0(mpsi), "COLUMNS") )
875 mpsinputSetSection(mpsi, MPS_COLUMNS);
876 else
877 mpsinputSyntaxerror(mpsi);
878
879 return SCIP_OKAY;
880 }
881
882 if( *mpsinputField1(mpsi) == 'N' )
883 {
884 if( *mpsinputObjname(mpsi) == '\0' )
885 mpsinputSetObjname(mpsi, mpsinputField2(mpsi));
886 else
887 mpsinputEntryIgnored(scip, mpsi, "row", mpsinputField2(mpsi), "objective function", "N", SCIP_VERBLEVEL_NORMAL);
888 }
889 else
890 {
891 SCIP_CONS* cons;
892 SCIP_Bool initial;
893 SCIP_Bool separate;
894 SCIP_Bool enforce;
895 SCIP_Bool check;
896 SCIP_Bool propagate;
897 SCIP_Bool local;
898 SCIP_Bool modifiable;
899 SCIP_Bool dynamic;
900 SCIP_Bool removable;
901
902 cons = SCIPfindCons(scip, mpsinputField2(mpsi));
903 if( cons != NULL )
904 break;
905
906 initial = mpsi->initialconss && (mpsinputSection(mpsi) == MPS_ROWS);
907 separate = TRUE;
908 enforce = (mpsinputSection(mpsi) != MPS_USERCUTS);
909 check = (mpsinputSection(mpsi) != MPS_USERCUTS);
910 propagate = TRUE;
911 local = FALSE;
912 modifiable = FALSE;
913 dynamic = mpsi->dynamicconss;
914 removable = mpsi->dynamicrows || (mpsinputSection(mpsi) == MPS_USERCUTS);
915
916 switch(*mpsinputField1(mpsi))
917 {
918 case 'G' :
919 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, mpsinputField2(mpsi), 0, NULL, NULL, 0.0, SCIPinfinity(scip),
920 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, FALSE) );
921 break;
922 case 'E' :
923 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, mpsinputField2(mpsi), 0, NULL, NULL, 0.0, 0.0,
924 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, FALSE) );
925 break;
926 case 'L' :
927 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, mpsinputField2(mpsi), 0, NULL, NULL, -SCIPinfinity(scip), 0.0,
928 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, FALSE) );
929 break;
930 default :
931 mpsinputSyntaxerror(mpsi);
932 return SCIP_OKAY;
933 }
934 SCIP_CALL( SCIPaddCons(scip, cons) );
935 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
936
937 /* if the file is of type cor, then the constraint names must be stored */
938 SCIP_CALL( addConsNameToStorage(scip, consnames, consnamessize, nconsnames, mpsinputField2(mpsi)) );
939 }
940 }
941 mpsinputSyntaxerror(mpsi);
942
943 return SCIP_OKAY;
944 }
945
946 /** Process COLUMNS section. */
947 static
readCols(MPSINPUT * mpsi,SCIP * scip,const char *** varnames,int * varnamessize,int * nvarnames)948 SCIP_RETCODE readCols(
949 MPSINPUT* mpsi, /**< mps input structure */
950 SCIP* scip, /**< SCIP data structure */
951 const char*** varnames, /**< storage for the variable names, or NULL */
952 int* varnamessize, /**< the size of the variable names storage, or NULL */
953 int* nvarnames /**< the number of stored variable names, or NULL */
954 )
955 {
956 char colname[MPS_MAX_NAMELEN] = { '\0' };
957 SCIP_CONS* cons;
958 SCIP_VAR* var;
959 SCIP_Real val;
960 SCIP_Bool usevartable;
961
962 SCIPdebugMsg(scip, "read columns\n");
963
964 var = NULL;
965 SCIP_CALL( SCIPgetBoolParam(scip, "misc/usevartable", &usevartable) );
966
967 while( mpsinputReadLine(mpsi) )
968 {
969 if( mpsinputField0(mpsi) != 0 )
970 {
971 if( strcmp(mpsinputField0(mpsi), "RHS") )
972 break;
973
974 /* add the last variable to the problem */
975 if( var != NULL )
976 {
977 SCIP_CALL( SCIPaddVar(scip, var) );
978 SCIP_CALL( SCIPreleaseVar(scip, &var) );
979 }
980 assert(var == NULL);
981
982 mpsinputSetSection(mpsi, MPS_RHS);
983 return SCIP_OKAY;
984 }
985 if( mpsinputField1(mpsi) == NULL || mpsinputField2(mpsi) == NULL || mpsinputField3(mpsi) == NULL )
986 break;
987
988 /* new column? */
989 if( strcmp(colname, mpsinputField1(mpsi)) )
990 {
991 /* add the last variable to the problem */
992 if( var != NULL )
993 {
994 SCIP_CALL( SCIPaddVar(scip, var) );
995 SCIP_CALL( SCIPreleaseVar(scip, &var) );
996 }
997 assert(var == NULL);
998
999 (void)SCIPmemccpy(colname, mpsinputField1(mpsi), '\0', MPS_MAX_NAMELEN - 1);
1000
1001 /* check whether we have seen this variable before, this would not allowed */
1002 if( usevartable && SCIPfindVar(scip, colname) != NULL )
1003 {
1004 SCIPerrorMessage("Coeffients of column <%s> don't appear consecutively (line: %d)\n",
1005 colname, mpsi->lineno);
1006
1007 return SCIP_READERROR;
1008 }
1009
1010 /* if the file type is a cor file, the the variable name must be stored */
1011 SCIP_CALL( addVarNameToStorage(scip, varnames, varnamessize, nvarnames, colname) );
1012
1013 if( mpsinputIsInteger(mpsi) )
1014 {
1015 /* for integer variables, default bounds are 0 <= x < 1(not +infinity, like it is for continuous variables), and default cost is 0 */
1016 SCIP_CALL( SCIPcreateVar(scip, &var, colname, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
1017 !mpsi->dynamiccols, mpsi->dynamiccols, NULL, NULL, NULL, NULL, NULL) );
1018 }
1019 else
1020 {
1021 /* for continuous variables, default bounds are 0 <= x, and default cost is 0 */
1022 SCIP_CALL( SCIPcreateVar(scip, &var, colname, 0.0, SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS,
1023 !mpsi->dynamiccols, mpsi->dynamiccols, NULL, NULL, NULL, NULL, NULL) );
1024 }
1025 }
1026 assert(var != NULL);
1027
1028 val = atof(mpsinputField3(mpsi));
1029
1030 if( !strcmp(mpsinputField2(mpsi), mpsinputObjname(mpsi)) )
1031 {
1032 SCIP_CALL( SCIPchgVarObj(scip, var, val) );
1033 }
1034 else
1035 {
1036 cons = SCIPfindCons(scip, mpsinputField2(mpsi));
1037 if( cons == NULL )
1038 mpsinputEntryIgnored(scip, mpsi, "Column", mpsinputField1(mpsi), "row", mpsinputField2(mpsi), SCIP_VERBLEVEL_FULL);
1039 else if( !SCIPisZero(scip, val) )
1040 {
1041 /* warn the user in case the coefficient is infinite */
1042 if( SCIPisInfinity(scip, REALABS(val)) )
1043 {
1044 SCIPwarningMessage(scip, "Coefficient of variable <%s> in constraint <%s> contains infinite value <%e>,"
1045 " consider adjusting SCIP infinity.\n", SCIPvarGetName(var), SCIPconsGetName(cons), val);
1046 }
1047 SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, val) );
1048 }
1049 }
1050 if( mpsinputField5(mpsi) != NULL )
1051 {
1052 assert(mpsinputField4(mpsi) != NULL);
1053
1054 val = atof(mpsinputField5(mpsi));
1055
1056 if( !strcmp(mpsinputField4(mpsi), mpsinputObjname(mpsi)) )
1057 {
1058 SCIP_CALL( SCIPchgVarObj(scip, var, val) );
1059 }
1060 else
1061 {
1062 cons = SCIPfindCons(scip, mpsinputField4(mpsi));
1063 if( cons == NULL )
1064 mpsinputEntryIgnored(scip, mpsi, "Column", mpsinputField1(mpsi), "row", mpsinputField4(mpsi), SCIP_VERBLEVEL_FULL);
1065 else if( !SCIPisZero(scip, val) )
1066 {
1067 SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, val) );
1068 }
1069 }
1070 }
1071 }
1072 mpsinputSyntaxerror(mpsi);
1073
1074 return SCIP_OKAY;
1075 }
1076
1077 /** Process RHS section. */
1078 static
readRhs(MPSINPUT * mpsi,SCIP * scip)1079 SCIP_RETCODE readRhs(
1080 MPSINPUT* mpsi, /**< mps input structure */
1081 SCIP* scip /**< SCIP data structure */
1082 )
1083 {
1084 char rhsname[MPS_MAX_NAMELEN] = { '\0' };
1085 SCIP_CONS* cons;
1086 SCIP_Real lhs;
1087 SCIP_Real rhs;
1088 SCIP_Real val;
1089
1090 SCIPdebugMsg(scip, "read right hand sides\n");
1091
1092 while( mpsinputReadLine(mpsi) )
1093 {
1094 if( mpsinputField0(mpsi) != NULL )
1095 {
1096 if( !strcmp(mpsinputField0(mpsi), "RANGES") )
1097 mpsinputSetSection(mpsi, MPS_RANGES);
1098 else if( !strcmp(mpsinputField0(mpsi), "BOUNDS") )
1099 mpsinputSetSection(mpsi, MPS_BOUNDS);
1100 else if( !strcmp(mpsinputField0(mpsi), "SOS") )
1101 mpsinputSetSection(mpsi, MPS_SOS);
1102 else if( !strcmp(mpsinputField0(mpsi), "QMATRIX") )
1103 mpsinputSetSection(mpsi, MPS_QMATRIX);
1104 else if( !strcmp(mpsinputField0(mpsi), "QUADOBJ") )
1105 mpsinputSetSection(mpsi, MPS_QUADOBJ);
1106 else if( !strcmp(mpsinputField0(mpsi), "QCMATRIX") )
1107 mpsinputSetSection(mpsi, MPS_QCMATRIX);
1108 else if( !strcmp(mpsinputField0(mpsi), "INDICATORS") )
1109 mpsinputSetSection(mpsi, MPS_INDICATORS);
1110 else if( !strcmp(mpsinputField0(mpsi), "ENDATA") )
1111 mpsinputSetSection(mpsi, MPS_ENDATA);
1112 else
1113 break;
1114 return SCIP_OKAY;
1115 }
1116 if( (mpsinputField2(mpsi) != NULL && mpsinputField3(mpsi) == NULL)
1117 || (mpsinputField4(mpsi) != NULL && mpsinputField5(mpsi) == NULL) )
1118 {
1119 SCIPwarningMessage(scip, "reading rhs section, a field is missing, assuming that the vector name is the missing one(, row identfier <%s>)\n", mpsinputField2(mpsi));
1120
1121 mpsinputInsertName(mpsi, "_RHS_", FALSE);
1122 }
1123
1124 if( mpsinputField1(mpsi) == NULL || mpsinputField2(mpsi) == NULL || mpsinputField3(mpsi) == NULL )
1125 break;
1126
1127 if( *rhsname == '\0' )
1128 (void)SCIPmemccpy(rhsname, mpsinputField1(mpsi), '\0', MPS_MAX_NAMELEN - 1);
1129
1130 if( !strcmp(rhsname, mpsinputField1(mpsi)) )
1131 {
1132 cons = SCIPfindCons(scip, mpsinputField2(mpsi));
1133 if( cons == NULL )
1134 {
1135 /* the rhs of the objective row is treated as objective constant */
1136 if( strcmp(mpsinputField2(mpsi), mpsinputObjname(mpsi)) == 0 )
1137 {
1138 val = atof(mpsinputField3(mpsi));
1139 SCIP_CALL( SCIPaddOrigObjoffset(scip, -val) );
1140 }
1141 else
1142 mpsinputEntryIgnored(scip, mpsi, "RHS", mpsinputField1(mpsi), "row", mpsinputField2(mpsi), SCIP_VERBLEVEL_NORMAL);
1143 }
1144 else
1145 {
1146 val = atof(mpsinputField3(mpsi));
1147
1148 /* find out the row sense */
1149 lhs = SCIPgetLhsLinear(scip, cons);
1150 rhs = SCIPgetRhsLinear(scip, cons);
1151 if( SCIPisInfinity(scip, -lhs) )
1152 {
1153 /* lhs = -infinity -> lower or equal */
1154 assert(SCIPisZero(scip, rhs));
1155 SCIP_CALL( SCIPchgRhsLinear(scip, cons, val) );
1156 }
1157 else if( SCIPisInfinity(scip, rhs) )
1158 {
1159 /* rhs = +infinity -> greater or equal */
1160 assert(SCIPisZero(scip, lhs));
1161 SCIP_CALL( SCIPchgLhsLinear(scip, cons, val) );
1162 }
1163 else
1164 {
1165 /* lhs > -infinity, rhs < infinity -> equality */
1166 assert(SCIPisZero(scip, lhs));
1167 assert(SCIPisZero(scip, rhs));
1168 SCIP_CALL( SCIPchgLhsLinear(scip, cons, val) );
1169 SCIP_CALL( SCIPchgRhsLinear(scip, cons, val) );
1170 }
1171 SCIPdebugMsg(scip, "RHS <%s> lhs: %g rhs: %g val: <%22.12g>\n", mpsinputField2(mpsi), lhs, rhs, val);
1172 }
1173 if( mpsinputField5(mpsi) != NULL )
1174 {
1175 cons = SCIPfindCons(scip, mpsinputField4(mpsi));
1176 if( cons == NULL )
1177 {
1178 /* the rhs of the objective row is treated as objective constant */
1179 if( strcmp(mpsinputField4(mpsi), mpsinputObjname(mpsi)) == 0 )
1180 {
1181 val = atof(mpsinputField5(mpsi));
1182 SCIP_CALL( SCIPaddOrigObjoffset(scip, -val) );
1183 }
1184 else
1185 mpsinputEntryIgnored(scip, mpsi, "RHS", mpsinputField1(mpsi), "row", mpsinputField4(mpsi), SCIP_VERBLEVEL_NORMAL);
1186 }
1187 else
1188 {
1189 val = atof(mpsinputField5(mpsi));
1190
1191 /* find out the row sense */
1192 lhs = SCIPgetLhsLinear(scip, cons);
1193 rhs = SCIPgetRhsLinear(scip, cons);
1194 if( SCIPisInfinity(scip, -lhs) )
1195 {
1196 /* lhs = -infinity -> lower or equal */
1197 assert(SCIPisZero(scip, rhs));
1198 SCIP_CALL( SCIPchgRhsLinear(scip, cons, val) );
1199 }
1200 else if( SCIPisInfinity(scip, rhs) )
1201 {
1202 /* rhs = +infinity -> greater or equal */
1203 assert(SCIPisZero(scip, lhs));
1204 SCIP_CALL( SCIPchgLhsLinear(scip, cons, val) );
1205 }
1206 else
1207 {
1208 /* lhs > -infinity, rhs < infinity -> equality */
1209 assert(SCIPisZero(scip, lhs));
1210 assert(SCIPisZero(scip, rhs));
1211 SCIP_CALL( SCIPchgLhsLinear(scip, cons, val) );
1212 SCIP_CALL( SCIPchgRhsLinear(scip, cons, val) );
1213 }
1214 SCIPdebugMsg(scip, "RHS <%s> lhs: %g rhs: %g val: <%22.12g>\n", mpsinputField4(mpsi), lhs, rhs, val);
1215 }
1216 }
1217 }
1218 }
1219 mpsinputSyntaxerror(mpsi);
1220
1221 return SCIP_OKAY;
1222 }
1223
1224 /** Process RANGES section */
1225 static
readRanges(MPSINPUT * mpsi,SCIP * scip)1226 SCIP_RETCODE readRanges(
1227 MPSINPUT* mpsi, /**< mps input structure */
1228 SCIP* scip /**< SCIP data structure */
1229 )
1230 {
1231 char rngname[MPS_MAX_NAMELEN] = { '\0' };
1232 SCIP_CONS* cons;
1233 SCIP_Real lhs;
1234 SCIP_Real rhs;
1235 SCIP_Real val;
1236
1237 SCIPdebugMsg(scip, "read ranges\n");
1238
1239 while( mpsinputReadLine(mpsi) )
1240 {
1241 if( mpsinputField0(mpsi) != NULL )
1242 {
1243 if( !strcmp(mpsinputField0(mpsi), "BOUNDS") )
1244 mpsinputSetSection(mpsi, MPS_BOUNDS);
1245 else if( !strcmp(mpsinputField0(mpsi), "SOS") )
1246 mpsinputSetSection(mpsi, MPS_SOS);
1247 else if( !strcmp(mpsinputField0(mpsi), "QMATRIX") )
1248 mpsinputSetSection(mpsi, MPS_QMATRIX);
1249 else if( !strcmp(mpsinputField0(mpsi), "QUADOBJ") )
1250 mpsinputSetSection(mpsi, MPS_QUADOBJ);
1251 else if( !strcmp(mpsinputField0(mpsi), "QCMATRIX") )
1252 mpsinputSetSection(mpsi, MPS_QCMATRIX);
1253 else if( !strcmp(mpsinputField0(mpsi), "INDICATORS") )
1254 mpsinputSetSection(mpsi, MPS_INDICATORS);
1255 else if( !strcmp(mpsinputField0(mpsi), "ENDATA") )
1256 mpsinputSetSection(mpsi, MPS_ENDATA);
1257 else
1258 break;
1259 return SCIP_OKAY;
1260 }
1261 if( (mpsinputField2(mpsi) != NULL && mpsinputField3(mpsi) == NULL)
1262 || (mpsinputField4(mpsi) != NULL && mpsinputField5(mpsi) == NULL) )
1263 {
1264 SCIPwarningMessage(scip, "reading ranged section, a field is missing, assuming that the vector name is the missing one(, row identfier <%s>)\n", mpsinputField2(mpsi));
1265
1266 mpsinputInsertName(mpsi, "_RNG_", FALSE);
1267 }
1268
1269 if( mpsinputField1(mpsi) == NULL || mpsinputField2(mpsi) == NULL || mpsinputField3(mpsi) == NULL )
1270 break;
1271
1272 if( *rngname == '\0' )
1273 (void)SCIPmemccpy(rngname, mpsinputField1(mpsi), '\0', MPS_MAX_NAMELEN - 1);
1274
1275 /* The rules are:
1276 * Row Sign LHS RHS
1277 * ----------------------------------------
1278 * G +/- rhs rhs + |range|
1279 * L +/- rhs - |range| rhs
1280 * E + rhs rhs + range
1281 * E - rhs + range rhs
1282 * ----------------------------------------
1283 */
1284 if( !strcmp(rngname, mpsinputField1(mpsi)) )
1285 {
1286 cons = SCIPfindCons(scip, mpsinputField2(mpsi));
1287 if( cons == NULL )
1288 mpsinputEntryIgnored(scip, mpsi, "Range", mpsinputField1(mpsi), "row", mpsinputField2(mpsi), SCIP_VERBLEVEL_NORMAL);
1289 else
1290 {
1291 val = atof(mpsinputField3(mpsi));
1292
1293 /* find out the row sense */
1294 lhs = SCIPgetLhsLinear(scip, cons);
1295 rhs = SCIPgetRhsLinear(scip, cons);
1296 if( SCIPisInfinity(scip, -lhs) )
1297 {
1298 /* lhs = -infinity -> lower or equal */
1299 SCIP_CALL( SCIPchgLhsLinear(scip, cons, rhs - REALABS(val)) );
1300 }
1301 else if( SCIPisInfinity(scip, rhs) )
1302 {
1303 /* rhs = +infinity -> greater or equal */
1304 SCIP_CALL( SCIPchgRhsLinear(scip, cons, lhs + REALABS(val)) );
1305 }
1306 else
1307 {
1308 /* lhs > -infinity, rhs < infinity -> equality */
1309 assert(SCIPisEQ(scip, lhs, rhs));
1310 if( val >= 0.0 )
1311 {
1312 SCIP_CALL( SCIPchgRhsLinear(scip, cons, rhs + val) );
1313 }
1314 else
1315 {
1316 SCIP_CALL( SCIPchgLhsLinear(scip, cons, lhs + val) );
1317 }
1318 }
1319 }
1320 if( mpsinputField5(mpsi) != NULL )
1321 {
1322 cons = SCIPfindCons(scip, mpsinputField4(mpsi));
1323 if( cons == NULL )
1324 mpsinputEntryIgnored(scip, mpsi, "Range", mpsinputField1(mpsi), "row", mpsinputField4(mpsi), SCIP_VERBLEVEL_NORMAL);
1325 else
1326 {
1327 val = atof(mpsinputField5(mpsi));
1328
1329 /* find out the row sense */
1330 lhs = SCIPgetLhsLinear(scip, cons);
1331 rhs = SCIPgetRhsLinear(scip, cons);
1332 if( SCIPisInfinity(scip, -lhs) )
1333 {
1334 /* lhs = -infinity -> lower or equal */
1335 SCIP_CALL( SCIPchgLhsLinear(scip, cons, rhs - REALABS(val)) );
1336 }
1337 else if( SCIPisInfinity(scip, rhs) )
1338 {
1339 /* rhs = +infinity -> greater or equal */
1340 SCIP_CALL( SCIPchgRhsLinear(scip, cons, lhs + REALABS(val)) );
1341 }
1342 else
1343 {
1344 /* lhs > -infinity, rhs < infinity -> equality */
1345 assert(SCIPisEQ(scip, lhs, rhs));
1346 if( val >= 0.0 )
1347 {
1348 SCIP_CALL( SCIPchgRhsLinear(scip, cons, rhs + val) );
1349 }
1350 else
1351 {
1352 SCIP_CALL( SCIPchgLhsLinear(scip, cons, lhs + val) );
1353 }
1354 }
1355 }
1356 }
1357 }
1358 }
1359 mpsinputSyntaxerror(mpsi);
1360
1361 return SCIP_OKAY;
1362 }
1363
1364 /** Process BOUNDS section. */
1365 static
readBounds(MPSINPUT * mpsi,SCIP * scip)1366 SCIP_RETCODE readBounds(
1367 MPSINPUT* mpsi, /**< mps input structure */
1368 SCIP* scip /**< SCIP data structure */
1369 )
1370 {
1371 char bndname[MPS_MAX_NAMELEN] = { '\0' };
1372 SCIP_VAR* var;
1373 SCIP_RETCODE retcode;
1374 SCIP_Real val;
1375 SCIP_Bool shifted;
1376
1377 SCIP_VAR** semicont;
1378 int nsemicont;
1379 int semicontsize;
1380
1381 retcode = SCIP_OKAY;
1382
1383 semicont = NULL;
1384 nsemicont = 0;
1385 semicontsize = 0;
1386
1387 SCIPdebugMsg(scip, "read bounds\n");
1388
1389 while( mpsinputReadLine(mpsi) )
1390 {
1391 if( mpsinputField0(mpsi) != 0 )
1392 {
1393 if( !strcmp(mpsinputField0(mpsi), "SOS") )
1394 mpsinputSetSection(mpsi, MPS_SOS);
1395 else if( !strcmp(mpsinputField0(mpsi), "QMATRIX") )
1396 mpsinputSetSection(mpsi, MPS_QMATRIX);
1397 else if( !strcmp(mpsinputField0(mpsi), "QUADOBJ") )
1398 mpsinputSetSection(mpsi, MPS_QUADOBJ);
1399 else if( !strcmp(mpsinputField0(mpsi), "QCMATRIX") )
1400 mpsinputSetSection(mpsi, MPS_QCMATRIX);
1401 else if( !strcmp(mpsinputField0(mpsi), "INDICATORS") )
1402 mpsinputSetSection(mpsi, MPS_INDICATORS);
1403 else if( !strcmp(mpsinputField0(mpsi), "ENDATA") )
1404 mpsinputSetSection(mpsi, MPS_ENDATA);
1405 else
1406 break;
1407 goto READBOUNDS_FINISH;
1408 }
1409
1410 shifted = FALSE;
1411
1412 /* Is the value field used ? */
1413 if( !strcmp(mpsinputField1(mpsi), "LO") /* lower bound given in field 4 */
1414 || !strcmp(mpsinputField1(mpsi), "UP") /* upper bound given in field 4 */
1415 || !strcmp(mpsinputField1(mpsi), "FX") /* fixed value given in field 4 */
1416 || !strcmp(mpsinputField1(mpsi), "LI") /* CPLEX extension: lower bound of integer variable given in field 4 */
1417 || !strcmp(mpsinputField1(mpsi), "UI") /* CPLEX extension: upper bound of integer variable given in field 4 */
1418 || !strcmp(mpsinputField1(mpsi), "SC") /* CPLEX extension: semi-continuous variable, upper bound given in field 4 */
1419 || !strcmp(mpsinputField1(mpsi), "SI") )/* CPLEX extension: semi-integer variable, upper bound given in field 4 */
1420 {
1421 if( mpsinputField3(mpsi) != NULL && mpsinputField4(mpsi) == NULL )
1422 {
1423 int l;
1424
1425 /* check what might be missing, if field 3 is a number the bound name might be missing */
1426 for( l = (int) strlen(mpsinputField3(mpsi)) - 1; l >= 0; --l )
1427 {
1428 if( mpsinputField3(mpsi)[l] != '.' && !isdigit(mpsinputField3(mpsi)[l]) )
1429 break;
1430 }
1431
1432 /* the bound name?! is missing */
1433 if( l < 0 )
1434 {
1435 SCIPwarningMessage(scip, "in bound section a name for value <%s> might be missing\n", mpsinputField3(mpsi));
1436
1437 mpsinputInsertName(mpsi, "_BND_", TRUE);
1438 shifted = TRUE;
1439 }
1440 /* the bound is be missing */
1441 else
1442 {
1443 SCIPwarningMessage(scip, "in bound section a value for column <%s> is missing, assuming 0.0\n", mpsinputField3(mpsi));
1444
1445 mpsinputInsertField4(mpsi, "0.0");
1446 shifted = TRUE;
1447 }
1448 }
1449 }
1450 else if( !strcmp(mpsinputField1(mpsi), "FR") /* free variable */
1451 || !strcmp(mpsinputField1(mpsi), "MI") /* lower bound is minus infinity */
1452 || !strcmp(mpsinputField1(mpsi), "PL") /* upper bound is plus infinity */
1453 || !strcmp(mpsinputField1(mpsi), "BV") ) /* CPLEX extension: binary variable */
1454 {
1455 if( mpsinputField2(mpsi) != NULL && mpsinputField3(mpsi) == NULL )
1456 {
1457 SCIPwarningMessage(scip, "in bound section a name for a column is missing\n");
1458
1459 mpsinputInsertName(mpsi, "_BND_", TRUE);
1460 shifted = TRUE;
1461 }
1462 }
1463 else
1464 {
1465 mpsinputSyntaxerror(mpsi);
1466 return SCIP_OKAY;
1467 }
1468
1469 if( mpsinputField1(mpsi) == NULL || mpsinputField2(mpsi) == NULL || mpsinputField3(mpsi) == NULL )
1470 break;
1471
1472 if( *bndname == '\0' )
1473 (void)SCIPmemccpy(bndname, mpsinputField2(mpsi), '\0', MPS_MAX_NAMELEN - 1);
1474
1475 /* Only read the first Bound in section */
1476 if( !strcmp(bndname, mpsinputField2(mpsi)) )
1477 {
1478 SCIP_VARTYPE oldvartype;
1479 SCIP_Bool infeasible;
1480
1481 var = SCIPfindVar(scip, mpsinputField3(mpsi));
1482 /* if variable did not appear in columns section before, then it may still come in later sections (QCMATRIX, QMATRIX, SOS, ...)
1483 * thus add it as continuous variables, which has default bounds 0.0 <= x, and default cost 0.0 */
1484 if( var == NULL )
1485 {
1486 SCIP_VAR* varcpy;
1487
1488 SCIP_CALL( SCIPcreateVar(scip, &var, mpsinputField3(mpsi), 0.0, SCIPinfinity(scip), 0.0,
1489 SCIP_VARTYPE_CONTINUOUS, !mpsi->dynamiccols, mpsi->dynamiccols, NULL, NULL, NULL, NULL, NULL) );
1490
1491 SCIP_CALL( SCIPaddVar(scip, var) );
1492 varcpy = var;
1493 SCIP_CALL( SCIPreleaseVar(scip, &varcpy) );
1494 /* mpsinputEntryIgnored(scip, mpsi, "column", mpsinputField3(mpsi), "bound", bndname, SCIP_VERBLEVEL_NORMAL); */
1495 }
1496 assert(var != NULL);
1497
1498 if( mpsinputField4(mpsi) == NULL )
1499 val = 0.0;
1500 else
1501 val = atof(mpsinputField4(mpsi));
1502
1503 /* remember variable type */
1504 oldvartype = SCIPvarGetType(var);
1505
1506 /* If a bound of a binary variable is given, the variable is converted into an integer variable
1507 * with default bounds 0 <= x <= infinity before applying the bound. Note that integer variables
1508 * are by default assumed to be binary, but an explicit lower bound of 0 turns them into integer variables.
1509 * Only if the upper bound is explicitly set to 1, we leave the variable as a binary one.
1510 */
1511 if( oldvartype == SCIP_VARTYPE_BINARY && !((mpsinputField1(mpsi)[0] == 'U' ||
1512 (mpsinputField1(mpsi)[0] == 'F' && mpsinputField1(mpsi)[1] == 'X')) && SCIPisFeasEQ(scip, val, 1.0))
1513 && !(mpsinputField1(mpsi)[0] == 'F' && mpsinputField1(mpsi)[1] == 'X'&& SCIPisFeasEQ(scip, val, 0.0)) )
1514 {
1515 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_INTEGER, &infeasible) );
1516 assert(!infeasible);
1517
1518 oldvartype = SCIP_VARTYPE_INTEGER;
1519 SCIP_CALL( SCIPchgVarUb(scip, var, SCIPinfinity(scip)) );
1520 }
1521
1522 /* switch variable type to continuous before applying the bound, this is necessary for stupid non-integral
1523 * bounds on general variables, which even might lead to infeasibility
1524 */
1525 if( oldvartype != SCIP_VARTYPE_CONTINUOUS )
1526 {
1527 assert(SCIP_VARTYPE_CONTINUOUS >= SCIP_VARTYPE_IMPLINT && SCIP_VARTYPE_IMPLINT >= SCIP_VARTYPE_INTEGER && SCIP_VARTYPE_INTEGER >= SCIP_VARTYPE_BINARY); /*lint !e506*/
1528 /* relaxing variable type */
1529 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_CONTINUOUS, &infeasible) );
1530 }
1531 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS);
1532
1533 switch( mpsinputField1(mpsi)[0] )
1534 {
1535 case 'L':
1536 if( !SCIPisZero(scip, SCIPvarGetLbGlobal(var)) && SCIPisLT(scip, val, SCIPvarGetLbGlobal(var)) )
1537 {
1538 SCIPwarningMessage(scip, "Relaxing already defined lower bound %g of variable <%s> to %g not allowed.\n", SCIPvarGetLbGlobal(var), SCIPvarGetName(var), val);
1539 }
1540
1541 SCIP_CALL( SCIPchgVarLb(scip, var, val) );
1542
1543 if( mpsinputField1(mpsi)[1] == 'I' ) /* CPLEX extension (Integer Bound) */
1544 {
1545 if( !SCIPisFeasIntegral(scip, val) )
1546 {
1547 SCIPwarningMessage(scip, "variable <%s> declared as integral has a non-integral lower bound (%.14g) -> if feasible, bounds will be adjusted\n", SCIPvarGetName(var), val);
1548 }
1549 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_INTEGER, &infeasible) );
1550 /* don't assert feasibility here because the presolver will and should detect a infeasibility */
1551 }
1552 else if( oldvartype < SCIP_VARTYPE_CONTINUOUS )
1553 {
1554 if( !SCIPisFeasIntegral(scip, val) )
1555 {
1556 SCIPwarningMessage(scip, "variable <%s> declared as integral has a non-integral lower bound (%.14g) -> if feasible, bounds will be adjusted\n", SCIPvarGetName(var), val);
1557 }
1558 }
1559
1560 break;
1561 case 'U':
1562 if( SCIPisGT(scip, val, SCIPvarGetUbGlobal(var)) )
1563 {
1564 SCIPwarningMessage(scip, "Relaxing already defined upper bound %g of variable <%s> to %g not allowed.\n", SCIPvarGetUbGlobal(var), SCIPvarGetName(var), val);
1565 }
1566
1567 SCIP_CALL( SCIPchgVarUb(scip, var, val) );
1568 if( mpsinputField1(mpsi)[1] == 'I' ) /* CPLEX extension (Integer Bound) */
1569 {
1570 if( !SCIPisFeasIntegral(scip, val) )
1571 {
1572 SCIPwarningMessage(scip, "variable <%s> declared as integral has a non-integral upper bound (%.14g) -> if feasible, bounds will be adjusted\n", SCIPvarGetName(var), val);
1573 }
1574
1575 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_INTEGER, &infeasible) );
1576 /* don't assert feasibility here because the presolver will and should detect an infeasibility */
1577 }
1578 else if( oldvartype < SCIP_VARTYPE_CONTINUOUS )
1579 {
1580 if( !SCIPisFeasIntegral(scip, val) )
1581 {
1582 SCIPwarningMessage(scip, "variable <%s> declared as integral has a non-integral upper bound (%.14g) -> if feasible, bounds will be adjusted\n", SCIPvarGetName(var), val);
1583 }
1584 }
1585 break;
1586 case 'S':
1587 assert(mpsinputField1(mpsi)[1] == 'C' || mpsinputField1(mpsi)[1] == 'I'); /* semi-continuous or semi-integer (CPLEX extension) */
1588 /* remember that variable is semi-continuous/-integer */
1589 if( semicontsize <= nsemicont )
1590 {
1591 semicontsize = SCIPcalcMemGrowSize(scip, nsemicont+1);
1592 if( semicont == NULL )
1593 {
1594 SCIP_CALL( SCIPallocBufferArray(scip, &semicont, semicontsize) );
1595 }
1596 else
1597 {
1598 SCIP_CALL( SCIPreallocBufferArray(scip, &semicont, semicontsize) );
1599 }
1600 }
1601 assert(semicont != NULL);
1602 semicont[nsemicont] = var;
1603 ++nsemicont;
1604
1605 if( mpsinputField1(mpsi)[1] == 'I' ) /* variable is semi-integer, hence change its type to integer (the "semi" part will be handled below) */
1606 {
1607 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_INTEGER, &infeasible) );
1608 /* don't assert feasibility here because the presolver will and should detect an infeasibility */
1609 }
1610
1611 /* if both bounds are infinite anyway, we do not need to print a warning or change the bound */
1612 if( !SCIPisInfinity(scip, val) || !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
1613 {
1614 if( SCIPisGT(scip, val, SCIPvarGetUbGlobal(var)) )
1615 {
1616 SCIPwarningMessage(scip, "Relaxing already defined upper bound %g of variable <%s> to %g not allowed.\n", SCIPvarGetUbGlobal(var), SCIPvarGetName(var), val);
1617 }
1618
1619 SCIP_CALL( SCIPchgVarUb(scip, var, val) );
1620 }
1621 break;
1622 case 'F':
1623 if( mpsinputField1(mpsi)[1] == 'X' )
1624 {
1625 SCIP_CALL( SCIPchgVarLb(scip, var, val) );
1626 SCIP_CALL( SCIPchgVarUb(scip, var, val) );
1627 }
1628 else
1629 {
1630 SCIP_CALL( SCIPchgVarLb(scip, var, -SCIPinfinity(scip)) );
1631 SCIP_CALL( SCIPchgVarUb(scip, var, +SCIPinfinity(scip)) );
1632 }
1633 break;
1634 case 'M':
1635 SCIP_CALL( SCIPchgVarLb(scip, var, -SCIPinfinity(scip)) );
1636 break;
1637 case 'P':
1638 SCIP_CALL( SCIPchgVarUb(scip, var, +SCIPinfinity(scip)) );
1639 break;
1640 case 'B' : /* CPLEX extension (Binary) */
1641 SCIP_CALL( SCIPchgVarLb(scip, var, 0.0) );
1642 SCIP_CALL( SCIPchgVarUb(scip, var, 1.0) );
1643 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
1644 /* don't assert feasibility here because the presolver will and should detect a infeasibility */
1645 break;
1646 default:
1647 mpsinputSyntaxerror(mpsi);
1648 return SCIP_OKAY;
1649 }
1650
1651 /* switch variable type back to old type if necessary */
1652 if( oldvartype < SCIPvarGetType(var) )
1653 {
1654 SCIP_CALL( SCIPchgVarType(scip, var, oldvartype, &infeasible) );
1655 }
1656 }
1657 else
1658 {
1659 /* check for syntax error */
1660 assert(*bndname != '\0');
1661 if( strcmp(bndname, mpsinputField3(mpsi)) == 0 && shifted )
1662 {
1663 mpsinputSyntaxerror(mpsi);
1664 return SCIP_OKAY;
1665 }
1666
1667 mpsinputEntryIgnored(scip, mpsi, "bound", mpsinputField2(mpsi), "variable", mpsinputField3(mpsi), SCIP_VERBLEVEL_NORMAL);
1668 }
1669 }
1670 mpsinputSyntaxerror(mpsi);
1671
1672 READBOUNDS_FINISH:
1673 if( nsemicont > 0 )
1674 {
1675 SCIP_CONS* cons;
1676 SCIP_VAR* vars[2];
1677 SCIP_BOUNDTYPE boundtypes[2];
1678 SCIP_Real bounds[2];
1679 char name[SCIP_MAXSTRLEN];
1680 SCIP_Real oldlb;
1681 int i;
1682
1683 assert(semicont != NULL);
1684
1685 /* add bound disjunction constraints for semi-continuous and semi-integer variables */
1686 for( i = 0; i < nsemicont; ++i )
1687 {
1688 var = semicont[i];
1689 assert(SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS);
1690
1691 oldlb = SCIPvarGetLbGlobal(var);
1692 assert(oldlb >= 0.0);
1693
1694 /* if no bound was specified (which we assume if we see lower bound 0.0),
1695 * then the default lower bound for a semi-continuous variable is 1.0 */
1696 if( oldlb == 0.0 )
1697 oldlb = 1.0;
1698
1699 /* change the lower bound to 0.0 */
1700 SCIP_CALL( SCIPchgVarLb(scip, var, 0.0) );
1701
1702 /* add a bound disjunction constraint to say var <= 0.0 or var >= oldlb */
1703 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "semicont_%s", SCIPvarGetName(var));
1704
1705 vars[0] = var;
1706 vars[1] = var;
1707 boundtypes[0] = SCIP_BOUNDTYPE_UPPER;
1708 boundtypes[1] = SCIP_BOUNDTYPE_LOWER;
1709 bounds[0] = 0.0;
1710 bounds[1] = oldlb;
1711
1712 retcode = SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vars, boundtypes, bounds,
1713 !mpsi->dynamiccols, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, mpsi->dynamicconss, mpsi->dynamiccols, FALSE);
1714
1715 if( retcode != SCIP_OKAY )
1716 break;
1717
1718 SCIP_CALL( SCIPaddCons(scip, cons) );
1719
1720 SCIPdebugMsg(scip, "add bound disjunction constraint for semi-continuity/-integrality of <%s>:\n\t", SCIPvarGetName(var));
1721 SCIPdebugPrintCons(scip, cons, NULL);
1722
1723 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1724 }
1725 }
1726
1727 SCIPfreeBufferArrayNull(scip, &semicont);
1728
1729 SCIP_CALL( retcode );
1730
1731 return SCIP_OKAY;
1732 }
1733
1734
1735 /** Process SOS section.
1736 *
1737 * We read the SOS section, which is a nonstandard section introduced by CPLEX.
1738 *
1739 * @note Currently we do not support the standard way of specifying SOS constraints via markers.
1740 */
1741 static
readSOS(MPSINPUT * mpsi,SCIP * scip)1742 SCIP_RETCODE readSOS(
1743 MPSINPUT* mpsi, /**< mps input structure */
1744 SCIP* scip /**< SCIP data structure */
1745 )
1746 {
1747 SCIP_Bool initial;
1748 SCIP_Bool separate;
1749 SCIP_Bool enforce;
1750 SCIP_Bool check;
1751 SCIP_Bool propagate;
1752 SCIP_Bool local;
1753 SCIP_Bool dynamic;
1754 SCIP_Bool removable;
1755 char name[MPS_MAX_NAMELEN] = { '\0' };
1756 SCIP_CONS* cons = NULL;
1757 int consType = -1;
1758 int cnt = 0;
1759
1760 SCIPdebugMsg(scip, "read SOS constraints\n");
1761
1762 /* standard settings for SOS constraints: */
1763 initial = mpsi->initialconss;
1764 separate = TRUE;
1765 enforce = TRUE;
1766 check = TRUE;
1767 propagate = TRUE;
1768 local = FALSE;
1769 dynamic = mpsi->dynamicconss;
1770 removable = mpsi->dynamicrows;
1771
1772 /* loop through section */
1773 while( mpsinputReadLine(mpsi) )
1774 {
1775 int type = -1;
1776
1777 /* check if next section is found */
1778 if( mpsinputField0(mpsi) != NULL )
1779 {
1780 if( !strcmp(mpsinputField0(mpsi), "ENDATA") )
1781 mpsinputSetSection(mpsi, MPS_ENDATA);
1782 else if( !strcmp(mpsinputField0(mpsi), "QMATRIX") )
1783 mpsinputSetSection(mpsi, MPS_QMATRIX);
1784 else if( !strcmp(mpsinputField0(mpsi), "QUADOBJ") )
1785 mpsinputSetSection(mpsi, MPS_QUADOBJ);
1786 else if( !strcmp(mpsinputField0(mpsi), "QCMATRIX") )
1787 mpsinputSetSection(mpsi, MPS_QCMATRIX);
1788 else if( !strcmp(mpsinputField0(mpsi), "INDICATORS") )
1789 mpsinputSetSection(mpsi, MPS_INDICATORS);
1790 break;
1791 }
1792 if( mpsinputField1(mpsi) == NULL )
1793 {
1794 SCIPerrorMessage("empty data in a non-comment line.\n");
1795 mpsinputSyntaxerror(mpsi);
1796 return SCIP_OKAY;
1797 }
1798
1799 /* check for new SOS set */
1800 if( strcmp(mpsinputField1(mpsi), "S1") == 0 )
1801 type = 1;
1802 if( strcmp(mpsinputField1(mpsi), "S2") == 0 )
1803 type = 2;
1804
1805 /* add last constraint and create a new one */
1806 if( type > 0 )
1807 {
1808 assert( type == 1 || type == 2 );
1809 if( cons != NULL )
1810 {
1811 /* add last constraint */
1812 SCIP_CALL( SCIPaddCons(scip, cons) );
1813 SCIPdebugMsg(scip, "(line %d) added constraint <%s>: ", mpsi->lineno, SCIPconsGetName(cons));
1814 SCIPdebugPrintCons(scip, cons, NULL);
1815 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1816 }
1817
1818 /* check name */
1819 if( mpsinputField2(mpsi) != NULL )
1820 (void)SCIPmemccpy(name, mpsinputField2(mpsi), '\0', MPS_MAX_NAMELEN - 1);
1821 else
1822 {
1823 /* create new name */
1824 (void) SCIPsnprintf(name, MPS_MAX_NAMELEN, "SOS%d", ++cnt);
1825 }
1826
1827 /* create new SOS constraint */
1828 if( type == 1 )
1829 {
1830 /* we do not know the name of the constraint */
1831 SCIP_CALL( SCIPcreateConsSOS1(scip, &cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate,
1832 local, dynamic, removable, FALSE) );
1833 }
1834 else
1835 {
1836 assert( type == 2 );
1837 SCIP_CALL( SCIPcreateConsSOS2(scip, &cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate,
1838 local, dynamic, removable, FALSE) );
1839 }
1840 consType = type;
1841 SCIPdebugMsg(scip, "created constraint <%s> of type %d.\n", name, type);
1842 /* note: we ignore the priorities! */
1843 }
1844 else
1845 {
1846 /* otherwise we are in the section given variables */
1847 SCIP_VAR* var;
1848 SCIP_Real weight;
1849 char* endptr;
1850
1851 if( consType != 1 && consType != 2 )
1852 {
1853 SCIPerrorMessage("missing SOS type specification.\n");
1854 mpsinputSyntaxerror(mpsi);
1855 return SCIP_OKAY;
1856 }
1857
1858 /* get variable */
1859 var = SCIPfindVar(scip, mpsinputField1(mpsi));
1860 if( var == NULL )
1861 {
1862 /* ignore unknown variables - we would not know the type anyway */
1863 mpsinputEntryIgnored(scip, mpsi, "column", mpsinputField1(mpsi), "SOS", name, SCIP_VERBLEVEL_NORMAL);
1864 }
1865 else
1866 {
1867 /* get weight */
1868 if( NULL == mpsinputField2(mpsi) )
1869 {
1870 SCIPerrorMessage("weight for variable <%s> not specified.\n", mpsinputField1(mpsi));
1871 mpsinputSyntaxerror(mpsi);
1872 return SCIP_OKAY;
1873 }
1874
1875 weight = strtod(mpsinputField2(mpsi), &endptr);
1876 if( endptr == mpsinputField2(mpsi) || *endptr != '\0' )
1877 {
1878 SCIPerrorMessage("weight for variable <%s> not specified.\n", mpsinputField1(mpsi));
1879 mpsinputSyntaxerror(mpsi);
1880 return SCIP_OKAY;
1881 }
1882
1883 /* add variable and weight */
1884 assert( consType == 1 || consType == 2 );
1885 switch( consType )
1886 {
1887 case 1:
1888 SCIP_CALL( SCIPaddVarSOS1(scip, cons, var, weight) );
1889 break;
1890 case 2:
1891 SCIP_CALL( SCIPaddVarSOS2(scip, cons, var, weight) );
1892 break;
1893 /* coverity[dead_error_begin] */
1894 default:
1895 SCIPerrorMessage("unknown SOS type: <%d>\n", type); /* should not happen */
1896 SCIPABORT();
1897 return SCIP_INVALIDDATA; /*lint !e527*/
1898 }
1899 SCIPdebugMsg(scip, "added variable <%s> with weight %g.\n", SCIPvarGetName(var), weight);
1900 }
1901 /* check other fields */
1902 if( (mpsinputField3(mpsi) != NULL && *mpsinputField3(mpsi) != '\0' ) ||
1903 (mpsinputField4(mpsi) != NULL && *mpsinputField4(mpsi) != '\0' ) ||
1904 (mpsinputField5(mpsi) != NULL && *mpsinputField5(mpsi) != '\0' ) )
1905 {
1906 SCIPwarningMessage(scip, "ignoring data in fields 3-5 <%s> <%s> <%s>.\n",
1907 mpsinputField3(mpsi), mpsinputField4(mpsi), mpsinputField5(mpsi));
1908 }
1909 }
1910 }
1911
1912 if( cons != NULL )
1913 {
1914 /* add last constraint */
1915 SCIP_CALL( SCIPaddCons(scip, cons) );
1916 SCIPdebugMsg(scip, "(line %d) added constraint <%s>: ", mpsi->lineno, SCIPconsGetName(cons));
1917 SCIPdebugPrintCons(scip, cons, NULL);
1918 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1919 }
1920
1921 return SCIP_OKAY;
1922 }
1923
1924
1925 /** Process QMATRIX or QUADOBJ section.
1926 *
1927 * - We read the QMATRIX or QUADOBJ section, which is a nonstandard section introduced by CPLEX.
1928 * - We create a quadratic constraint for this matrix and add a variable to the objective to
1929 * represent the value of the QMATRIX.
1930 * - For a QMATRIX, we expect that both lower and upper diagonal elements are given and every
1931 * coefficient has to be divided by 2.0.
1932 * - For a QUADOBJ, we expect that only the upper diagonal elements are given and thus only
1933 * coefficients on the diagonal have to be divided by 2.0.
1934 */
1935 static
readQMatrix(MPSINPUT * mpsi,SCIP_Bool isQuadObj,SCIP * scip)1936 SCIP_RETCODE readQMatrix(
1937 MPSINPUT* mpsi, /**< mps input structure */
1938 SCIP_Bool isQuadObj, /**< whether we actually read a QUADOBJ section */
1939 SCIP* scip /**< SCIP data structure */
1940 )
1941 {
1942 SCIP_VAR** quadvars1;
1943 SCIP_VAR** quadvars2;
1944 SCIP_Real* quadcoefs;
1945 SCIP_RETCODE retcode;
1946 int cnt = 0; /* number of qmatrix elements processed so far */
1947 int size; /* size of quad* arrays */
1948
1949 SCIPdebugMsg(scip, "read %s objective\n", isQuadObj ? "QUADOBJ" : "QMATRIX");
1950
1951 retcode = SCIP_OKAY;
1952
1953 size = 1;
1954 SCIP_CALL( SCIPallocBufferArray(scip, &quadvars1, size) );
1955 SCIP_CALL( SCIPallocBufferArray(scip, &quadvars2, size) );
1956 SCIP_CALL( SCIPallocBufferArray(scip, &quadcoefs, size) );
1957
1958 /* loop through section */
1959 /* coverity[tainted_data] */
1960 while( mpsinputReadLine(mpsi) )
1961 {
1962 /* otherwise we are in the section given variables */
1963 SCIP_VAR* var1;
1964 SCIP_VAR* var2;
1965 SCIP_Real coef;
1966
1967 /* check if next section is found */
1968 if( mpsinputField0(mpsi) != NULL )
1969 {
1970 if( !strcmp(mpsinputField0(mpsi), "QCMATRIX") )
1971 mpsinputSetSection(mpsi, MPS_QCMATRIX);
1972 else if( !strcmp(mpsinputField0(mpsi), "INDICATORS") )
1973 mpsinputSetSection(mpsi, MPS_INDICATORS);
1974 else if( !strcmp(mpsinputField0(mpsi), "ENDATA") )
1975 mpsinputSetSection(mpsi, MPS_ENDATA);
1976 break;
1977 }
1978 if( mpsinputField1(mpsi) == NULL && mpsinputField2(mpsi) == NULL )
1979 {
1980 SCIPerrorMessage("empty data in a non-comment line.\n");
1981 mpsinputSyntaxerror(mpsi);
1982 SCIPfreeBufferArray(scip, &quadvars1);
1983 SCIPfreeBufferArray(scip, &quadvars2);
1984 SCIPfreeBufferArray(scip, &quadcoefs);
1985 return SCIP_OKAY;
1986 }
1987
1988 /* get first variable */
1989 var1 = SCIPfindVar(scip, mpsinputField1(mpsi));
1990 if( var1 == NULL )
1991 {
1992 /* ignore unknown variables - we would not know the type anyway */
1993 mpsinputEntryIgnored(scip, mpsi, "column", mpsinputField1(mpsi), "QMatrix", "QMATRIX", SCIP_VERBLEVEL_NORMAL);
1994 }
1995 else
1996 {
1997 int k;
1998 for( k = 1; k <= 2; ++k )
1999 {
2000 /* get second variable */
2001 var2 = SCIPfindVar(scip, k == 1 ? mpsinputField2(mpsi) : mpsinputField4(mpsi));
2002 if( var2 == NULL )
2003 {
2004 /* ignore unknown variables - we would not know the type anyway */
2005 mpsinputEntryIgnored(scip, mpsi, "column", mpsinputField2(mpsi), "QMatrix", "QMATRIX", SCIP_VERBLEVEL_NORMAL);
2006 }
2007 else
2008 {
2009 const char* field;
2010 char* endptr;
2011
2012 /* get coefficient */
2013 field = (k == 1 ? mpsinputField3(mpsi) : mpsinputField5(mpsi));
2014 if( NULL == field )
2015 {
2016 SCIPerrorMessage("coefficient of term <%s>*<%s> not specified.\n", SCIPvarGetName(var1), SCIPvarGetName(var2));
2017 mpsinputSyntaxerror(mpsi);
2018 SCIPfreeBufferArray(scip, &quadvars1);
2019 SCIPfreeBufferArray(scip, &quadvars2);
2020 SCIPfreeBufferArray(scip, &quadcoefs);
2021 return SCIP_OKAY;
2022 }
2023
2024 coef = strtod(field, &endptr);
2025 if( endptr == field || *endptr != '\0' )
2026 {
2027 SCIPerrorMessage("coefficient of term <%s>*<%s> not specified.\n", SCIPvarGetName(var1), SCIPvarGetName(var2));
2028 mpsinputSyntaxerror(mpsi);
2029 SCIPfreeBufferArray(scip, &quadvars1);
2030 SCIPfreeBufferArray(scip, &quadvars2);
2031 SCIPfreeBufferArray(scip, &quadcoefs);
2032 return SCIP_OKAY;
2033 }
2034
2035 /* store variables and coefficient */
2036 if( cnt >= size )
2037 {
2038 int newsize = SCIPcalcMemGrowSize(scip, size+1);
2039 assert(newsize > size);
2040 SCIP_CALL( SCIPreallocBufferArray(scip, &quadvars1, newsize) );
2041 SCIP_CALL( SCIPreallocBufferArray(scip, &quadvars2, newsize) );
2042 SCIP_CALL( SCIPreallocBufferArray(scip, &quadcoefs, newsize) );
2043 size = newsize;
2044 }
2045 assert(cnt < size);
2046 quadvars1[cnt] = var1;
2047 quadvars2[cnt] = var2;
2048 quadcoefs[cnt] = coef;
2049
2050 /* diagonal elements have to be divided by 2.0
2051 * in a QMATRIX section also off-diagonal have to be divided by 2.0, since both lower and upper diagonal elements are given
2052 */
2053 if( var1 == var2 || !isQuadObj )
2054 quadcoefs[cnt] /= 2.0;
2055 ++cnt;
2056
2057 SCIPdebugMsg(scip, "stored term %g*<%s>*<%s>.\n", coef, SCIPvarGetName(var1), SCIPvarGetName(var2));
2058 }
2059
2060 if( mpsinputField4(mpsi) == NULL || *mpsinputField4(mpsi) == '\0' )
2061 break;
2062
2063 if( mpsinputField5(mpsi) == NULL || *mpsinputField5(mpsi) == '\0' )
2064 {
2065 /* ignore unknown variables - we would not know the type anyway */
2066 mpsinputEntryIgnored(scip, mpsi, "column", mpsinputField4(mpsi), "QMatrix", "QMATRIX", SCIP_VERBLEVEL_NORMAL);
2067 break;
2068 }
2069 }
2070 }
2071 }
2072
2073 /* add constraint */
2074 if( cnt )
2075 {
2076 SCIP_Bool initial, separate, enforce, check, propagate;
2077 SCIP_Bool local, modifiable, dynamic, removable;
2078 SCIP_CONS* cons = NULL;
2079 SCIP_VAR* qmatrixvar = NULL;
2080 SCIP_Real lhs, rhs;
2081 SCIP_Real minusone = -1.0;
2082
2083 /* determine settings; note that reading/{initialconss,dynamicconss,dynamicrows,dynamiccols} apply only to model
2084 * constraints and variables, not to an auxiliary objective constraint (otherwise it can happen that an auxiliary
2085 * objective variable is loose with infinite best bound, triggering the problem that an LP that is unbounded
2086 * because of loose variables with infinite best bound cannot be solved)
2087 */
2088 initial = TRUE;
2089 separate = TRUE;
2090 enforce = TRUE;
2091 check = TRUE;
2092 propagate = TRUE;
2093 local = FALSE;
2094 modifiable = FALSE;
2095 dynamic = FALSE;
2096 removable = FALSE;
2097
2098 SCIP_CALL( SCIPcreateVar(scip, &qmatrixvar, "qmatrixvar", -SCIPinfinity(scip), SCIPinfinity(scip), 1.0,
2099 SCIP_VARTYPE_CONTINUOUS, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
2100 SCIP_CALL( SCIPaddVar(scip, qmatrixvar) );
2101
2102 if( mpsinputObjsense(mpsi) == SCIP_OBJSENSE_MINIMIZE )
2103 {
2104 lhs = -SCIPinfinity(scip);
2105 rhs = 0.0;
2106 }
2107 else
2108 {
2109 lhs = 0.0;
2110 rhs = SCIPinfinity(scip);
2111 }
2112
2113 retcode = SCIPcreateConsQuadratic(scip, &cons, "qmatrix", 1, &qmatrixvar, &minusone, cnt, quadvars1, quadvars2, quadcoefs, lhs, rhs,
2114 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable);
2115
2116 if( retcode == SCIP_OKAY )
2117 {
2118 SCIP_CALL( SCIPaddCons(scip, cons) );
2119 SCIPdebugMsg(scip, "(line %d) added constraint <%s>: ", mpsi->lineno, SCIPconsGetName(cons));
2120 SCIPdebugPrintCons(scip, cons, NULL);
2121
2122 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2123 SCIP_CALL( SCIPreleaseVar(scip, &qmatrixvar) );
2124 }
2125 }
2126 else
2127 {
2128 SCIPwarningMessage(scip, "%s section has no entries.\n", isQuadObj ? "QUADOBJ" : "QMATRIX");
2129 }
2130
2131 SCIPfreeBufferArray(scip, &quadvars1);
2132 SCIPfreeBufferArray(scip, &quadvars2);
2133 SCIPfreeBufferArray(scip, &quadcoefs);
2134
2135 SCIP_CALL( retcode );
2136
2137 return SCIP_OKAY;
2138 }
2139
2140
2141 /** Process QCMATRIX section.
2142 *
2143 * We read the QCMATRIX section, which is a nonstandard section introduced by CPLEX.
2144 *
2145 * We replace the corresponding linear constraint by a quadratic constraint which contains the
2146 * original linear constraint plus the quadratic part specified in the QCMATRIX.
2147 */
2148 static
readQCMatrix(MPSINPUT * mpsi,SCIP * scip)2149 SCIP_RETCODE readQCMatrix(
2150 MPSINPUT* mpsi, /**< mps input structure */
2151 SCIP* scip /**< SCIP data structure */
2152 )
2153 {
2154 SCIP_CONS* lincons; /* the linear constraint that was added for the corresponding row */
2155 SCIP_VAR** quadvars1;
2156 SCIP_VAR** quadvars2;
2157 SCIP_Real* quadcoefs;
2158 SCIP_RETCODE retcode;
2159 int cnt = 0; /* number of qcmatrix elements processed so far */
2160 int size; /* size of quad* arrays */
2161
2162 if( mpsinputField1(mpsi) == NULL )
2163 {
2164 SCIPerrorMessage("no row name in QCMATRIX line.\n");
2165 mpsinputSyntaxerror(mpsi);
2166 return SCIP_OKAY;
2167 }
2168
2169 retcode = SCIP_OKAY;
2170
2171 SCIPdebugMsg(scip, "read QCMATRIX section for row <%s>\n", mpsinputField1(mpsi));
2172
2173 lincons = SCIPfindCons(scip, mpsinputField1(mpsi));
2174 if( lincons == NULL )
2175 {
2176 SCIPerrorMessage("no row under name <%s> processed so far.\n", mpsinputField1(mpsi));
2177 mpsinputSyntaxerror(mpsi);
2178 return SCIP_OKAY;
2179 }
2180
2181 size = 1;
2182 SCIP_CALL( SCIPallocBufferArray(scip, &quadvars1, size) );
2183 SCIP_CALL( SCIPallocBufferArray(scip, &quadvars2, size) );
2184 SCIP_CALL( SCIPallocBufferArray(scip, &quadcoefs, size) );
2185
2186 /* loop through section */
2187 /* coverity[tainted_data] */
2188 while( mpsinputReadLine(mpsi) )
2189 {
2190 /* otherwise we are in the section given variables */
2191 SCIP_VAR* var1;
2192 SCIP_VAR* var2;
2193 SCIP_Real coef;
2194
2195 /* check if next section is found */
2196 if( mpsinputField0(mpsi) != NULL )
2197 {
2198 if( !strcmp(mpsinputField0(mpsi), "QMATRIX") )
2199 mpsinputSetSection(mpsi, MPS_QMATRIX);
2200 else if( !strcmp(mpsinputField0(mpsi), "QUADOBJ") )
2201 mpsinputSetSection(mpsi, MPS_QUADOBJ);
2202 else if( !strcmp(mpsinputField0(mpsi), "QCMATRIX") )
2203 mpsinputSetSection(mpsi, MPS_QCMATRIX);
2204 else if( !strcmp(mpsinputField0(mpsi), "INDICATORS") )
2205 mpsinputSetSection(mpsi, MPS_INDICATORS);
2206 else if( !strcmp(mpsinputField0(mpsi), "ENDATA") )
2207 mpsinputSetSection(mpsi, MPS_ENDATA);
2208 break;
2209 }
2210 if( mpsinputField1(mpsi) == NULL && mpsinputField2(mpsi) == NULL )
2211 {
2212 SCIPerrorMessage("empty data in a non-comment line.\n");
2213 mpsinputSyntaxerror(mpsi);
2214
2215 goto TERMINATE;
2216 }
2217
2218 /* get first variable */
2219 var1 = SCIPfindVar(scip, mpsinputField1(mpsi));
2220 if( var1 == NULL )
2221 {
2222 /* ignore unknown variables - we would not know the type anyway */
2223 mpsinputEntryIgnored(scip, mpsi, "column", mpsinputField1(mpsi), "QCMatrix", SCIPconsGetName(lincons), SCIP_VERBLEVEL_NORMAL);
2224 }
2225 else
2226 {
2227 /* get second variable */
2228 var2 = SCIPfindVar(scip, mpsinputField2(mpsi));
2229 if( var2 == NULL )
2230 {
2231 /* ignore unknown variables - we would not know the type anyway */
2232 mpsinputEntryIgnored(scip, mpsi, "column", mpsinputField2(mpsi), "QCMatrix", SCIPconsGetName(lincons), SCIP_VERBLEVEL_NORMAL);
2233 }
2234 else
2235 {
2236 char* endptr;
2237 if( mpsinputField3(mpsi) == NULL )
2238 {
2239 SCIPerrorMessage("coefficient of term <%s>*<%s> not specified.\n", mpsinputField1(mpsi), mpsinputField2(mpsi));
2240 mpsinputSyntaxerror(mpsi);
2241
2242 goto TERMINATE;
2243 }
2244
2245 /* get coefficient */
2246 coef = strtod(mpsinputField3(mpsi), &endptr);
2247 if( endptr == mpsinputField3(mpsi) || *endptr != '\0' )
2248 {
2249 SCIPerrorMessage("coefficient of term <%s>*<%s> not specified.\n", mpsinputField1(mpsi), mpsinputField2(mpsi));
2250 mpsinputSyntaxerror(mpsi);
2251
2252 goto TERMINATE;
2253 }
2254
2255 /* store variables and coefficient */
2256 if( cnt >= size )
2257 {
2258 int newsize = SCIPcalcMemGrowSize(scip, size+1);
2259 assert(newsize > size);
2260 SCIP_CALL( SCIPreallocBufferArray(scip, &quadvars1, newsize) );
2261 SCIP_CALL( SCIPreallocBufferArray(scip, &quadvars2, newsize) );
2262 SCIP_CALL( SCIPreallocBufferArray(scip, &quadcoefs, newsize) );
2263 size = newsize;
2264 }
2265 assert(cnt < size);
2266 quadvars1[cnt] = var1;
2267 quadvars2[cnt] = var2;
2268 quadcoefs[cnt] = coef;
2269 ++cnt;
2270
2271 SCIPdebugMsg(scip, "stored term %g*<%s>*<%s>.\n", coef, SCIPvarGetName(var1), SCIPvarGetName(var2));
2272
2273 /* check other fields */
2274 if( (mpsinputField4(mpsi) != NULL && *mpsinputField4(mpsi) != '\0' ) ||
2275 (mpsinputField5(mpsi) != NULL && *mpsinputField5(mpsi) != '\0' ) )
2276 {
2277 SCIPwarningMessage(scip, "ignoring data in fields 4 and 5 <%s> <%s>.\n", mpsinputField4(mpsi), mpsinputField5(mpsi));
2278 }
2279 }
2280 }
2281 }
2282
2283 /* replace linear constraint by quadratic constraint */
2284 if( cnt )
2285 {
2286 SCIP_CONS* cons = NULL;
2287
2288 retcode = SCIPcreateConsQuadratic(scip, &cons, SCIPconsGetName(lincons),
2289 SCIPgetNVarsLinear(scip, lincons), SCIPgetVarsLinear(scip, lincons), SCIPgetValsLinear(scip, lincons),
2290 cnt, quadvars1, quadvars2, quadcoefs, SCIPgetLhsLinear(scip, lincons), SCIPgetRhsLinear(scip, lincons),
2291 SCIPconsIsInitial(lincons), SCIPconsIsSeparated(lincons), SCIPconsIsEnforced(lincons), SCIPconsIsChecked(lincons),
2292 SCIPconsIsPropagated(lincons), SCIPconsIsLocal(lincons), SCIPconsIsModifiable(lincons), SCIPconsIsDynamic(lincons),
2293 SCIPconsIsRemovable(lincons));
2294
2295 if( retcode != SCIP_OKAY )
2296 goto TERMINATE;
2297
2298 SCIP_CALL( SCIPaddCons(scip, cons) );
2299 SCIPdebugMsg(scip, "(line %d) added constraint <%s>: ", mpsi->lineno, SCIPconsGetName(cons));
2300 SCIPdebugPrintCons(scip, cons, NULL);
2301
2302 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2303
2304 SCIP_CALL( SCIPdelCons(scip, lincons) );
2305 }
2306 else
2307 {
2308 SCIPwarningMessage(scip, "QCMATRIX section has no entries.\n");
2309 }
2310
2311 TERMINATE:
2312 SCIPfreeBufferArray(scip, &quadcoefs);
2313 SCIPfreeBufferArray(scip, &quadvars2);
2314 SCIPfreeBufferArray(scip, &quadvars1);
2315
2316 SCIP_CALL( retcode );
2317
2318 return SCIP_OKAY;
2319 }
2320
2321
2322 /** Process INDICATORS section.
2323 *
2324 * We read the INDICATORS section, which is a nonstandard section introduced by CPLEX.
2325 * Note that CPLEX does not allow ranged rows.
2326 *
2327 * If the linear constraints are equations or ranged rows, we generate two indicator
2328 * constraints.
2329 *
2330 * The section has to come after the QMATRIX* sections.
2331 */
2332 static
readIndicators(MPSINPUT * mpsi,SCIP * scip)2333 SCIP_RETCODE readIndicators(
2334 MPSINPUT* mpsi, /**< mps input structure */
2335 SCIP* scip /**< SCIP data structure */
2336 )
2337 {
2338 SCIP_Bool initial;
2339 SCIP_Bool separate;
2340 SCIP_Bool enforce;
2341 SCIP_Bool check;
2342 SCIP_Bool propagate;
2343 SCIP_Bool local;
2344 SCIP_Bool dynamic;
2345 SCIP_Bool removable;
2346 SCIP_Bool stickingatnode;
2347 char name[MPS_MAX_NAMELEN] = { '\0' };
2348
2349 SCIPdebugMsg(scip, "read INDICATORS constraints\n");
2350
2351 /* standard settings for indicator constraints: */
2352 initial = mpsi->initialconss;
2353 separate = TRUE;
2354 enforce = TRUE;
2355 check = TRUE;
2356 propagate = TRUE;
2357 local = FALSE;
2358 dynamic = mpsi->dynamicconss;
2359 removable = mpsi->dynamicrows;
2360 stickingatnode = FALSE;
2361
2362 /* loop through section */
2363 while( mpsinputReadLine(mpsi) )
2364 {
2365 SCIP_CONSHDLR* conshdlr;
2366 SCIP_VARTYPE slackvartype;
2367 SCIP_CONS* cons;
2368 SCIP_CONS* lincons;
2369 SCIP_VAR* binvar;
2370 SCIP_VAR* slackvar;
2371 SCIP_Real lhs;
2372 SCIP_Real rhs;
2373 SCIP_Real sign;
2374 SCIP_VAR** linvars;
2375 SCIP_Real* linvals;
2376 int nlinvars;
2377 int i;
2378
2379 /* check if next section is found */
2380 if( mpsinputField0(mpsi) != NULL )
2381 {
2382 if( !strcmp(mpsinputField0(mpsi), "ENDATA") )
2383 mpsinputSetSection(mpsi, MPS_ENDATA);
2384 break;
2385 }
2386 if( mpsinputField1(mpsi) == NULL || mpsinputField2(mpsi) == NULL )
2387 {
2388 SCIPerrorMessage("empty data in a non-comment line.\n");
2389 mpsinputSyntaxerror(mpsi);
2390 return SCIP_OKAY;
2391 }
2392
2393 /* check for new indicator constraint */
2394 if( strcmp(mpsinputField1(mpsi), "IF") != 0 )
2395 {
2396 SCIPerrorMessage("Indicator constraints need to be introduced by 'IF' in column 1.\n");
2397 mpsinputSyntaxerror(mpsi);
2398 return SCIP_OKAY;
2399 }
2400
2401 /* get linear constraint (row) */
2402 lincons = SCIPfindCons(scip, mpsinputField2(mpsi));
2403 if( lincons == NULL )
2404 {
2405 SCIPerrorMessage("row <%s> does not exist.\n", mpsinputField2(mpsi));
2406 mpsinputSyntaxerror(mpsi);
2407 return SCIP_OKAY;
2408 }
2409
2410 /* check whether constraint is really linear */
2411 conshdlr = SCIPconsGetHdlr(lincons);
2412 if( strcmp(SCIPconshdlrGetName(conshdlr), "linear") != 0 )
2413 {
2414 SCIPerrorMessage("constraint <%s> is not linear.\n", mpsinputField2(mpsi));
2415 mpsinputSyntaxerror(mpsi);
2416 return SCIP_OKAY;
2417 }
2418
2419 /* get binary variable */
2420 binvar = SCIPfindVar(scip, mpsinputField3(mpsi));
2421 if( binvar == NULL )
2422 {
2423 SCIPerrorMessage("binary variable <%s> does not exist.\n", mpsinputField3(mpsi));
2424 mpsinputSyntaxerror(mpsi);
2425 return SCIP_OKAY;
2426 }
2427
2428 /* check type */
2429 if( SCIPvarGetType(binvar) != SCIP_VARTYPE_BINARY )
2430 {
2431 SCIPerrorMessage("variable <%s> is not binary.\n", mpsinputField3(mpsi));
2432 mpsinputSyntaxerror(mpsi);
2433 return SCIP_OKAY;
2434 }
2435
2436 /* check whether we need the negated variable */
2437 if( mpsinputField4(mpsi) != NULL )
2438 {
2439 if( *mpsinputField4(mpsi) == '0' )
2440 {
2441 SCIP_VAR* var;
2442 SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &var) );
2443 binvar = var;
2444 assert( binvar != NULL );
2445 }
2446 else
2447 {
2448 if( *mpsinputField4(mpsi) != '1' )
2449 {
2450 SCIPerrorMessage("binary variable <%s> can only take values 0/1 (%s).\n", mpsinputField3(mpsi), mpsinputField4(mpsi));
2451 mpsinputSyntaxerror(mpsi);
2452 return SCIP_OKAY;
2453 }
2454 }
2455 }
2456
2457 /* check lhs/rhs */
2458 lhs = SCIPgetLhsLinear(scip, lincons);
2459 rhs = SCIPgetRhsLinear(scip, lincons);
2460 nlinvars = SCIPgetNVarsLinear(scip, lincons);
2461 linvars = SCIPgetVarsLinear(scip, lincons);
2462 linvals = SCIPgetValsLinear(scip, lincons);
2463
2464 sign = -1.0;
2465 if( !SCIPisInfinity(scip, -lhs) )
2466 {
2467 if( SCIPisInfinity(scip, rhs) )
2468 sign = 1.0;
2469 else
2470 {
2471 /* create second indicator constraint */
2472 SCIP_VAR** vars;
2473 SCIP_Real* vals;
2474 SCIP_RETCODE retcode;
2475
2476 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlinvars) );
2477 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlinvars) );
2478 for( i = 0; i < nlinvars; ++i )
2479 {
2480 vars[i] = linvars[i];
2481 vals[i] = -linvals[i];
2482 }
2483
2484 /* create new name */
2485 (void) SCIPsnprintf(name, MPS_MAX_NAMELEN, "indlhs_%s", SCIPconsGetName(lincons));
2486
2487 /* create indicator constraint */
2488 retcode = SCIPcreateConsIndicator(scip, &cons, name, binvar, nlinvars, vars, vals, -lhs,
2489 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode);
2490
2491 if( retcode == SCIP_OKAY )
2492 {
2493 SCIP_CALL( SCIPaddCons(scip, cons) );
2494 SCIPdebugMsg(scip, "created indicator constraint <%s>\n", mpsinputField2(mpsi));
2495 SCIPdebugPrintCons(scip, cons, NULL);
2496 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2497 }
2498
2499 SCIPfreeBufferArray(scip, &vals);
2500 SCIPfreeBufferArray(scip, &vars);
2501
2502 SCIP_CALL( retcode );
2503 }
2504 }
2505
2506 /* check if slack variable can be made implicitly integer */
2507 slackvartype = SCIP_VARTYPE_IMPLINT;
2508 for (i = 0; i < nlinvars; ++i)
2509 {
2510 if( ! SCIPvarIsIntegral(linvars[i]) || ! SCIPisIntegral(scip, linvals[i]) )
2511 {
2512 slackvartype = SCIP_VARTYPE_CONTINUOUS;
2513 break;
2514 }
2515 }
2516
2517 /* create slack variable */
2518 if ( ! SCIPisInfinity(scip, -lhs) )
2519 (void) SCIPsnprintf(name, MPS_MAX_NAMELEN, "indslack_indrhs_%s", SCIPconsGetName(lincons));
2520 else
2521 (void) SCIPsnprintf(name, MPS_MAX_NAMELEN, "indslack_%s", SCIPconsGetName(lincons));
2522 SCIP_CALL( SCIPcreateVar(scip, &slackvar, name, 0.0, SCIPinfinity(scip), 0.0, slackvartype, TRUE, FALSE,
2523 NULL, NULL, NULL, NULL, NULL) );
2524
2525 /* add slack variable */
2526 SCIP_CALL( SCIPaddVar(scip, slackvar) );
2527 SCIP_CALL( SCIPaddCoefLinear(scip, lincons, slackvar, sign) );
2528
2529 /* correct linear constraint and create new name */
2530 if ( ! SCIPisInfinity(scip, -lhs) && ! SCIPisInfinity(scip, rhs) )
2531 {
2532 /* we have added lhs above and only need the rhs */
2533 SCIP_CALL( SCIPchgLhsLinear(scip, lincons, -SCIPinfinity(scip) ) );
2534 (void) SCIPsnprintf(name, MPS_MAX_NAMELEN, "indrhs_%s", SCIPconsGetName(lincons));
2535 }
2536 else
2537 (void) SCIPsnprintf(name, MPS_MAX_NAMELEN, "ind_%s", SCIPconsGetName(lincons));
2538
2539 /* create indicator constraint */
2540 SCIP_CALL( SCIPcreateConsIndicatorLinCons(scip, &cons, name, binvar, lincons, slackvar,
2541 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
2542
2543 SCIP_CALL( SCIPaddCons(scip, cons) );
2544 SCIPdebugMsg(scip, "created indicator constraint <%s>", mpsinputField2(mpsi));
2545 SCIPdebugPrintCons(scip, cons, NULL);
2546 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2547 SCIP_CALL( SCIPreleaseVar(scip, &slackvar) );
2548 }
2549
2550 return SCIP_OKAY;
2551 }
2552
2553
2554 /** Read LP in "MPS File Format".
2555 *
2556 * A specification of the MPS format can be found at
2557 *
2558 * http://plato.asu.edu/ftp/mps_format.txt,
2559 * ftp://ftp.caam.rice.edu/pub/people/bixby/miplib/mps_format,
2560 *
2561 * and in the
2562 *
2563 * CPLEX Reference Manual
2564 *
2565 * This routine should read all valid MPS format files.
2566 * What it will not do, is to find all cases where a file is ill formed.
2567 * If this happens it may complain and read nothing or read "something".
2568 */
2569 static
readMps(SCIP * scip,const char * filename,const char *** varnames,const char *** consnames,int * varnamessize,int * consnamessize,int * nvarnames,int * nconsnames)2570 SCIP_RETCODE readMps(
2571 SCIP* scip, /**< SCIP data structure */
2572 const char* filename, /**< name of the input file */
2573 const char*** varnames, /**< storage for the variable names, or NULL */
2574 const char*** consnames, /**< storage for the constraint names, or NULL */
2575 int* varnamessize, /**< the size of the variable names storage, or NULL */
2576 int* consnamessize, /**< the size of the constraint names storage, or NULL */
2577 int* nvarnames, /**< the number of stored variable names, or NULL */
2578 int* nconsnames /**< the number of stored constraint names, or NULL */
2579 )
2580 {
2581 SCIP_FILE* fp;
2582 MPSINPUT* mpsi;
2583 SCIP_RETCODE retcode;
2584 SCIP_Bool error = TRUE;
2585
2586 assert(scip != NULL);
2587 assert(filename != NULL);
2588
2589 fp = SCIPfopen(filename, "r");
2590 if( fp == NULL )
2591 {
2592 SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
2593 SCIPprintSysError(filename);
2594 return SCIP_NOFILE;
2595 }
2596
2597 SCIP_CALL( mpsinputCreate(scip, &mpsi, fp) );
2598
2599 SCIP_CALL_TERMINATE( retcode, readName(scip, mpsi), TERMINATE );
2600
2601 SCIP_CALL_TERMINATE( retcode, SCIPcreateProb(scip, mpsi->probname, NULL, NULL, NULL, NULL, NULL, NULL, NULL), TERMINATE );
2602
2603 if( mpsinputSection(mpsi) == MPS_OBJSEN )
2604 {
2605 SCIP_CALL_TERMINATE( retcode, readObjsen(scip, mpsi), TERMINATE );
2606 }
2607 if( mpsinputSection(mpsi) == MPS_OBJNAME )
2608 {
2609 SCIP_CALL_TERMINATE( retcode, readObjname(scip, mpsi), TERMINATE );
2610 }
2611 while( mpsinputSection(mpsi) == MPS_ROWS
2612 || mpsinputSection(mpsi) == MPS_USERCUTS
2613 || mpsinputSection(mpsi) == MPS_LAZYCONS )
2614 {
2615 SCIP_CALL_TERMINATE( retcode, readRows(mpsi, scip, consnames, consnamessize, nconsnames), TERMINATE );
2616 }
2617 if( mpsinputSection(mpsi) == MPS_COLUMNS )
2618 {
2619 SCIP_CALL_TERMINATE( retcode, readCols(mpsi, scip, varnames, varnamessize, nvarnames), TERMINATE );
2620 }
2621 if( mpsinputSection(mpsi) == MPS_RHS )
2622 {
2623 SCIP_CALL_TERMINATE( retcode, readRhs(mpsi, scip), TERMINATE );
2624 }
2625 if( mpsinputSection(mpsi) == MPS_RANGES )
2626 {
2627 SCIP_CALL_TERMINATE( retcode, readRanges(mpsi, scip), TERMINATE );
2628 }
2629 if( mpsinputSection(mpsi) == MPS_BOUNDS )
2630 {
2631 SCIP_CALL_TERMINATE( retcode, readBounds(mpsi, scip), TERMINATE );
2632 }
2633 if( mpsinputSection(mpsi) == MPS_SOS )
2634 {
2635 SCIP_CALL_TERMINATE( retcode, readSOS(mpsi, scip), TERMINATE );
2636 }
2637 while( mpsinputSection(mpsi) == MPS_QCMATRIX )
2638 {
2639 SCIP_CALL_TERMINATE( retcode, readQCMatrix(mpsi, scip), TERMINATE );
2640 }
2641 if( mpsinputSection(mpsi) == MPS_QMATRIX )
2642 {
2643 SCIP_CALL_TERMINATE( retcode, readQMatrix(mpsi, FALSE, scip), TERMINATE );
2644 }
2645 if( mpsinputSection(mpsi) == MPS_QUADOBJ )
2646 {
2647 SCIP_CALL_TERMINATE( retcode, readQMatrix(mpsi, TRUE, scip), TERMINATE );
2648 }
2649 while( mpsinputSection(mpsi) == MPS_QCMATRIX )
2650 {
2651 SCIP_CALL_TERMINATE( retcode, readQCMatrix(mpsi, scip), TERMINATE );
2652 }
2653 if( mpsinputSection(mpsi) == MPS_INDICATORS )
2654 {
2655 SCIP_CALL_TERMINATE( retcode, readIndicators(mpsi, scip), TERMINATE );
2656 }
2657 if( mpsinputSection(mpsi) != MPS_ENDATA )
2658 mpsinputSyntaxerror(mpsi);
2659
2660 SCIPfclose(fp);
2661
2662 error = mpsinputHasError(mpsi);
2663
2664 if( !error )
2665 {
2666 SCIP_CALL_TERMINATE( retcode, SCIPsetObjsense(scip, mpsinputObjsense(mpsi)), TERMINATE );
2667 }
2668
2669 TERMINATE:
2670 mpsinputFree(scip, &mpsi);
2671
2672 if( error )
2673 return SCIP_READERROR;
2674 else
2675 return SCIP_OKAY;
2676 }
2677
2678 /*
2679 * local methods for writing problem
2680 */
2681
2682 /** gets the key (i.e. the name) of the given namefreq */
2683 static
SCIP_DECL_HASHGETKEY(hashGetKeyNamefreq)2684 SCIP_DECL_HASHGETKEY(hashGetKeyNamefreq)
2685 { /*lint --e{715}*/
2686 CONSNAMEFREQ* consnamefreq = (CONSNAMEFREQ*)elem;
2687
2688 assert(consnamefreq != NULL);
2689 assert(consnamefreq->consname != NULL);
2690
2691 return (void*)consnamefreq->consname;
2692 }
2693
2694 /** returns TRUE iff both keys (i.e. strings) are equal up to max length*/
2695 static
SCIP_DECL_HASHKEYEQ(hashKeyEqString)2696 SCIP_DECL_HASHKEYEQ(hashKeyEqString)
2697 { /*lint --e{715}*/
2698 const char* string1 = (const char*)key1;
2699 const char* string2 = (const char*)key2;
2700
2701 return (strncmp(string1, string2, MPS_MAX_NAMELEN - 1) == 0);
2702 }
2703
2704 /** hash key retrieval function for variables */
2705 static
SCIP_DECL_HASHGETKEY(hashGetKeyVar)2706 SCIP_DECL_HASHGETKEY(hashGetKeyVar)
2707 { /*lint --e{715}*/
2708 return elem;
2709 }
2710
2711 /** returns TRUE iff the indices of both variables are equal */
2712 static
SCIP_DECL_HASHKEYEQ(hashKeyEqVar)2713 SCIP_DECL_HASHKEYEQ(hashKeyEqVar)
2714 { /*lint --e{715}*/
2715 if( key1 == key2 )
2716 return TRUE;
2717 return FALSE;
2718 }
2719
2720 /** returns the hash value of the key */
2721 static
SCIP_DECL_HASHKEYVAL(hashKeyValVar)2722 SCIP_DECL_HASHKEYVAL(hashKeyValVar)
2723 { /*lint --e{715}*/
2724 assert( SCIPvarGetIndex((SCIP_VAR*) key) >= 0 );
2725 return (unsigned int) SCIPvarGetIndex((SCIP_VAR*) key);
2726 }
2727
2728
2729 /** computes the field width such that the output file is nicely arranged */
2730 static
computeFieldWidth(unsigned int width)2731 unsigned int computeFieldWidth(
2732 unsigned int width /**< required width */
2733 )
2734 {
2735 width = MAX(8u, width);
2736 return MIN(MPS_MAX_FIELDLEN, width);
2737 }
2738
2739
2740 /** output two strings in columns 1 and 2 with computed widths */
2741 static
printRecord(SCIP * scip,FILE * file,const char * col1,const char * col2,unsigned int maxnamelen)2742 void printRecord(
2743 SCIP* scip, /**< SCIP data structure */
2744 FILE* file, /**< output file (or NULL for standard output) */
2745 const char* col1, /**< column 1 */
2746 const char* col2, /**< column 2 */
2747 unsigned int maxnamelen /**< maximum name length */
2748 )
2749 {
2750 unsigned int fieldwidth;
2751 char format[32];
2752
2753 assert( scip != NULL );
2754 assert( col1 != NULL );
2755 assert( col2 != NULL );
2756 assert( strlen(col1) < MPS_MAX_NAMELEN );
2757 assert( strlen(col2) < MPS_MAX_VALUELEN );
2758 assert( maxnamelen > 0 );
2759
2760 fieldwidth = computeFieldWidth(maxnamelen);
2761 (void) SCIPsnprintf(format, 32," %%-%ds %%%ds ", fieldwidth, MPS_MAX_VALUELEN - 1);
2762
2763 SCIPinfoMessage(scip, file, (const char *)format, col1, col2);
2764 }
2765
2766 /** output two strings in columns 1 (width 2) and 2 (width 8) */
2767 static
printStart(SCIP * scip,FILE * file,const char * col1,const char * col2,int maxnamelen)2768 void printStart(
2769 SCIP* scip, /**< SCIP data structure */
2770 FILE* file, /**< output file (or NULL for standard output) */
2771 const char* col1, /**< column 1 */
2772 const char* col2, /**< column 2 */
2773 int maxnamelen /**< maximum name length (-1 if irrelevant) */
2774 )
2775 {
2776 unsigned int fieldwidth;
2777 char format[32];
2778
2779 assert( scip != NULL );
2780 assert( col1 != NULL );
2781 assert( col2 != NULL );
2782 assert( strlen(col1) <= 2 );
2783 assert( strlen(col2) < MPS_MAX_NAMELEN );
2784 assert( maxnamelen == -1 || maxnamelen > 0 );
2785
2786 if( maxnamelen < 0 )
2787 {
2788 /* format does not matter */
2789 (void) SCIPsnprintf(format, 32, " %%-2.2s %%-s ");
2790 }
2791 else
2792 {
2793 fieldwidth = computeFieldWidth((unsigned int) maxnamelen);
2794 (void) SCIPsnprintf(format, 32, " %%-2.2s %%-%ds ", fieldwidth);
2795 }
2796
2797 SCIPinfoMessage(scip, file, (const char*)format, col1, col2);
2798 }
2799
2800 /** prints the given data as column entry */
2801 static
printEntry(SCIP * scip,FILE * file,const char * varname,const char * consname,SCIP_Real value,int * recordcnt,unsigned int maxnamelen)2802 void printEntry(
2803 SCIP* scip, /**< SCIP data structure */
2804 FILE* file, /**< output file (or NULL for standard output) */
2805 const char* varname, /**< variable name */
2806 const char* consname, /**< constraint name */
2807 SCIP_Real value, /**< value to display */
2808 int* recordcnt, /**< pointer to store the number of records per line */
2809 unsigned int maxnamelen /**< maximum name length */
2810 )
2811 {
2812 char valuestr[MPS_MAX_VALUELEN] = { '\0' };
2813
2814 assert( scip != NULL );
2815 assert( recordcnt != NULL );
2816 assert( *recordcnt >= 0 && *recordcnt < 2 );
2817
2818 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", value);
2819
2820 if( *recordcnt == 0 )
2821 {
2822 /* start new line with an empty first column and the variable name in the second column */
2823 printStart(scip, file, "", varname, (int) maxnamelen);
2824 *recordcnt = 0;
2825 }
2826
2827 printRecord(scip, file, consname, valuestr, maxnamelen);
2828 (*recordcnt)++;
2829
2830 if( *recordcnt == 2 )
2831 {
2832 /* each line can have at most two records */
2833 SCIPinfoMessage(scip, file, "\n");
2834 *recordcnt = 0;
2835 }
2836 }
2837
2838 /** prints the constraint type to file stream */
2839 static
printRowType(SCIP * scip,FILE * file,SCIP_Real lhs,SCIP_Real rhs,const char * name)2840 void printRowType(
2841 SCIP* scip, /**< SCIP data structure */
2842 FILE* file, /**< output file (or NULL for standard output) */
2843 SCIP_Real lhs, /**< left hand side */
2844 SCIP_Real rhs, /**< right hand side */
2845 const char* name /**< constraint name */
2846 )
2847 {
2848 char rowtype[2];
2849
2850 assert( scip != NULL );
2851 assert( !SCIPisInfinity(scip, -lhs) || !SCIPisInfinity(scip, rhs) );
2852 assert( SCIPisGT(scip, rhs, lhs) || SCIPisEQ(scip, lhs, rhs) );
2853 assert( name != NULL );
2854
2855 if( SCIPisEQ(scip, lhs, rhs) )
2856 (void) SCIPsnprintf(rowtype, 2, "%s", "E");
2857 else
2858 {
2859 /* in case the right hand side and the left hand side are not infinity we print a
2860 * less or equal constraint and put the right hand side in the RHS section and the
2861 * left hand side (hidden) in the RANGE section */
2862 if( !SCIPisInfinity(scip, rhs) )
2863 (void) SCIPsnprintf(rowtype, 2, "%s", "L");
2864 else
2865 {
2866 assert( !SCIPisInfinity(scip, -lhs) );
2867 (void) SCIPsnprintf(rowtype, 2, "%s", "G");
2868 }
2869 }
2870
2871 printStart(scip, file, rowtype, name, -1);
2872 SCIPinfoMessage(scip, file, "\n");
2873 }
2874
2875
2876 /** initializes the sparse matrix */
2877 static
initializeMatrix(SCIP * scip,SPARSEMATRIX ** matrix,int slots)2878 SCIP_RETCODE initializeMatrix(
2879 SCIP* scip, /**< SCIP data structure */
2880 SPARSEMATRIX** matrix, /**< pointer to sparse matrix containing the entries */
2881 int slots /**< number of slots */
2882 )
2883 {
2884 SCIP_CALL( SCIPallocBuffer(scip, matrix) );
2885 (*matrix)->nentries = 0;
2886 (*matrix)->sentries = slots;
2887 SCIP_CALL( SCIPallocBufferArray(scip, &(*matrix)->values, (*matrix)->sentries) );
2888 SCIP_CALL( SCIPallocBufferArray(scip, &(*matrix)->columns, (*matrix)->sentries) );
2889 SCIP_CALL( SCIPallocBufferArray(scip, &(*matrix)->rows, (*matrix)->sentries) );
2890
2891 return SCIP_OKAY;
2892 }
2893
2894 /** this method takes care that the required capacity is available in the sparse matrix */
2895 static
checkSparseMatrixCapacity(SCIP * scip,SPARSEMATRIX * matrix,int capacity)2896 SCIP_RETCODE checkSparseMatrixCapacity(
2897 SCIP* scip, /**< SCIP data structure */
2898 SPARSEMATRIX* matrix, /**< sparse matrix for storing the coefficient */
2899 int capacity /**< needed capacity */
2900 )
2901 {
2902 if( matrix->nentries + capacity >= matrix->sentries )
2903 {
2904 matrix->sentries = matrix->sentries * 2 + capacity;
2905 SCIP_CALL( SCIPreallocBufferArray(scip, &matrix->values, matrix->sentries) );
2906 SCIP_CALL( SCIPreallocBufferArray(scip, &matrix->columns, matrix->sentries) );
2907 SCIP_CALL( SCIPreallocBufferArray(scip, &matrix->rows, matrix->sentries) );
2908 }
2909 return SCIP_OKAY;
2910 }
2911
2912 /** frees the sparse matrix */
2913 static
freeMatrix(SCIP * scip,SPARSEMATRIX * matrix)2914 void freeMatrix(
2915 SCIP* scip, /**< SCIP data structure */
2916 SPARSEMATRIX* matrix /**< sparse matrix to free */
2917 )
2918 {
2919 SCIPfreeBufferArray(scip, &matrix->rows);
2920 SCIPfreeBufferArray(scip, &matrix->columns);
2921 SCIPfreeBufferArray(scip, &matrix->values);
2922
2923 SCIPfreeBuffer(scip, &matrix);
2924 }
2925
2926
2927 /** computes the coefficient for the given variables and linear constraint information */
2928 static
getLinearCoeffs(SCIP * scip,const char * consname,SCIP_VAR ** vars,SCIP_Real * vals,int nvars,SCIP_Bool transformed,SPARSEMATRIX * matrix,SCIP_Real * rhs)2929 SCIP_RETCODE getLinearCoeffs(
2930 SCIP* scip, /**< SCIP data structure */
2931 const char* consname, /**< name of the constraint */
2932 SCIP_VAR** vars, /**< array of variables */
2933 SCIP_Real* vals, /**< array of coefficients values (or NULL if all coefficient values are 1) */
2934 int nvars, /**< number of variables */
2935 SCIP_Bool transformed, /**< transformed constraint? */
2936 SPARSEMATRIX* matrix, /**< sparse matrix for storing the coefficient */
2937 SCIP_Real* rhs /**< pointer to right hand side */
2938 )
2939 {
2940 SCIP_VAR** activevars;
2941 SCIP_Real* activevals;
2942 SCIP_Real activeconstant = 0.0;
2943
2944 int nactivevars;
2945 int requiredsize;
2946 int v;
2947
2948 assert( scip != NULL );
2949 assert( nvars == 0 || vars != NULL );
2950 assert( !SCIPisInfinity(scip, *rhs) );
2951 assert( matrix != NULL );
2952
2953 /* if the variables array contains no variables, then return without
2954 * doing any thing; The MPS format and LP format do not forbid this
2955 * situation */
2956 if( nvars == 0 )
2957 return SCIP_OKAY;
2958
2959 /* duplicate variable and value array */
2960 nactivevars = nvars;
2961 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars ) );
2962
2963 if( vals != NULL )
2964 {
2965 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars ) );
2966 }
2967 else
2968 {
2969 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) );
2970
2971 for( v = 0; v < nactivevars; ++v )
2972 activevals[v] = 1.0;
2973 }
2974
2975 /* retransform given variables to active variables */
2976 if( transformed )
2977 {
2978 SCIP_CALL( SCIPgetProbvarLinearSum(scip, activevars, activevals, &nactivevars, nactivevars, &activeconstant, &requiredsize, TRUE) );
2979
2980 if( requiredsize > nactivevars )
2981 {
2982 SCIP_CALL( SCIPreallocBufferArray(scip, &activevars, requiredsize) );
2983 SCIP_CALL( SCIPreallocBufferArray(scip, &activevals, requiredsize) );
2984
2985 SCIP_CALL( SCIPgetProbvarLinearSum(scip, activevars, activevals, &nactivevars, requiredsize, &activeconstant, &requiredsize, TRUE) );
2986 assert( requiredsize <= nactivevars );
2987 }
2988 }
2989 else
2990 {
2991 for( v = 0; v < nactivevars; ++v )
2992 {
2993 SCIP_CALL( SCIPvarGetOrigvarSum(&activevars[v], &activevals[v], &activeconstant) );
2994
2995 /* negated variables with an original counterpart may also be returned by SCIPvarGetOrigvarSum();
2996 * make sure we get the original variable in that case
2997 */
2998 if( SCIPvarGetStatus(activevars[v]) == SCIP_VARSTATUS_NEGATED )
2999 {
3000 activevars[v] = SCIPvarGetNegatedVar(activevars[v]);
3001 activevals[v] *= -1.0;
3002 activeconstant += 1.0;
3003 }
3004 }
3005 }
3006
3007 /* copy the (matrix) row into the sparse matrix */
3008 SCIP_CALL( checkSparseMatrixCapacity(scip, matrix, nactivevars) );
3009 assert( matrix->nentries + nactivevars < matrix->sentries );
3010
3011 for( v = 0; v < nactivevars; ++v )
3012 {
3013 matrix->values[matrix->nentries] = activevals[v];
3014 matrix->columns[matrix->nentries] = activevars[v];
3015 matrix->rows[matrix->nentries] = consname;
3016 matrix->nentries++;
3017 }
3018
3019 /* adjust right hand side */
3020 (*rhs) -= activeconstant;
3021
3022 /* free buffer arrays */
3023 SCIPfreeBufferArray(scip, &activevals);
3024 SCIPfreeBufferArray(scip, &activevars);
3025
3026 return SCIP_OKAY;
3027 }
3028
3029
3030 /** check whether given variables are aggregated and put them into an array without duplication */
3031 static
collectAggregatedVars(SCIP * scip,SCIP_VAR ** vars,int nvars,SCIP_VAR *** aggvars,int * naggvars,int * saggvars,SCIP_HASHTABLE * varAggregated)3032 SCIP_RETCODE collectAggregatedVars(
3033 SCIP* scip, /**< SCIP data structure */
3034 SCIP_VAR** vars, /**< variable array */
3035 int nvars, /**< number of active variables in the problem */
3036 SCIP_VAR*** aggvars, /**< pointer to array storing the aggregated variables on output */
3037 int* naggvars, /**< pointer to number of aggregated variables on output */
3038 int* saggvars, /**< pointer to number of slots in aggvars array */
3039 SCIP_HASHTABLE* varAggregated /**< hashtable for checking duplicates */
3040 )
3041 {
3042 int v;
3043
3044 assert( scip != NULL );
3045 assert( aggvars != NULL );
3046 assert( naggvars != NULL );
3047 assert( saggvars != NULL );
3048
3049 /* check variables */
3050 for( v = 0; v < nvars; ++v )
3051 {
3052 SCIP_VARSTATUS status;
3053 SCIP_VAR* var;
3054
3055 var = vars[v];
3056 status = SCIPvarGetStatus(var);
3057
3058 /* collect aggregated variables in a list */
3059 if( status >= SCIP_VARSTATUS_AGGREGATED )
3060 {
3061 assert( status == SCIP_VARSTATUS_AGGREGATED || status == SCIP_VARSTATUS_MULTAGGR || status == SCIP_VARSTATUS_NEGATED );
3062 assert( varAggregated != NULL );
3063
3064 if( ! SCIPhashtableExists(varAggregated, (void*) var) )
3065 {
3066 /* possibly enlarge array */
3067 if ( *saggvars <= *naggvars )
3068 {
3069 int newsize;
3070 newsize = SCIPcalcMemGrowSize(scip, *naggvars + 1);
3071 assert( newsize > *saggvars );
3072 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggvars, *saggvars, newsize) );
3073 *saggvars = newsize;
3074 }
3075
3076 (*aggvars)[*naggvars] = var;
3077 (*naggvars)++;
3078 SCIP_CALL( SCIPhashtableInsert(varAggregated, (void*) var) );
3079 assert( *naggvars <= *saggvars );
3080 }
3081 }
3082 }
3083 return SCIP_OKAY;
3084 }
3085
3086
3087 /** method check if the variable names are not longer than MPS_MAX_NAMELEN - 1*/
3088 static
checkVarnames(SCIP * scip,SCIP_VAR ** vars,int nvars,unsigned int * maxnamelen,const char *** varnames,SCIP_HASHMAP ** varnameHashmap)3089 SCIP_RETCODE checkVarnames(
3090 SCIP* scip, /**< SCIP data structure */
3091 SCIP_VAR** vars, /**< array of variables */
3092 int nvars, /**< number of variables */
3093 unsigned int* maxnamelen, /**< pointer to store the maximum name length */
3094 const char*** varnames, /**< pointer to array of variable names */
3095 SCIP_HASHMAP** varnameHashmap /**< pointer to hash map storing variable, variable name mapping */
3096 )
3097 {
3098 int v;
3099 int faulty;
3100 char* varname;
3101 SCIP_VAR* var;
3102
3103 assert( scip != NULL );
3104 assert( vars != NULL );
3105 assert( maxnamelen != NULL );
3106
3107 faulty = 0;
3108
3109 /* allocate memory */
3110 SCIP_CALL( SCIPhashmapCreate(varnameHashmap, SCIPblkmem(scip), nvars) );
3111 SCIP_CALL( SCIPallocBufferArray(scip, varnames, nvars) );
3112
3113 /* check if the variable names are not to long */
3114 for( v = 0; v < nvars; ++v )
3115 {
3116 size_t l;
3117
3118 var = vars[v];
3119 assert( var != NULL );
3120
3121 l = strlen(SCIPvarGetName(var));
3122
3123 if( l >= MPS_MAX_NAMELEN )
3124 {
3125 faulty++;
3126 (*maxnamelen) = MPS_MAX_NAMELEN - 1;
3127 }
3128 else
3129 {
3130 (*maxnamelen) = MAX(*maxnamelen, (unsigned int) l);
3131 }
3132
3133 SCIP_CALL( SCIPallocBufferArray(scip, &varname, (int) *maxnamelen + 1) );
3134 (void) SCIPsnprintf(varname, (int)(*maxnamelen) + 1, "%s", SCIPvarGetName(var) );
3135
3136 /* insert variable with variable name into hash map */
3137 assert( !SCIPhashmapExists(*varnameHashmap, var) );
3138 SCIP_CALL( SCIPhashmapInsert(*varnameHashmap, var, (void*) varname) );
3139
3140 (*varnames)[v] = varname;
3141 }
3142
3143 if( faulty > 0 )
3144 {
3145 SCIPwarningMessage(scip, "there are %d variable names which have to be cut down to %d characters; LP might be corrupted\n",
3146 faulty, MPS_MAX_NAMELEN - 1);
3147 }
3148 return SCIP_OKAY;
3149 }
3150
3151 /** method check if the constraint names are not longer than MPS_MAX_NAMELEN - 1 */
3152 static
checkConsnames(SCIP * scip,SCIP_CONS ** conss,int nconss,SCIP_Bool transformed,unsigned int * maxnamelen,const char *** consnames,SCIP_Bool * error)3153 SCIP_RETCODE checkConsnames(
3154 SCIP* scip, /**< SCIP data structure */
3155 SCIP_CONS** conss, /**< array of all constraints */
3156 int nconss, /**< number of all constraints */
3157 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */
3158 unsigned int* maxnamelen, /**< pointer to store the maximum name length */
3159 const char*** consnames, /**< pointer to array of constraint names */
3160 SCIP_Bool* error /**< pointer to store whether all constraint names exist */
3161 )
3162 {
3163 SCIP_HASHTABLE* consfreq;
3164 CONSNAMEFREQ* consnamefreqs;
3165 SCIP_CONS* cons;
3166 char* consname;
3167 int i;
3168
3169 assert(scip != NULL);
3170 assert(maxnamelen != NULL);
3171
3172 *error = FALSE;
3173
3174 /* allocate memory */
3175 SCIP_CALL( SCIPallocBufferArray(scip, &consnamefreqs, nconss) );
3176 SCIP_CALL( SCIPallocBufferArray(scip, consnames, nconss) );
3177 SCIP_CALL( SCIPhashtableCreate(&consfreq, SCIPblkmem(scip), SCIP_HASHSIZE_NAMES,
3178 hashGetKeyNamefreq, hashKeyEqString, SCIPhashKeyValString, NULL) );
3179
3180 for( i = 0; i < nconss; ++i )
3181 {
3182 CONSNAMEFREQ* consnamefreq;
3183 size_t l;
3184 int freq;
3185
3186 cons = conss[i];
3187 assert( cons != NULL );
3188
3189 /* in case the transformed problem is written, only constraints are posted which are enabled in the current node */
3190 assert(!transformed || SCIPconsIsEnabled(cons));
3191
3192 l = strlen(SCIPconsGetName(cons));
3193
3194 if( l == 0 )
3195 {
3196 SCIPwarningMessage(scip, "At least one name of a constraint is empty, so file will be written with generic names.\n");
3197 *error = TRUE;
3198
3199 goto TERMINATE;
3200 }
3201
3202 consnamefreqs[i].consname = SCIPconsGetName(cons);
3203 consnamefreqs[i].freq = 0;
3204 freq = 0;
3205
3206 /* check for duplicate names */
3207 if( NULL != (consnamefreq = (CONSNAMEFREQ *)SCIPhashtableRetrieve(consfreq, (void*)SCIPconsGetName(cons))) )
3208 {
3209 consnamefreq->freq += 1;
3210 consnamefreqs[i] = *consnamefreq;
3211 freq = consnamefreq->freq;
3212 }
3213 SCIP_CALL( SCIPhashtableInsert(consfreq, (void*)(&consnamefreqs[i])) );
3214
3215 /* the new length is the length of the old name + a '_' and the freq number which has floor(log10(freq)) + 1 characters */
3216 if( freq > 0 )
3217 l = l + 1 + (size_t)log10((SCIP_Real) freq) + 1;
3218
3219 if( l >= MPS_MAX_NAMELEN )
3220 {
3221 SCIPwarningMessage(scip, "Constraints have duplicate name and are too long to fix, so file will be written with generic names.\n");
3222 *error = TRUE;
3223
3224 goto TERMINATE;
3225 }
3226
3227 (*maxnamelen) = MAX(*maxnamelen, (unsigned int) l);
3228
3229 SCIP_CALL( SCIPallocBufferArray(scip, &consname, (int) l + 1) );
3230 if( freq > 0 )
3231 (void) SCIPsnprintf(consname, (int)l + 1, "%s_%d", SCIPconsGetName(cons), freq);
3232 else
3233 (void) SCIPsnprintf(consname, (int)l + 1, "%s", SCIPconsGetName(cons));
3234
3235 (*consnames)[i] = consname;
3236 }
3237
3238 TERMINATE:
3239 SCIPfreeBufferArray(scip, &consnamefreqs);
3240
3241 if( *error )
3242 {
3243 --i; /*lint !e445*/
3244 for( ; i >= 0; --i) /*lint !e445*/
3245 {
3246 SCIPfreeBufferArray(scip, &((*consnames)[i]));
3247 }
3248 SCIPfreeBufferArray(scip, consnames);
3249 }
3250
3251 SCIPhashtableFree(&consfreq);
3252
3253 return SCIP_OKAY;
3254 }
3255
3256
3257 /** outputs the COLUMNS section of the MPS format */
3258 static
printColumnSection(SCIP * scip,FILE * file,SPARSEMATRIX * matrix,SCIP_HASHMAP * varnameHashmap,SCIP_HASHTABLE * indicatorSlackHash,unsigned int maxnamelen)3259 void printColumnSection(
3260 SCIP* scip, /**< SCIP data structure */
3261 FILE* file, /**< output file, or NULL if standard output should be used */
3262 SPARSEMATRIX* matrix, /**< sparse matrix containing the entries */
3263 SCIP_HASHMAP* varnameHashmap, /**< map from SCIP_VAR* to variable name */
3264 SCIP_HASHTABLE* indicatorSlackHash, /**< hashtable containing slack variables from indicators (or NULL) */
3265 unsigned int maxnamelen /**< maximum name length */
3266 )
3267 {
3268 SCIP_Bool intSection;
3269 SCIP_VAR* var;
3270 const char* varname;
3271 SCIP_Real value;
3272 int v;
3273 int recordcnt;
3274
3275 /* sort sparse matrix w.r.t. the variable indices */
3276 SCIPsortPtrPtrReal((void**) matrix->columns, (void**) matrix->rows, matrix->values, SCIPvarComp, matrix->nentries);
3277
3278 /* print COLUMNS section */
3279 SCIPinfoMessage(scip, file, "COLUMNS\n");
3280
3281 intSection = FALSE;
3282
3283 for( v = 0; v < matrix->nentries; )
3284 {
3285 var = matrix->columns[v];
3286 assert( var != NULL );
3287
3288 /* skip slack variables in output */
3289 if( indicatorSlackHash != NULL && SCIPhashtableExists(indicatorSlackHash, var) )
3290 {
3291 ++v;
3292 continue;
3293 }
3294
3295 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS && intSection )
3296 {
3297 /* end integer section in MPS format */
3298 printStart(scip, file, "", "INTEND", (int) maxnamelen);
3299 printRecord(scip, file, "'MARKER'", "", maxnamelen);
3300 printRecord(scip, file, "'INTEND'", "", maxnamelen);
3301 SCIPinfoMessage(scip, file, "\n");
3302 intSection = FALSE;
3303 }
3304 else if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !intSection )
3305 {
3306 /* start integer section in MPS format */
3307 printStart(scip, file, "", "INTSTART", (int) maxnamelen);
3308 printRecord(scip, file, "'MARKER'", "", maxnamelen);
3309 printRecord(scip, file, "'INTORG'", "", maxnamelen);
3310 SCIPinfoMessage(scip, file, "\n");
3311 intSection = TRUE;
3312 }
3313
3314 SCIPdebugMsg(scip, "create entries for variable <%s>\n", SCIPvarGetName(var));
3315
3316 /* record count; there are at most two records per line */
3317 recordcnt = 0;
3318
3319 /* get variable name */
3320 assert ( SCIPhashmapExists(varnameHashmap, var) );
3321 varname = (const char*) SCIPhashmapGetImage(varnameHashmap, var);
3322
3323 /* output all entries of the same variable */
3324 do
3325 {
3326 value = matrix->values[v];
3327
3328 /* print record to file */
3329 printEntry(scip, file, varname, matrix->rows[v], value, &recordcnt, maxnamelen);
3330 v++;
3331 }
3332 while( v < matrix->nentries && var == matrix->columns[v] );
3333
3334 if( recordcnt == 1 )
3335 SCIPinfoMessage(scip, file, "\n");
3336 }
3337 /* end integer section, if the columns sections ends with integer variables */
3338 if( intSection )
3339 {
3340 /* end integer section in MPS format */
3341 printStart(scip, file, "", "INTEND", (int) maxnamelen);
3342 printRecord(scip, file, "'MARKER'", "", maxnamelen);
3343 printRecord(scip, file, "'INTEND'", "", maxnamelen);
3344 SCIPinfoMessage(scip, file, "\n");
3345 }
3346 }
3347
3348
3349 /** outputs the right hand side section */
3350 static
printRhsSection(SCIP * scip,FILE * file,int nconss,const char ** consnames,SCIP_Real * rhss,unsigned int maxnamelen,SCIP_Real objoffset)3351 void printRhsSection(
3352 SCIP* scip, /**< SCIP data structure */
3353 FILE* file, /**< output file, or NULL if standard output should be used */
3354 int nconss, /**< number of constraints */
3355 const char** consnames, /**< constraint names */
3356 SCIP_Real* rhss, /**< right hand side array */
3357 unsigned int maxnamelen, /**< maximum name length */
3358 SCIP_Real objoffset /**< objective offset */
3359 )
3360 {
3361 int recordcnt = 0;
3362 int c;
3363
3364 assert( rhss != NULL );
3365
3366 SCIPinfoMessage(scip, file, "RHS\n");
3367 SCIPdebugMsg(scip, "start printing RHS section\n");
3368
3369 /* take care of the linear constraints */
3370 for( c = 0; c < nconss; ++c )
3371 {
3372 /* skip all constraints which have a right hand side of infinity */
3373 if( SCIPisInfinity(scip, rhss[c]) )
3374 continue;
3375
3376 assert(consnames[c] != NULL);
3377
3378 printEntry(scip, file, "RHS", consnames[c], rhss[c], &recordcnt, maxnamelen);
3379 }
3380
3381 if( ! SCIPisZero(scip, objoffset) )
3382 {
3383 /* write objective offset (-1 because it is moved to the rhs) */
3384 printEntry(scip, file, "RHS", "Obj", -objoffset, &recordcnt, maxnamelen);
3385 }
3386
3387 if( recordcnt == 1 )
3388 SCIPinfoMessage(scip, file, "\n");
3389 }
3390
3391
3392 /** outputs the range section */
3393 static
printRangeSection(SCIP * scip,FILE * file,SCIP_CONS ** conss,int nconss,const char ** consnames,SCIP_Bool transformed,unsigned int maxnamelen)3394 void printRangeSection(
3395 SCIP* scip, /**< SCIP data structure */
3396 FILE* file, /**< output file, or NULL if standard output should be used */
3397 SCIP_CONS** conss, /**< constraint array */
3398 int nconss, /**< number of constraints */
3399 const char** consnames, /**< constraint names */
3400 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */
3401 unsigned int maxnamelen /**< maximum name length */
3402 )
3403 {
3404 int c;
3405 int recordcnt = 0;
3406
3407 SCIP_CONSHDLR* conshdlr;
3408 const char* conshdlrname;
3409
3410 SCIP_CONS* cons;
3411 SCIP_Real lhs;
3412 SCIP_Real rhs;
3413
3414 SCIPinfoMessage(scip, file, "RANGES\n");
3415 SCIPdebugMsg(scip, "start printing RANGES section\n");
3416
3417 for( c = 0; c < nconss; ++c )
3418 {
3419 cons = conss[c];
3420 assert( cons != NULL);
3421
3422 /* in case the transformed problems is written only constraint are posted which are enabled in the current node;
3423 * the conss array should only contain relevant constraints
3424 */
3425 assert( !transformed || SCIPconsIsEnabled(cons) );
3426
3427 assert( consnames[c] != NULL );
3428
3429 conshdlr = SCIPconsGetHdlr(cons);
3430 assert( conshdlr != NULL );
3431
3432 conshdlrname = SCIPconshdlrGetName(conshdlr);
3433
3434 if( strcmp(conshdlrname, "linear") == 0 )
3435 {
3436 lhs = SCIPgetLhsLinear(scip, cons);
3437 rhs = SCIPgetRhsLinear(scip, cons);
3438 }
3439 else if( strcmp(conshdlrname, "varbound") == 0 )
3440 {
3441 lhs = SCIPgetLhsVarbound(scip, cons);
3442 rhs = SCIPgetRhsVarbound(scip, cons);
3443 }
3444 else
3445 continue;
3446
3447 if( !SCIPisInfinity(scip, -lhs) && !SCIPisInfinity(scip, rhs) && !SCIPisEQ(scip, rhs, lhs) )
3448 {
3449 assert( SCIPisGT(scip, rhs, lhs) );
3450 printEntry(scip, file, "RANGE", consnames[c], rhs - lhs, &recordcnt, maxnamelen);
3451 }
3452 }
3453 if(recordcnt == 1 )
3454 SCIPinfoMessage(scip, file, "\n");
3455 }
3456
3457 /** print bound section name */
3458 static
printBoundSectionName(SCIP * scip,FILE * file)3459 void printBoundSectionName(
3460 SCIP* scip, /**< SCIP data structure */
3461 FILE* file /**< output file, or NULL if standard output should be used */
3462 )
3463 {
3464 SCIPinfoMessage(scip, file, "BOUNDS\n");
3465 SCIPdebugMsg(scip, "start printing BOUNDS section\n");
3466 }
3467
3468 /** output bound section */
3469 static
printBoundSection(SCIP * scip,FILE * file,SCIP_VAR ** vars,int nvars,SCIP_VAR ** aggvars,int naggvars,SCIP_VAR ** fixvars,int nfixvars,SCIP_Bool transformed,const char ** varnames,SCIP_HASHTABLE * indicatorSlackHash,unsigned int maxnamelen)3470 void printBoundSection(
3471 SCIP* scip, /**< SCIP data structure */
3472 FILE* file, /**< output file, or NULL if standard output should be used */
3473 SCIP_VAR** vars, /**< active variables */
3474 int nvars, /**< number of active variables */
3475 SCIP_VAR** aggvars, /**< needed aggregated variables */
3476 int naggvars, /**< number of aggregated variables */
3477 SCIP_VAR** fixvars, /**< all fixed variables (or NULL if nfixvars is 0) */
3478 int nfixvars, /**< number of fixed variables */
3479 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */
3480 const char** varnames, /**< array with variable names */
3481 SCIP_HASHTABLE* indicatorSlackHash, /**< hashtable containing slack variables from indicators (or NULL) */
3482 unsigned int maxnamelen /**< maximum name length */
3483 )
3484 {
3485 int v;
3486 SCIP_VAR* var;
3487 SCIP_Real lb;
3488 SCIP_Real ub;
3489 SCIP_Bool sectionName;
3490 const char* varname;
3491 char valuestr[MPS_MAX_VALUELEN] = { '\0' };
3492
3493 assert(scip != NULL);
3494 assert(vars != NULL);
3495 assert(nfixvars == 0 || fixvars != NULL);
3496
3497 sectionName = FALSE;
3498
3499 /* output the active variables */
3500 for( v = 0; v < nvars; ++v )
3501 {
3502 var = vars[v];
3503 assert( var != NULL );
3504
3505 /* skip slack variables in output */
3506 if( indicatorSlackHash != NULL && SCIPhashtableExists(indicatorSlackHash, var) )
3507 continue;
3508
3509 /* get variable name */
3510 varname = varnames[v];
3511 assert(strncmp(varname, SCIPvarGetName(var), maxnamelen) == 0);
3512
3513 if( transformed )
3514 {
3515 /* in case the transformed is written only local bounds are posted
3516 * which are valid in the current node */
3517 lb = SCIPvarGetLbLocal(var);
3518 ub = SCIPvarGetUbLocal(var);
3519 }
3520 else
3521 {
3522 lb = SCIPvarGetLbOriginal(var);
3523 ub = SCIPvarGetUbOriginal(var);
3524 }
3525
3526 /* take care of binary variables */
3527 if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
3528 {
3529 if( !sectionName )
3530 {
3531 printBoundSectionName(scip, file);
3532 sectionName = TRUE;
3533 }
3534
3535 if( !SCIPisFeasZero(scip, lb) || !SCIPisFeasEQ(scip, ub, 1.0) )
3536 {
3537 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", lb);
3538 printStart(scip, file, "LO", "Bound", (int) maxnamelen);
3539 printRecord(scip, file, varname, valuestr, maxnamelen);
3540 SCIPinfoMessage(scip, file, "\n");
3541
3542 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", ub);
3543 printStart(scip, file, "UP", "Bound", (int) maxnamelen);
3544 printRecord(scip, file, varname, valuestr, maxnamelen);
3545 }
3546 else
3547 {
3548 printStart(scip, file, "BV", "Bound", (int) maxnamelen);
3549 printRecord(scip, file, varname, "", maxnamelen);
3550 }
3551 SCIPinfoMessage(scip, file, "\n");
3552
3553 continue;
3554 }
3555
3556 /* take care of free variables */
3557 if( SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub) )
3558 {
3559 if( !sectionName )
3560 {
3561 printBoundSectionName(scip, file);
3562 sectionName = TRUE;
3563 }
3564
3565 /* variable is free */
3566 printStart(scip, file, "FR", "Bound", (int) maxnamelen);
3567 printRecord(scip, file, varname, "", maxnamelen);
3568 SCIPinfoMessage(scip, file, "\n");
3569 continue;
3570 }
3571
3572 /* take care of fixed variables */
3573 if( SCIPisEQ(scip, lb, ub) )
3574 {
3575 if( !sectionName )
3576 {
3577 printBoundSectionName(scip, file);
3578 sectionName = TRUE;
3579 }
3580
3581 /* variable is fixed */
3582 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", lb);
3583 printStart(scip, file, "FX", "Bound", (int) maxnamelen);
3584 printRecord(scip, file, varname, valuestr, maxnamelen);
3585 SCIPinfoMessage(scip, file, "\n");
3586 continue;
3587 }
3588
3589 /* print lower bound */
3590 if( SCIPisInfinity(scip, -lb) )
3591 {
3592 if( !sectionName )
3593 {
3594 printBoundSectionName(scip, file);
3595 sectionName = TRUE;
3596 }
3597
3598 /* the free variables are processed above */
3599 assert( !SCIPisInfinity(scip, ub) );
3600 printStart(scip, file, "MI", "Bound", (int) maxnamelen);
3601 printRecord(scip, file, varname, "", maxnamelen);
3602 SCIPinfoMessage(scip, file, "\n");
3603 }
3604 else
3605 {
3606 if( SCIPisZero(scip, lb) )
3607 {
3608 lb = 0.0;
3609 }
3610 else
3611 {
3612 if( !sectionName )
3613 {
3614 printBoundSectionName(scip, file);
3615 sectionName = TRUE;
3616 }
3617
3618 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", lb);
3619 printStart(scip, file, "LO", "Bound", (int) maxnamelen);
3620 printRecord(scip, file, varname, valuestr, maxnamelen);
3621 SCIPinfoMessage(scip, file, "\n");
3622 }
3623 }
3624
3625 /* print upper bound, infinity has to be printed for integer (!) variables, because during
3626 * reading an mps file no upper bound of an integer variable means that the upper bound will
3627 * be set to 1 instead of +infinity (like it is for continuous variables) */
3628 if( SCIPisInfinity(scip, ub) )
3629 {
3630 if( !sectionName )
3631 {
3632 printBoundSectionName(scip, file);
3633 sectionName = TRUE;
3634 }
3635
3636 /* the free variables are processed above */
3637 assert( !SCIPisInfinity(scip, -lb) );
3638 printStart(scip, file, "PL", "Bound", (int) maxnamelen);
3639 printRecord(scip, file, varname, "", maxnamelen);
3640 SCIPinfoMessage(scip, file, "\n");
3641 }
3642 else
3643 {
3644 if( !sectionName )
3645 {
3646 printBoundSectionName(scip, file);
3647 sectionName = TRUE;
3648 }
3649
3650 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", ub);
3651 printStart(scip, file, "UP", "Bound", (int) maxnamelen);
3652 printRecord(scip, file, varname, valuestr, maxnamelen);
3653 SCIPinfoMessage(scip, file, "\n");
3654 }
3655 }
3656
3657 /* output aggregated variables as 'free', except if they are binary */
3658 for( v = 0; v < naggvars; ++v )
3659 {
3660 if( !sectionName )
3661 {
3662 printBoundSectionName(scip, file);
3663 sectionName = TRUE;
3664 }
3665
3666 var = aggvars[v];
3667 assert( var != NULL );
3668
3669 /* get variable name */
3670 varname = varnames[nvars + v];
3671 assert(strncmp(varname, SCIPvarGetName(var), maxnamelen) == 0);
3672
3673 /* take care of binary variables */
3674 if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
3675 {
3676 printStart(scip, file, "BV", "Bound", (int) maxnamelen);
3677 printRecord(scip, file, varname, "", maxnamelen);
3678 SCIPinfoMessage(scip, file, "\n");
3679 }
3680 else
3681 {
3682 /* variable is free */
3683 printStart(scip, file, "FR", "Bound", (int) maxnamelen);
3684 printRecord(scip, file, varname, "", maxnamelen);
3685 SCIPinfoMessage(scip, file, "\n");
3686 }
3687 }
3688
3689 /* output all fixed variables */
3690 for( v = 0; v < nfixvars; ++v )
3691 {
3692 /* we should print the transformed problem, otherwise no fixed variable should exists */
3693 assert(transformed);
3694 assert(fixvars != NULL && fixvars[v] != NULL);
3695
3696 /* cppcheck-suppress nullPointer */
3697 var = fixvars[v];
3698
3699 assert(var != NULL);
3700 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
3701
3702 /* get variable name */
3703 varname = varnames[nvars + naggvars + v];
3704 assert(strncmp(varname, SCIPvarGetName(var), maxnamelen) == 0);
3705
3706 /* only local bounds are posted which are valid in the current node */
3707 lb = SCIPvarGetLbLocal(var);
3708 ub = SCIPvarGetUbLocal(var);
3709 assert(SCIPisEQ(scip, lb, ub));
3710
3711 if( !sectionName )
3712 {
3713 printBoundSectionName(scip, file);
3714 sectionName = TRUE;
3715 }
3716
3717 /* print fixed variable */
3718 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", lb);
3719 printStart(scip, file, "FX", "Bound", (int) maxnamelen);
3720 printRecord(scip, file, varname, valuestr, maxnamelen);
3721 SCIPinfoMessage(scip, file, "\n");
3722 }
3723 }
3724
3725
3726 /*
3727 * Callback methods of reader
3728 */
3729
3730 /** copy method for reader plugins (called when SCIP copies plugins) */
3731 /**! [SnippetReaderCopyMps] */
3732 static
SCIP_DECL_READERCOPY(readerCopyMps)3733 SCIP_DECL_READERCOPY(readerCopyMps)
3734 { /*lint --e{715}*/
3735 assert(scip != NULL);
3736 assert(reader != NULL);
3737 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
3738
3739 /* call inclusion method of reader */
3740 SCIP_CALL( SCIPincludeReaderMps(scip) );
3741
3742 return SCIP_OKAY;
3743 }
3744 /**! [SnippetReaderCopyMps] */
3745
3746 /** destructor of reader to free user data (called when SCIP is exiting) */
3747 /**! [SnippetReaderFreeMps] */
3748 static
SCIP_DECL_READERFREE(readerFreeMps)3749 SCIP_DECL_READERFREE(readerFreeMps)
3750 {
3751 SCIP_READERDATA* readerdata;
3752
3753 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
3754 readerdata = SCIPreaderGetData(reader);
3755 assert(readerdata != NULL);
3756 SCIPfreeBlockMemory(scip, &readerdata);
3757
3758 return SCIP_OKAY;
3759 }
3760 /**! [SnippetReaderFreeMps] */
3761
3762 /** problem reading method of reader */
3763 static
SCIP_DECL_READERREAD(readerReadMps)3764 SCIP_DECL_READERREAD(readerReadMps)
3765 { /*lint --e{715}*/
3766 assert(reader != NULL);
3767 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
3768
3769 SCIP_CALL( SCIPreadMps(scip, reader, filename, result, NULL, NULL, NULL, NULL, NULL, NULL) );
3770
3771 return SCIP_OKAY;
3772 }
3773
3774
3775 /** problem writing method of reader */
3776 static
SCIP_DECL_READERWRITE(readerWriteMps)3777 SCIP_DECL_READERWRITE(readerWriteMps)
3778 { /*lint --e{715}*/
3779 assert(reader != NULL);
3780 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
3781
3782 SCIP_CALL( SCIPwriteMps(scip, reader, file, name, transformed, objsense, objscale, objoffset, vars,
3783 nvars, nbinvars, nintvars, nimplvars, ncontvars, fixedvars, nfixedvars, conss, nconss, result) );
3784
3785 return SCIP_OKAY;
3786 }
3787
3788
3789 /*
3790 * mps file reader specific interface methods
3791 */
3792
3793 /** includes the mps file reader in SCIP */
SCIPincludeReaderMps(SCIP * scip)3794 SCIP_RETCODE SCIPincludeReaderMps(
3795 SCIP* scip /**< SCIP data structure */
3796 )
3797 {
3798 SCIP_READERDATA* readerdata;
3799 SCIP_READER* reader;
3800
3801 /* create reader data */
3802 SCIP_CALL( SCIPallocBlockMemory(scip, &readerdata) );
3803
3804 /* include reader */
3805 SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, readerdata) );
3806
3807 /* set non fundamental callbacks via setter functions */
3808 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyMps) );
3809 SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeMps) );
3810 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadMps) );
3811 SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteMps) );
3812
3813 /* add lp-reader parameters */
3814 SCIP_CALL( SCIPaddBoolParam(scip,
3815 "reading/" READER_NAME "/linearize-and-constraints",
3816 "should possible \"and\" constraint be linearized when writing the mps file?",
3817 &readerdata->linearizeands, TRUE, DEFAULT_LINEARIZE_ANDS, NULL, NULL) );
3818 SCIP_CALL( SCIPaddBoolParam(scip,
3819 "reading/" READER_NAME "/aggrlinearization-ands",
3820 "should an aggregated linearization for and constraints be used?",
3821 &readerdata->aggrlinearizationands, TRUE, DEFAULT_AGGRLINEARIZATION_ANDS, NULL, NULL) );
3822
3823 return SCIP_OKAY;
3824 }
3825
3826
3827 /** reads problem from file */
SCIPreadMps(SCIP * scip,SCIP_READER * reader,const char * filename,SCIP_RESULT * result,const char *** varnames,const char *** consnames,int * varnamessize,int * consnamessize,int * nvarnames,int * nconsnames)3828 SCIP_RETCODE SCIPreadMps(
3829 SCIP* scip, /**< SCIP data structure */
3830 SCIP_READER* reader, /**< the file reader itself */
3831 const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */
3832 SCIP_RESULT* result, /**< pointer to store the result of the file reading call */
3833 const char*** varnames, /**< storage for the variable names, or NULL */
3834 const char*** consnames, /**< storage for the constraint names, or NULL */
3835 int* varnamessize, /**< the size of the variable names storage, or NULL */
3836 int* consnamessize, /**< the size of the constraint names storage, or NULL */
3837 int* nvarnames, /**< the number of stored variable names, or NULL */
3838 int* nconsnames /**< the number of stored constraint names, or NULL */
3839 )
3840 {
3841 SCIP_RETCODE retcode;
3842
3843 assert(reader != NULL);
3844 assert(scip != NULL);
3845 assert(result != NULL);
3846
3847 retcode = readMps(scip, filename, varnames, consnames, varnamessize, consnamessize, nvarnames, nconsnames);
3848
3849 if( retcode == SCIP_PLUGINNOTFOUND )
3850 retcode = SCIP_READERROR;
3851
3852 if( retcode == SCIP_NOFILE || retcode == SCIP_READERROR )
3853 return retcode;
3854
3855 SCIP_CALL( retcode );
3856
3857 *result = SCIP_SUCCESS;
3858
3859 return SCIP_OKAY;
3860 }
3861
3862
3863 /** writes problem to file */
SCIPwriteMps(SCIP * scip,SCIP_READER * reader,FILE * file,const char * name,SCIP_Bool transformed,SCIP_OBJSENSE objsense,SCIP_Real objscale,SCIP_Real objoffset,SCIP_VAR ** vars,int nvars,int nbinvars,int nintvars,int nimplvars,int ncontvars,SCIP_VAR ** fixedvars,int nfixedvars,SCIP_CONS ** conss,int nconss,SCIP_RESULT * result)3864 SCIP_RETCODE SCIPwriteMps(
3865 SCIP* scip, /**< SCIP data structure */
3866 SCIP_READER* reader, /**< the file reader itself */
3867 FILE* file, /**< output file, or NULL if standard output should be used */
3868 const char* name, /**< problem name */
3869 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */
3870 SCIP_OBJSENSE objsense, /**< objective sense */
3871 SCIP_Real objscale, /**< scalar applied to objective function; external objective value is
3872 * extobj = objsense * objscale * (intobj + objoffset) */
3873 SCIP_Real objoffset, /**< objective offset from bound shifting and fixing */
3874 SCIP_VAR** vars, /**< array with active variables ordered binary, integer, implicit, continuous */
3875 int nvars, /**< number of active variables in the problem */
3876 int nbinvars, /**< number of binary variables */
3877 int nintvars, /**< number of general integer variables */
3878 int nimplvars, /**< number of implicit integer variables */
3879 int ncontvars, /**< number of continuous variables */
3880 SCIP_VAR** fixedvars, /**< array with fixed and aggregated variables */
3881 int nfixedvars, /**< number of fixed and aggregated variables in the problem */
3882 SCIP_CONS** conss, /**< array with constraints of the problem */
3883 int nconss, /**< number of constraints in the problem */
3884 SCIP_RESULT* result /**< pointer to store the result of the file writing call */
3885 )
3886 {
3887 SCIP_READERDATA* readerdata;
3888 int naddrows;
3889 int faulty = 0;
3890 int c;
3891 int v;
3892 int k;
3893 char* namestr;
3894
3895 SCIP_CONS* cons = NULL;
3896 const char* consname;
3897 const char** consnames;
3898
3899 SCIP_CONSHDLR* conshdlr;
3900 const char* conshdlrname;
3901
3902 SCIP_Real lhs;
3903 SCIP_Real rhs;
3904 SCIP_Real* rhss;
3905 SCIP_Real value;
3906
3907 SCIP_VAR* var = NULL;
3908 const char* varname;
3909 const char** varnames;
3910
3911 char valuestr[MPS_MAX_VALUELEN] = { '\0' };
3912
3913 SCIP_CONS** consIndicator;
3914 SCIP_CONS** consSOS1;
3915 SCIP_CONS** consSOS2;
3916 SCIP_CONS** consQuadratic;
3917 SCIP_CONS** consSOC;
3918 int nConsIndicator;
3919 int nConsSOS1;
3920 int nConsSOS2;
3921 int nConsQuadratic;
3922 int nConsSOC;
3923
3924 SCIP_HASHMAP* varnameHashmap; /* hash map from SCIP_VAR* to variable name */
3925 SPARSEMATRIX* matrix;
3926
3927 SCIP_VAR** aggvars;
3928 int naggvars = 0;
3929 int saggvars;
3930 SCIP_HASHTABLE* varFixedHash;
3931 SCIP_HASHTABLE* indicatorSlackHash;
3932
3933 SCIP_VAR** fixvars = NULL;
3934 int nfixvars = 0;
3935
3936 SCIP_VAR** consvars;
3937 int nconsvars;
3938 SCIP_Real* vals;
3939 SCIP_Longint* weights;
3940
3941 SCIP_Bool needRANGES;
3942 unsigned int maxnamelen;
3943
3944 SCIP_Bool error;
3945
3946 assert(reader != NULL);
3947 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
3948 assert(scip != NULL);
3949 assert(result != NULL);
3950
3951 needRANGES = FALSE;
3952 maxnamelen = 0;
3953 nConsSOS1 = 0;
3954 nConsSOS2 = 0;
3955 nConsQuadratic = 0;
3956 nConsSOC = 0;
3957 nConsIndicator = 0;
3958
3959 /* check if the constraint names are too long and build the constraint names */
3960 SCIP_CALL( checkConsnames(scip, conss, nconss, transformed, &maxnamelen, &consnames, &error) );
3961 if( error )
3962 {
3963 /* call writing with generic names */
3964 if( transformed )
3965 {
3966 SCIPwarningMessage(scip, "write transformed problem with generic variable and constraint names\n");
3967 SCIP_CALL( SCIPprintTransProblem(scip, file, "mps", TRUE) );
3968 }
3969 else
3970 {
3971 SCIPwarningMessage(scip, "write original problem with generic variable and constraint names\n");
3972 SCIP_CALL( SCIPprintOrigProblem(scip, file, "mps", TRUE) );
3973 }
3974 *result = SCIP_SUCCESS;
3975
3976 return SCIP_OKAY;
3977 }
3978
3979 /* check if the variable names are not too long and build the "variable" -> "variable name" hash map */
3980 SCIP_CALL( checkVarnames(scip, vars, nvars, &maxnamelen, &varnames, &varnameHashmap) );
3981
3982 /* collect SOS, quadratic, and indicator constraints in array for later output */
3983 SCIP_CALL( SCIPallocBufferArray(scip, &consSOS1, nconss) );
3984 SCIP_CALL( SCIPallocBufferArray(scip, &consSOS2, nconss) );
3985 SCIP_CALL( SCIPallocBufferArray(scip, &consQuadratic, nconss) );
3986 SCIP_CALL( SCIPallocBufferArray(scip, &consSOC, nconss) );
3987 SCIP_CALL( SCIPallocBufferArray(scip, &consIndicator, nconss) );
3988
3989 /* nfixedvars counts all variables with status SCIP_VARSTATUS_FIXED, SCIP_VARSTATUS_AGGREGATED, SCIP_VARSTATUS_MULTAGGR, but not SCIP_VARSTATUS_NEGATED */
3990 saggvars = nfixedvars;
3991 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &aggvars, saggvars) );
3992
3993 /* create hashtable for storing aggregated variables */
3994 if( nfixedvars > 0 )
3995 {
3996 SCIP_CALL( SCIPhashtableCreate(&varFixedHash, SCIPblkmem(scip), nfixedvars, hashGetKeyVar, hashKeyEqVar, hashKeyValVar, NULL) );
3997 }
3998 else
3999 varFixedHash = NULL;
4000
4001 if( nvars > 0 )
4002 {
4003 SCIP_CALL( SCIPhashtableCreate(&indicatorSlackHash, SCIPblkmem(scip), nvars, hashGetKeyVar, hashKeyEqVar, hashKeyValVar, NULL) );
4004 }
4005 else
4006 indicatorSlackHash = NULL;
4007
4008 /* initialize sparse matrix */
4009 SCIP_CALL( initializeMatrix(scip, &matrix, (nvars * 2 + nfixedvars)) );
4010 assert( matrix->sentries >= nvars );
4011
4012 readerdata = SCIPreaderGetData(reader);
4013 assert(readerdata != NULL);
4014
4015 naddrows = 0;
4016
4017 /* determine and-constraints and printing format to resize necessary arrays */
4018 if( readerdata->linearizeands )
4019 {
4020 SCIP_CONSHDLR* andconshdlr = SCIPfindConshdlr(scip, "and");
4021
4022 if( andconshdlr != NULL )
4023 {
4024 /* need to check for and-constraints, note that in the original problem you cannot get the number of
4025 * and-constraints by one call */
4026 for( c = nconss - 1; c >= 0; --c )
4027 {
4028 conshdlr = SCIPconsGetHdlr(conss[c]);
4029 assert(conshdlr != NULL);
4030
4031 conshdlrname = SCIPconshdlrGetName(conshdlr);
4032
4033 if( strcmp(conshdlrname, "and") == 0 )
4034 {
4035 if( readerdata->aggrlinearizationands )
4036 ++naddrows;
4037 else
4038 naddrows += SCIPgetNVarsAnd(scip, conss[c]);
4039 }
4040 }
4041 assert(naddrows >= 0);
4042
4043 if( naddrows > 0 )
4044 {
4045 /* resize consnames vector */
4046 SCIP_CALL( SCIPreallocBufferArray(scip, &consnames, nconss + naddrows) );
4047 }
4048 }
4049 }
4050
4051 /* initialize rhs vector */
4052 SCIP_CALL( SCIPallocBufferArray(scip, &rhss, nconss + naddrows) );
4053
4054 /* print statistics as comment to file stream */
4055 SCIPinfoMessage(scip, file, "* SCIP STATISTICS\n");
4056 SCIPinfoMessage(scip, file, "* Problem name : %s\n", name);
4057 SCIPinfoMessage(scip, file, "* Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n",
4058 nvars, nbinvars, nintvars, nimplvars, ncontvars);
4059 SCIPinfoMessage(scip, file, "* Constraints : %d\n", nconss);
4060
4061 /* print NAME of the problem */
4062 SCIPinfoMessage(scip, file, "%-14s%s\n", "NAME", name);
4063
4064 /* print OBJSENSE of the problem */
4065 SCIPinfoMessage(scip, file, "OBJSENSE\n");
4066 SCIPinfoMessage(scip, file, "%s\n", objsense == SCIP_OBJSENSE_MAXIMIZE ? " MAX" : " MIN");
4067
4068 /* start ROWS section */
4069 SCIPinfoMessage(scip, file, "ROWS\n");
4070
4071 /* print row type for the objective function */
4072 printStart(scip, file, "N", "Obj", -1);
4073 SCIPinfoMessage(scip, file, "\n");
4074
4075 /* first fill the matrix with the objective coefficients */
4076 for( v = 0; v < nvars; ++v )
4077 {
4078 /* take care of the objective entry */
4079 var = vars[v];
4080 value = SCIPvarGetObj(var);
4081
4082 /* we also want to add integer variables to the columns section, even if the objective value is 0, because it
4083 * might happen that they only exist in non-linear constraints, which leads to no other line in the column section
4084 * and therefore do not mark the variable as an integer
4085 */
4086 if( !SCIPisZero(scip, value) || SCIPvarGetType(var) < SCIP_VARTYPE_IMPLINT
4087 || ((SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == 0)
4088 && (SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == 0)) )
4089 {
4090 assert( matrix->nentries < matrix->sentries );
4091
4092 matrix->values[matrix->nentries] = objscale * value;
4093 matrix->columns[matrix->nentries] = var;
4094 matrix->rows[matrix->nentries] = "Obj";
4095 matrix->nentries++;
4096 }
4097 }
4098
4099 /* loop over all constraints */
4100 k = nconss;
4101 for( c = 0; c < nconss; ++c )
4102 {
4103 cons = conss[c];
4104 assert( cons != NULL);
4105
4106 /* in case the transformed problems is written only constraint are posted which are enabled in the current node;
4107 * the conss array should only contain relevant constraints
4108 */
4109 assert( !transformed || SCIPconsIsEnabled(cons) );
4110
4111 conshdlr = SCIPconsGetHdlr(cons);
4112 assert( conshdlr != NULL );
4113
4114 conshdlrname = SCIPconshdlrGetName(conshdlr);
4115
4116 /* construct constraint name */
4117 consname = consnames[c];
4118
4119 /* init rhs value to infinity (would then ignored) */
4120 rhss[c] = SCIPinfinity(scip);
4121
4122 if( strcmp(conshdlrname, "linear") == 0 )
4123 {
4124 lhs = SCIPgetLhsLinear(scip, cons);
4125 rhs = SCIPgetRhsLinear(scip, cons);
4126
4127 /* there is nothing to do if the left hand side is minus infinity and the right side is infinity */
4128 if( !SCIPisInfinity(scip, -lhs) || !SCIPisInfinity(scip, rhs) )
4129 {
4130 if( !SCIPisInfinity(scip, -lhs) && !SCIPisInfinity(scip, rhs) && !SCIPisEQ(scip, lhs, rhs) )
4131 needRANGES = TRUE;
4132
4133 /* print row entry */
4134 printRowType(scip, file, lhs, rhs, consname);
4135
4136 if( SCIPisInfinity(scip, rhs) )
4137 rhss[c] = lhs;
4138 else
4139 rhss[c] = rhs;
4140
4141 assert( !SCIPisInfinity(scip, rhss[c]) );
4142
4143 /* compute column entries */
4144 SCIP_CALL( getLinearCoeffs(scip, consname, SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons),
4145 SCIPgetNVarsLinear(scip, cons), transformed, matrix, &rhss[c]) );
4146 }
4147 }
4148 else if( strcmp(conshdlrname, "setppc") == 0 )
4149 {
4150 /* print row entry */
4151 switch( SCIPgetTypeSetppc(scip, cons) )
4152 {
4153 case SCIP_SETPPCTYPE_PARTITIONING :
4154 printRowType(scip, file, 1.0, 1.0, consname);
4155 break;
4156 case SCIP_SETPPCTYPE_PACKING :
4157 printRowType(scip, file, -SCIPinfinity(scip), 1.0, consname);
4158 break;
4159 case SCIP_SETPPCTYPE_COVERING :
4160 printRowType(scip, file, 1.0, SCIPinfinity(scip), consname);
4161 break;
4162 }
4163
4164 rhss[c] = 1.0;
4165
4166 /* compute column entries */
4167 SCIP_CALL( getLinearCoeffs(scip, consname, SCIPgetVarsSetppc(scip, cons), NULL, SCIPgetNVarsSetppc(scip, cons), transformed, matrix, &rhss[c]) );
4168 }
4169 else if( strcmp(conshdlrname, "logicor") == 0 )
4170 {
4171 /* print row entry */
4172 printRowType(scip, file, 1.0, SCIPinfinity(scip), consname);
4173
4174 rhss[c] = 1.0;
4175
4176 /* compute column entries */
4177 SCIP_CALL( getLinearCoeffs(scip, consname, SCIPgetVarsLogicor(scip, cons), NULL, SCIPgetNVarsLogicor(scip, cons), transformed, matrix, &rhss[c]) );
4178 }
4179 else if( strcmp(conshdlrname, "knapsack") == 0 )
4180 {
4181 int i;
4182
4183 /* print row entry */
4184 printRowType(scip, file, -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), consname);
4185
4186 nconsvars = SCIPgetNVarsKnapsack(scip, cons);
4187 weights = SCIPgetWeightsKnapsack(scip, cons);
4188
4189 /* copy Longint array to SCIP_Real array */
4190 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nconsvars ) );
4191 for( i = 0; i < nconsvars; ++i )
4192 vals[i] = (SCIP_Real)weights[i];
4193
4194 rhss[c] = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons);
4195
4196 /* compute column entries */
4197 SCIP_CALL( getLinearCoeffs(scip, consname, SCIPgetVarsKnapsack(scip, cons), vals, nconsvars, transformed, matrix, &rhss[c]) );
4198
4199 SCIPfreeBufferArray(scip, &vals);
4200 }
4201 else if( strcmp(conshdlrname, "varbound") == 0 )
4202 {
4203 lhs = SCIPgetLhsVarbound(scip, cons);
4204 rhs = SCIPgetRhsVarbound(scip, cons);
4205
4206 /* there is nothing to do if the left hand side is minus infinity and the right side is infinity */
4207 if( !SCIPisInfinity(scip, -lhs) || !SCIPisInfinity(scip, rhs) )
4208 {
4209 if( !SCIPisInfinity(scip, -lhs) && !SCIPisInfinity(scip, rhs) && !SCIPisEQ(scip, lhs, rhs) )
4210 needRANGES = TRUE;
4211
4212 /* print row entry */
4213 printRowType(scip, file, lhs, rhs, consname);
4214
4215 /* allocate memory */
4216 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) );
4217 SCIP_CALL( SCIPallocBufferArray(scip, &vals, 2) );
4218
4219 consvars[0] = SCIPgetVarVarbound(scip, cons);
4220 consvars[1] = SCIPgetVbdvarVarbound(scip, cons);
4221
4222 vals[0] = 1.0;
4223 vals[1] = SCIPgetVbdcoefVarbound(scip, cons);
4224
4225 if( SCIPisInfinity(scip, rhs) )
4226 rhss[c] = lhs;
4227 else
4228 rhss[c] = rhs;
4229
4230 assert( !SCIPisInfinity(scip, rhss[c]) );
4231
4232 /* compute column entries */
4233 SCIP_CALL( getLinearCoeffs(scip, consname, consvars, vals, 2, transformed, matrix, &rhss[c]) );
4234
4235 SCIPfreeBufferArray(scip, &vals);
4236 SCIPfreeBufferArray(scip, &consvars);
4237 }
4238 }
4239 else if( strcmp(conshdlrname, "indicator") == 0 )
4240 {
4241 SCIP_VAR* slackvar;
4242 SCIP_VAR* binvar;
4243
4244 /* store slack variable in hash */
4245 slackvar = SCIPgetSlackVarIndicator(cons);
4246 assert( slackvar != NULL );
4247 assert( indicatorSlackHash != NULL );
4248 assert( !SCIPhashtableExists(indicatorSlackHash, (void*) slackvar) );
4249 SCIP_CALL( SCIPhashtableInsert(indicatorSlackHash, (void*) slackvar) );
4250
4251 /* if slackvariable is aggregated, we store it in the list of aggregated variables */
4252 if ( SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
4253 {
4254 SCIP_CALL( collectAggregatedVars(scip, &slackvar, 1, &aggvars, &naggvars, &saggvars, varFixedHash) );
4255 }
4256
4257 /* store aggregated variables */
4258 binvar = SCIPgetBinaryVarIndicator(cons);
4259 if( SCIPvarIsNegated(binvar) )
4260 binvar = SCIPvarGetNegatedVar(binvar);
4261 assert( binvar != NULL );
4262 SCIP_CALL( collectAggregatedVars(scip, &binvar, 1, &aggvars, &naggvars, &saggvars, varFixedHash) );
4263
4264 /* indicator constraint do not have a right hand side; mark this with SCIPinfinity(scip) */
4265 rhss[c] = SCIPinfinity(scip);
4266
4267 /* store constraint */
4268 consIndicator[nConsIndicator++] = cons;
4269 continue;
4270 }
4271 else if( strcmp(conshdlrname, "SOS1") == 0 )
4272 {
4273 /* store constraint */
4274 consSOS1[nConsSOS1++] = cons;
4275
4276 /* check for aggregated variables in SOS1 constraints for later output
4277 * of aggregations as linear constraints */
4278 consvars = SCIPgetVarsSOS1(scip, cons);
4279 nconsvars = SCIPgetNVarsSOS1(scip, cons);
4280
4281 /* SOS constraint do not have a right hand side; mark this with SCIPinfinity(scip) */
4282 rhss[c] = SCIPinfinity(scip);
4283
4284 SCIP_CALL( collectAggregatedVars(scip, consvars, nconsvars, &aggvars, &naggvars, &saggvars, varFixedHash) );
4285 }
4286 else if( strcmp(conshdlrname, "SOS2") == 0 )
4287 {
4288 /* store constraint */
4289 consSOS2[nConsSOS2++] = cons;
4290
4291 /* check for aggregated variables in SOS2 constraints for later output aggregations as linear constraints */
4292 consvars = SCIPgetVarsSOS2(scip, cons);
4293 nconsvars = SCIPgetNVarsSOS2(scip, cons);
4294
4295 /* SOS constraint do not have a right hand side; mark this with SCIPinfinity(scip) */
4296 rhss[c] = SCIPinfinity(scip);
4297
4298 SCIP_CALL( collectAggregatedVars(scip, consvars, nconsvars, &aggvars, &naggvars, &saggvars, varFixedHash) );
4299 }
4300 else if( strcmp(conshdlrname, "quadratic") == 0 )
4301 {
4302 SCIP_VAR** quadvars;
4303 SCIP_Real* quadvarlincoefs;
4304 int j;
4305
4306 /* store constraint */
4307 consQuadratic[nConsQuadratic++] = cons;
4308
4309 /* collect linear coefficients of quadratic part */
4310 SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, SCIPgetNQuadVarTermsQuadratic(scip, cons)) );
4311 SCIP_CALL( SCIPallocBufferArray(scip, &quadvarlincoefs, SCIPgetNQuadVarTermsQuadratic(scip, cons)) );
4312 for( j = 0; j < SCIPgetNQuadVarTermsQuadratic(scip, cons); ++j )
4313 {
4314 quadvars[j] = SCIPgetQuadVarTermsQuadratic(scip, cons)[j].var;
4315 quadvarlincoefs[j] = SCIPgetQuadVarTermsQuadratic(scip, cons)[j].lincoef;
4316 }
4317
4318 lhs = SCIPgetLhsQuadratic(scip, cons);
4319 rhs = SCIPgetRhsQuadratic(scip, cons);
4320
4321 /* there is nothing to do if the left hand side is minus infinity and the right side is infinity */
4322 if( !SCIPisInfinity(scip, -lhs) || !SCIPisInfinity(scip, rhs) )
4323 {
4324 if( !SCIPisInfinity(scip, -lhs) && !SCIPisInfinity(scip, rhs) && !SCIPisEQ(scip, lhs, rhs) )
4325 needRANGES = TRUE;
4326
4327 /* print row entry */
4328 printRowType(scip, file, lhs, rhs, consname);
4329
4330 if( SCIPisInfinity(scip, rhs) )
4331 rhss[c] = lhs;
4332 else
4333 rhss[c] = rhs;
4334
4335 assert( !SCIPisInfinity(scip, rhss[c]) );
4336
4337 /* compute column entries for linear part */
4338 SCIP_CALL( getLinearCoeffs(scip, consname, SCIPgetLinearVarsQuadratic(scip, cons), SCIPgetCoefsLinearVarsQuadratic(scip, cons),
4339 SCIPgetNLinearVarsQuadratic(scip, cons), transformed, matrix, &rhss[c]) );
4340
4341 /* compute column entries for linear part in quadratic part */
4342 SCIP_CALL( getLinearCoeffs(scip, consname, quadvars, quadvarlincoefs, SCIPgetNQuadVarTermsQuadratic(scip, cons),
4343 transformed, matrix, &rhss[c]) );
4344 }
4345
4346 /* check for aggregated variables in quadratic part of quadratic constraints for later output of
4347 * aggregations as linear constraints */
4348 consvars = quadvars;
4349 nconsvars = SCIPgetNQuadVarTermsQuadratic(scip, cons);
4350
4351 SCIP_CALL( collectAggregatedVars(scip, consvars, nconsvars, &aggvars, &naggvars, &saggvars, varFixedHash) );
4352
4353 SCIPfreeBufferArray(scip, &quadvars);
4354 SCIPfreeBufferArray(scip, &quadvarlincoefs);
4355 }
4356 else if( strcmp(conshdlrname, "soc") == 0 )
4357 {
4358 /* SOC constraints are of the form lhsconstant + sum_i (lhscoef_i*(lhsvar_i+lhsoffset_i))^2 <= (rhscoef*(rhsvar+rhsoffset))^2 */
4359 SCIP_Real* lincoefs;
4360 SCIP_Real coef;
4361 SCIP_Real offset;
4362
4363 /* store constraint */
4364 consSOC[nConsSOC++] = cons;
4365
4366 consvars = SCIPgetLhsVarsSOC(scip, cons);
4367 nconsvars = SCIPgetNLhsVarsSOC(scip, cons);
4368
4369 rhs = -SCIPgetLhsConstantSOC(scip, cons);
4370
4371 /* offsets on lhs give linear coefficients that need to be processed here */
4372 SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nconsvars) );
4373
4374 for( v = 0; v < nconsvars; ++v )
4375 {
4376 offset = SCIPgetLhsOffsetsSOC(scip, cons)[v];
4377 coef = SCIPgetLhsCoefsSOC(scip, cons)[v];
4378
4379 lincoefs[v] = 2 * offset * coef * coef;
4380 rhs -= offset * offset * coef * coef;
4381 }
4382
4383 SCIP_CALL( getLinearCoeffs(scip, consname, SCIPgetLhsVarsSOC(scip, cons), lincoefs, nconsvars, transformed, matrix, &rhs) );
4384
4385 SCIPfreeBufferArray(scip, &lincoefs);
4386
4387 /* if there is an offsets on rhs, then we have linear a coefficient that need to be processed here */
4388 if( SCIPgetRhsOffsetSOC(scip, cons) != 0.0 )
4389 {
4390 SCIP_VAR* rhsvar;
4391 SCIP_Real lincoef;
4392
4393 coef = SCIPgetRhsCoefSOC(scip, cons);
4394 offset = SCIPgetRhsOffsetSOC(scip, cons);
4395 rhsvar = SCIPgetRhsVarSOC(scip, cons);
4396 lincoef = -2 * offset * coef * coef;
4397 rhs += offset * offset * coef * coef;
4398
4399 SCIP_CALL( getLinearCoeffs(scip, consname, &rhsvar, &lincoef, 1, transformed, matrix, &rhs) );
4400 }
4401
4402 assert(!SCIPisInfinity(scip, ABS(rhs)));
4403
4404 /* print row entry */
4405 printRowType(scip, file, -SCIPinfinity(scip), rhs, consname);
4406
4407 rhss[c] = rhs;
4408
4409 /* check for aggregated variables in for later output of aggregations as linear constraints */
4410 SCIP_CALL( collectAggregatedVars(scip, consvars, nconsvars, &aggvars, &naggvars, &saggvars, varFixedHash) );
4411 var = SCIPgetRhsVarSOC(scip, cons);
4412 SCIP_CALL( collectAggregatedVars(scip, &var, 1, &aggvars, &naggvars, &saggvars, varFixedHash) );
4413 }
4414 else if( strcmp(conshdlrname, "and") == 0 )
4415 {
4416 if( readerdata->linearizeands )
4417 {
4418 SCIP_VAR** rowvars;
4419 SCIP_VAR** operands;
4420 SCIP_VAR* resultant;
4421 SCIP_Real* rowvals;
4422 char* rowname;
4423 int nrowvars;
4424 int l;
4425 int n;
4426
4427 nrowvars = SCIPgetNVarsAnd(scip, cons);
4428 operands = SCIPgetVarsAnd(scip, cons);
4429 resultant = SCIPgetResultantAnd(scip, cons);
4430
4431 /* allocate buffer array */
4432 SCIP_CALL( SCIPallocBufferArray(scip, &rowvars, nrowvars + 1) );
4433 SCIP_CALL( SCIPallocBufferArray(scip, &rowvals, nrowvars + 1) );
4434
4435 /* get length of constraint name */
4436 l = (int) strlen(consname);
4437
4438 /* the tight relaxtion, number of and-constraint operands rows */
4439 if( !readerdata->aggrlinearizationands )
4440 {
4441 rowvars[0] = resultant;
4442 rowvals[0] = 1.0;
4443 rowvals[1] = -1.0;
4444
4445 /* compute maximal length for rowname */
4446 /* coverity[negative_returns] */
4447 n = (int) log10((double)nrowvars) + 1 + l;
4448
4449 /* assure maximal allowed value */
4450 if( n >= MPS_MAX_NAMELEN )
4451 n = MPS_MAX_NAMELEN - 1;
4452
4453 /* update maxnamelen */
4454 maxnamelen = MAX(maxnamelen, (unsigned int) n);
4455
4456 /* print operator rows */
4457 for( v = 0; v < nrowvars; ++v )
4458 {
4459 /* compute maximal length for rowname */
4460 if( v == 0 )
4461 n = 2;
4462 else
4463 n = (int) log10((double)v) + 2;
4464 n += l;
4465
4466 /* assure maximal allowed value */
4467 if( n >= MPS_MAX_NAMELEN )
4468 {
4469 n = MPS_MAX_NAMELEN - 1;
4470 ++faulty;
4471 }
4472
4473 /* need memory for additional row */
4474 SCIP_CALL( SCIPallocBufferArray(scip, &rowname, n + 1) );
4475
4476 assert(k < nconss + naddrows);
4477 consnames[k] = rowname;
4478
4479 (void) SCIPsnprintf(rowname, n + 1, "%s_%d", consname, v);
4480 rowvars[1] = operands[v];
4481
4482 /* print row entry */
4483 printRowType(scip, file, -SCIPinfinity(scip), 0.0, rowname);
4484
4485 rhss[k] = 0.0;
4486
4487 /* compute column entries */
4488 SCIP_CALL( getLinearCoeffs(scip, rowname, rowvars, rowvals, 2, transformed, matrix, &rhss[k]) );
4489 ++k;
4490 }
4491 }
4492
4493 /* prepare for next row */
4494 for( v = nrowvars - 1; v >= 0; --v )
4495 {
4496 rowvars[v] = operands[v];
4497 rowvals[v] = -1.0;
4498 }
4499
4500 rowvars[nrowvars] = resultant;
4501
4502 /* the weak relaxtion, only one constraint */
4503 if( readerdata->aggrlinearizationands )
4504 {
4505 /* compute maximal length for rowname */
4506 n = l + 3;
4507
4508 /* assure maximal allowed value */
4509 if( n >= MPS_MAX_NAMELEN )
4510 {
4511 n = MPS_MAX_NAMELEN - 1;
4512 ++faulty;
4513 }
4514
4515 /* update maxnamelen */
4516 maxnamelen = MAX(maxnamelen, (unsigned int) n);
4517
4518 /* need memory for additional row */
4519 SCIP_CALL( SCIPallocBufferArray(scip, &rowname, n + 1) );
4520
4521 assert(k < nconss + naddrows);
4522 consnames[k] = rowname;
4523
4524 /* adjust rowname of constraint */
4525 (void) SCIPsnprintf(rowname, n + 1, "%s_op", consname);
4526
4527 rowvals[nrowvars] = (SCIP_Real) nrowvars;
4528
4529 /* print row entry */
4530 printRowType(scip, file, -SCIPinfinity(scip), 0.0, rowname);
4531
4532 rhss[k] = 0.0;
4533
4534 /* compute column entries */
4535 SCIP_CALL( getLinearCoeffs(scip, rowname, rowvars, rowvals, nrowvars + 1, transformed, matrix, &rhss[k]) );
4536
4537 SCIPdebugMsg(scip, "%g, %g\n", rowvals[1], rhss[k]);
4538 ++k;
4539 }
4540
4541 rowvals[nrowvars] = 1.0;
4542
4543 /* print row entry */
4544 printRowType(scip, file, -nrowvars + 1.0, SCIPinfinity(scip), consname);
4545
4546 rhss[c] = -nrowvars + 1.0;
4547
4548 /* compute column entries */
4549 SCIP_CALL( getLinearCoeffs(scip, consname, rowvars, rowvals, nrowvars + 1, transformed, matrix, &rhss[c]) );
4550
4551 /* free buffer array */
4552 SCIPfreeBufferArray(scip, &rowvals);
4553 SCIPfreeBufferArray(scip, &rowvars);
4554 }
4555 else
4556 {
4557 /* and constraint printing not enabled; mark this with SCIPinfinity(scip) */
4558 rhss[c] = SCIPinfinity(scip);
4559
4560 SCIPwarningMessage(scip, "change parameter \"reading/" READER_NAME "/linearize-and-constraints\" to TRUE to print and-constraints\n");
4561 }
4562 }
4563 else
4564 {
4565 /* unknown constraint type; mark this with SCIPinfinity(scip) */
4566 rhss[c] = SCIPinfinity(scip);
4567
4568 SCIPwarningMessage(scip, "constraint handler <%s> cannot print requested format\n", conshdlrname );
4569 }
4570 }
4571
4572 if( faulty > 0 )
4573 {
4574 SCIPwarningMessage(scip, "there are %d and-constraint-rownames which have to be cut down to %d characters; MPS file might be corrupted\n",
4575 faulty, MPS_MAX_NAMELEN - 1);
4576 }
4577
4578 /* free hash table */
4579 if( varFixedHash != NULL )
4580 SCIPhashtableFree(&varFixedHash);
4581
4582 if( indicatorSlackHash != NULL && nConsIndicator == 0 )
4583 {
4584 SCIPhashtableFree(&indicatorSlackHash);
4585 assert( indicatorSlackHash == NULL );
4586 }
4587
4588 if( naggvars > 0 )
4589 {
4590 /* construct variables name of the needed aggregated variables and the constraint names for the aggregation constraints */
4591
4592 /* realloc memory */
4593 SCIP_CALL( SCIPreallocBufferArray(scip, &consnames, nconss + naddrows + naggvars) );
4594 SCIP_CALL( SCIPreallocBufferArray(scip, &rhss, nconss + naddrows + naggvars) );
4595 SCIP_CALL( SCIPreallocBufferArray(scip, &varnames, nvars + naggvars) );
4596
4597 for( c = 0; c < naggvars; ++c )
4598 {
4599 size_t l;
4600
4601 /* create variable name */
4602 var = aggvars[c];
4603
4604 l = strlen(SCIPvarGetName(var));
4605 if( l >= MPS_MAX_NAMELEN )
4606 maxnamelen = MPS_MAX_NAMELEN - 1;
4607 else
4608 maxnamelen = MAX(maxnamelen, (unsigned int) l);
4609
4610 SCIP_CALL( SCIPallocBufferArray(scip, &namestr, MPS_MAX_NAMELEN) );
4611 (void) SCIPsnprintf(namestr, MPS_MAX_NAMELEN, "%s", SCIPvarGetName(var) );
4612
4613 /* insert variable with variable name into hash map */
4614 varnames[nvars + c] = namestr;
4615 assert( !SCIPhashmapExists(varnameHashmap, var) );
4616 SCIP_CALL( SCIPhashmapInsert(varnameHashmap, var, (void*) namestr) );
4617
4618 /* output row type (it is an equation) */
4619 SCIP_CALL( SCIPallocBufferArray(scip, &namestr, MPS_MAX_NAMELEN) ); /* note that namestr above is freed via varnames */
4620 (void) SCIPsnprintf(namestr, MPS_MAX_NAMELEN, "aggr_%s", SCIPvarGetName(var));
4621 printRowType(scip, file, 1.0, 1.0, namestr);
4622
4623 l = strlen(namestr);
4624 maxnamelen = MAX(maxnamelen, (unsigned int) l);
4625 consnames[nconss + naddrows + c] = namestr;
4626 rhss[nconss + naddrows + c] = 0.0;
4627
4628 /* compute column entries */
4629 SCIP_CALL( getLinearCoeffs(scip, namestr, &(aggvars[c]), NULL, 1, transformed, matrix, &rhss[nconss + naddrows + c]) );
4630
4631 /* add the aggregated variables to the sparse matrix */
4632 SCIP_CALL( checkSparseMatrixCapacity(scip, matrix, 1) );
4633 matrix->values[matrix->nentries] = -1.0;
4634 matrix->columns[matrix->nentries] = aggvars[c];
4635 matrix->rows[matrix->nentries] = namestr;
4636 matrix->nentries++;
4637 }
4638 }
4639
4640 /* collect also fixed variables, because they might not be removed from all constraints */
4641 /* @todo only collect fixed variables in the non-linear constraint types, where they (could not be)/(were not) removed */
4642 if( nfixedvars > 0 )
4643 {
4644 int startpos = nvars + naggvars;
4645 /* construct variables name of fixed variables */
4646
4647 /* realloc memory */
4648 SCIP_CALL( SCIPreallocBufferArray(scip, &varnames, startpos + nfixedvars) );
4649
4650 /* allocate memory for fixed variables */
4651 SCIP_CALL( SCIPallocBufferArray(scip, &fixvars, nfixedvars) );
4652
4653 for( v = nfixedvars - 1; v >= 0; --v )
4654 {
4655 /* create variable name */
4656 var = fixedvars[v];
4657
4658 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED )
4659 {
4660 size_t l;
4661 l = strlen(SCIPvarGetName(var));
4662 if( l >= MPS_MAX_NAMELEN )
4663 maxnamelen = MPS_MAX_NAMELEN - 1;
4664 else
4665 maxnamelen = MAX(maxnamelen, (unsigned int) l);
4666
4667 SCIP_CALL( SCIPallocBufferArray(scip, &namestr, MPS_MAX_NAMELEN) );
4668 (void) SCIPsnprintf(namestr, MPS_MAX_NAMELEN, "%s", SCIPvarGetName(var) );
4669
4670 varnames[startpos + nfixvars] = namestr;
4671 fixvars[nfixvars] = var;
4672 ++nfixvars;
4673
4674 /* insert variable with variable name into hash map */
4675 assert(!SCIPhashmapExists(varnameHashmap, var));
4676 SCIP_CALL( SCIPhashmapInsert(varnameHashmap, var, (void*) namestr) );
4677
4678 /* add the fixed variables to the sparse matrix, needed for columns section */
4679 SCIP_CALL( checkSparseMatrixCapacity(scip, matrix, 1) );
4680 matrix->values[matrix->nentries] = 0.0;
4681 matrix->columns[matrix->nentries] = var;
4682 matrix->rows[matrix->nentries] = "Obj";
4683 matrix->nentries++;
4684 }
4685 }
4686 }
4687
4688 /* output COLUMNS section */
4689 printColumnSection(scip, file, matrix, varnameHashmap, indicatorSlackHash, maxnamelen);
4690
4691 /* output RHS section */
4692 printRhsSection(scip, file, nconss + naddrows +naggvars, consnames, rhss, maxnamelen, objscale * objoffset);
4693
4694 /* output RANGES section */
4695 if( needRANGES )
4696 printRangeSection(scip, file, conss, nconss, consnames, transformed, maxnamelen);
4697
4698 /* output BOUNDS section */
4699 printBoundSection(scip, file, vars, nvars, aggvars, naggvars, fixvars, nfixvars, transformed, varnames, indicatorSlackHash, maxnamelen);
4700
4701 if( nfixedvars > 0 )
4702 {
4703 SCIPfreeBufferArray(scip, &fixvars);
4704 }
4705
4706 /* print SOS section */
4707 if( nConsSOS1 > 0 || nConsSOS2 > 0 )
4708 {
4709 SCIP_Real* sosweights;
4710
4711 SCIPinfoMessage(scip, file, "SOS\n");
4712 SCIPdebugMsg(scip, "start printing SOS section\n");
4713
4714 SCIP_CALL( SCIPallocBufferArray(scip, &namestr, MPS_MAX_NAMELEN) );
4715
4716 /* first output SOS1 constraints */
4717 for( c = 0; c < nConsSOS1; ++c )
4718 {
4719 cons = consSOS1[c];
4720 consvars = SCIPgetVarsSOS1(scip, cons);
4721 nconsvars = SCIPgetNVarsSOS1(scip, cons);
4722 sosweights = SCIPgetWeightsSOS1(scip, cons);
4723 (void) SCIPsnprintf(namestr, MPS_MAX_NAMELEN, "%s", SCIPconsGetName(cons) );
4724
4725 printStart(scip, file, "S1", namestr, -1);
4726 SCIPinfoMessage(scip, file, "\n");
4727
4728 for( v = 0; v < nconsvars; ++v )
4729 {
4730 /* get variable name */
4731 assert ( SCIPhashmapExists(varnameHashmap, consvars[v]) );
4732 varname = (const char*) SCIPhashmapGetImage(varnameHashmap, consvars[v]);
4733
4734 printStart(scip, file, "", varname, (int) maxnamelen);
4735
4736 if( sosweights != NULL )
4737 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", sosweights[v]);
4738 else
4739 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25d ", v);
4740
4741 SCIPinfoMessage(scip, file, "%25s\n", valuestr);
4742 }
4743 }
4744
4745 /* next output SOS2 constraints */
4746 for( c = 0; c < nConsSOS2; ++c )
4747 {
4748 cons = consSOS2[c];
4749 consvars = SCIPgetVarsSOS2(scip, cons);
4750 nconsvars = SCIPgetNVarsSOS2(scip, cons);
4751 sosweights = SCIPgetWeightsSOS2(scip, cons);
4752 (void) SCIPsnprintf(namestr, MPS_MAX_NAMELEN, "%s", SCIPconsGetName(cons) );
4753
4754 printStart(scip, file, "S2", namestr, -1);
4755 SCIPinfoMessage(scip, file, "\n");
4756
4757 for( v = 0; v < nconsvars; ++v )
4758 {
4759 /* get variable name */
4760 assert ( SCIPhashmapExists(varnameHashmap, consvars[v]) );
4761 varname = (const char*) SCIPhashmapGetImage(varnameHashmap, consvars[v]);
4762
4763 printStart(scip, file, "", varname, (int) maxnamelen);
4764
4765 if( sosweights != NULL )
4766 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", sosweights[v]);
4767 else
4768 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25d ", v);
4769
4770 SCIPinfoMessage(scip, file, "%25s\n", valuestr);
4771 }
4772 }
4773 SCIPfreeBufferArray(scip, &namestr);
4774 }
4775
4776 /* print QCMATRIX sections for quadratic constraints
4777 * in difference to a quadratic term in the objective function, the quadratic part is not divided by 2 here
4778 */
4779 if( nConsQuadratic > 0 )
4780 {
4781 SCIP_QUADVARTERM* quadvarterms;
4782 SCIP_BILINTERM* bilinterms;
4783 const char* varname2;
4784 int nbilin;
4785
4786 SCIPdebugMsg(scip, "start printing QCMATRIX sections for quadratic constraints\n");
4787 SCIP_CALL( SCIPallocBufferArray(scip, &namestr, MPS_MAX_NAMELEN) );
4788
4789 for( c = 0; c < nConsQuadratic; ++c )
4790 {
4791 cons = consQuadratic[c];
4792 nconsvars = SCIPgetNQuadVarTermsQuadratic(scip, cons);
4793 quadvarterms = SCIPgetQuadVarTermsQuadratic(scip, cons);
4794 bilinterms = SCIPgetBilinTermsQuadratic(scip, cons);
4795 nbilin = SCIPgetNBilinTermsQuadratic(scip, cons);
4796
4797 (void) SCIPsnprintf(namestr, MPS_MAX_NAMELEN, "%s", SCIPconsGetName(cons) );
4798
4799 SCIPinfoMessage(scip, file, "QCMATRIX %s\n", namestr);
4800
4801 /* print x^2 terms */
4802 for( v = 0; v < nconsvars; ++v )
4803 {
4804 if( quadvarterms[v].sqrcoef == 0.0 )
4805 continue;
4806
4807 /* get variable name */
4808 assert ( SCIPhashmapExists(varnameHashmap, quadvarterms[v].var) );
4809 varname = (const char*) SCIPhashmapGetImage(varnameHashmap, quadvarterms[v].var);
4810
4811 /* get coefficient as string */
4812 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", quadvarterms[v].sqrcoef);
4813
4814 /* print "x x coeff" line */
4815 printStart(scip, file, "", varname, (int) maxnamelen);
4816 printRecord(scip, file, varname, valuestr, maxnamelen);
4817 SCIPinfoMessage(scip, file, "\n");
4818 }
4819
4820 /* print bilinear terms; CPLEX format expects a symmetric matrix with all coefficients specified,
4821 * i.e., we have to split bilinear coefficients into two off diagonal elements */
4822 for( v = 0; v < nbilin; ++v )
4823 {
4824 if( bilinterms[v].coef == 0.0 )
4825 continue;
4826
4827 /* get name of first variable */
4828 assert ( SCIPhashmapExists(varnameHashmap, bilinterms[v].var1) );
4829 varname = (const char*) SCIPhashmapGetImage(varnameHashmap, bilinterms[v].var1);
4830
4831 /* get name of second variable */
4832 assert ( SCIPhashmapExists(varnameHashmap, bilinterms[v].var2) );
4833 varname2 = (const char*) SCIPhashmapGetImage(varnameHashmap, bilinterms[v].var2);
4834
4835 /* get coefficient as string */
4836 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", 0.5*bilinterms[v].coef);
4837
4838 /* print "x y coeff/2" line */
4839 printStart(scip, file, "", varname, (int) maxnamelen);
4840 printRecord(scip, file, varname2, valuestr, maxnamelen);
4841 SCIPinfoMessage(scip, file, "\n");
4842
4843 /* print "y x coeff/2" line */
4844 printStart(scip, file, "", varname2, (int) maxnamelen);
4845 printRecord(scip, file, varname, valuestr, maxnamelen);
4846 SCIPinfoMessage(scip, file, "\n");
4847 }
4848 }
4849
4850 SCIPfreeBufferArray(scip, &namestr);
4851 }
4852
4853 /* print QCMATRIX sections for second order cone constraints */
4854 if( nConsSOC > 0 )
4855 {
4856 SCIP_Real* coefs;
4857
4858 SCIPdebugMsg(scip, "start printing QCMATRIX sections for soc constraints\n");
4859 SCIP_CALL( SCIPallocBufferArray(scip, &namestr, MPS_MAX_NAMELEN) );
4860
4861 for( c = 0; c < nConsSOC; ++c )
4862 {
4863 cons = consSOC[c];
4864 consvars = SCIPgetLhsVarsSOC(scip, cons);
4865 nconsvars = SCIPgetNLhsVarsSOC(scip, cons);
4866 coefs = SCIPgetLhsCoefsSOC(scip, cons);
4867
4868 (void) SCIPsnprintf(namestr, MPS_MAX_NAMELEN, "%s", SCIPconsGetName(cons) );
4869 SCIPinfoMessage(scip, file, "QCMATRIX %s\n", namestr);
4870
4871 /* print alpha_i^2 x_i^2 terms */
4872 for( v = 0; v < nconsvars; ++v )
4873 {
4874 if( coefs[v] == 0.0 )
4875 continue;
4876
4877 /* get variable name */
4878 assert ( SCIPhashmapExists(varnameHashmap, consvars[v]) );
4879 varname = (const char*) SCIPhashmapGetImage(varnameHashmap, consvars[v]);
4880
4881 /* get coefficient^2 as string */
4882 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", coefs[v]*coefs[v]);
4883
4884 /* print "x x coeff" line */
4885 printStart(scip, file, "", varname, (int) maxnamelen);
4886 printRecord(scip, file, varname, valuestr, maxnamelen);
4887 SCIPinfoMessage(scip, file, "\n");
4888 }
4889
4890 /* print -(alpha_{n+1} x_{n+1})^2 term */
4891
4892 /* get variable name */
4893 var = SCIPgetRhsVarSOC(scip, cons);
4894 assert ( SCIPhashmapExists(varnameHashmap, var) );
4895 varname = (const char*) SCIPhashmapGetImage(varnameHashmap, var);
4896
4897 /* get -coefficient^2 as string */
4898 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25.15g", -SCIPgetRhsCoefSOC(scip, cons)*SCIPgetRhsCoefSOC(scip, cons));
4899
4900 /* print "x x coeff" line */
4901 printStart(scip, file, "", varname, (int) maxnamelen);
4902 printRecord(scip, file, varname, valuestr, maxnamelen);
4903 SCIPinfoMessage(scip, file, "\n");
4904 }
4905
4906 SCIPfreeBufferArray(scip, &namestr);
4907 }
4908
4909 /* print indicator section */
4910 if( nConsIndicator > 0 )
4911 {
4912 SCIP_CALL( SCIPallocBufferArray(scip, &namestr, MPS_MAX_NAMELEN) );
4913
4914 SCIPinfoMessage(scip, file, "INDICATORS\n");
4915 SCIPdebugMsg(scip, "start printing INDICATOR section\n");
4916
4917 /* output each indicator constraint */
4918 for( c = 0; c < nConsIndicator; ++c )
4919 {
4920 SCIP_CONS* lincons;
4921 SCIP_VAR* slackvar;
4922 SCIP_VAR* binvar;
4923
4924 cons = consIndicator[c];
4925 binvar = SCIPgetBinaryVarIndicator(cons);
4926 lincons = SCIPgetLinearConsIndicator(cons);
4927 slackvar = SCIPgetSlackVarIndicator(cons);
4928
4929 /* linvars always contains slack variable, thus nlinvars >= 1 */
4930 if( SCIPgetNVarsLinear(scip, lincons) <= 1 || SCIPconsIsDeleted(lincons) )
4931 continue;
4932
4933 /* create variable and value strings */
4934 if( SCIPvarIsNegated(binvar) )
4935 {
4936 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25d", 0);
4937 assert( SCIPvarGetNegatedVar(binvar) != NULL );
4938 assert( SCIPhashmapExists(varnameHashmap, SCIPvarGetNegatedVar(binvar)) );
4939 varname = (const char*) SCIPhashmapGetImage(varnameHashmap, SCIPvarGetNegatedVar(binvar));
4940 }
4941 else
4942 {
4943 (void) SCIPsnprintf(valuestr, MPS_MAX_VALUELEN, "%25d", 1);
4944 assert ( SCIPhashmapExists(varnameHashmap, binvar) );
4945 varname = (const char*) SCIPhashmapGetImage(varnameHashmap, binvar);
4946 }
4947
4948 /* write records */
4949 if ( SCIPvarGetStatus(slackvar) == SCIP_VARSTATUS_AGGREGATED )
4950 {
4951 /* for aggregated variables output name of aggregating constraint */
4952 (void) SCIPsnprintf(namestr, MPS_MAX_NAMELEN, "aggr_%s", SCIPvarGetName(slackvar));
4953 printStart(scip, file, "IF", namestr, (int) maxnamelen);
4954 printRecord(scip, file, varname, valuestr, maxnamelen);
4955 SCIPinfoMessage(scip, file, "\n");
4956 }
4957 else
4958 {
4959 printStart(scip, file, "IF", SCIPconsGetName(lincons), (int) maxnamelen);
4960 printRecord(scip, file, varname, valuestr, maxnamelen);
4961 SCIPinfoMessage(scip, file, "\n");
4962 }
4963 }
4964 SCIPfreeBufferArray(scip, &namestr);
4965 }
4966
4967 /* free matrix data structure */
4968 freeMatrix(scip, matrix);
4969
4970 /* free slackvar hashtable */
4971 if( indicatorSlackHash != NULL )
4972 SCIPhashtableFree(&indicatorSlackHash);
4973
4974 /* free variable hashmap */
4975 SCIPhashmapFree(&varnameHashmap);
4976
4977 SCIPfreeBlockMemoryArray(scip, &aggvars, saggvars);
4978 SCIPfreeBufferArray(scip, &rhss);
4979
4980 /* free buffer arrays for SOS1, SOS2, and quadratic */
4981 SCIPfreeBufferArray(scip, &consIndicator);
4982 SCIPfreeBufferArray(scip, &consSOC);
4983 SCIPfreeBufferArray(scip, &consQuadratic);
4984 SCIPfreeBufferArray(scip, &consSOS2);
4985 SCIPfreeBufferArray(scip, &consSOS1);
4986
4987 /* free variable and constraint name array */
4988 for( v = nvars + naggvars + nfixvars - 1; v >= 0; --v )
4989 SCIPfreeBufferArray(scip, &varnames[v]);
4990 SCIPfreeBufferArray(scip, &varnames);
4991
4992 for( c = nconss + naddrows + naggvars - 1; c >= 0; --c )
4993 SCIPfreeBufferArray(scip, &consnames[c]);
4994 SCIPfreeBufferArray(scip, &consnames);
4995
4996 /* print end of data line */
4997 SCIPinfoMessage(scip, file, "ENDATA");
4998
4999 *result = SCIP_SUCCESS;
5000
5001 return SCIP_OKAY;
5002 }
5003