Scippy

SCIP

Solving Constraint Integer Programs

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