1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file reader_cip.c
17 * @ingroup DEFPLUGINS_READER
18 * @brief CIP file reader
19 * @author Stefan Heinz
20 * @author Marc Pfetsch
21 * @author Michael Winkler
22 *
23 */
24
25 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26
27 #include "blockmemshell/memory.h"
28 #include <ctype.h>
29 #include "scip/cons_linear.h"
30 #include "scip/pub_fileio.h"
31 #include "scip/pub_message.h"
32 #include "scip/pub_misc.h"
33 #include "scip/pub_reader.h"
34 #include "scip/pub_var.h"
35 #include "scip/reader_cip.h"
36 #include "scip/scip_cons.h"
37 #include "scip/scip_mem.h"
38 #include "scip/scip_message.h"
39 #include "scip/scip_numerics.h"
40 #include "scip/scip_param.h"
41 #include "scip/scip_prob.h"
42 #include "scip/scip_reader.h"
43 #include "scip/scip_var.h"
44 #include <string.h>
45
46 #if !defined(_WIN32) && !defined(_WIN64)
47 #include <strings.h> /*lint --e{766}*/ /* needed for strncasecmp() */
48 #endif
49
50 #define READER_NAME "cipreader"
51 #define READER_DESC "file reader for CIP (Constraint Integer Program) format"
52 #define READER_EXTENSION "cip"
53
54 #define DEFAULT_CIP_WRITEFIXEDVARS TRUE /**< Should fixed and aggregated variables be written when writing? */
55
56
57 /** CIP reading data */
58 struct SCIP_ReaderData
59 {
60 SCIP_Bool writefixedvars; /**< Should fixed and aggregated variables be written when writing? */
61 };
62
63
64 /** Section of the in CIP files */
65 enum CipSection
66 {
67 CIP_START, /**< start tag */
68 CIP_STATISTIC, /**< statistics section */
69 CIP_OBJECTIVE, /**< objective */
70 CIP_VARS, /**< list of (free) variables */
71 CIP_FIXEDVARS, /**< list of fixed variables */
72 CIP_CONSTRAINTS, /**< constraints */
73 CIP_END /**< end of file tag */
74 };
75 typedef enum CipSection CIPSECTION; /**< Section of the in CIP files */
76
77
78 /*
79 * Data structures
80 */
81
82 /** CIP reading data */
83 struct CipInput
84 {
85 SCIP_FILE* file; /**< input file */
86 char* strbuf; /**< string buffer for input lines */
87 int len; /**< length of strbuf */
88 int readingsize; /**< size of block in which len is increased if necessary */
89 int linenumber; /**< number of line in input file */
90 CIPSECTION section; /**< current section */
91 SCIP_Bool haserror; /**< some error occurred */
92 SCIP_Bool endfile; /**< we have reached the end of the file */
93 };
94 typedef struct CipInput CIPINPUT; /**< CIP reading data */
95
96
97 /*
98 * Local methods for reading/parsing
99 */
100
101 /** get next input line; this are all characters until the next semicolon */
102 static
getInputString(SCIP * scip,CIPINPUT * cipinput)103 SCIP_RETCODE getInputString(
104 SCIP* scip, /**< SCIP data structure */
105 CIPINPUT* cipinput /**< CIP parsing data */
106 )
107 {
108 char* endline;
109 char* endcharacter;
110 char* windowsendlinechar;
111
112 assert(cipinput != NULL);
113
114 /* read next line */
115 cipinput->endfile = (SCIPfgets(cipinput->strbuf, cipinput->len, cipinput->file) == NULL);
116
117 if( cipinput->endfile )
118 {
119 /* clear the line for safety reason */
120 BMSclearMemoryArray(cipinput->strbuf, cipinput->len);
121 return SCIP_OKAY;
122 }
123
124 cipinput->linenumber++;
125 endline = strchr(cipinput->strbuf, '\n');
126
127 endcharacter = strchr(cipinput->strbuf, ';');
128 while( endline == NULL || (endcharacter == NULL && cipinput->section == CIP_CONSTRAINTS && strncmp(cipinput->strbuf, "END", 3) != 0 ) )
129 {
130 int pos;
131
132 /* we refill the buffer from the '\n' character */
133 if( endline == NULL )
134 pos = cipinput->len - 1;
135 else
136 pos = (int) (endline - cipinput->strbuf);
137
138 /* don't erase the '\n' from all buffers for constraints */
139 if( endline != NULL && cipinput->section == CIP_CONSTRAINTS )
140 pos++;
141
142 /* if necessary reallocate memory */
143 if( pos + cipinput->readingsize >= cipinput->len )
144 {
145 cipinput->len = SCIPcalcMemGrowSize(scip, pos + cipinput->readingsize);
146 SCIP_CALL( SCIPreallocBufferArray(scip, &(cipinput->strbuf), cipinput->len) );
147 }
148
149 /* read next line */
150 cipinput->endfile = (SCIPfgets(&(cipinput->strbuf[pos]), cipinput->len - pos, cipinput->file) == NULL);
151
152 if( cipinput->endfile )
153 {
154 /* clear the line for safety reason */
155 BMSclearMemoryArray(cipinput->strbuf, cipinput->len);
156 return SCIP_OKAY;
157 }
158
159 cipinput->linenumber++;
160 endline = strrchr(cipinput->strbuf, '\n');
161 endcharacter = strchr(cipinput->strbuf, ';');
162 }
163 assert(endline != NULL);
164
165 /*SCIPdebugMsg(scip, "read line: %s\n", cipinput->strbuf);*/
166
167 /* check for windows "carriage return" endline character */
168 windowsendlinechar = strrchr(cipinput->strbuf, '\r');
169 if( windowsendlinechar != NULL && windowsendlinechar + 1 == endline )
170 --endline;
171 else
172 /* if the assert should not hold we found a windows "carriage return" which was not at the end of the line */
173 assert(windowsendlinechar == NULL);
174
175 if( cipinput->section == CIP_CONSTRAINTS && endcharacter != NULL && endline - endcharacter != 1 )
176 {
177 SCIPerrorMessage("Constraint line has to end with ';\\n' (line: %d).\n", cipinput->linenumber);
178 cipinput->haserror = TRUE;
179 return SCIP_OKAY; /* return error at hightest level */
180 }
181
182 *endline = '\0';
183
184 return SCIP_OKAY;
185 }
186
187 /** read the problem name out of the statistics */
188 static
getStart(SCIP * scip,CIPINPUT * cipinput)189 void getStart(
190 SCIP* scip, /**< SCIP data structure */
191 CIPINPUT* cipinput /**< CIP parsing data */
192 )
193 {
194 char* buf;
195
196 assert(scip != NULL);
197
198 buf = cipinput->strbuf;
199
200 if( strncmp(buf, "STATISTICS", 9) == 0 )
201 {
202 cipinput->section = CIP_STATISTIC;
203 return;
204 }
205
206 if( strncmp(buf, "VARIABLES", 8) == 0 || strncmp(buf, "FIXED", 5) == 0 || strncmp(buf, "CONSTRAINTS", 11) == 0 || strncmp(buf, "OBJECTIVE", 9) == 0 )
207 {
208 SCIPerrorMessage("Syntax Error: File has to start with 'STATISTICS' section.\n");
209 cipinput->haserror = TRUE;
210 }
211 }
212
213
214 /** read the problem name out of the statistics */
215 static
getStatistics(SCIP * scip,CIPINPUT * cipinput)216 SCIP_RETCODE getStatistics(
217 SCIP* scip, /**< SCIP data structure */
218 CIPINPUT* cipinput /**< CIP parsing data */
219 )
220 {
221 char* buf;
222
223 buf = cipinput->strbuf;
224
225 if( strncmp(buf, "OBJECTIVE", 9) == 0 )
226 {
227 cipinput->section = CIP_OBJECTIVE;
228 return SCIP_OKAY;
229 }
230
231 SCIPdebugMsg(scip, "parse statistics\n");
232
233 if( strncmp(buf, " Problem name", 14) == 0 )
234 {
235 char* name;
236 char* s;
237
238 name = strchr(buf, ':');
239
240 if( name == NULL )
241 {
242 SCIPwarningMessage(scip, "did not find problem name (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf);
243 return SCIP_OKAY; /* no error, might work with empty problem name */
244 }
245
246 /* skip ':' */
247 ++name;
248
249 /* make sure that we terminate the string at comments ('#') or newline ('\r', '\n')*/
250 if( NULL != (s = strpbrk(name, "#\r\n")) )
251 *s = '\0';
252
253 /* remove white space (tabs, ' ') in front of the name */
254 while( isspace((unsigned char)* name) )
255 ++name;
256
257 /* set problem name */
258 SCIP_CALL( SCIPsetProbName(scip, name) );
259
260 SCIPdebugMsg(scip, "problem name <%s>\n", name);
261 }
262
263 return SCIP_OKAY;
264 }
265
266 /** read objective sense, offset, and scale */
267 static
getObjective(SCIP * scip,CIPINPUT * cipinput,SCIP_Real * objscale,SCIP_Real * objoffset)268 SCIP_RETCODE getObjective(
269 SCIP* scip, /**< SCIP data structure */
270 CIPINPUT* cipinput, /**< CIP parsing data */
271 SCIP_Real* objscale, /**< buffer where to multiply with objective scale */
272 SCIP_Real* objoffset /**< buffer where to add with objective offset */
273 )
274 {
275 char* buf;
276 char* name;
277
278 assert(objscale != NULL);
279 assert(objoffset != NULL);
280
281 buf = cipinput->strbuf;
282
283 if( strncmp(buf, "VARIABLES", 8) == 0 )
284 cipinput->section = CIP_VARS;
285 else if( strncmp(buf, "FIXED", 5) == 0 )
286 cipinput->section = CIP_FIXEDVARS;
287 else if( strncmp(buf, "CONSTRAINTS", 11) == 0 )
288 cipinput->section = CIP_CONSTRAINTS;
289 else if( strncmp(buf, "END", 3) == 0 )
290 cipinput->section = CIP_END;
291
292 if( cipinput->section != CIP_OBJECTIVE )
293 return SCIP_OKAY;
294
295 SCIPdebugMsg(scip, "parse objective information\n");
296
297 /* remove white space */
298 while ( isspace((unsigned char)* buf) )
299 ++buf;
300
301 if( strncasecmp(buf, "Sense", 5) == 0 )
302 {
303 SCIP_OBJSENSE objsense;
304
305 name = strchr(buf, ':');
306
307 if( name == NULL )
308 {
309 SCIPwarningMessage(scip, "did not find objective sense (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf);
310 return SCIP_OKAY; /* no error - might work with default */
311 }
312
313 /* skip ':' */
314 ++name;
315
316 /* remove white space in front of the name */
317 while( isspace((unsigned char)* name) )
318 ++name;
319
320 if( strncasecmp(name, "minimize", 3) == 0 )
321 objsense = SCIP_OBJSENSE_MINIMIZE;
322 else if( strncasecmp(name, "maximize", 3) == 0 )
323 objsense = SCIP_OBJSENSE_MAXIMIZE;
324 else
325 {
326 SCIPwarningMessage(scip, "unknown objective sense '%s' (line: %d):\n%s\n", name, cipinput->linenumber, cipinput->strbuf);
327 return SCIP_OKAY; /* no error - might work with default */
328 }
329
330 /* set problem name */
331 SCIP_CALL( SCIPsetObjsense(scip, objsense) );
332 SCIPdebugMsg(scip, "objective sense <%s>\n", objsense == SCIP_OBJSENSE_MINIMIZE ? "minimize" : "maximize");
333 }
334 else if( strncasecmp(buf, "Offset", 6) == 0 )
335 {
336 SCIP_Real off = 0;
337 char* endptr;
338
339 name = strchr(buf, ':');
340
341 if( name == NULL )
342 {
343 SCIPwarningMessage(scip, "did not find offset (line: %d)\n", cipinput->linenumber);
344 return SCIP_OKAY;
345 }
346
347 /* skip ':' */
348 ++name;
349
350 /* remove white space in front of the name */
351 while(isspace((unsigned char)*name))
352 ++name;
353
354 if ( SCIPstrToRealValue(name, &off, &endptr) )
355 {
356 *objoffset += off;
357 SCIPdebugMsg(scip, "offset <%g> (total: %g)\n", off, *objoffset);
358 }
359 else
360 {
361 SCIPwarningMessage(scip, "could not parse offset (line: %d)\n%s\n", cipinput->linenumber, cipinput->strbuf);
362 return SCIP_OKAY;
363 }
364 }
365 else if( strncasecmp(buf, "Scale", 5) == 0 )
366 {
367 SCIP_Real scale = 1.0;
368 char* endptr;
369
370 name = strchr(buf, ':');
371
372 if( name == NULL )
373 {
374 SCIPwarningMessage(scip, "did not find scale (line: %d)\n", cipinput->linenumber);
375 return SCIP_OKAY;
376 }
377
378 /* skip ':' */
379 ++name;
380
381 /* remove white space in front of the name */
382 while(isspace((unsigned char)*name))
383 ++name;
384
385 if ( SCIPstrToRealValue(name, &scale, &endptr) )
386 {
387 *objscale *= scale;
388 SCIPdebugMsg(scip, "objscale <%g> (total: %g)\n", scale, *objscale);
389 }
390 else
391 {
392 SCIPwarningMessage(scip, "could not parse objective scale (line: %d)\n%s\n", cipinput->linenumber, cipinput->strbuf);
393 return SCIP_OKAY;
394 }
395 }
396
397 return SCIP_OKAY;
398 }
399
400 /** read variable */
401 static
getVariable(SCIP * scip,CIPINPUT * cipinput,SCIP_Bool initial,SCIP_Bool removable,SCIP_Real objscale)402 SCIP_RETCODE getVariable(
403 SCIP* scip, /**< SCIP data structure */
404 CIPINPUT* cipinput, /**< CIP parsing data */
405 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
406 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
407 SCIP_Real objscale /**< objective scale */
408 )
409 {
410 SCIP_Bool success;
411 SCIP_VAR* var;
412 char* buf;
413 char* endptr;
414
415 buf = cipinput->strbuf;
416
417 if( strncmp(buf, "FIXED", 5) == 0 )
418 cipinput->section = CIP_FIXEDVARS;
419 else if( strncmp(buf, "CONSTRAINTS", 4) == 0 )
420 cipinput->section = CIP_CONSTRAINTS;
421 else if( strncmp(buf, "END", 3) == 0 )
422 cipinput->section = CIP_END;
423
424 if( cipinput->section != CIP_VARS )
425 return SCIP_OKAY;
426
427 SCIPdebugMsg(scip, "parse variable\n");
428
429 /* parse the variable */
430 SCIP_CALL( SCIPparseVar(scip, &var, buf, initial, removable, NULL, NULL, NULL, NULL, NULL, &endptr, &success) );
431
432 if( !success )
433 {
434 SCIPerrorMessage("syntax error in variable information (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf);
435 cipinput->haserror = TRUE;
436 return SCIP_OKAY;
437 }
438
439 if( objscale != 1.0 )
440 {
441 SCIP_CALL( SCIPchgVarObj(scip, var, SCIPvarGetObj(var) * objscale) );
442 }
443
444 SCIP_CALL( SCIPaddVar(scip, var) );
445
446 SCIPdebug( SCIP_CALL( SCIPprintVar(scip, var, NULL) ) );
447
448 SCIP_CALL( SCIPreleaseVar(scip, &var) );
449
450 return SCIP_OKAY;
451 }
452
453 /** read fixed variable */
454 static
getFixedVariable(SCIP * scip,CIPINPUT * cipinput)455 SCIP_RETCODE getFixedVariable(
456 SCIP* scip, /**< SCIP data structure */
457 CIPINPUT* cipinput /**< CIP parsing data */
458 )
459 {
460 SCIP_Bool success;
461 SCIP_VAR* var;
462 char* buf;
463 char* endptr;
464 char name[SCIP_MAXSTRLEN];
465
466 buf = cipinput->strbuf;
467
468 if( strncmp(buf, "CONSTRAINTS", 11) == 0 )
469 cipinput->section = CIP_CONSTRAINTS;
470 else if( strncmp(buf, "END", 3) == 0 )
471 cipinput->section = CIP_END;
472
473 if( cipinput->section != CIP_FIXEDVARS )
474 return SCIP_OKAY;
475
476 SCIPdebugMsg(scip, "parse fixed variable\n");
477
478 /* parse the variable */
479 SCIP_CALL( SCIPparseVar(scip, &var, buf, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL, &endptr, &success) );
480
481 if( !success )
482 {
483 SCIPerrorMessage("syntax error in variable information (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf);
484 cipinput->haserror = TRUE;
485 return SCIP_OKAY;
486 }
487
488 /* skip intermediate stuff */
489 buf = endptr;
490
491 while ( *buf != '\0' && (*buf == ' ' || *buf == ',') )
492 ++buf;
493
494 /* check whether variable is fixed */
495 if ( strncmp(buf, "fixed:", 6) == 0 )
496 {
497 SCIP_CALL( SCIPaddVar(scip, var) );
498 SCIPdebug( SCIP_CALL( SCIPprintVar(scip, var, NULL) ) );
499 }
500 else if ( strncmp(buf, "negated:", 8) == 0 )
501 {
502 SCIP_CONS* lincons;
503 SCIP_VAR* negvar;
504 SCIP_Real vals[2];
505 SCIP_VAR* vars[2];
506
507 buf += 8;
508
509 /* we can just parse the next variable (ignoring all other information in between) */
510 SCIP_CALL( SCIPparseVarName(scip, buf, &negvar, &endptr) );
511
512 if ( negvar == NULL )
513 {
514 SCIPerrorMessage("could not parse negated variable (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf);
515 cipinput->haserror = TRUE;
516 return SCIP_OKAY;
517 }
518 assert(SCIPvarIsBinary(var));
519 assert(SCIPvarIsBinary(negvar));
520
521 SCIP_CALL( SCIPaddVar(scip, var) );
522
523 SCIPdebugMsg(scip, "creating negated variable <%s> (of <%s>) ...\n", SCIPvarGetName(var), SCIPvarGetName(negvar) );
524 SCIPdebug( SCIP_CALL( SCIPprintVar(scip, var, NULL) ) );
525
526 /* add linear constraint for negation */
527 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "neg_%s", SCIPvarGetName(var) );
528 vars[0] = var;
529 vars[1] = negvar;
530 vals[0] = 1.0;
531 vals[1] = 1.0;
532 SCIPdebugMsg(scip, "coupling constraint:\n");
533 SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, 2, vars, vals, 1.0, 1.0, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
534 SCIPdebugPrintCons(scip, lincons, NULL);
535 SCIP_CALL( SCIPaddCons(scip, lincons) );
536 SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
537 }
538 else if ( strncmp(buf, "aggregated:", 11) == 0 )
539 {
540 /* handle (multi-)aggregated variables */
541 SCIP_CONS* lincons;
542 SCIP_Real* vals;
543 SCIP_VAR** vars;
544 SCIP_Real rhs = 0.0;
545 const char* str;
546 int nvarssize = 20;
547 int requsize;
548 int nvars;
549
550 buf += 11;
551
552 SCIPdebugMsg(scip, "parsing aggregated variable <%s> ...\n", SCIPvarGetName(var));
553
554 /* first parse constant */
555 if ( ! SCIPstrToRealValue(buf, &rhs, &endptr) )
556 {
557 SCIPerrorMessage("expected constant when aggregated variable information (line: %d):\n%s\n", cipinput->linenumber, buf);
558 cipinput->haserror = TRUE;
559 return SCIP_OKAY;
560 }
561
562 /* check whether constant is 0.0 */
563 str = endptr;
564 while ( *str != '\0' && isspace(*str) )
565 ++str;
566 /* if next char is '<' we found a variable -> constant is 0 */
567 if ( *str != '<' )
568 {
569 SCIPdebugMsg(scip, "constant: %f\n", rhs);
570 buf = endptr;
571 }
572 else
573 {
574 /* otherwise keep buf */
575 rhs = 0.0;
576 }
577
578 /* initialize buffers for storing the variables and values */
579 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvarssize) );
580 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvarssize) );
581
582 vars[0] = var;
583 vals[0] = -1.0;
584 --nvarssize;
585
586 /* parse linear sum to get variables and coefficients */
587 SCIP_CALL( SCIPparseVarsLinearsum(scip, buf, &(vars[1]), &(vals[1]), &nvars, nvarssize, &requsize, &endptr, &success) );
588 if ( success && requsize > nvarssize )
589 {
590 /* realloc buffers and try again */
591 nvarssize = requsize;
592 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, nvarssize + 1) );
593 SCIP_CALL( SCIPreallocBufferArray(scip, &vals, nvarssize + 1) );
594
595 SCIP_CALL( SCIPparseVarsLinearsum(scip, buf, &(vars[1]), &(vals[1]), &nvars, nvarssize, &requsize, &endptr, &success) );
596 assert( ! success || requsize <= nvarssize); /* if successful, then should have had enough space now */
597 }
598
599 if( success )
600 {
601 /* add aggregated variable */
602 SCIP_CALL( SCIPaddVar(scip, var) );
603
604 /* special handling of variables that seem to be slack variables of indicator constraints */
605 str = SCIPvarGetName(var);
606 if ( strncmp(str, "indslack", 8) == 0 )
607 {
608 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "indlin");
609 (void) strncat(name, str+8, SCIP_MAXSTRLEN-7);
610 }
611 else if ( strncmp(str, "t_indslack", 10) == 0 )
612 {
613 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "indlin");
614 (void) strncat(name, str+10, SCIP_MAXSTRLEN-7);
615 }
616 else
617 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var) );
618
619 /* add linear constraint for (multi-)aggregation */
620 SCIPdebugMsg(scip, "coupling constraint:\n");
621 SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, nvars + 1, vars, vals, -rhs, -rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
622 SCIPdebugPrintCons(scip, lincons, NULL);
623 SCIP_CALL( SCIPaddCons(scip, lincons) );
624 SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
625 }
626 else
627 {
628 SCIPwarningMessage(scip, "Could not read (multi-)aggregated variable <%s>: dependent variables unkown - consider changing the order (line: %d):\n%s\n",
629 SCIPvarGetName(var), cipinput->linenumber, buf);
630 }
631
632 SCIPfreeBufferArray(scip, &vals);
633 SCIPfreeBufferArray(scip, &vars);
634 }
635 else
636 {
637 SCIPerrorMessage("unknown section when parsing variables (line: %d):\n%s\n", cipinput->linenumber, buf);
638 cipinput->haserror = TRUE;
639 return SCIP_OKAY;
640 }
641 SCIP_CALL( SCIPreleaseVar(scip, &var) );
642
643 return SCIP_OKAY;
644 }
645
646 /** read constraint */
647 static
getConstraint(SCIP * scip,CIPINPUT * cipinput,SCIP_Bool initial,SCIP_Bool dynamic,SCIP_Bool removable)648 SCIP_RETCODE getConstraint(
649 SCIP* scip, /**< SCIP data structure */
650 CIPINPUT* cipinput, /**< CIP parsing data */
651 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
652 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
653 SCIP_Bool dynamic, /**< Is constraint subject to aging?
654 * Usually set to FALSE. Set to TRUE for own cuts which
655 * are separated as constraints. */
656 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
657 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
658 )
659 {
660 SCIP_CONS* cons;
661 char* buf;
662 char* copybuf;
663 SCIP_RETCODE retcode;
664 SCIP_Bool separate;
665 SCIP_Bool enforce;
666 SCIP_Bool check;
667 SCIP_Bool propagate;
668 SCIP_Bool local;
669 SCIP_Bool modifiable;
670 SCIP_Bool success;
671 int len;
672
673 buf = cipinput->strbuf;
674
675 if( strncmp(buf, "END", 3) == 0 )
676 {
677 cipinput->section = CIP_END;
678 return SCIP_OKAY;
679 }
680
681 SCIPdebugMsg(scip, "parse constraints in line %d\n", cipinput->linenumber);
682
683 separate = TRUE;
684 enforce = TRUE;
685 check = TRUE;
686 propagate = TRUE;
687 local = FALSE;
688 modifiable = FALSE;
689
690 /* get length of line and check for correct ending of constraint line */
691 len = (int)strlen(buf);
692 if( len < 1 )
693 {
694 SCIPerrorMessage("syntax error: expected constraint in line %d.\n", cipinput->linenumber);
695 cipinput->haserror = TRUE;
696 return SCIP_OKAY;
697 }
698 if ( buf[len - 1] != ';' )
699 {
700 SCIPerrorMessage("syntax error: line has to end with ';' (line: %d)\n", cipinput->linenumber);
701 cipinput->haserror = TRUE;
702 return SCIP_OKAY;
703 }
704
705 /* copy buffer for working purpose */
706 SCIP_CALL( SCIPduplicateBufferArray(scip, ©buf, buf, len) );
707 copybuf[len - 1] = '\0';
708
709 /* parse the constraint */
710 retcode = SCIPparseCons(scip, &cons, copybuf,
711 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, FALSE, &success);
712
713 /* free temporary buffer */
714 SCIPfreeBufferArray(scip, ©buf);
715
716 SCIP_CALL( retcode );
717
718 if( !success )
719 {
720 SCIPerrorMessage("syntax error when reading constraint (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf);
721 cipinput->haserror = TRUE;
722 return SCIP_OKAY;
723 }
724
725 SCIP_CALL( SCIPaddCons(scip, cons) );
726 SCIPdebugPrintCons(scip, cons, NULL);
727 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
728
729 return SCIP_OKAY;
730 }
731
732 /*
733 * Callback methods of reader
734 */
735
736 /** copy method for reader plugins (called when SCIP copies plugins) */
737 static
SCIP_DECL_READERCOPY(readerCopyCip)738 SCIP_DECL_READERCOPY(readerCopyCip)
739 { /*lint --e{715}*/
740 assert(scip != NULL);
741 assert(reader != NULL);
742 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
743
744 /* call inclusion method of reader */
745 SCIP_CALL( SCIPincludeReaderCip(scip) );
746
747 return SCIP_OKAY;
748 }
749
750 /** destructor of reader to free user data (called when SCIP is exiting) */
751 static
SCIP_DECL_READERFREE(readerFreeCip)752 SCIP_DECL_READERFREE(readerFreeCip)
753 {
754 SCIP_READERDATA* readerdata;
755
756 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
757 readerdata = SCIPreaderGetData(reader);
758 assert(readerdata != NULL);
759 SCIPfreeBlockMemory(scip, &readerdata);
760
761 return SCIP_OKAY;
762 }
763
764
765 /** problem reading method of reader */
766 static
SCIP_DECL_READERREAD(readerReadCip)767 SCIP_DECL_READERREAD(readerReadCip)
768 { /*lint --e{715}*/
769 CIPINPUT cipinput;
770 SCIP_Real objscale;
771 SCIP_Real objoffset;
772 SCIP_Bool initialconss;
773 SCIP_Bool dynamicconss;
774 SCIP_Bool dynamiccols;
775 SCIP_Bool dynamicrows;
776 SCIP_Bool initialvar;
777 SCIP_Bool removablevar;
778 SCIP_RETCODE retcode;
779
780 if( NULL == (cipinput.file = SCIPfopen(filename, "r")) )
781 {
782 SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
783 SCIPprintSysError(filename);
784 return SCIP_NOFILE;
785 }
786
787 cipinput.len = 131071;
788 SCIP_CALL( SCIPallocBufferArray(scip, &(cipinput.strbuf), cipinput.len) );
789
790 cipinput.linenumber = 0;
791 cipinput.section = CIP_START;
792 cipinput.haserror = FALSE;
793 cipinput.endfile = FALSE;
794 cipinput.readingsize = 65535;
795
796 SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
797
798 SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &initialconss) );
799 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &dynamiccols) );
800 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &dynamicconss) );
801 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &dynamicrows) );
802
803 initialvar = !dynamiccols;
804 removablevar = dynamiccols;
805
806 objscale = 1.0;
807 objoffset = 0.0;
808
809 while( cipinput.section != CIP_END && !cipinput.haserror )
810 {
811 /* get next input string */
812 SCIP_CALL( getInputString(scip, &cipinput) );
813
814 if( cipinput.endfile )
815 break;
816
817 switch( cipinput.section )
818 {
819 case CIP_START:
820 getStart(scip, &cipinput);
821 break;
822 case CIP_STATISTIC:
823 SCIP_CALL( getStatistics(scip, &cipinput) );
824 break;
825 case CIP_OBJECTIVE:
826 SCIP_CALL( getObjective(scip, &cipinput, &objscale, &objoffset) );
827 break;
828 case CIP_VARS:
829 retcode = getVariable(scip, &cipinput, initialvar, removablevar, objscale);
830
831 if( retcode == SCIP_READERROR )
832 {
833 cipinput.haserror = TRUE;
834 goto TERMINATE;
835 }
836 SCIP_CALL(retcode);
837
838 break;
839 case CIP_FIXEDVARS:
840 retcode = getFixedVariable(scip, &cipinput);
841
842 if( retcode == SCIP_READERROR )
843 {
844 cipinput.haserror = TRUE;
845 goto TERMINATE;
846 }
847 SCIP_CALL(retcode);
848
849 break;
850 case CIP_CONSTRAINTS:
851 retcode = getConstraint(scip, &cipinput, initialconss, dynamicconss, dynamicrows);
852
853 if( retcode == SCIP_READERROR )
854 {
855 cipinput.haserror = TRUE;
856 goto TERMINATE;
857 }
858 SCIP_CALL(retcode);
859
860 break;
861 default:
862 SCIPerrorMessage("invalid CIP state\n");
863 SCIPABORT();
864 return SCIP_INVALIDDATA; /*lint !e527*/
865 } /*lint !e788*/
866 }
867
868 if( !SCIPisZero(scip, objoffset) && !cipinput.haserror )
869 {
870 SCIP_VAR* objoffsetvar;
871
872 objoffset *= objscale;
873 SCIP_CALL( SCIPcreateVar(scip, &objoffsetvar, "objoffset", objoffset, objoffset, 1.0, SCIP_VARTYPE_CONTINUOUS,
874 TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
875 SCIP_CALL( SCIPaddVar(scip, objoffsetvar) );
876 SCIP_CALL( SCIPreleaseVar(scip, &objoffsetvar) );
877 SCIPdebugMsg(scip, "added variables <objoffset> for objective offset of <%g>\n", objoffset);
878 }
879
880 if( cipinput.section != CIP_END && !cipinput.haserror )
881 {
882 SCIPerrorMessage("unexpected EOF\n");
883 }
884
885 TERMINATE:
886 /* close file stream */
887 SCIPfclose(cipinput.file);
888
889 SCIPfreeBufferArray(scip, &cipinput.strbuf);
890
891 if( cipinput.haserror )
892 return SCIP_READERROR;
893
894 /* successfully parsed cip format */
895 *result = SCIP_SUCCESS;
896 return SCIP_OKAY;
897 }
898
899 /** hash key retrieval function for variables */
900 static
SCIP_DECL_HASHGETKEY(hashGetKeyVar)901 SCIP_DECL_HASHGETKEY(hashGetKeyVar)
902 { /*lint --e{715}*/
903 return elem;
904 }
905
906 /** returns TRUE iff the indices of both variables are equal */
907 static
SCIP_DECL_HASHKEYEQ(hashKeyEqVar)908 SCIP_DECL_HASHKEYEQ(hashKeyEqVar)
909 { /*lint --e{715}*/
910 if( key1 == key2 )
911 return TRUE;
912 return FALSE;
913 }
914
915 /** returns the hash value of the key */
916 static
SCIP_DECL_HASHKEYVAL(hashKeyValVar)917 SCIP_DECL_HASHKEYVAL(hashKeyValVar)
918 { /*lint --e{715}*/
919 assert( SCIPvarGetIndex((SCIP_VAR*) key) >= 0 );
920 return (unsigned int) SCIPvarGetIndex((SCIP_VAR*) key);
921 }
922
923 /** problem writing method of reader */
924 static
SCIP_DECL_READERWRITE(readerWriteCip)925 SCIP_DECL_READERWRITE(readerWriteCip)
926 { /*lint --e{715}*/
927 SCIP_HASHTABLE* varhash = NULL;
928 SCIP_READERDATA* readerdata;
929 int i;
930
931 assert(reader != NULL);
932 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
933
934 SCIPinfoMessage(scip, file, "STATISTICS\n");
935 SCIPinfoMessage(scip, file, " Problem name : %s\n", name);
936 SCIPinfoMessage(scip, file, " Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n",
937 nvars, nbinvars, nintvars, nimplvars, ncontvars);
938 SCIPinfoMessage(scip, file, " Constraints : %d initial, %d maximal\n", startnconss, maxnconss);
939
940 SCIPinfoMessage(scip, file, "OBJECTIVE\n");
941 SCIPinfoMessage(scip, file, " Sense : %s\n", objsense == SCIP_OBJSENSE_MINIMIZE ? "minimize" : "maximize");
942 if( !SCIPisZero(scip, objoffset) )
943 SCIPinfoMessage(scip, file, " Offset : %+.15g\n", objoffset);
944 if( !SCIPisEQ(scip, objscale, 1.0) )
945 SCIPinfoMessage(scip, file, " Scale : %.15g\n", objscale);
946
947 if ( nfixedvars > 0 )
948 {
949 /* set up hash table for variables that have been written property (used for writing out fixed vars in the right order) */
950 SCIP_CALL( SCIPhashtableCreate(&varhash, SCIPblkmem(scip), nvars + nfixedvars, hashGetKeyVar, hashKeyEqVar, hashKeyValVar, NULL) );
951 }
952
953 if ( nvars + nfixedvars > 0 )
954 {
955 SCIPinfoMessage(scip, file, "VARIABLES\n");
956 }
957
958 if( nvars > 0 )
959 {
960 for( i = 0; i < nvars; ++i )
961 {
962 SCIP_VAR* var;
963
964 var = vars[i];
965 assert( var != NULL );
966 SCIP_CALL( SCIPprintVar(scip, var, file) );
967 if ( varhash != NULL )
968 {
969 /* add free variable to hashtable */
970 if ( ! SCIPhashtableExists(varhash, (void*) var) )
971 {
972 SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) );
973 }
974 }
975 }
976 }
977
978 readerdata = SCIPreaderGetData(reader);
979 assert(readerdata != NULL);
980
981 if( readerdata->writefixedvars && nfixedvars > 0 )
982 {
983 int nwritten = 0;
984
985 SCIPinfoMessage(scip, file, "FIXED\n");
986
987 /* loop through variables until each has been written after the variables that it depends on have been written; this
988 * requires several runs over the variables, but the depth (= number of loops) is usually small. */
989 while ( nwritten < nfixedvars )
990 {
991 SCIPdebugMsg(scip, "written %d of %d fixed variables.\n", nwritten, nfixedvars);
992 for (i = 0; i < nfixedvars; ++i)
993 {
994 SCIP_VAR* var;
995 SCIP_VAR* tmpvar;
996
997 var = fixedvars[i];
998 assert( var != NULL );
999
1000 /* skip variables already written */
1001 if ( SCIPhashtableExists(varhash, (void*) var) )
1002 continue;
1003
1004 switch ( SCIPvarGetStatus(var) )
1005 {
1006 case SCIP_VARSTATUS_FIXED:
1007
1008 /* fixed variables can simply be output and added to the hashtable */
1009 SCIP_CALL( SCIPprintVar(scip, var, file) );
1010 assert( ! SCIPhashtableExists(varhash, (void*) var) );
1011 SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) );
1012 ++nwritten;
1013
1014 break;
1015
1016 case SCIP_VARSTATUS_NEGATED:
1017
1018 tmpvar = SCIPvarGetNegationVar(var);
1019 assert( tmpvar != NULL );
1020 assert( var == SCIPvarGetNegatedVar(tmpvar) );
1021
1022 /* if the negated variable has been written, we can write the current variable */
1023 if ( SCIPhashtableExists(varhash, (void*) tmpvar) )
1024 {
1025 SCIP_CALL( SCIPprintVar(scip, var, file) );
1026 assert( ! SCIPhashtableExists(varhash, (void*) var) );
1027 SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) );
1028 ++nwritten;
1029 }
1030 break;
1031
1032 case SCIP_VARSTATUS_AGGREGATED:
1033
1034 tmpvar = SCIPvarGetAggrVar(var);
1035 assert( tmpvar != NULL );
1036
1037 /* if the aggregating variable has been written, we can write the current variable */
1038 if ( SCIPhashtableExists(varhash, (void*) tmpvar) )
1039 {
1040 SCIP_CALL( SCIPprintVar(scip, var, file) );
1041 assert( ! SCIPhashtableExists(varhash, (void*) var) );
1042 SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) );
1043 ++nwritten;
1044 }
1045 break;
1046
1047 case SCIP_VARSTATUS_MULTAGGR:
1048 {
1049 SCIP_VAR** aggrvars;
1050 int naggrvars;
1051 int j;
1052
1053 /* get the active representation */
1054 SCIP_CALL( SCIPflattenVarAggregationGraph(scip, var) );
1055
1056 naggrvars = SCIPvarGetMultaggrNVars(var);
1057 aggrvars = SCIPvarGetMultaggrVars(var);
1058 assert(aggrvars != NULL || naggrvars == 0);
1059
1060 for (j = 0; j < naggrvars; ++j)
1061 {
1062 if( !SCIPhashtableExists(varhash, (void*) aggrvars[j]) ) /*lint !e613*/
1063 break;
1064 }
1065
1066 /* if all multi-aggregating variables have been written, we can write the current variable */
1067 if ( j >= naggrvars )
1068 {
1069 SCIP_CALL( SCIPprintVar(scip, var, file) );
1070 assert( ! SCIPhashtableExists(varhash, (void*) var) );
1071 SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) );
1072 ++nwritten;
1073 }
1074 break;
1075 }
1076
1077 case SCIP_VARSTATUS_ORIGINAL:
1078 case SCIP_VARSTATUS_LOOSE:
1079 case SCIP_VARSTATUS_COLUMN:
1080 SCIPerrorMessage("Only fixed variables are allowed to be present in fixedvars list.\n");
1081 SCIPABORT();
1082 return SCIP_ERROR; /*lint !e527*/
1083 }
1084 }
1085 }
1086 }
1087
1088 if( nconss > 0 )
1089 {
1090 SCIPinfoMessage(scip, file, "CONSTRAINTS\n");
1091
1092 for( i = 0; i < nconss; ++i )
1093 {
1094 SCIP_CALL( SCIPprintCons(scip, conss[i], file) );
1095 SCIPinfoMessage(scip, file, ";\n");
1096 }
1097 }
1098 SCIPinfoMessage(scip, file, "END\n");
1099
1100 *result = SCIP_SUCCESS;
1101
1102 if( nfixedvars > 0 )
1103 SCIPhashtableFree(&varhash);
1104 else
1105 assert(varhash == NULL);
1106
1107 return SCIP_OKAY;
1108 }
1109
1110
1111 /*
1112 * reader specific interface methods
1113 */
1114
1115 /** includes the cip file reader in SCIP */
SCIPincludeReaderCip(SCIP * scip)1116 SCIP_RETCODE SCIPincludeReaderCip(
1117 SCIP* scip /**< SCIP data structure */
1118 )
1119 {
1120 SCIP_READERDATA* readerdata;
1121 SCIP_READER* reader;
1122
1123 /* create cip reader data */
1124 SCIP_CALL( SCIPallocBlockMemory(scip, &readerdata) );
1125
1126 /* include reader */
1127 SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, readerdata) );
1128
1129 /* set non fundamental callbacks via setter functions */
1130 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyCip) );
1131 SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeCip) );
1132 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadCip) );
1133 SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteCip) );
1134
1135 /* add cip reader parameters */
1136 SCIP_CALL( SCIPaddBoolParam(scip,
1137 "reading/cipreader/writefixedvars", "should fixed and aggregated variables be printed (if not, re-parsing might fail)",
1138 &readerdata->writefixedvars, FALSE, DEFAULT_CIP_WRITEFIXEDVARS, NULL, NULL) );
1139
1140 return SCIP_OKAY;
1141 }
1142