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