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_opb.c
17 * @ingroup DEFPLUGINS_READER
18 * @brief pseudo-Boolean file reader (opb format)
19 * @author Stefan Heinz
20 * @author Michael Winkler
21 *
22 * This file reader parses the @a opb format and is also used by the @a wbo reader for the @a wbo format. For a
23 * detailed description of this format see
24 *
25 * - http://www.cril.univ-artois.fr/PB07/solver_req.html
26 * - http://www.cril.univ-artois.fr/PB10/format.pdf
27 *
28 * The syntax of the input file format can be described by a simple Backus-Naur
29 * form. \<formula\> is the start symbol of this grammar.
30 *
31 * \<formula\>::= \<sequence_of_comments\>
32 * [\<objective\>] | [\<softheader\>]
33 * \<sequence_of_comments_or_constraints\>
34 *
35 * \<sequence_of_comments\>::= \<comment\> [\<sequence_of_comments\>]
36 * \<comment\>::= "*" \<any_sequence_of_characters_other_than_EOL\> \<EOL\>
37 * \<sequence_of_comments_or_constraints\>::=\<comment_or_constraint\> [\<sequence_of_comments_or_constraints\>]
38 * \<comment_or_constraint\>::=\<comment\>|\<constraint\>
39 *
40 * \<objective\>::= "min:" \<zeroOrMoreSpace\> \<sum\> ";"
41 * \<constraint\>::= \<sum\> \<relational_operator\> \<zeroOrMoreSpace\> \<integer\> \<zeroOrMoreSpace\> ";"
42 *
43 * \<sum\>::= \<weightedterm\> | \<weightedterm\> \<sum\>
44 * \<weightedterm\>::= \<integer\> \<oneOrMoreSpace\> \<term\> \<oneOrMoreSpace\>
45 *
46 * \<integer\>::= \<unsigned_integer\> | "+" \<unsigned_integer\> | "-" \<unsigned_integer\>
47 * \<unsigned_integer\>::= \<digit\> | \<digit\>\<unsigned_integer\>
48 *
49 * \<relational_operator\>::= "\>=" | "="
50 *
51 * \<variablename\>::= "x" \<unsigned_integer\>
52 *
53 * \<oneOrMoreSpace\>::= " " [\<oneOrMoreSpace\>]
54 * \<zeroOrMoreSpace\>::= [" " \<zeroOrMoreSpace\>]
55 *
56 * For linear pseudo-Boolean instances, \<term\> is defined as
57 *
58 * \<term\>::=\<variablename\>
59 *
60 * For non-linear instances, \<term\> is defined as
61 *
62 * \<term\>::= \<oneOrMoreLiterals\>
63 * \<oneOrMoreLiterals\>::= \<literal\> | \<literal\> \<oneOrMoreSpace\> \<oneOrMoreLiterals\>
64 * \<literal\>::= \<variablename\> | "~"\<variablename\>
65 *
66 * For wbo-files are the following additional/changed things possible.
67 *
68 * \<softheader\>::= "soft:" [\<unsigned integer\>] ";"
69 *
70 * \<comment_or_constraint\>::=\<comment\>|\<constraint\>|\<softconstraint\>
71 *
72 * \<softconstraint\>::= "[" \<zeroOrMoreSpace\> \<unsigned integer\> \<zeroOrMoreSpace\> "]" \<constraint\>
73 *
74 */
75
76 /* Our parser should also be lax by handling variable names and it's possible to read doubles instead of integer and
77 * possible some more :). */
78
79 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
80
81 #include "blockmemshell/memory.h"
82 #include <ctype.h>
83 #include "scip/cons_and.h"
84 #include "scip/cons_indicator.h"
85 #include "scip/cons_knapsack.h"
86 #include "scip/cons_linear.h"
87 #include "scip/cons_logicor.h"
88 #include "scip/cons_pseudoboolean.h"
89 #include "scip/cons_setppc.h"
90 #include "scip/cons_varbound.h"
91 #include "scip/debug.h"
92 #include "scip/pub_cons.h"
93 #include "scip/pub_fileio.h"
94 #include "scip/pub_message.h"
95 #include "scip/pub_misc.h"
96 #include "scip/pub_misc_sort.h"
97 #include "scip/pub_reader.h"
98 #include "scip/pub_var.h"
99 #include "scip/reader_opb.h"
100 #include "scip/scip_cons.h"
101 #include "scip/scip_mem.h"
102 #include "scip/scip_message.h"
103 #include "scip/scip_numerics.h"
104 #include "scip/scip_param.h"
105 #include "scip/scip_prob.h"
106 #include "scip/scip_reader.h"
107 #include "scip/scip_solvingstats.h"
108 #include "scip/scip_var.h"
109 #include <stdlib.h>
110 #include <string.h>
111
112 #if !defined(_WIN32) && !defined(_WIN64)
113 #include <strings.h> /*lint --e{766}*/ /* needed for strncasecmp() */
114 #endif
115
116 #define READER_NAME "opbreader"
117 #define READER_DESC "file reader for pseudo-Boolean problem in opb format"
118 #define READER_EXTENSION "opb"
119
120 #define GENCONSNAMES TRUE /* remove if no constraint names should be generated */
121 #define LINEAROBJECTIVE TRUE /* will all non-linear parts inside the objective function be linearized or will
122 * an artificial integer variable be created which will represent the objective
123 * function
124 */
125
126 #define INDICATORVARNAME "indicatorvar" /* standard part of name for all indicator variables */
127 #define INDICATORSLACKVARNAME "indslack" /* standard part of name for all indicator slack variables; should be the same in cons_indicator */
128 #define TOPCOSTCONSNAME "topcostcons" /* standard name for artificial topcost constraint in wbo problems */
129
130 /*
131 * Data structures
132 */
133 #define OPB_MAX_LINELEN 65536 /**< size of the line buffer for reading or writing */
134 #define OPB_MAX_PUSHEDTOKENS 2
135 #define OPB_INIT_COEFSSIZE 8192
136
137 /** Section in OPB File */
138 enum OpbExpType
139 {
140 OPB_EXP_NONE,
141 OPB_EXP_UNSIGNED,
142 OPB_EXP_SIGNED
143 };
144 typedef enum OpbExpType OPBEXPTYPE;
145
146 enum OpbSense
147 {
148 OPB_SENSE_NOTHING,
149 OPB_SENSE_LE,
150 OPB_SENSE_GE,
151 OPB_SENSE_EQ
152 };
153 typedef enum OpbSense OPBSENSE;
154
155 /** OPB reading data */
156 struct OpbInput
157 {
158 SCIP_FILE* file;
159 char linebuf[OPB_MAX_LINELEN+1];
160 char* token;
161 char* tokenbuf;
162 char* pushedtokens[OPB_MAX_PUSHEDTOKENS];
163 int npushedtokens;
164 int linenumber;
165 int linepos;
166 int bufpos;
167 SCIP_OBJSENSE objsense;
168 SCIP_Bool comment;
169 SCIP_Bool endline;
170 SCIP_Bool eof;
171 SCIP_Bool haserror;
172 int nproblemcoeffs;
173 SCIP_Bool wbo;
174 SCIP_Real topcost;
175 int nindvars;
176 #if GENCONSNAMES == TRUE
177 int consnumber;
178 #endif
179 };
180
181 typedef struct OpbInput OPBINPUT;
182
183 static const char commentchars[] = "*";
184 /*
185 * Local methods (for reading)
186 */
187
188 /** issues an error message and marks the OPB data to have errors */
189 static
190 void syntaxError(
191 SCIP* scip, /**< SCIP data structure */
192 OPBINPUT* opbinput, /**< OPB reading data */
193 const char* msg /**< error message */
194 )
195 {
196 assert(scip != NULL);
197 assert(opbinput != NULL);
198
199 SCIPerrorMessage("Syntax error in line %d: %s found <%s>\n", opbinput->linenumber, msg, opbinput->token);
200 if( opbinput->linebuf[strlen(opbinput->linebuf)-1] == '\n' )
201 {
202 SCIPerrorMessage(" input: %s", opbinput->linebuf);
203 }
204 else
205 {
206 SCIPerrorMessage(" input: %s\n", opbinput->linebuf);
207 }
208
209 opbinput->haserror = TRUE;
210 }
211
212 /** returns whether a syntax error was detected */
213 static
214 SCIP_Bool hasError(
215 OPBINPUT* opbinput /**< OPB reading data */
216 )
217 {
218 assert(opbinput != NULL);
219
220 return opbinput->haserror;
221 }
222
223 /** returns whether the given character is a token delimiter */
224 static
225 SCIP_Bool isDelimChar(
226 char c /**< input character */
227 )
228 {
229 switch (c)
230 {
231 case ' ':
232 case '\f':
233 case '\n':
234 case '\r':
235 case '\t':
236 case '\v':
237 case '\0':
238 return TRUE;
239 default:
240 return FALSE;
241 }
242 }
243
244 /** returns whether the given character is a single token */
245 static
246 SCIP_Bool isTokenChar(
247 char c /**< input character */
248 )
249 {
250 switch (c)
251 {
252 case '-':
253 case '+':
254 case ':':
255 case '<':
256 case '>':
257 case '=':
258 case '[':
259 case ']':
260 case ';':
261 return TRUE;
262 default:
263 return FALSE;
264 }
265 }
266
267 /** returns whether the current character is member of a value string */
268 static
269 SCIP_Bool isValueChar(
270 char c, /**< input character */
271 char nextc, /**< next input character */
272 SCIP_Bool firstchar, /**< is the given character the first char of the token? */
273 SCIP_Bool* hasdot, /**< pointer to update the dot flag */
274 OPBEXPTYPE* exptype /**< pointer to update the exponent type */
275 )
276 {
277 assert(hasdot != NULL);
278 assert(exptype != NULL);
279
280 if( isdigit((unsigned char)c) )
281 return TRUE;
282 else if( (*exptype == OPB_EXP_NONE) && !(*hasdot) && (c == '.') )
283 {
284 *hasdot = TRUE;
285 return TRUE;
286 }
287 else if( !firstchar && (*exptype == OPB_EXP_NONE) && (c == 'e' || c == 'E') )
288 {
289 if( nextc == '+' || nextc == '-' )
290 {
291 *exptype = OPB_EXP_SIGNED;
292 return TRUE;
293 }
294 else if( isdigit((unsigned char)nextc) )
295 {
296 *exptype = OPB_EXP_UNSIGNED;
297 return TRUE;
298 }
299 }
300 else if( (*exptype == OPB_EXP_SIGNED) && (c == '+' || c == '-') )
301 {
302 *exptype = OPB_EXP_UNSIGNED;
303 return TRUE;
304 }
305
306 return FALSE;
307 }
308
309 /** reads the next line from the input file into the line buffer; skips comments;
310 * returns whether a line could be read
311 */
312 static
313 SCIP_Bool getNextLine(
314 SCIP* scip, /**< SCIP data structure */
315 OPBINPUT* opbinput /**< OPB reading data */
316 )
317 {
318 int i;
319
320 assert(opbinput != NULL);
321
322 /* if we previously detected a comment we have to parse the remaining line away if there is something left */
323 if( !opbinput->endline && opbinput->comment )
324 {
325 SCIPdebugMsg(scip, "Throwing rest of comment away.\n");
326
327 do
328 {
329 opbinput->linebuf[OPB_MAX_LINELEN-2] = '\0';
330 (void)SCIPfgets(opbinput->linebuf, (int) sizeof(opbinput->linebuf), opbinput->file);
331 }
332 while( opbinput->linebuf[OPB_MAX_LINELEN-2] != '\0' );
333
334 opbinput->comment = FALSE;
335 opbinput->endline = TRUE;
336 }
337
338 /* clear the line */
339 opbinput->linebuf[OPB_MAX_LINELEN-2] = '\0';
340
341 /* set line position */
342 if( opbinput->endline )
343 {
344 opbinput->linepos = 0;
345 opbinput->linenumber++;
346 }
347 else
348 opbinput->linepos += OPB_MAX_LINELEN - 2;
349
350 if( SCIPfgets(opbinput->linebuf, (int) sizeof(opbinput->linebuf), opbinput->file) == NULL )
351 return FALSE;
352
353 opbinput->bufpos = 0;
354
355 if( opbinput->linebuf[OPB_MAX_LINELEN-2] != '\0' )
356 {
357 char* last;
358
359 /* buffer is full; erase last token since it might be incomplete */
360 opbinput->endline = FALSE;
361 last = strrchr(opbinput->linebuf, ' ');
362
363 if( last == NULL )
364 {
365 SCIPwarningMessage(scip, "we read %d character from the file; these might indicates a corrupted input file!",
366 OPB_MAX_LINELEN - 2);
367 opbinput->linebuf[OPB_MAX_LINELEN-2] = '\0';
368 SCIPdebugMsg(scip, "the buffer might be corrupted\n");
369 }
370 else
371 {
372 SCIPfseek(opbinput->file, -(long) strlen(last), SEEK_CUR);
373 SCIPdebugMsg(scip, "correct buffer, reread the last %ld characters\n", (long) strlen(last));
374 *last = '\0';
375 }
376 }
377 else
378 {
379 /* found end of line */
380 opbinput->endline = TRUE;
381 }
382
383 opbinput->linebuf[OPB_MAX_LINELEN-1] = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */
384
385 opbinput->comment = FALSE;
386
387 /* skip characters after comment symbol */
388 for( i = 0; commentchars[i] != '\0'; ++i )
389 {
390 char* commentstart;
391
392 commentstart = strchr(opbinput->linebuf, commentchars[i]);
393 if( commentstart != NULL )
394 {
395 *commentstart = '\0';
396 *(commentstart+1) = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */
397 opbinput->comment = TRUE;
398 break;
399 }
400 }
401
402 SCIPdebugMsg(scip, "%s\n", opbinput->linebuf);
403
404 return TRUE;
405 }
406
407 /** swaps the addresses of two pointers */
408 static
409 void swapPointers(
410 char** pointer1, /**< first pointer */
411 char** pointer2 /**< second pointer */
412 )
413 {
414 char* tmp;
415
416 tmp = *pointer1;
417 *pointer1 = *pointer2;
418 *pointer2 = tmp;
419 }
420
421 /** reads the next token from the input file into the token buffer; returns whether a token was read */
422 static
423 SCIP_Bool getNextToken(
424 SCIP* scip, /**< SCIP data structure */
425 OPBINPUT* opbinput /**< OPB reading data */
426 )
427 {
428 SCIP_Bool hasdot;
429 OPBEXPTYPE exptype;
430 char* buf;
431 int tokenlen;
432
433 assert(opbinput != NULL);
434 assert(opbinput->bufpos < OPB_MAX_LINELEN);
435
436 /* check the token stack */
437 if( opbinput->npushedtokens > 0 )
438 {
439 swapPointers(&opbinput->token, &opbinput->pushedtokens[opbinput->npushedtokens-1]);
440 opbinput->npushedtokens--;
441 SCIPdebugMsg(scip, "(line %d) read token again: '%s'\n", opbinput->linenumber, opbinput->token);
442 return TRUE;
443 }
444
445 /* skip delimiters */
446 buf = opbinput->linebuf;
447 while( isDelimChar(buf[opbinput->bufpos]) )
448 {
449 if( buf[opbinput->bufpos] == '\0' )
450 {
451 if( !getNextLine(scip, opbinput) )
452 {
453 SCIPdebugMsg(scip, "(line %d) end of file\n", opbinput->linenumber);
454 return FALSE;
455 }
456 assert(opbinput->bufpos == 0);
457 }
458 else
459 {
460 opbinput->bufpos++;
461 opbinput->linepos++;
462 }
463 }
464 assert(opbinput->bufpos < OPB_MAX_LINELEN);
465 assert(!isDelimChar(buf[opbinput->bufpos]));
466
467 /* check if the token is a value */
468 hasdot = FALSE;
469 exptype = OPB_EXP_NONE;
470 if( isValueChar(buf[opbinput->bufpos], buf[opbinput->bufpos+1], TRUE, &hasdot, &exptype) )
471 {
472 /* read value token */
473 tokenlen = 0;
474 do
475 {
476 assert(tokenlen < OPB_MAX_LINELEN);
477 assert(!isDelimChar(buf[opbinput->bufpos]));
478 opbinput->token[tokenlen] = buf[opbinput->bufpos];
479 tokenlen++;
480 opbinput->bufpos++;
481 opbinput->linepos++;
482 }
483 while( isValueChar(buf[opbinput->bufpos], buf[opbinput->bufpos+1], FALSE, &hasdot, &exptype) );
484 }
485 else
486 {
487 /* read non-value token */
488 tokenlen = 0;
489 do
490 {
491 assert(tokenlen < OPB_MAX_LINELEN);
492 opbinput->token[tokenlen] = buf[opbinput->bufpos];
493 tokenlen++;
494 opbinput->bufpos++;
495 opbinput->linepos++;
496 if( tokenlen == 1 && isTokenChar(opbinput->token[0]) )
497 break;
498 }
499 while( !isDelimChar(buf[opbinput->bufpos]) && !isTokenChar(buf[opbinput->bufpos]) );
500
501 /* if the token is an equation sense '<', '>', or '=', skip a following '='
502 * if the token is an equality token '=' and the next character is a '<' or '>',
503 * replace the token by the inequality sense
504 */
505 if( tokenlen >= 1
506 && (opbinput->token[tokenlen-1] == '<' || opbinput->token[tokenlen-1] == '>' || opbinput->token[tokenlen-1] == '=')
507 && buf[opbinput->bufpos] == '=' )
508 {
509 opbinput->bufpos++;
510 opbinput->linepos++;
511 }
512 else if( opbinput->token[tokenlen-1] == '=' && (buf[opbinput->bufpos] == '<' || buf[opbinput->bufpos] == '>') )
513 {
514 opbinput->token[tokenlen-1] = buf[opbinput->bufpos];
515 opbinput->bufpos++;
516 opbinput->linepos++;
517 }
518 }
519 assert(tokenlen < OPB_MAX_LINELEN);
520 opbinput->token[tokenlen] = '\0';
521
522 SCIPdebugMsg(scip, "(line %d) read token: '%s'\n", opbinput->linenumber, opbinput->token);
523
524 return TRUE;
525 }
526
527 /** puts the current token on the token stack, such that it is read at the next call to getNextToken() */
528 static
529 void pushToken(
530 OPBINPUT* opbinput /**< OPB reading data */
531 )
532 {
533 assert(opbinput != NULL);
534 assert(opbinput->npushedtokens < OPB_MAX_PUSHEDTOKENS);
535
536 swapPointers(&opbinput->pushedtokens[opbinput->npushedtokens], &opbinput->token);
537 opbinput->npushedtokens++;
538 }
539
540 /** puts the buffered token on the token stack, such that it is read at the next call to getNextToken() */
541 static
542 void pushBufferToken(
543 OPBINPUT* opbinput /**< OPB reading data */
544 )
545 {
546 assert(opbinput != NULL);
547 assert(opbinput->npushedtokens < OPB_MAX_PUSHEDTOKENS);
548
549 swapPointers(&opbinput->pushedtokens[opbinput->npushedtokens], &opbinput->tokenbuf);
550 opbinput->npushedtokens++;
551 }
552
553 /** swaps the current token with the token buffer */
554 static
555 void swapTokenBuffer(
556 OPBINPUT* opbinput /**< OPB reading data */
557 )
558 {
559 assert(opbinput != NULL);
560
561 swapPointers(&opbinput->token, &opbinput->tokenbuf);
562 }
563
564 /** checks whether the current token is a section identifier, and if yes, switches to the corresponding section */
565 static
566 SCIP_Bool isEndLine(
567 OPBINPUT* opbinput /**< OPB reading data */
568 )
569 {
570 assert(opbinput != NULL);
571
572 if( *(opbinput->token) == ';')
573 return TRUE;
574
575 return FALSE;
576 }
577
578 /** returns whether the current token is a sign */
579 static
580 SCIP_Bool isSign(
581 OPBINPUT* opbinput, /**< OPB reading data */
582 int* sign /**< pointer to update the sign */
583 )
584 {
585 assert(opbinput != NULL);
586 assert(sign != NULL);
587 assert(*sign == +1 || *sign == -1);
588
589 if( strlen(opbinput->token) == 1 )
590 {
591 assert(opbinput->token[1] == '\0');
592
593 if( *opbinput->token == '+' )
594 return TRUE;
595 else if( *opbinput->token == '-' )
596 {
597 *sign *= -1;
598 return TRUE;
599 }
600 }
601
602 return FALSE;
603 }
604
605 /** returns whether the current token is a value */
606 static
607 SCIP_Bool isValue(
608 SCIP* scip, /**< SCIP data structure */
609 OPBINPUT* opbinput, /**< OPB reading data */
610 SCIP_Real* value /**< pointer to store the value (unchanged, if token is no value) */
611 )
612 {
613 assert(opbinput != NULL);
614 assert(value != NULL);
615
616 if( strcasecmp(opbinput->token, "INFINITY") == 0 || strcasecmp(opbinput->token, "INF") == 0 )
617 {
618 *value = SCIPinfinity(scip);
619 return TRUE;
620 }
621 else
622 {
623 double val;
624 char* endptr;
625
626 val = strtod(opbinput->token, &endptr);
627 if( endptr != opbinput->token && *endptr == '\0' )
628 {
629 *value = val;
630 if( strlen(opbinput->token) > 18 )
631 opbinput->nproblemcoeffs++;
632 return TRUE;
633 }
634 }
635
636 return FALSE;
637 }
638
639 /** returns whether the current token is an equation sense */
640 static
641 SCIP_Bool isSense(
642 OPBINPUT* opbinput, /**< OPB reading data */
643 OPBSENSE* sense /**< pointer to store the equation sense, or NULL */
644 )
645 {
646 assert(opbinput != NULL);
647
648 if( strcmp(opbinput->token, "<") == 0 )
649 {
650 if( sense != NULL )
651 *sense = OPB_SENSE_LE;
652 return TRUE;
653 }
654 else if( strcmp(opbinput->token, ">") == 0 )
655 {
656 if( sense != NULL )
657 *sense = OPB_SENSE_GE;
658 return TRUE;
659 }
660 else if( strcmp(opbinput->token, "=") == 0 )
661 {
662 if( sense != NULL )
663 *sense = OPB_SENSE_EQ;
664 return TRUE;
665 }
666
667 return FALSE;
668 }
669
670 /** returns whether the current token is a value */
671 static
672 SCIP_Bool isStartingSoftConstraintWeight(
673 SCIP* scip, /**< SCIP data structure */
674 OPBINPUT* opbinput /**< OPB reading data */
675 )
676 {
677 assert(scip != NULL);
678 assert(opbinput != NULL);
679
680 if( strcmp(opbinput->token, "[") == 0 )
681 return TRUE;
682
683 return FALSE;
684 }
685
686 /** returns whether the current token is a value */
687 static
688 SCIP_Bool isEndingSoftConstraintWeight(
689 SCIP* scip, /**< SCIP data structure */
690 OPBINPUT* opbinput /**< OPB reading data */
691 )
692 {
693 assert(scip != NULL);
694 assert(opbinput != NULL);
695
696 if( strcmp(opbinput->token, "]") == 0 )
697 return TRUE;
698
699 return FALSE;
700 }
701
702 /** create binary variable with given name */
703 static
704 SCIP_RETCODE createVariable(
705 SCIP* scip, /**< SCIP data structure */
706 SCIP_VAR** var, /**< pointer to store the variable */
707 char* name /**< name for the variable */
708 )
709 {
710 SCIP_VAR* newvar;
711 SCIP_Bool dynamiccols;
712 SCIP_Bool initial;
713 SCIP_Bool removable;
714
715 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &dynamiccols) );
716 initial = !dynamiccols;
717 removable = dynamiccols;
718
719 /* create new variable of the given name */
720 SCIPdebugMsg(scip, "creating new variable: <%s>\n", name);
721
722 SCIP_CALL( SCIPcreateVar(scip, &newvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
723 initial, removable, NULL, NULL, NULL, NULL, NULL) );
724 SCIP_CALL( SCIPaddVar(scip, newvar) );
725 *var = newvar;
726
727 /* because the variable was added to the problem, it is captured by SCIP and we
728 * can safely release it right now without making the returned *var invalid */
729 SCIP_CALL( SCIPreleaseVar(scip, &newvar) );
730
731 return SCIP_OKAY;
732 }
733
734 /** returns the variable with the given name, or creates a new variable if it does not exist */
735 static
736 SCIP_RETCODE getVariableOrTerm(
737 SCIP* scip, /**< SCIP data structure */
738 OPBINPUT* opbinput, /**< OPB reading data */
739 SCIP_VAR*** vars, /**< pointer to store the variables */
740 int* nvars, /**< pointer to store the number of variables */
741 int* varssize /**< pointer to store the varsize, if changed (should already be initialized) */
742 )
743 {
744 SCIP_Bool negated;
745 char* name;
746
747 assert(scip != NULL);
748 assert(opbinput != NULL);
749 assert(vars != NULL);
750 assert(nvars != NULL);
751 assert(varssize != NULL);
752 assert(*varssize >= 0);
753
754 *nvars = 0;
755
756 name = opbinput->token;
757 assert(name != NULL);
758
759 /* parse AND terms */
760 while(!isdigit((unsigned char) *name ) && !isTokenChar(*name) && !opbinput->haserror )
761 {
762 SCIP_VAR* var;
763
764 negated = FALSE;
765 if( *name == '~' )
766 {
767 negated = TRUE;
768 ++name;
769 }
770
771 var = SCIPfindVar(scip, name);
772 if( var == NULL )
773 {
774 SCIP_CALL( createVariable(scip, &var, name) );
775 }
776
777 if( negated )
778 {
779 SCIP_VAR* negvar;
780 SCIP_CALL( SCIPgetNegatedVar(scip, var, &negvar) );
781
782 var = negvar;
783 }
784
785 /* reallocated memory */
786 if( *nvars == *varssize )
787 {
788 *varssize = SCIPcalcMemGrowSize(scip, *varssize + 1);
789 SCIP_CALL( SCIPreallocBufferArray(scip, vars, *varssize) );
790 }
791
792 (*vars)[*nvars] = var;
793 ++(*nvars);
794
795 if( !getNextToken(scip, opbinput) )
796 opbinput->haserror = TRUE;
797
798 name = opbinput->token;
799 }
800
801 /* check if we found at least on variable */
802 if( *nvars == 0 )
803 syntaxError(scip, opbinput, "expected a variable name");
804
805 pushToken(opbinput);
806
807 return SCIP_OKAY;
808 }
809
810 /** reads an objective or constraint with name and coefficients */
811 static
812 SCIP_RETCODE readCoefficients(
813 SCIP*const scip, /**< SCIP data structure */
814 OPBINPUT*const opbinput, /**< OPB reading data */
815 char*const name, /**< pointer to store the name of the line; must be at least of size
816 * OPB_MAX_LINELEN */
817 SCIP_VAR*** linvars, /**< pointer to store the array with linear variables (must be freed by caller) */
818 SCIP_Real** lincoefs, /**< pointer to store the array with linear coefficients (must be freed by caller) */
819 int*const nlincoefs, /**< pointer to store the number of linear coefficients */
820 SCIP_VAR**** terms, /**< pointer to store the array with nonlinear variables (must be freed by caller) */
821 SCIP_Real** termcoefs, /**< pointer to store the array with nonlinear coefficients (must be freed by caller) */
822 int** ntermvars, /**< pointer to store the number of nonlinear variables in the terms (must be freed by caller) */
823 int*const ntermcoefs, /**< pointer to store the number of nonlinear coefficients */
824 SCIP_Bool*const newsection, /**< pointer to store whether a new section was encountered */
825 SCIP_Bool*const isNonlinear, /**< pointer to store if we have a nonlinear constraint */
826 SCIP_Bool*const issoftcons, /**< pointer to store whether it is a soft constraint (for wbo files) */
827 SCIP_Real*const weight /**< pointer to store the weight of the soft constraint */
828 )
829 {
830 SCIP_VAR** tmpvars;
831 SCIP_Real* tmpcoefs;
832 SCIP_Bool havesign;
833 SCIP_Bool havevalue;
834 SCIP_Bool haveweightstart;
835 SCIP_Bool haveweightend;
836 SCIP_Real coef;
837 int coefsign;
838 int lincoefssize;
839 int termcoefssize;
840 int tmpvarssize;
841 int ntmpcoefs;
842 int ntmpvars;
843
844 assert(opbinput != NULL);
845 assert(name != NULL);
846 assert(linvars != NULL);
847 assert(lincoefs != NULL);
848 assert(nlincoefs != NULL);
849 assert(terms != NULL);
850 assert(termcoefs != NULL);
851 assert(ntermvars != NULL);
852 assert(ntermcoefs != NULL);
853 assert(newsection != NULL);
854
855 *linvars = NULL;
856 *lincoefs = NULL;
857 *terms = NULL;
858 *termcoefs = NULL;
859 *ntermvars = NULL;
860 *name = '\0';
861 *nlincoefs = 0;
862 *ntermcoefs = 0;
863 *newsection = FALSE;
864 *isNonlinear = FALSE;
865 *issoftcons = FALSE;
866
867 SCIPdebugMsg(scip, "read coefficients\n");
868
869 /* read the first token, which may be the name of the line */
870 if( getNextToken(scip, opbinput) )
871 {
872 /* remember the token in the token buffer */
873 swapTokenBuffer(opbinput);
874
875 /* get the next token and check, whether it is a colon */
876 if( getNextToken(scip, opbinput) )
877 {
878 if( strcmp(opbinput->token, ":") == 0 )
879 {
880 /* the second token was a colon ':' the first token is a constraint name */
881 (void)SCIPmemccpy(name, opbinput->tokenbuf, '\0', SCIP_MAXSTRLEN);
882
883 name[SCIP_MAXSTRLEN-1] = '\0';
884 SCIPdebugMsg(scip, "(line %d) read constraint name: '%s'\n", opbinput->linenumber, name);
885
886 /* all but the first coefficient need a sign */
887 if( strcmp(name, "soft") == 0 && (SCIPgetNVars(scip) > 0 || SCIPgetNConss(scip) > 0) )
888 {
889 syntaxError(scip, opbinput, "Soft top cost line needs to be the first non-comment line, and without any objective function.\n");
890 return SCIP_OKAY;
891 }
892 }
893 else
894 {
895 /* the second token was no colon: push the tokens back onto the token stack and parse them as coefficients */
896 SCIPdebugMsg(scip, "(line %d) constraint has no name\n", opbinput->linenumber);
897 pushToken(opbinput);
898 pushBufferToken(opbinput);
899 }
900 }
901 else
902 {
903 /* there was only one token left: push it back onto the token stack and parse it as coefficient */
904 pushBufferToken(opbinput);
905 }
906 }
907 else
908 {
909 assert(SCIPfeof( opbinput->file ) );
910 opbinput->eof = TRUE;
911 return SCIP_OKAY;
912 }
913
914 /* initialize buffers for storing the coefficients */
915 lincoefssize = OPB_INIT_COEFSSIZE;
916 termcoefssize = OPB_INIT_COEFSSIZE;
917 tmpvarssize = OPB_INIT_COEFSSIZE;
918 SCIP_CALL( SCIPallocBufferArray(scip, linvars, lincoefssize) );
919 SCIP_CALL( SCIPallocBufferArray(scip, lincoefs, lincoefssize) );
920 SCIP_CALL( SCIPallocBufferArray(scip, terms, termcoefssize) );
921 SCIP_CALL( SCIPallocBufferArray(scip, termcoefs, termcoefssize) );
922 SCIP_CALL( SCIPallocBufferArray(scip, ntermvars, termcoefssize) );
923 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, tmpvarssize) );
924 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, tmpvarssize) );
925
926 /* read the coefficients */
927 coefsign = +1;
928 coef = 1.0;
929 havesign = FALSE;
930 havevalue = FALSE;
931 haveweightstart = FALSE;
932 haveweightend = FALSE;
933 ntmpcoefs = 0;
934 ntmpvars = 0;
935 while( getNextToken(scip, opbinput) && !hasError(opbinput) )
936 {
937 if( isEndLine(opbinput) )
938 {
939 *newsection = TRUE;
940 goto TERMINATE;
941 }
942
943 /* check if we reached an equation sense */
944 if( isSense(opbinput, NULL) )
945 {
946 /* put the sense back onto the token stack */
947 pushToken(opbinput);
948 goto TERMINATE;
949 }
950
951 /* check if we read a sign */
952 if( isSign(opbinput, &coefsign) )
953 {
954 SCIPdebugMsg(scip, "(line %d) read coefficient sign: %+d\n", opbinput->linenumber, coefsign);
955 havesign = TRUE;
956 continue;
957 }
958
959 /* check if we read a value */
960 if( isValue(scip, opbinput, &coef) )
961 {
962 /* coefficients without a sign are treated as "+" */
963 if( (*nlincoefs > 0 || *ntermcoefs > 0 || ntmpcoefs > 0) && !havesign )
964 {
965 coefsign = 1;
966 havesign = TRUE;
967 }
968
969 SCIPdebugMsg(scip, "(line %d) read coefficient value: %g with sign %+d\n", opbinput->linenumber, coef, coefsign);
970 if( havevalue )
971 {
972 syntaxError(scip, opbinput, "two consecutive values");
973 goto TERMINATE;
974 }
975 havevalue = TRUE;
976
977 /* if we read a wbo file, the first line should be something like "soft: <weight>;", where weight is a value or nothing */
978 if( strcmp(name, "soft") == 0 )
979 {
980 assert(ntmpcoefs == 0);
981
982 tmpcoefs[ntmpcoefs] = coefsign * coef;
983 ++ntmpcoefs;
984 }
985
986 continue;
987 }
988
989 /* check if we are reading a soft constraint line, it start with "[<weight>]", where weight is a value */
990 if( *nlincoefs == 0 && *ntermcoefs == 0 && ntmpcoefs == 0 && !havesign && !havevalue && strcmp(name, "soft") != 0 && isStartingSoftConstraintWeight(scip, opbinput) )
991 {
992 if( !opbinput->wbo )
993 {
994 SCIPwarningMessage(scip, "Found in line %d a soft constraint, without having read a starting top-cost line.\n", opbinput->linenumber);
995 }
996 haveweightstart = TRUE;
997
998 continue;
999 }
1000 if( *nlincoefs == 0 && *ntermcoefs == 0 && ntmpcoefs == 0 && havevalue && haveweightstart && isEndingSoftConstraintWeight(scip, opbinput) )
1001 {
1002 *weight = coefsign * coef;
1003 SCIPdebugMsg(scip, "(line %d) found soft constraint weight: %g\n", opbinput->linenumber, *weight);
1004
1005 coefsign = +1;
1006 havesign = FALSE;
1007 havevalue = FALSE;
1008 haveweightend = TRUE;
1009 *issoftcons = TRUE;
1010
1011 continue;
1012 }
1013
1014 /* if we read a '[' we should already read a ']', which indicates that we read a soft constraint,
1015 * we have a parsing error */
1016 if( haveweightstart != haveweightend )
1017 {
1018 syntaxError(scip, opbinput, "Wrong soft constraint.");
1019 goto TERMINATE;
1020 }
1021
1022 /* if we read the first non-comment line of a wbo file we should never be here */
1023 if( strcmp(name, "soft") == 0 )
1024 {
1025 syntaxError(scip, opbinput, "Wrong soft top cost line.");
1026 goto TERMINATE;
1027 }
1028
1029 /* the token is a variable name: get the corresponding variables (or create a new ones) */
1030 SCIP_CALL( getVariableOrTerm(scip, opbinput, &tmpvars, &ntmpvars, &tmpvarssize) );
1031
1032 if( ntmpvars > 1 )
1033 {
1034 /* insert non-linear term */
1035 *isNonlinear = TRUE;
1036
1037 SCIPdebugMsg(scip, "(line %d) found linear term: %+g", opbinput->linenumber, coefsign * coef);
1038 #ifndef NDEBUG
1039 {
1040 int v;
1041 for( v = 0; v < ntmpvars; ++v )
1042 {
1043 SCIPdebugMsgPrint(scip, " %s * ", SCIPvarGetName(tmpvars[v]));
1044 }
1045 SCIPdebugMsgPrint(scip, "\n");
1046 }
1047 #endif
1048 if( !SCIPisZero(scip, coef) )
1049 {
1050 assert(*ntermcoefs <= termcoefssize);
1051 /* resize the terms, ntermvars, and termcoefs array if needed */
1052 if( *ntermcoefs == termcoefssize )
1053 {
1054 termcoefssize = SCIPcalcMemGrowSize(scip, termcoefssize + 1);
1055 SCIP_CALL( SCIPreallocBufferArray(scip, terms, termcoefssize) );
1056 SCIP_CALL( SCIPreallocBufferArray(scip, termcoefs, termcoefssize) );
1057 SCIP_CALL( SCIPreallocBufferArray(scip, ntermvars, termcoefssize) );
1058 }
1059 assert(*ntermcoefs < termcoefssize);
1060
1061 /* get memory for the last term */
1062 SCIP_CALL( SCIPallocBufferArray(scip, &((*terms)[*ntermcoefs]), ntmpvars) ); /*lint !e866 */
1063
1064 /* set the number of variable in this term */
1065 (*ntermvars)[*ntermcoefs] = ntmpvars;
1066
1067 /* add all variables */
1068 for( --ntmpvars; ntmpvars >= 0; --ntmpvars )
1069 {
1070 (*terms)[*ntermcoefs][ntmpvars] = tmpvars[ntmpvars];
1071 }
1072 /* add coefficient */
1073 (*termcoefs)[*ntermcoefs] = coefsign * coef;
1074
1075 /***********************/
1076 if( !SCIPisIntegral(scip, (*termcoefs)[*ntermcoefs]) )
1077 {
1078 SCIPwarningMessage(scip, "coefficient %g in line %d not integral.\n", (*termcoefs)[*ntermcoefs], opbinput->linenumber);
1079 }
1080
1081 ++(*ntermcoefs);
1082 }
1083
1084 /* reset the flags and coefficient value for the next coefficient */
1085 coefsign = +1;
1086 coef = 1.0;
1087 havesign = FALSE;
1088 havevalue = FALSE;
1089 ntmpvars = 0;
1090 }
1091 else
1092 {
1093 assert(ntmpvars == 1);
1094 /* insert linear term */
1095 SCIPdebugMsg(scip, "(line %d) found linear term: %+g<%s>\n", opbinput->linenumber, coefsign * coef, SCIPvarGetName(tmpvars[0]));
1096 if( !SCIPisZero(scip, coef) )
1097 {
1098 assert(*nlincoefs <= lincoefssize);
1099 /* resize the vars and coefs array if needed */
1100 if( *nlincoefs >= lincoefssize )
1101 {
1102 lincoefssize = SCIPcalcMemGrowSize(scip, lincoefssize + 1);
1103 SCIP_CALL( SCIPreallocBufferArray(scip, linvars, lincoefssize) );
1104 SCIP_CALL( SCIPreallocBufferArray(scip, lincoefs, lincoefssize) );
1105 }
1106 assert(*nlincoefs < lincoefssize);
1107
1108 /* add coefficient */
1109 (*linvars)[*nlincoefs] = tmpvars[0];
1110 (*lincoefs)[*nlincoefs] = coefsign * coef;
1111
1112 /***********************/
1113 if( !SCIPisIntegral(scip, (*lincoefs)[*nlincoefs]) )
1114 {
1115 SCIPwarningMessage(scip, "coefficient %g in line %d not integral.\n", (*lincoefs)[*nlincoefs], opbinput->linenumber);
1116 }
1117
1118 ++(*nlincoefs);
1119 }
1120
1121 /* reset the flags and coefficient value for the next coefficient */
1122 coefsign = +1;
1123 coef = 1.0;
1124 havesign = FALSE;
1125 havevalue = FALSE;
1126 ntmpvars = 0;
1127 }
1128 }
1129
1130 TERMINATE:
1131 if( !opbinput->haserror )
1132 {
1133 /* all variables should be in the right arrays */
1134 assert(ntmpvars == 0);
1135 /* the following is only the case if we read topcost's of a wbo file, we need to move this topcost value to the
1136 * right array */
1137 if( ntmpcoefs > 0 )
1138 {
1139 /* maximal one topcost value is possible */
1140 assert(ntmpcoefs == 1);
1141 /* no other coefficient should be found here */
1142 assert(*nlincoefs == 0 && *ntermcoefs == 0);
1143
1144 /* copy value */
1145 (*lincoefs)[*nlincoefs] = tmpcoefs[0];
1146
1147 /***********************/
1148 if( !SCIPisIntegral(scip, (*lincoefs)[*nlincoefs]) )
1149 {
1150 SCIPwarningMessage(scip, "topcost not integral.\n");
1151 }
1152
1153 *nlincoefs = 1;
1154 }
1155 }
1156 /* clear memory */
1157 SCIPfreeBufferArray(scip, &tmpcoefs);
1158 SCIPfreeBufferArray(scip, &tmpvars);
1159
1160 return SCIP_OKAY;
1161 }
1162
1163 /** set the objective section */
1164 static
1165 SCIP_RETCODE setObjective(
1166 SCIP*const scip, /**< SCIP data structure */
1167 OPBINPUT*const opbinput, /**< OPB reading data */
1168 const char* sense, /**< objective sense */
1169 SCIP_VAR**const linvars, /**< array of linear variables */
1170 SCIP_Real*const coefs, /**< array of objective values for linear variables */
1171 int const ncoefs, /**< number of coefficients for linear part */
1172 SCIP_VAR***const terms, /**< array with nonlinear variables */
1173 SCIP_Real*const termcoefs, /**< array of objective values for nonlinear variables */
1174 int*const ntermvars, /**< number of nonlinear variables in the terms */
1175 int const ntermcoefs /**< number of nonlinear coefficients */
1176 )
1177 {
1178 assert(scip != NULL);
1179 assert(opbinput != NULL);
1180 assert(isEndLine(opbinput));
1181 assert(ncoefs == 0 || (linvars != NULL && coefs != NULL));
1182 assert(ntermcoefs == 0 || (terms != NULL && ntermvars != NULL && termcoefs != NULL));
1183
1184 if( !hasError(opbinput) )
1185 {
1186 SCIP_VAR* var;
1187 int v;
1188 char name[SCIP_MAXSTRLEN];
1189
1190 if( strcmp(sense, "max" ) == 0 )
1191 opbinput->objsense = SCIP_OBJSENSE_MAXIMIZE;
1192
1193 /* @todo: what todo with non-linear objectives, maybe create the necessary and-constraints and add the arising linear
1194 * objective (with and-resultants) or add a integer variable to this constraint and put only this variable in the
1195 * objective, for this we need to expand the pseudo-boolean constraints to handle integer variables
1196 *
1197 * integer variant is not implemented
1198 */
1199 if( ntermcoefs > 0 )
1200 {
1201 #if (LINEAROBJECTIVE == TRUE)
1202 /* all non-linear parts are created as and-constraints, even if the same non-linear part was already part of the objective function */
1203
1204 SCIP_VAR** vars;
1205 int nvars;
1206 int t;
1207 SCIP_CONS* andcons;
1208
1209 for( t = 0; t < ntermcoefs; ++t )
1210 {
1211 assert(terms != NULL); /* for lint */
1212 assert(ntermvars != NULL);
1213 assert(termcoefs != NULL);
1214
1215 vars = terms[t];
1216 nvars = ntermvars[t];
1217 assert(vars != NULL);
1218 assert(nvars > 1);
1219
1220 /* create auxiliary variable */
1221 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, ARTIFICIALVARNAMEPREFIX"obj_%d", t);
1222 SCIP_CALL( SCIPcreateVar(scip, &var, name, 0.0, 1.0, termcoefs[t], SCIP_VARTYPE_BINARY,
1223 TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
1224
1225 /* @todo: check if it is better to change the branching priority for the artificial variables */
1226 #if 1
1227 /* change branching priority of artificial variable to -1 */
1228 SCIP_CALL( SCIPchgVarBranchPriority(scip, var, -1) );
1229 #endif
1230
1231 /* add auxiliary variable to the problem */
1232 SCIP_CALL( SCIPaddVar(scip, var) );
1233
1234 #ifdef WITH_DEBUG_SOLUTION
1235 if( SCIPdebugIsMainscip(scip) )
1236 {
1237 SCIP_Real val = 0.0;
1238
1239 for( v = nvars - 1; v >= 0; --v )
1240 {
1241 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[v], &val) );
1242 assert(SCIPisFeasZero(scip, val) || SCIPisFeasEQ(scip, val, 1.0));
1243
1244 if( val < 0.5 )
1245 break;
1246 }
1247 SCIP_CALL( SCIPdebugAddSolVal(scip, var, (val < 0.5) ? 0.0 : 1.0) );
1248 }
1249 #endif
1250
1251 /* @todo: check whether all constraint creation flags are the best option */
1252 /* create and-constraint */
1253 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "obj_andcons_%d", t);
1254 SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, var, nvars, vars,
1255 TRUE, TRUE, TRUE, TRUE, TRUE,
1256 FALSE, FALSE, FALSE, FALSE, FALSE) );
1257 SCIP_CALL( SCIPaddCons(scip, andcons) );
1258 SCIPdebugPrintCons(scip, andcons, NULL);
1259 SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
1260
1261 SCIP_CALL( SCIPreleaseVar(scip, &var) );
1262 }
1263 #else /* now the integer variant */
1264 SCIP_CONS* pseudocons;
1265 SCIP_Real lb;
1266 SCIP_Real ub;
1267
1268 lb = 0.0;
1269 ub = 0.0;
1270
1271 /* add all non linear coefficients up */
1272 for( v = 0; v < ntermcoefs; ++v )
1273 {
1274 if( termcoefs[v] < 0 )
1275 lb += termcoefs[v];
1276 else
1277 ub += termcoefs[v];
1278 }
1279 /* add all linear coefficients up */
1280 for( v = 0; v < ncoefs; ++v )
1281 {
1282 if( coefs[v] < 0 )
1283 lb += coefs[v];
1284 else
1285 ub += coefs[v];
1286 }
1287 assert(lb < ub);
1288
1289 /* create auxiliary variable */
1290 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "artificial_int_obj");
1291 SCIP_CALL( SCIPcreateVar(scip, &var, name, lb, ub, 1.0, SCIP_VARTYPE_INTEGER,
1292 TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
1293
1294 /* @todo: check if it is better to change the branching priority for the artificial variables */
1295 #if 1
1296 /* change branching priority of artificial variable to -1 */
1297 SCIP_CALL( SCIPchgVarBranchPriority(scip, var, -1) );
1298 #endif
1299 /* add auxiliary variable to the problem */
1300 SCIP_CALL( SCIPaddVar(scip, var) );
1301
1302 #ifdef WITH_DEBUG_SOLUTION
1303 if( SCIPdebugIsMainscip(scip) )
1304 {
1305 SCIP_Real artval = 0.0;
1306 SCIP_Real val;
1307
1308 for( t = 0; t < ntermcoefs; ++t )
1309 {
1310 vars = terms[t];
1311 nvars = ntermvars[t];
1312 assert(vars != NULL);
1313 assert(nvars > 1);
1314
1315 for( v = nvars - 1; v >= 0; --v )
1316 {
1317 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[v], &val) );
1318 assert(SCIPisFeasZero(scip, val) || SCIPisFeasEQ(scip, val, 1.0));
1319
1320 if( val < 0.5 )
1321 break;
1322 }
1323
1324 artval += (((val < 0.5) ? 0.0 : 1.0) * termcoefs[t]);
1325 }
1326 assert(SCIPisFeasLE(scip, lb, artval) && SCIPisFeasGE(scip, ub, artval));
1327
1328 SCIP_CALL( SCIPdebugAddSolVal(scip, var, artval) );
1329 }
1330 #endif
1331
1332 /* create artificial objection function constraint containing the artificial integer variable */
1333 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "artificial_obj_cons");
1334 SCIP_CALL( SCIPcreateConsPseudoboolean(scip, &pseudocons, name, linvars, ncoefs, coefs, terms, ntermcoefs,
1335 ntermvars, termcoefs, NULL, 0.0, FALSE, var, 0.0, 0.0,
1336 TRUE, TRUE, TRUE, TRUE, TRUE,
1337 FALSE, FALSE, FALSE, FALSE, FALSE) );
1338
1339 SCIP_CALL( SCIPaddCons(scip, pseudocons) );
1340 SCIPdebugPrintCons(scip, pseudocons, NULL);
1341 SCIP_CALL( SCIPreleaseCons(scip, &pseudocons) );
1342
1343 SCIP_CALL( SCIPreleaseVar(scip, &var) );
1344
1345 return SCIP_OKAY;
1346 #endif
1347 }
1348 /* set the objective values */
1349 for( v = 0; v < ncoefs; ++v )
1350 {
1351 assert(linvars != NULL); /* for lint */
1352 assert(coefs != NULL);
1353
1354 if( SCIPvarIsNegated(linvars[v]) )
1355 {
1356 SCIP_VAR* negvar = SCIPvarGetNegationVar(linvars[v]);
1357
1358 SCIP_CALL( SCIPaddOrigObjoffset(scip, coefs[v]) );
1359 SCIP_CALL( SCIPchgVarObj(scip, negvar, SCIPvarGetObj(negvar) - coefs[v]) );
1360 }
1361 else
1362 {
1363 SCIP_CALL( SCIPchgVarObj(scip, linvars[v], SCIPvarGetObj(linvars[v]) + coefs[v]) );
1364 }
1365 }
1366 }
1367
1368 return SCIP_OKAY;
1369 }
1370
1371 /** reads the constraints section */
1372 static
1373 SCIP_RETCODE readConstraints(
1374 SCIP* scip, /**< SCIP data structure */
1375 OPBINPUT* opbinput, /**< OPB reading data */
1376 int* nNonlinearConss /**< pointer to store number of nonlinear constraints */
1377 )
1378 {
1379 char name[OPB_MAX_LINELEN];
1380 SCIP_CONS* cons;
1381 SCIP_VAR** linvars;
1382 SCIP_Real* lincoefs;
1383 int nlincoefs;
1384 SCIP_VAR*** terms;
1385 SCIP_Real* termcoefs;
1386 int* ntermvars;
1387 int ntermcoefs;
1388 OPBSENSE sense;
1389 SCIP_RETCODE retcode;
1390 SCIP_Real sidevalue;
1391 SCIP_Real lhs;
1392 SCIP_Real rhs;
1393 SCIP_Bool newsection;
1394 SCIP_Bool initialconss;
1395 SCIP_Bool dynamicconss;
1396 SCIP_Bool dynamicrows;
1397 SCIP_Bool initial;
1398 SCIP_Bool separate;
1399 SCIP_Bool enforce;
1400 SCIP_Bool check;
1401 SCIP_Bool propagate;
1402 SCIP_Bool local;
1403 SCIP_Bool modifiable;
1404 SCIP_Bool dynamic;
1405 SCIP_Bool removable;
1406 SCIP_Bool isNonlinear;
1407 int sidesign;
1408 SCIP_Bool issoftcons;
1409 SCIP_Real weight;
1410 SCIP_VAR* indvar;
1411 char indname[SCIP_MAXSTRLEN];
1412 int t;
1413
1414 assert(scip != NULL);
1415 assert(opbinput != NULL);
1416 assert(nNonlinearConss != NULL);
1417
1418 weight = -SCIPinfinity(scip);
1419 retcode = SCIP_OKAY;
1420
1421 /* read the objective coefficients */
1422 SCIP_CALL( readCoefficients(scip, opbinput, name, &linvars, &lincoefs, &nlincoefs, &terms, &termcoefs, &ntermvars, &ntermcoefs, &newsection, &isNonlinear, &issoftcons, &weight) );
1423
1424 if( hasError(opbinput) || opbinput->eof )
1425 goto TERMINATE;
1426 if( newsection )
1427 {
1428 if( strcmp(name, "min") == 0 || strcmp(name, "max") == 0 )
1429 {
1430 if( opbinput->wbo )
1431 {
1432 syntaxError(scip, opbinput, "Cannot have an objective function when having soft constraints.\n");
1433 goto TERMINATE;
1434 }
1435
1436 /* set objective function */
1437 SCIP_CALL( setObjective(scip, opbinput, name, linvars, lincoefs, nlincoefs, terms, termcoefs, ntermvars, ntermcoefs) );
1438 }
1439 else if( strcmp(name, "soft") == 0 )
1440 {
1441 /* we have a "weighted boolean optimization"-file(wbo) */
1442 opbinput->wbo = TRUE;
1443 if( nlincoefs == 0 )
1444 opbinput->topcost = SCIPinfinity(scip);
1445 else
1446 {
1447 assert(nlincoefs == 1);
1448 assert(lincoefs != NULL);
1449 opbinput->topcost = lincoefs[0];
1450 }
1451 SCIPdebugMsg(scip, "Weighted Boolean Optimization problem has topcost of %g\n", opbinput->topcost);
1452 }
1453 else if( nlincoefs > 0 )
1454 syntaxError(scip, opbinput, "expected constraint sense '=' or '>='");
1455 goto TERMINATE;
1456 }
1457
1458 /* read the constraint sense */
1459 if( !getNextToken(scip, opbinput) )
1460 {
1461 syntaxError(scip, opbinput, "expected constraint sense.");
1462 goto TERMINATE;
1463 }
1464 if( !isSense(opbinput, &sense) )
1465 {
1466 syntaxError(scip, opbinput, "expected constraint sense '=' or '>='.");
1467 goto TERMINATE;
1468 }
1469
1470 /* read the right hand side */
1471 sidesign = +1;
1472 if( !getNextToken(scip, opbinput) )
1473 {
1474 syntaxError(scip, opbinput, "missing right hand side");
1475 goto TERMINATE;
1476 }
1477 if( isSign(opbinput, &sidesign) )
1478 {
1479 if( !getNextToken(scip, opbinput) )
1480 {
1481 syntaxError(scip, opbinput, "missing value of right hand side");
1482 goto TERMINATE;
1483 }
1484 }
1485 if( !isValue(scip, opbinput, &sidevalue) )
1486 {
1487 syntaxError(scip, opbinput, "expected value as right hand side");
1488 goto TERMINATE;
1489 }
1490 sidevalue *= sidesign;
1491
1492 /* check if we reached the line end */
1493 if( !getNextToken(scip, opbinput) || !isEndLine(opbinput) )
1494 {
1495 syntaxError(scip, opbinput, "expected endline character ';'");
1496 goto TERMINATE;
1497 }
1498
1499 /* assign the left and right hand side, depending on the constraint sense */
1500 switch( sense ) /*lint !e530*/
1501 {
1502 case OPB_SENSE_GE:
1503 lhs = sidevalue;
1504 rhs = SCIPinfinity(scip);
1505 break;
1506 case OPB_SENSE_LE:
1507 lhs = -SCIPinfinity(scip);
1508 rhs = sidevalue;
1509 break;
1510 case OPB_SENSE_EQ:
1511 lhs = sidevalue;
1512 rhs = sidevalue;
1513 break;
1514 case OPB_SENSE_NOTHING:
1515 default:
1516 SCIPerrorMessage("invalid constraint sense <%d>\n", sense);
1517 return SCIP_INVALIDDATA;
1518 }
1519
1520 /* create and add the linear constraint */
1521 SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &initialconss) );
1522 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &dynamicrows) );
1523 SCIP_CALL( SCIPgetBoolParam(scip, "reading/" READER_NAME "/dynamicconss", &dynamicconss) );
1524
1525 initial = initialconss;
1526 separate = TRUE;
1527 enforce = TRUE;
1528 check = TRUE;
1529 propagate = TRUE;
1530 local = FALSE;
1531 modifiable = FALSE;
1532 dynamic = FALSE;/*dynamicconss;*/
1533 removable = dynamicrows;
1534
1535 /* create corresponding constraint */
1536 if( issoftcons )
1537 {
1538 (void) SCIPsnprintf(indname, SCIP_MAXSTRLEN, INDICATORVARNAME"%d", opbinput->nindvars);
1539 ++(opbinput->nindvars);
1540 SCIP_CALL( createVariable(scip, &indvar, indname) );
1541
1542 assert(!SCIPisInfinity(scip, -weight));
1543 SCIP_CALL( SCIPchgVarObj(scip, indvar, weight) );
1544 }
1545 else
1546 indvar = NULL;
1547
1548 if( ntermcoefs > 0 || issoftcons )
1549 {
1550 #if GENCONSNAMES == TRUE
1551 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "pseudoboolean%d", opbinput->consnumber);
1552 ++(opbinput->consnumber);
1553 #else
1554 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "pseudoboolean");
1555 #endif
1556 retcode = SCIPcreateConsPseudoboolean(scip, &cons, name, linvars, nlincoefs, lincoefs, terms, ntermcoefs,
1557 ntermvars, termcoefs, indvar, weight, issoftcons, NULL, lhs, rhs,
1558 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, FALSE);
1559 if( retcode != SCIP_OKAY )
1560 goto TERMINATE;
1561 }
1562 else
1563 {
1564 #if GENCONSNAMES == TRUE
1565 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "linear%d", opbinput->consnumber);
1566 ++(opbinput->consnumber);
1567 #else
1568 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "linear");
1569 #endif
1570 retcode = SCIPcreateConsLinear(scip, &cons, name, nlincoefs, linvars, lincoefs, lhs, rhs,
1571 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, FALSE);
1572 if( retcode != SCIP_OKAY )
1573 goto TERMINATE;
1574 }
1575
1576 SCIP_CALL( SCIPaddCons(scip, cons) );
1577 SCIPdebugMsg(scip, "(line %d) created constraint: ", opbinput->linenumber);
1578 SCIPdebugPrintCons(scip, cons, NULL);
1579 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1580
1581 if( isNonlinear )
1582 ++(*nNonlinearConss);
1583
1584 TERMINATE:
1585
1586 /* free memory */
1587 for( t = ntermcoefs - 1; t >= 0; --t )
1588 {
1589 assert(terms != NULL); /* for lint */
1590 SCIPfreeBufferArrayNull(scip, &(terms[t]));
1591 }
1592
1593 SCIPfreeBufferArrayNull(scip, &ntermvars);
1594 SCIPfreeBufferArrayNull(scip, &termcoefs);
1595 SCIPfreeBufferArrayNull(scip, &terms);
1596 SCIPfreeBufferArrayNull(scip, &lincoefs);
1597 SCIPfreeBufferArrayNull(scip, &linvars);
1598
1599 SCIP_CALL( retcode );
1600
1601 return SCIP_OKAY;
1602 }
1603
1604 /** tries to read the first comment line which usually contains information about the max size of "and" products */
1605 static
1606 SCIP_RETCODE getMaxAndConsDim(
1607 SCIP* scip, /**< SCIP data structure */
1608 OPBINPUT* opbinput, /**< OPB reading data */
1609 const char* filename, /**< name of the input file */
1610 SCIP_Real* objoffset /**< pointer to store objective offset */
1611 )
1612 {
1613 SCIP_Bool stop;
1614 char* commentstart;
1615 char* nproducts;
1616 char* str;
1617 int i;
1618
1619 assert(scip != NULL);
1620 assert(opbinput != NULL);
1621 assert(objoffset != NULL);
1622
1623 stop = FALSE;
1624 commentstart = NULL;
1625 nproducts = NULL;
1626
1627 *objoffset = 0.0;
1628
1629 do
1630 {
1631 if( SCIPfgets(opbinput->linebuf, (int) sizeof(opbinput->linebuf), opbinput->file) == NULL )
1632 {
1633 assert(SCIPfeof( opbinput->file ) );
1634 break;
1635 }
1636
1637 /* read characters after comment symbol */
1638 for( i = 0; commentchars[i] != '\0'; ++i )
1639 {
1640 commentstart = strchr(opbinput->linebuf, commentchars[i]);
1641
1642 /* found a comment line */
1643 if( commentstart != NULL )
1644 {
1645 /* search for "#product= xyz" in comment line, where xyz represents the number of and constraints */
1646 nproducts = strstr(opbinput->linebuf, "#product= ");
1647 if( nproducts != NULL )
1648 {
1649 const char delimchars[] = " \t";
1650 char* pos;
1651
1652 nproducts += strlen("#product= ");
1653
1654 pos = strtok(nproducts, delimchars);
1655
1656 if( pos != NULL )
1657 {
1658 SCIPdebugMsg(scip, "%d products supposed to be in file.\n", atoi(pos));
1659 }
1660
1661 pos = strtok (NULL, delimchars);
1662
1663 if( pos != NULL && strcmp(pos, "sizeproduct=") == 0 )
1664 {
1665 pos = strtok (NULL, delimchars);
1666 if( pos != NULL )
1667 {
1668 SCIPdebugMsg(scip, "sizeproducts = %d\n", atoi(pos));
1669 }
1670 }
1671
1672 stop = TRUE;
1673 }
1674
1675 /* search for "Obj. offset : <number>" in comment line */
1676 str = strstr(opbinput->linebuf, "Obj. offset : ");
1677 if( str != NULL )
1678 {
1679 str += strlen("Obj. offset : ");
1680 *objoffset = atof(str);
1681 break;
1682 }
1683
1684 break;
1685 }
1686 }
1687 }
1688 while(commentstart != NULL && !stop);
1689
1690 opbinput->linebuf[0] = '\0';
1691
1692 #if 0 /* following lines should be correct, but it seems that gzseek does not reset the position if standing at the end of a file */
1693 /* reset filereader pointer to the beginning */
1694 (void) SCIPfseek(opbinput->file, 0, SEEK_SET);
1695 #else
1696 SCIPfclose(opbinput->file);
1697 opbinput->file = SCIPfopen(filename, "r");
1698 #endif
1699
1700 return SCIP_OKAY;
1701 }
1702
1703 /** reads an OPB file */
1704 static
1705 SCIP_RETCODE readOPBFile(
1706 SCIP* scip, /**< SCIP data structure */
1707 OPBINPUT* opbinput, /**< OPB reading data */
1708 const char* filename /**< name of the input file */
1709 )
1710 {
1711 SCIP_Real objoffset;
1712 int nNonlinearConss;
1713 int i;
1714
1715 assert(scip != NULL);
1716 assert(opbinput != NULL);
1717
1718 /* open file */
1719 opbinput->file = SCIPfopen(filename, "r");
1720 if( opbinput->file == NULL )
1721 {
1722 SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
1723 SCIPprintSysError(filename);
1724 return SCIP_NOFILE;
1725 }
1726
1727 /* @todo: reading additional information about the number of and constraints in comments to avoid reallocating
1728 * "opbinput.andconss"
1729 */
1730
1731 /* tries to read the first comment line which usually contains information about the max size of "and" products */
1732 SCIP_CALL( getMaxAndConsDim(scip, opbinput, filename, &objoffset) );
1733
1734 BMSclearMemoryArray(opbinput->linebuf, OPB_MAX_LINELEN);
1735
1736 /* create problem */
1737 SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
1738
1739 if( ! SCIPisZero(scip, objoffset) )
1740 {
1741 SCIP_CALL( SCIPaddOrigObjoffset(scip, objoffset) );
1742 }
1743
1744 nNonlinearConss = 0;
1745
1746 while( !SCIPfeof( opbinput->file ) && !hasError(opbinput) )
1747 {
1748 SCIP_CALL( readConstraints(scip, opbinput, &nNonlinearConss) );
1749 }
1750
1751 /* if we read a wbo file we need to make sure that the top cost won't be exceeded */
1752 if( opbinput->wbo )
1753 {
1754 SCIP_VAR** topcostvars;
1755 SCIP_Real* topcosts;
1756 SCIP_VAR** vars;
1757 int nvars;
1758 int ntopcostvars;
1759 SCIP_Longint topcostrhs;
1760 SCIP_CONS* topcostcons;
1761
1762 nvars = SCIPgetNVars(scip);
1763 vars = SCIPgetVars(scip);
1764 assert(nvars > 0 || vars != NULL);
1765
1766 SCIP_CALL( SCIPallocBufferArray(scip, &topcostvars, nvars) );
1767 SCIP_CALL( SCIPallocBufferArray(scip, &topcosts, nvars) );
1768
1769 ntopcostvars = 0;
1770 for( i = nvars - 1; i >= 0; --i )
1771 if( !SCIPisZero(scip, SCIPvarGetObj(vars[i])) )
1772 {
1773 topcostvars[ntopcostvars] = vars[i];
1774 topcosts[ntopcostvars] = SCIPvarGetObj(vars[i]);
1775 ++ntopcostvars;
1776 }
1777
1778 if( SCIPisIntegral(scip, opbinput->topcost) )
1779 topcostrhs = (SCIP_Longint) SCIPfloor(scip, opbinput->topcost - 1);
1780 else
1781 topcostrhs = (SCIP_Longint) SCIPfloor(scip, opbinput->topcost);
1782
1783 SCIP_CALL( SCIPcreateConsLinear(scip, &topcostcons, TOPCOSTCONSNAME, ntopcostvars, topcostvars, topcosts, -SCIPinfinity(scip),
1784 (SCIP_Real) topcostrhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
1785 SCIP_CALL( SCIPaddCons(scip, topcostcons) );
1786 SCIPdebugPrintCons(scip, topcostcons, NULL);
1787 SCIP_CALL( SCIPreleaseCons(scip, &topcostcons) );
1788
1789 SCIPfreeBufferArray(scip, &topcosts);
1790 SCIPfreeBufferArray(scip, &topcostvars);
1791 }
1792
1793 /* close file */
1794 SCIPfclose(opbinput->file);
1795
1796 return SCIP_OKAY;
1797 }
1798
1799
1800 /*
1801 * Local methods (for writing)
1802 */
1803
1804 /** transforms given and constraint variables to the corresponding active or negated variables */
1805 static
1806 SCIP_RETCODE getBinVarsRepresentatives(
1807 SCIP*const scip, /**< SCIP data structure */
1808 SCIP_VAR**const vars, /**< vars array to get active variables for */
1809 int const nvars, /**< pointer to number of variables and values in vars and vals array */
1810 SCIP_Bool const transformed /**< transformed constraint? */
1811 )
1812 {
1813 SCIP_Bool negated;
1814 int v;
1815
1816 assert( scip != NULL );
1817 assert( vars != NULL );
1818 assert( nvars > 0 );
1819
1820 if( transformed )
1821 {
1822 for( v = nvars - 1; v >= 0; --v )
1823 {
1824 /* gets a binary variable that is equal to the given binary variable, and that is either active, fixed, or
1825 * multi-aggregated, or the negated variable of an active, fixed, or multi-aggregated variable
1826 */
1827 SCIP_CALL( SCIPgetBinvarRepresentative( scip, vars[v], &vars[v], &negated) );
1828 }
1829 }
1830 else
1831 {
1832 SCIP_Real scalar;
1833 SCIP_Real constant;
1834
1835 for( v = nvars - 1; v >= 0; --v )
1836 {
1837 scalar = 1.0;
1838 constant = 0.0;
1839
1840 /* retransforms given variable, scalar and constant to the corresponding original variable, scalar and constant,
1841 * if possible; if the retransformation is impossible, NULL is returned as variable
1842 */
1843 SCIP_CALL( SCIPvarGetOrigvarSum(&vars[v], &scalar, &constant) );
1844
1845 if( vars[v] == NULL )
1846 {
1847 SCIPdebugMsg(scip, "A variable couldn't retransformed to an original variable.\n");
1848 return SCIP_INVALIDDATA;
1849 }
1850 if( SCIPisEQ(scip, scalar, -1.0) && SCIPisEQ(scip, constant, 1.0) )
1851 {
1852 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &vars[v]) );
1853 }
1854 else
1855 {
1856 if( !SCIPisEQ(scip, scalar, 1.0) || !SCIPisZero(scip, constant) )
1857 {
1858 SCIPdebugMsg(scip, "A variable couldn't retransformed to an original variable or a negated variable of an original variable (scalar = %g, constant = %g).\n", scalar, constant);
1859 return SCIP_INVALIDDATA;
1860 }
1861 }
1862 }
1863 }
1864
1865 return SCIP_OKAY;
1866 }
1867
1868 /** transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant */
1869 static
1870 SCIP_RETCODE getActiveVariables(
1871 SCIP* scip, /**< SCIP data structure */
1872 SCIP_VAR** vars, /**< vars array to get active variables for */
1873 SCIP_Real* scalars, /**< scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
1874 int* nvars, /**< pointer to number of variables and values in vars and vals array */
1875 SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */
1876 SCIP_Bool transformed /**< transformed constraint? */
1877 )
1878 {
1879 int requiredsize;
1880 int v;
1881
1882 assert(scip != NULL);
1883 assert(vars != NULL);
1884 assert(scalars != NULL);
1885 assert(nvars != NULL);
1886 assert(constant != NULL);
1887
1888 if( transformed )
1889 {
1890 SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize, TRUE) );
1891
1892 if( requiredsize > *nvars )
1893 {
1894 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) );
1895 SCIP_CALL( SCIPreallocBufferArray(scip, &scalars, requiredsize) );
1896
1897 SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize, TRUE) );
1898 assert( requiredsize <= *nvars );
1899 }
1900 }
1901 else
1902 for( v = 0; v < *nvars; ++v )
1903 {
1904 SCIP_CALL( SCIPvarGetOrigvarSum(&vars[v], &scalars[v], constant) );
1905
1906 if( vars[v] == NULL )
1907 return SCIP_INVALIDDATA;
1908 }
1909
1910 return SCIP_OKAY;
1911 }
1912
1913 /* computes all and-resultants and their corresponding constraint variables */
1914 static
1915 SCIP_RETCODE computeAndConstraintInfos(
1916 SCIP*const scip, /**< SCIP data structure */
1917 SCIP_Bool const transformed, /**< transformed problem? */
1918 SCIP_VAR*** resvars, /**< pointer to store all resultant variables */
1919 int* nresvars, /**< pointer to store the number of all resultant variables */
1920 SCIP_VAR**** andvars, /**< pointer to store to all resultant variables their corresponding active( or negated) and-constraint variables */
1921 int** nandvars, /**< pointer to store the number of all corresponding and-variables to their corresponding resultant variable */
1922 SCIP_Bool*const existandconshdlr, /**< pointer to store whether the and-constrainthandler exists*/
1923 SCIP_Bool*const existands /**< pointer to store if their exists some and-constraints */
1924 )
1925 {
1926 SCIP_CONSHDLR* conshdlr;
1927
1928 assert(scip != NULL);
1929 assert(resvars != NULL);
1930 assert(nresvars != NULL);
1931 assert(andvars != NULL);
1932 assert(nandvars != NULL);
1933 assert(existandconshdlr != NULL);
1934 assert(existands != NULL);
1935
1936 *resvars = NULL;
1937 *nandvars = NULL;
1938 *andvars = NULL;
1939 *nresvars = 0;
1940
1941 /* detect all and-resultants */
1942 conshdlr = SCIPfindConshdlr(scip, "and");
1943 if( conshdlr != NULL )
1944 {
1945 SCIP_CONS** andconss;
1946 int nandconss;
1947 int* shouldnotbeinand;
1948 int a;
1949 int c;
1950 int r;
1951 int v;
1952 int pos;
1953 int ncontainedands;
1954
1955 andconss = NULL;
1956 nandconss = 0;
1957 *existandconshdlr = TRUE;
1958
1959 /* if we write the original problem we need to get the original and constraints */
1960 if( !transformed )
1961 {
1962 SCIP_CONS** origconss;
1963 int norigconss;
1964
1965 origconss = SCIPgetOrigConss(scip);
1966 norigconss = SCIPgetNOrigConss(scip);
1967
1968 /* allocate memory for all possible and-constraints */
1969 SCIP_CALL( SCIPallocBufferArray(scip, &andconss, norigconss) );
1970
1971 /* collect all original and-constraints */
1972 for( c = norigconss - 1; c >= 0; --c )
1973 {
1974 conshdlr = SCIPconsGetHdlr(origconss[c]);
1975 assert( conshdlr != NULL );
1976
1977 if( strcmp(SCIPconshdlrGetName(conshdlr), "and") == 0 )
1978 {
1979 andconss[nandconss] = origconss[c];
1980 ++nandconss;
1981 }
1982 }
1983 }
1984 else
1985 {
1986 nandconss = SCIPconshdlrGetNConss(conshdlr);
1987 andconss = SCIPconshdlrGetConss(conshdlr);
1988 }
1989
1990 assert(andconss != NULL || nandconss == 0);
1991
1992 *nresvars = nandconss;
1993
1994 if( nandconss > 0 )
1995 {
1996 *existands = TRUE;
1997
1998 assert(andconss != NULL);
1999
2000 SCIP_CALL( SCIPallocMemoryArray(scip, resvars, *nresvars) );
2001 SCIP_CALL( SCIPallocMemoryArray(scip, andvars, *nresvars) );
2002 SCIP_CALL( SCIPallocMemoryArray(scip, nandvars, *nresvars) );
2003
2004 /* collect all and-constraint variables */
2005 for( c = nandconss - 1; c >= 0; --c )
2006 {
2007 SCIP_VAR** scipandvars;
2008
2009 assert(andconss[c] != NULL);
2010
2011 scipandvars = SCIPgetVarsAnd(scip, andconss[c]);
2012 (*nandvars)[c] = SCIPgetNVarsAnd(scip, andconss[c]);
2013 SCIP_CALL( SCIPduplicateMemoryArray(scip, &((*andvars)[c]), scipandvars, (*nandvars)[c]) ); /*lint !e866 */
2014 SCIP_CALL( getBinVarsRepresentatives(scip, (*andvars)[c], (*nandvars)[c], transformed) );
2015
2016 (*resvars)[c] = SCIPgetResultantAnd(scip, andconss[c]);
2017
2018 assert((*andvars)[c] != NULL && (*nandvars)[c] > 0);
2019 assert((*resvars)[c] != NULL);
2020 }
2021
2022 /* sorted the array */
2023 SCIPsortPtrPtrInt((void**)(*resvars), (void**)(*andvars), (*nandvars), SCIPvarComp, (*nresvars));
2024 }
2025 else
2026 *existands = FALSE;
2027
2028 SCIP_CALL( SCIPallocBufferArray(scip, &shouldnotbeinand, *nresvars) );
2029
2030 /* check that all and-constraints doesn't contain any and-resultants, if they do try to resolve this */
2031 /* attention: if resolving leads to x = x*y*... , we can't do anything here ( this only means (... >=x and) y >= x, so normally the and-constraint needs to be
2032 deleted and the inequality from before needs to be added ) */
2033 assert(*nandvars != NULL || *nresvars == 0);
2034 for( r = *nresvars - 1; r >= 0; --r )
2035 {
2036 ncontainedands = 0;
2037 shouldnotbeinand[ncontainedands] = r;
2038 ++ncontainedands;
2039 v = 0;
2040
2041 assert(*nandvars != NULL);
2042 while( v < (*nandvars)[r] )
2043 {
2044 assert(*andvars != NULL);
2045 assert(*resvars != NULL);
2046 if( SCIPsortedvecFindPtr((void**)(*resvars), SCIPvarComp, (*andvars)[r][v], *nresvars, &pos) )
2047 {
2048 /* check if the found position "pos" is equal to an already visited and resultant in this constraint,
2049 * than here could exist a directed cycle
2050 */
2051 /* better use tarjan's algorithm
2052 * <http://algowiki.net/wiki/index.php?title=Tarjan%27s_algorithm>,
2053 * <http://en.wikipedia.org/wiki/Tarjan%E2%80%99s_strongly_connected_components_algorithm>
2054 * because it could be that the same resultant is part of this and-constraint and than it would fail
2055 * without no cycle
2056 * Note1: tarjans standard algorithm doesn't find cycle from one node to the same;
2057 * Note2: when tarjan's algorithm find a cycle, it's still possible that this cycle is not "real" e.g.
2058 * y = y ~y z (z can also be a product) where y = 0 follows and therefor only "0 = z" is necessary
2059 */
2060 for( a = ncontainedands - 1; a >= 0; --a )
2061 if( shouldnotbeinand[a] == pos )
2062 {
2063 SCIPwarningMessage(scip, "This should not happen here. The and-constraint with resultant variable: ");
2064 SCIP_CALL( SCIPprintVar(scip, (*resvars)[r], NULL) );
2065 SCIPwarningMessage(scip, "possible contains a loop with and-resultant:");
2066 SCIP_CALL( SCIPprintVar(scip, (*resvars)[pos], NULL) );
2067
2068 /* free memory iff necessary */
2069 SCIPfreeBufferArray(scip, &shouldnotbeinand);
2070 if( !transformed )
2071 {
2072 SCIPfreeBufferArray(scip, &andconss);
2073 }
2074 return SCIP_INVALIDDATA;
2075 }
2076 SCIPdebugMsg(scip, "Another and-constraint contains and-resultant:");
2077 SCIPdebug( SCIP_CALL( SCIPprintVar(scip, (*resvars)[pos], NULL) ) );
2078 SCIPdebugMsg(scip, "Trying to resolve.\n");
2079
2080 shouldnotbeinand[ncontainedands] = pos;
2081 ++ncontainedands;
2082
2083 /* try to resolve containing ands */
2084
2085 /* resize array and number of variables */
2086 (*nandvars)[r] = (*nandvars)[r] + (*nandvars)[pos] - 1;
2087 SCIP_CALL( SCIPreallocMemoryArray(scip, &((*andvars)[r]), (*nandvars)[r]) ); /*lint !e866 */
2088
2089 /* copy all variables */
2090 for( a = (*nandvars)[pos] - 1; a >= 0; --a )
2091 (*andvars)[r][(*nandvars)[r] - a - 1] = (*andvars)[pos][a];
2092
2093 /* check same position with new variable, so we do not increase v */
2094 }
2095 else
2096 ++v;
2097 }
2098 }
2099 SCIPfreeBufferArray(scip, &shouldnotbeinand);
2100
2101 /* free memory iff necessary */
2102 if( !transformed )
2103 {
2104 SCIPfreeBufferArray(scip, &andconss);
2105 }
2106 }
2107 else
2108 {
2109 SCIPdebugMsg(scip, "found no and-constraint-handler\n");
2110 *existands = FALSE;
2111 *existandconshdlr = FALSE;
2112 }
2113
2114 return SCIP_OKAY;
2115 }
2116
2117 /** clears the given line buffer */
2118 static
2119 void clearBuffer(
2120 char* linebuffer, /**< line */
2121 int* linecnt /**< number of characters in line */
2122 )
2123 {
2124 assert( linebuffer != NULL );
2125 assert( linecnt != NULL );
2126
2127 (*linecnt) = 0;
2128 linebuffer[0] = '\0';
2129 }
2130
2131
2132 /** ends the given line with '\\0' and prints it to the given file stream */
2133 static
2134 void writeBuffer(
2135 SCIP* scip, /**< SCIP data structure */
2136 FILE* file, /**< output file (or NULL for standard output) */
2137 char* linebuffer, /**< line */
2138 int* linecnt /**< number of characters in line */
2139 )
2140 {
2141 assert( scip != NULL );
2142 assert( linebuffer != NULL );
2143 assert( linecnt != NULL );
2144 assert( 0 <= *linecnt && *linecnt < OPB_MAX_LINELEN );
2145
2146 if( (*linecnt) > 0 )
2147 {
2148 linebuffer[(*linecnt)] = '\0';
2149 SCIPinfoMessage(scip, file, "%s", linebuffer);
2150 clearBuffer(linebuffer, linecnt);
2151 }
2152 }
2153
2154
2155 /** appends extension to line and prints it to the give file stream if the line buffer get full */
2156 static
2157 void appendBuffer(
2158 SCIP* scip, /**< SCIP data structure */
2159 FILE* file, /**< output file (or NULL for standard output) */
2160 char* linebuffer, /**< line buffer */
2161 int* linecnt, /**< number of characters in line */
2162 const char* extension /**< string to extent the line */
2163 )
2164 {
2165 assert(scip != NULL);
2166 assert(linebuffer != NULL);
2167 assert(linecnt != NULL);
2168 assert(extension != NULL);
2169
2170 if( (*linecnt) + (int) strlen(extension) >= OPB_MAX_LINELEN - 1 )
2171 writeBuffer(scip, file, linebuffer, linecnt);
2172
2173 /* append extension to linebuffer */
2174 (void) strncat(linebuffer, extension, OPB_MAX_LINELEN - (unsigned int)(*linecnt));
2175 (*linecnt) += (int) strlen(extension);
2176 }
2177
2178 /** write objective function */
2179 static
2180 SCIP_RETCODE writeOpbObjective(
2181 SCIP*const scip, /**< SCIP data structure */
2182 FILE*const file, /**< output file, or NULL if standard output should be used */
2183 SCIP_VAR**const vars, /**< array with active (binary) variables */
2184 int const nvars, /**< number of active variables in the problem */
2185 SCIP_VAR** const resvars, /**< array of resultant variables */
2186 int const nresvars, /**< number of resultant variables */
2187 SCIP_VAR**const*const andvars, /**< corresponding array of and-variables */
2188 int const*const nandvars, /**< array of numbers of corresponding and-variables */
2189 SCIP_OBJSENSE const objsense, /**< objective sense */
2190 SCIP_Real const objscale, /**< scalar applied to objective function; external objective value is
2191 * extobj = objsense * objscale * (intobj + objoffset) */
2192 SCIP_Real const objoffset, /**< objective offset from bound shifting and fixing */
2193 char const*const multisymbol, /**< the multiplication symbol to use between coefficient and variable */
2194 SCIP_Bool const existands, /**< does some and-constraints exist? */
2195 SCIP_Bool const transformed /**< TRUE iff problem is the transformed problem */
2196 )
2197 {
2198 SCIP_VAR* var;
2199 char linebuffer[OPB_MAX_LINELEN+1];
2200 char buffer[OPB_MAX_LINELEN];
2201 SCIP_Longint mult;
2202 SCIP_Bool objective;
2203 int v;
2204 int linecnt;
2205 int pos;
2206
2207 assert(scip != NULL);
2208 assert(file != NULL);
2209 assert(vars != NULL || nvars == 0);
2210 assert(resvars != NULL || nresvars == 0);
2211 assert(andvars != NULL || nandvars == NULL);
2212 assert(multisymbol != NULL);
2213
2214 mult = 1;
2215 objective = FALSE;
2216
2217 clearBuffer(linebuffer, &linecnt);
2218
2219 /* check if a objective function exits and compute the multiplier to
2220 * shift the coefficients to integers */
2221 for( v = 0; v < nvars; ++v )
2222 {
2223 var = vars[v]; /*lint !e613 */
2224
2225 #ifndef NDEBUG
2226 {
2227 /* in case the original problem has to be posted the variables have to be either "original" or "negated" */
2228 if( !transformed )
2229 assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL ||
2230 SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED );
2231 }
2232 #endif
2233
2234 /* we found a indicator variable so we assume this is a wbo file */
2235 if( strstr(SCIPvarGetName(var), INDICATORVARNAME) != NULL )
2236 {
2237 /* find the topcost linear inequality which gives us the maximal cost which could be violated by our
2238 * solution, which is an artificial constraint and print this at first
2239 *
2240 * @note: only linear constraint handler is enough in problem stage, otherwise it could be any upgraded linear
2241 * constraint which handles pure binary variables
2242 */
2243 SCIP_CONSHDLR* conshdlr;
2244 SCIP_CONS* topcostcons;
2245 SCIP_Bool printed;
2246
2247 printed = FALSE;
2248 topcostcons = SCIPfindCons(scip, TOPCOSTCONSNAME);
2249
2250 if( topcostcons != NULL )
2251 {
2252 conshdlr = SCIPconsGetHdlr(topcostcons);
2253 assert(conshdlr != NULL);
2254
2255 if( strcmp(SCIPconshdlrGetName(conshdlr), "linear") == 0 )
2256 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "soft: %g;\n", SCIPgetRhsLinear(scip, topcostcons));
2257 else if( strcmp(SCIPconshdlrGetName(conshdlr), "knapsack") == 0 )
2258 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "soft: %SCIP_LONGINT_FORMAT;\n",
2259 SCIPgetCapacityKnapsack(scip, topcostcons));
2260 else if( strcmp(SCIPconshdlrGetName(conshdlr), "setppc") == 0 )
2261 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "soft: 1;\n");
2262 else
2263 {
2264 SCIPABORT();
2265 return SCIP_INVALIDDATA; /*lint !e527 */
2266 }
2267 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2268 writeBuffer(scip, file, linebuffer, &linecnt);
2269 printed = TRUE;
2270 }
2271 /* following works only in transformed stage */
2272 else
2273 {
2274 /* first try linear constraints */
2275 conshdlr = SCIPfindConshdlr(scip, "linear");
2276
2277 if( conshdlr != NULL )
2278 {
2279 SCIP_CONS** conss;
2280 int nconss;
2281 int c;
2282
2283 conss = SCIPconshdlrGetConss(conshdlr);
2284 nconss = SCIPconshdlrGetNConss(conshdlr);
2285
2286 assert(conss != NULL || nconss == 0);
2287
2288 for( c = 0; c < nconss; ++c )
2289 {
2290 SCIP_VAR** linvars;
2291 int nlinvars;
2292 int w;
2293 SCIP_Bool topcostfound;
2294 SCIP_CONS* cons;
2295
2296 cons = conss[c]; /*lint !e613 */
2297 assert(cons != NULL);
2298
2299 linvars = SCIPgetVarsLinear(scip, cons);
2300 nlinvars = SCIPgetNVarsLinear(scip, cons);
2301
2302 assert(linvars != NULL || nlinvars == 0);
2303 topcostfound = FALSE;
2304
2305 for( w = 0; w < nlinvars; ++w )
2306 {
2307 if( strstr(SCIPvarGetName(linvars[w]), INDICATORVARNAME) != NULL ) /*lint !e613 */
2308 topcostfound = TRUE;
2309 else
2310 {
2311 assert(!topcostfound);
2312 topcostfound = FALSE;
2313 }
2314 }
2315
2316 if( topcostfound )
2317 {
2318 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "soft: %g;\n", SCIPgetRhsLinear(scip, cons));
2319 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2320 writeBuffer(scip, file, linebuffer, &linecnt);
2321 printed = TRUE;
2322 break;
2323 }
2324 }
2325 }
2326
2327 if( !printed )
2328 {
2329 /* second try knapsack constraints */
2330 conshdlr = SCIPfindConshdlr(scip, "knapsack");
2331
2332 if( conshdlr != NULL )
2333 {
2334 SCIP_CONS** conss;
2335 int nconss;
2336 int c;
2337
2338 conss = SCIPconshdlrGetConss(conshdlr);
2339 nconss = SCIPconshdlrGetNConss(conshdlr);
2340
2341 assert(conss != NULL || nconss == 0);
2342
2343 for( c = 0; c < nconss; ++c )
2344 {
2345 SCIP_VAR** topvars;
2346 int ntopvars;
2347 int w;
2348 SCIP_Bool topcostfound;
2349 SCIP_CONS* cons;
2350
2351 cons = conss[c]; /*lint !e613 */
2352 assert(cons != NULL);
2353
2354 topvars = SCIPgetVarsKnapsack(scip, cons);
2355 ntopvars = SCIPgetNVarsKnapsack(scip, cons);
2356
2357 assert(topvars != NULL || ntopvars == 0);
2358 topcostfound = FALSE;
2359
2360 for( w = 0; w < ntopvars; ++w )
2361 {
2362 if( strstr(SCIPvarGetName(topvars[w]), INDICATORVARNAME) != NULL ) /*lint !e613 */
2363 topcostfound = TRUE;
2364 else
2365 {
2366 assert(!topcostfound);
2367 topcostfound = FALSE;
2368 }
2369 }
2370
2371 if( topcostfound )
2372 {
2373 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "soft: %SCIP_LONGINT_FORMAT;\n",
|
(1) Event invalid_type: |
Argument "SCIPgetCapacityKnapsack(scip, cons)" to format specifier "%S" was expected to have type "wchar_t *" but has type "long long". [details] |
2374 SCIPgetCapacityKnapsack(scip, cons));
2375 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2376 writeBuffer(scip, file, linebuffer, &linecnt);
2377 printed = TRUE;
2378 break;
2379 }
2380 }
2381 }
2382 }
2383
2384 if( !printed )
2385 {
2386 /* third try setppc constraints */
2387 conshdlr = SCIPfindConshdlr(scip, "setppc");
2388
2389 if( conshdlr != NULL )
2390 {
2391 SCIP_CONS** conss;
2392 int nconss;
2393 int c;
2394
2395 conss = SCIPconshdlrGetConss(conshdlr);
2396 nconss = SCIPconshdlrGetNConss(conshdlr);
2397
2398 assert(conss != NULL || nconss == 0);
2399
2400 for( c = 0; c < nconss; ++c )
2401 {
2402 SCIP_VAR** topvars;
2403 int ntopvars;
2404 int w;
2405 SCIP_Bool topcostfound;
2406 SCIP_CONS* cons;
2407
2408 cons = conss[c]; /*lint !e613 */
2409 assert(cons != NULL);
2410
2411 topvars = SCIPgetVarsSetppc(scip, cons);
2412 ntopvars = SCIPgetNVarsSetppc(scip, cons);
2413
2414 assert(topvars != NULL || ntopvars == 0);
2415 topcostfound = FALSE;
2416
2417 for( w = 0; w < ntopvars; ++w )
2418 {
2419 if( strstr(SCIPvarGetName(topvars[w]), INDICATORVARNAME) != NULL ) /*lint !e613 */
2420 topcostfound = TRUE;
2421 else
2422 {
2423 assert(!topcostfound);
2424 topcostfound = FALSE;
2425 }
2426 }
2427
2428 if( topcostfound )
2429 {
2430 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "soft: 1;\n");
2431 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2432 writeBuffer(scip, file, linebuffer, &linecnt);
2433 printed = TRUE;
2434 break;
2435 }
2436 }
2437 }
2438 }
2439 }
2440
2441 /* no topcost constraint found, so print empty topcost line, which means there is no upper bound on violated soft constraints */
2442 if( !printed )
2443 {
2444 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "soft: ;\n");
2445 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2446 writeBuffer(scip, file, linebuffer, &linecnt);
2447 }
2448
2449 return SCIP_OKAY;
2450 }
2451
2452 if( !SCIPisZero(scip, SCIPvarGetObj(var)) )
2453 {
2454 objective = TRUE;
2455 while( !SCIPisIntegral(scip, SCIPvarGetObj(var) * mult) )
2456 {
2457 assert(mult * 10 > mult);
2458 mult *= 10;
2459 }
2460 }
2461 }
2462
2463 if( objective )
2464 {
2465 /* there exist a objective function*/
2466 SCIPinfoMessage(scip, file, "* Obj. scale : %.15g\n", objscale * mult);
2467 SCIPinfoMessage(scip, file, "* Obj. offset : %.15g\n", objoffset);
2468
2469 clearBuffer(linebuffer, &linecnt);
2470
2471 /* opb format supports only minimization; therefore, a maximization problem has to be converted */
2472 if( objsense == SCIP_OBJSENSE_MAXIMIZE )
2473 mult *= -1;
2474
2475 SCIPdebugMsg(scip, "print objective function multiplied with %" SCIP_LONGINT_FORMAT "\n", mult);
2476
2477 appendBuffer(scip, file, linebuffer, &linecnt, "min:");
2478
2479 #ifndef NDEBUG
2480 if( existands )
2481 {
2482 int c;
2483 /* check that these variables are sorted */
2484 for( c = nresvars - 1; c > 0; --c )
2485 assert(SCIPvarGetIndex(resvars[c]) >= SCIPvarGetIndex(resvars[c - 1])); /*lint !e613 */
2486 }
2487 #endif
2488
2489 for( v = nvars - 1; v >= 0; --v )
2490 {
2491 SCIP_Bool negated;
2492 var = vars[v]; /*lint !e613 */
2493
2494 assert(var != NULL);
2495
2496 if( SCIPisZero(scip, SCIPvarGetObj(var)) )
2497 continue;
2498
2499 negated = SCIPvarIsNegated(var);
2500
2501 assert( linecnt != 0 );
2502
2503 if( SCIPvarGetObj(var) * mult > (SCIP_Real)SCIP_LONGINT_MAX )
2504 {
2505 SCIPerrorMessage("Integral objective value to big (mult = %" SCIP_LONGINT_FORMAT ", value = %g, mult*value = %g, printingvalue = %" SCIP_LONGINT_FORMAT ")for printing in opb format.\n", mult, SCIPvarGetObj(var), SCIPvarGetObj(var) * mult, (SCIP_Longint) SCIPround(scip, SCIPvarGetObj(var) * mult));
2506 }
2507
2508 /* replace and-resultant with corresponding variables */
2509 if( existands && SCIPsortedvecFindPtr((void**)resvars, SCIPvarComp, var, nresvars, &pos) )
2510 {
2511 int a;
2512
2513 assert(andvars != NULL);
2514 assert(nandvars != NULL);
2515 assert(pos >= 0 && nandvars[pos] > 0 && andvars[pos] != NULL);
2516 assert(andvars[pos][nandvars[pos] - 1] != NULL);
2517
2518 negated = SCIPvarIsNegated(andvars[pos][nandvars[pos] - 1]);
2519
2520 /* print and-vars */
2521 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, " %+" SCIP_LONGINT_FORMAT "%s%s%s",
2522 (SCIP_Longint) (SCIPvarGetObj(var) * mult), multisymbol, negated ? "~" : "",
2523 strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(andvars[pos][nandvars[pos] - 1]) : andvars[pos][nandvars[pos] - 1]), "x"));
2524 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2525
2526 for(a = nandvars[pos] - 2; a >= 0; --a )
2527 {
2528 negated = SCIPvarIsNegated(andvars[pos][a]);
2529
2530 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%s%s%s", multisymbol, negated ? "~" : "", strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(andvars[pos][a]) : andvars[pos][a]), "x"));
2531 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2532 }
2533 }
2534 else
2535 {
2536 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, " %+" SCIP_LONGINT_FORMAT "%s%s%s",
2537 (SCIP_Longint) (SCIPvarGetObj(var) * mult), multisymbol, negated ? "~" : "", strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(var) : var), "x"));
2538 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2539 }
2540 }
2541
2542 /* and objective function line ends with a ';' */
2543 appendBuffer(scip, file, linebuffer, &linecnt, " ;\n");
2544 writeBuffer(scip, file, linebuffer, &linecnt);
2545 }
2546
2547 return SCIP_OKAY;
2548 }
2549
2550 /* print maybe non linear row in OPB format to file stream */
2551 static
2552 SCIP_RETCODE printNLRow(
2553 SCIP*const scip, /**< SCIP data structure */
2554 FILE*const file, /**< output file (or NULL for standard output) */
2555 char const*const type, /**< row type ("=" or ">=") */
2556 SCIP_VAR**const vars, /**< array of variables */
2557 SCIP_Real const*const vals, /**< array of values */
2558 int const nvars, /**< number of variables */
2559 SCIP_Real lhs, /**< left hand side */
2560 SCIP_VAR** const resvars, /**< array of resultant variables */
2561 int const nresvars, /**< number of resultant variables */
2562 SCIP_VAR**const*const andvars, /**< corresponding array of and-variables */
2563 int const*const nandvars, /**< array of numbers of corresponding and-variables */
2564 SCIP_Longint weight, /**< if we found a soft constraint this is the weight, otherwise 0 */
2565 SCIP_Longint*const mult, /**< multiplier for the coefficients */
2566 char const*const multisymbol /**< the multiplication symbol to use between coefficient and variable */
2567 )
2568 {
2569 SCIP_VAR* var;
2570 char buffer[OPB_MAX_LINELEN];
2571 char linebuffer[OPB_MAX_LINELEN + 1];
2572 int v;
2573 int pos;
2574 int linecnt;
2575
2576 assert(scip != NULL);
2577 assert(strcmp(type, "=") == 0 || strcmp(type, ">=") == 0);
2578 assert(mult != NULL);
2579 assert(resvars != NULL);
2580 assert(nresvars > 0);
2581 assert(andvars != NULL && nandvars != NULL);
2582
2583 clearBuffer(linebuffer, &linecnt);
2584
2585 /* check if all coefficients are internal; if not commentstart multiplier */
2586 for( v = 0; v < nvars; ++v )
2587 {
2588 while( !SCIPisIntegral(scip, vals[v] * (*mult)) )
2589 {
2590 if( ABS(*mult) > ABS(*mult * 10) )
2591 return SCIP_INVALIDDATA;
2592 (*mult) *= 10;
2593 }
2594 }
2595
2596 while( !SCIPisIntegral(scip, lhs * (*mult)) )
2597 {
2598 if( ABS(*mult) > ABS(*mult * 10) )
2599 return SCIP_INVALIDDATA;
2600 (*mult) *= 10;
2601 }
2602
2603 /* print comment line if we have to multiply the coefficients to get integrals */
2604 if( ABS(*mult) != 1 )
2605 SCIPinfoMessage(scip, file, "* the following constraint is multiplied by %" SCIP_LONGINT_FORMAT " to get integral coefficients\n", ABS(*mult) );
2606
2607 #ifndef NDEBUG
2608 /* check that these variables are sorted */
2609 for( v = nresvars - 1; v > 0; --v )
2610 assert(SCIPvarGetIndex(resvars[v]) >= SCIPvarGetIndex(resvars[v - 1]));
2611 #endif
2612
2613 /* if we have a soft constraint print the weight*/
2614 if( weight != 0 )
2615 {
2616 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "[%+" SCIP_LONGINT_FORMAT "] ", weight);
2617 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2618 }
2619
2620 /* print coefficients */
2621 for( v = 0; v < nvars; ++v )
2622 {
2623 SCIP_Bool negated;
2624
2625 var = vars[v];
2626 assert( var != NULL );
2627
2628 negated = SCIPvarIsNegated(var);
2629
2630 /* replace and-resultant with corresponding variables */
2631 if( SCIPsortedvecFindPtr((void**)resvars, SCIPvarComp, var, nresvars, &pos) )
2632 {
2633 int a;
2634
2635 assert(andvars != NULL);
2636 assert(nandvars != NULL);
2637 assert(pos >= 0 && nandvars[pos] > 0 && andvars[pos] != NULL);
2638 assert(andvars[pos][nandvars[pos] - 1] != NULL);
2639
2640 negated = SCIPvarIsNegated(andvars[pos][nandvars[pos] - 1]);
2641
2642 if( vals[v] * (*mult) > (SCIP_Real)SCIP_LONGINT_MAX )
2643 {
2644 SCIPerrorMessage("Integral coefficient to big (mult = %" SCIP_LONGINT_FORMAT ", value = %g, mult*value = %g, printingvalue = %" SCIP_LONGINT_FORMAT ")for printing in opb format.\n", *mult, vals[v], vals[v] * (*mult), (SCIP_Longint) SCIPround(scip, vals[v] * (*mult)));
2645 }
2646
2647 /* print and-vars */
2648 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%+" SCIP_LONGINT_FORMAT "%s%s%s",
2649 (SCIP_Longint) SCIPround(scip, vals[v] * (*mult)), multisymbol, negated ? "~" : "",
2650 strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(andvars[pos][nandvars[pos] - 1]) : andvars[pos][nandvars[pos] - 1]), "x") );
2651 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2652
2653 for(a = nandvars[pos] - 2; a >= 0; --a )
2654 {
2655 negated = SCIPvarIsNegated(andvars[pos][a]);
2656
2657 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%s%s%s", multisymbol, negated ? "~" : "", strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(andvars[pos][a]) : andvars[pos][a]), "x"));
2658 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2659 }
2660
2661 appendBuffer(scip, file, linebuffer, &linecnt, " ");
2662 }
2663 else
2664 {
2665 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%+" SCIP_LONGINT_FORMAT "%s%s%s ",
2666 (SCIP_Longint) SCIPround(scip, vals[v] * (*mult)), multisymbol, negated ? "~" : "", strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(var) : var), "x"));
2667 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2668 }
2669 }
2670
2671 /* print left hand side */
2672 if( SCIPisZero(scip, lhs) )
2673 lhs = 0.0;
2674
2675 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%s %" SCIP_LONGINT_FORMAT " ;\n", type, (SCIP_Longint) (lhs * (*mult)) );
2676 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2677
2678 writeBuffer(scip, file, linebuffer, &linecnt);
2679
2680 return SCIP_OKAY;
2681 }
2682
2683
2684 /** prints given maybe non-linear constraint information in OPB format to file stream */
2685 static
2686 SCIP_RETCODE printNonLinearCons(
2687 SCIP*const scip, /**< SCIP data structure */
2688 FILE*const file, /**< output file (or NULL for standard output) */
2689 SCIP_VAR**const vars, /**< array of variables */
2690 SCIP_Real*const vals, /**< array of coefficients values (or NULL if all coefficient values are 1) */
2691 int const nvars, /**< number of variables */
2692 SCIP_Real const lhs, /**< left hand side */
2693 SCIP_Real const rhs, /**< right hand side */
2694 SCIP_VAR** const resvars, /**< array of resultant variables */
2695 int const nresvars, /**< number of resultant variables */
2696 SCIP_VAR**const*const andvars, /**< corresponding array of and-variables */
2697 int const*const nandvars, /**< array of numbers of corresponding and-variables */
2698 SCIP_Longint weight, /**< if we found a soft constraint this is the weight, otherwise 0 */
2699 SCIP_Bool const transformed, /**< transformed constraint? */
2700 char const*const multisymbol /**< the multiplication symbol to use between coefficient and variable */
2701 )
2702 {
2703 SCIP_VAR** activevars;
2704 SCIP_Real* activevals;
2705 SCIP_Real activeconstant;
2706 SCIP_Longint mult;
2707 SCIP_RETCODE retcode;
2708 int v;
2709 int nactivevars;
2710
2711 assert(scip != NULL);
2712 assert(vars != NULL);
2713 assert(nvars > 0);
2714 assert(lhs <= rhs);
2715 assert(resvars != NULL);
2716 assert(nresvars > 0);
2717 assert(andvars != NULL && nandvars != NULL);
2718
2719 if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
2720 return SCIP_OKAY;
2721
2722 activeconstant = 0.0;
2723 nactivevars = nvars;
2724
2725 /* duplicate variable and value array */
2726 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars ) );
2727 if( vals != NULL )
2728 {
2729 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars ) );
2730 }
2731 else
2732 {
2733 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) );
2734
2735 for( v = 0; v < nactivevars; ++v )
2736 activevals[v] = 1.0;
2737 }
2738
2739 /* retransform given variables to active variables */
2740 SCIP_CALL( getActiveVariables(scip, activevars, activevals, &nactivevars, &activeconstant, transformed) );
2741
2742 mult = 1;
2743 retcode = SCIP_OKAY;
2744
2745 /* print row(s) in OPB format */
2746 if( SCIPisEQ(scip, lhs, rhs) )
2747 {
2748 assert( !SCIPisInfinity(scip, rhs) );
2749
2750 /* equality constraint */
2751 retcode = printNLRow(scip, file, "=", activevars, activevals, nactivevars, rhs - activeconstant, resvars,
2752 nresvars, andvars, nandvars, weight, &mult, multisymbol);
2753 }
2754 else
2755 {
2756 if( !SCIPisInfinity(scip, -lhs) )
2757 {
2758 /* print inequality ">=" */
2759 retcode = printNLRow(scip, file, ">=", activevars, activevals, nactivevars, lhs - activeconstant, resvars,
2760 nresvars, andvars, nandvars, weight, &mult, multisymbol);
2761 }
2762
2763 if( !SCIPisInfinity(scip, rhs) )
2764 {
2765 mult *= -1;
2766
2767 /* print inequality ">=" and multiplying all coefficients by -1 */
2768 retcode = printNLRow(scip, file, ">=", activevars, activevals, nactivevars, rhs - activeconstant, resvars,
2769 nresvars, andvars, nandvars, weight, &mult, multisymbol);
2770 }
2771 }
2772
2773 /* free buffer arrays */
2774 SCIPfreeBufferArray(scip, &activevars);
2775 SCIPfreeBufferArray(scip, &activevals);
2776
2777 return retcode;
2778 }
2779
2780
2781 /* print row in OPB format to file stream */
2782 static
2783 SCIP_RETCODE printRow(
2784 SCIP* scip, /**< SCIP data structure */
2785 FILE* file, /**< output file (or NULL for standard output) */
2786 const char* type, /**< row type ("=" or ">=") */
2787 SCIP_VAR** vars, /**< array of variables */
2788 SCIP_Real* vals, /**< array of values */
2789 int nvars, /**< number of variables */
2790 SCIP_Real lhs, /**< left hand side */
2791 SCIP_Longint weight, /**< if we found a soft constraint this is the weight, otherwise 0 */
2792 SCIP_Longint* mult, /**< multiplier for the coefficients */
2793 const char* multisymbol /**< the multiplication symbol to use between coefficient and variable */
2794 )
2795 {
2796 SCIP_VAR* var;
2797 char buffer[OPB_MAX_LINELEN];
2798 char linebuffer[OPB_MAX_LINELEN + 1];
2799 int v;
2800 int linecnt;
2801
2802 assert(scip != NULL);
2803 assert(strcmp(type, "=") == 0 || strcmp(type, ">=") == 0);
2804 assert(mult != NULL);
2805
2806 clearBuffer(linebuffer, &linecnt);
2807
2808 /* if we found the topcost linear inequality which gives us the maximal cost which could be violated by our solution,
2809 * we can stop printing because it is an artificial constraint
2810 */
2811 if( nvars > 0 && strstr(SCIPvarGetName(vars[0]), INDICATORVARNAME) != NULL )
2812 return SCIP_OKAY;
2813
2814 /* check if all coefficients are integral; if not commentstart multiplier */
2815 for( v = 0; v < nvars; ++v )
2816 {
2817 while( !SCIPisIntegral(scip, vals[v] * (*mult)) )
2818 {
2819 if( ABS(*mult) > ABS(*mult * 10) )
2820 return SCIP_INVALIDDATA;
2821 (*mult) *= 10;
2822 }
2823 }
2824
2825 while( !SCIPisIntegral(scip, lhs * (*mult)) )
2826 {
2827 if( ABS(*mult) > ABS(*mult * 10) )
2828 return SCIP_INVALIDDATA;
2829 (*mult) *= 10;
2830 }
2831
2832 /* print comment line if we have to multiply the coefficients to get integrals */
2833 if( ABS(*mult) != 1 )
2834 SCIPinfoMessage(scip, file, "* the following constraint is multiplied by %" SCIP_LONGINT_FORMAT " to get integral coefficients\n", ABS(*mult) );
2835
2836 /* if we have a soft constraint print the weight*/
2837 if( weight != 0 )
2838 {
2839 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "[%+" SCIP_LONGINT_FORMAT "] ", weight);
2840 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2841 }
2842
2843 /* print coefficients */
2844 for( v = 0; v < nvars; ++v )
2845 {
2846 SCIP_Bool negated;
2847
2848 var = vars[v];
2849 assert( var != NULL );
2850
2851 negated = SCIPvarIsNegated(var);
2852
2853 if( vals[v] * (*mult) > (SCIP_Real)SCIP_LONGINT_MAX )
2854 {
2855 SCIPerrorMessage("Integral coefficient to big (mult = %" SCIP_LONGINT_FORMAT ", value = %g, mult*value = %g, printingvalue = %" SCIP_LONGINT_FORMAT ")for printing in opb format.\n", *mult, vals[v], vals[v] * (*mult), (SCIP_Longint) SCIPround(scip, vals[v] * (*mult)));
2856 }
2857
2858 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%+" SCIP_LONGINT_FORMAT "%s%s%s ",
2859 (SCIP_Longint) SCIPround(scip, vals[v] * (*mult)), multisymbol, negated ? "~" : "", strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(var) : var), "x"));
2860 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2861 }
2862
2863 /* print left hand side */
2864 if( SCIPisZero(scip, lhs) )
2865 lhs = 0.0;
2866
2867 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%s %" SCIP_LONGINT_FORMAT " ;\n", type, (SCIP_Longint) (lhs * (*mult)) );
2868 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
2869
2870 writeBuffer(scip, file, linebuffer, &linecnt);
2871
2872 return SCIP_OKAY;
2873 }
2874
2875
2876 /** prints given linear constraint information in OPB format to file stream */
2877 static
2878 SCIP_RETCODE printLinearCons(
2879 SCIP* scip, /**< SCIP data structure */
2880 FILE* file, /**< output file (or NULL for standard output) */
2881 SCIP_VAR** vars, /**< array of variables */
2882 SCIP_Real* vals, /**< array of coefficients values (or NULL if all coefficient values are 1) */
2883 int nvars, /**< number of variables */
2884 SCIP_Real lhs, /**< left hand side */
2885 SCIP_Real rhs, /**< right hand side */
2886 SCIP_Longint weight, /**< if we found a soft constraint this is the weight, otherwise 0 */
2887 SCIP_Bool transformed, /**< transformed constraint? */
2888 const char* multisymbol /**< the multiplication symbol to use between coefficient and variable */
2889 )
2890 {
2891 SCIP_VAR** activevars;
2892 SCIP_Real* activevals;
2893 int nactivevars;
2894 SCIP_Real activeconstant;
2895 SCIP_Longint mult;
2896 SCIP_RETCODE retcode;
2897 int v;
2898
2899 assert( scip != NULL );
2900 assert( vars != NULL );
2901 assert( nvars > 0 );
2902 assert( lhs <= rhs );
2903
2904 if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
2905 return SCIP_OKAY;
2906
2907 activeconstant = 0.0;
2908
2909 /* duplicate variable and value array */
2910 nactivevars = nvars;
2911 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars ) );
2912 if( vals != NULL )
2913 {
2914 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars ) );
2915 }
2916 else
2917 {
2918 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) );
2919
2920 for( v = 0; v < nactivevars; ++v )
2921 activevals[v] = 1.0;
2922 }
2923
2924 /* retransform given variables to active variables */
2925 SCIP_CALL( getActiveVariables(scip, activevars, activevals, &nactivevars, &activeconstant, transformed) );
2926
2927 mult = 1;
2928 retcode = SCIP_OKAY;
2929
2930 /* print row(s) in OPB format */
2931 if( SCIPisEQ(scip, lhs, rhs) )
2932 {
2933 assert( !SCIPisInfinity(scip, rhs) );
2934
2935 /* equality constraint */
2936 retcode = printRow(scip, file, "=", activevars, activevals, nactivevars, rhs - activeconstant, weight, &mult,
2937 multisymbol);
2938 }
2939 else
2940 {
2941 if( !SCIPisInfinity(scip, -lhs) )
2942 {
2943 /* print inequality ">=" */
2944 retcode = printRow(scip, file, ">=", activevars, activevals, nactivevars, lhs - activeconstant, weight, &mult,
2945 multisymbol);
2946 }
2947
2948 if( !SCIPisInfinity(scip, rhs) )
2949 {
2950 mult *= -1;
2951
2952 /* print inequality ">=" and multiplying all coefficients by -1 */
2953 retcode = printRow(scip, file, ">=", activevars, activevals, nactivevars, rhs - activeconstant, weight, &mult,
2954 multisymbol);
2955 }
2956 }
2957
2958 /* free buffer arrays */
2959 SCIPfreeBufferArray(scip, &activevars);
2960 SCIPfreeBufferArray(scip, &activevals);
2961
2962 return retcode;
2963 }
2964
2965 /* print row in OPB format to file stream */
2966 static
2967 SCIP_RETCODE printPBRow(
2968 SCIP*const scip, /**< SCIP data structure */
2969 FILE*const file, /**< output file (or NULL for standard output) */
2970 const char* type, /**< row type ("=" or ">=") */
2971 SCIP_VAR**const linvars, /**< array of variables */
2972 SCIP_Real*const linvals, /**< array of values */
2973 int const nlinvars, /**< number of variables */
2974 SCIP_VAR***const termvars, /**< term array with array of variables to print */
2975 int*const ntermvars, /**< array with number of variables in each term */
2976 SCIP_Real*const termvals, /**< array of coefficient values for non-linear variables */
2977 int const ntermvals, /**< number non-linear variables in the problem */
2978 SCIP_Bool**const negatedarrays, /**< array of arrays to know which variable in a non-linear part is negated */
2979 SCIP_VAR*const indvar, /**< indicator variable, or NULL */
2980 SCIP_Real lhs, /**< left hand side */
2981 SCIP_Longint* mult, /**< multiplier for the coefficients */
2982 const char* multisymbol /**< the multiplication symbol to use between coefficient and variable */
2983 )
2984 {
2985 SCIP_VAR* var;
2986 char buffer[OPB_MAX_LINELEN];
2987 char linebuffer[OPB_MAX_LINELEN + 1];
2988 int v;
2989 int t;
2990 int linecnt;
2991
2992 assert(scip != NULL);
2993 assert(strcmp(type, "=") == 0 || strcmp(type, ">=") == 0);
2994 assert(linvars != NULL || nlinvars == 0);
2995 assert(linvals != NULL || nlinvars == 0);
2996 assert(termvars != NULL || ntermvals == 0);
2997 assert(ntermvars != NULL || ntermvals == 0);
2998 assert(termvals != NULL || ntermvals == 0);
2999 assert(negatedarrays != NULL || ntermvals == 0);
3000 assert(mult != NULL);
3001
3002 clearBuffer(linebuffer, &linecnt);
3003
3004 /* if we found the topcost linear inequality which gives us the maximal cost which could be violated by our solution,
3005 * we can stop printing because it is an artificial constraint
3006 */
3007 if( ntermvals == 0 && nlinvars > 0 && strstr(SCIPvarGetName(linvars[0]), INDICATORVARNAME) != NULL ) /*lint !e613 */
3008 return SCIP_OKAY;
3009
3010 /* check if all linear coefficients are internal; if not commentstart multiplier */
3011 for( v = 0; v < nlinvars; ++v )
3012 {
3013 while( !SCIPisIntegral(scip, linvals[v] * (*mult)) ) /*lint !e613 */
3014 {
3015 if( ABS(*mult) > ABS(*mult * 10) )
3016 return SCIP_INVALIDDATA;
3017 (*mult) *= 10;
3018 }
3019 }
3020
3021 /* check if all non-linear coefficients are internal; if not commentstart multiplier */
3022 for( v = 0; v < ntermvals; ++v )
3023 {
3024 while( !SCIPisIntegral(scip, termvals[v] * (*mult)) ) /*lint !e613 */
3025 {
3026 if( ABS(*mult) > ABS(*mult * 10) )
3027 return SCIP_INVALIDDATA;
3028 (*mult) *= 10;
3029 }
3030 }
3031
3032 while( !SCIPisIntegral(scip, lhs * (*mult)) )
3033 {
3034 if( ABS(*mult) > ABS(*mult * 10) )
3035 return SCIP_INVALIDDATA;
3036 (*mult) *= 10;
3037 }
3038
3039 /* print comment line if we have to multiply the coefficients to get integrals */
3040 if( ABS(*mult) != 1 )
3041 SCIPinfoMessage(scip, file, "* the following constraint is multiplied by %" SCIP_LONGINT_FORMAT " to get integral coefficients\n", ABS(*mult) );
3042
3043 /* if indicator variable exist we have a soft constraint */
3044 if( indvar != NULL )
3045 {
3046 SCIP_Real weight;
3047
3048 weight = SCIPvarGetObj(indvar);
3049 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "[%+g] ", weight);
3050 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
3051 }
3052
3053 /* print linear part */
3054 for( v = 0; v < nlinvars; ++v )
3055 {
3056 SCIP_Bool negated;
3057
3058 var = linvars[v]; /*lint !e613 */
3059 assert(var != NULL);
3060
3061 negated = SCIPvarIsNegated(var);
3062
3063 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%+" SCIP_LONGINT_FORMAT "%s%s%s ",
3064 (SCIP_Longint) SCIPround(scip, linvals[v] * (*mult)), multisymbol, negated ? "~" : "", strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(var) : var), "x")); /*lint !e613 */
3065 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
3066 }
3067
3068 /* print non-linear part */
3069 for( t = 0; t < ntermvals; ++t )
3070 {
3071 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%+" SCIP_LONGINT_FORMAT, (SCIP_Longint) SCIPround(scip, termvals[t] * (*mult))); /*lint !e613 */
3072 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
3073
3074 for( v = 0; v < ntermvars[t]; ++v ) /*lint !e613 */
3075 {
3076 SCIP_Bool negated;
3077
3078 var = termvars[t][v]; /*lint !e613 */
3079 assert(var != NULL);
3080
3081 negated = negatedarrays[t][v]; /*lint !e613 */
3082
3083 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%s%s%s", multisymbol, negated ? "~" : "", strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(var) : var), "x"));
3084 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
3085 }
3086 appendBuffer(scip, file, linebuffer, &linecnt, " ");
3087 }
3088
3089 /* print left hand side */
3090 if( SCIPisZero(scip, lhs) )
3091 lhs = 0.0;
3092
3093 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%s %" SCIP_LONGINT_FORMAT " ;\n", type, (SCIP_Longint) (lhs * (*mult)) );
3094 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
3095
3096 writeBuffer(scip, file, linebuffer, &linecnt);
3097
3098 return SCIP_OKAY;
3099 }
3100
3101
3102 /** prints given pseudo boolean constraint information in OPB format to file stream */
3103 static
3104 SCIP_RETCODE printPseudobooleanCons(
3105 SCIP*const scip, /**< SCIP data structure */
3106 FILE*const file, /**< output file, or NULL if standard output should be used */
3107 SCIP_VAR**const linvars, /**< array with variables of linear part */
3108 SCIP_Real*const linvals, /**< array of coefficients values of linear part */
3109 int const nlinvars, /**< number variables in linear part of the problem */
3110 SCIP_VAR***const termvars, /**< term array with array of variables to print */
3111 int*const ntermvars, /**< array with number of variables in each term */
3112 SCIP_Real*const termvals, /**< array of coefficient values for non-linear variables */
3113 int const ntermvals, /**< number non-linear variables in the problem */
3114 SCIP_VAR*const indvar, /**< indicator variable, or NULL */
3115 SCIP_Real const lhs, /**< left hand side of constraint */
3116 SCIP_Real const rhs, /**< right hand side of constraint */
3117 SCIP_Bool transformed, /**< should the transformed problem be printed ? */
3118 const char* multisymbol /**< the multiplication symbol to use between coefficient and variable */
3119 )
3120 {
3121 SCIP_VAR*** activetermvars;
3122 SCIP_Bool** negatedarrays;
3123 SCIP_VAR** activelinvars;
3124 SCIP_Real* activelinvals;
3125 int nactivelinvars;
3126 SCIP_Real activelinconstant;
3127 SCIP_Longint mult;
3128 SCIP_RETCODE retcode;
3129 int v;
3130
3131 assert(scip != NULL);
3132 assert(linvars != NULL || nlinvars == 0);
3133 assert(linvals != NULL || nlinvars == 0);
3134 assert(termvars != NULL || 0 == ntermvals);
3135 assert(ntermvars != NULL || 0 == ntermvals);
3136 assert(termvals != NULL || 0 == ntermvals);
3137 assert(lhs <= rhs);
3138
3139 if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
3140 return SCIP_OKAY;
3141
3142 activelinconstant = 0.0;
3143
3144 /* duplicate variable and value array for linear part */
3145 nactivelinvars = nlinvars;
3146 if( nactivelinvars > 0 )
3147 {
3148 SCIP_CALL( SCIPduplicateBufferArray(scip, &activelinvars, linvars, nactivelinvars ) );
3149 SCIP_CALL( SCIPduplicateBufferArray(scip, &activelinvals, linvals, nactivelinvars ) );
3150
3151 /* retransform given variables to active variables */
3152 SCIP_CALL( getActiveVariables(scip, activelinvars, activelinvals, &nactivelinvars, &activelinconstant, transformed) );
3153 }
3154 else
3155 {
3156 activelinvars = NULL;
3157 activelinvals = NULL;
3158 }
3159
3160 /* create non-linear information for printing */
3161 if( ntermvals > 0 )
3162 {
3163 assert(termvars != NULL);
3164 assert(ntermvars != NULL);
3165 assert(termvals != NULL);
3166
3167 SCIP_CALL( SCIPallocBufferArray(scip, &activetermvars, ntermvals) );
3168 SCIP_CALL( SCIPallocBufferArray(scip, &negatedarrays, ntermvals) );
3169 for( v = ntermvals - 1; v >= 0; --v )
3170 {
3171 assert(ntermvars[v] > 0); /*lint !e613 */
3172
3173 if( transformed )
3174 {
3175 SCIP_CALL( SCIPallocBufferArray(scip, &(activetermvars[v]), ntermvars[v]) ); /*lint !e866 */
3176 SCIP_CALL( SCIPallocBufferArray(scip, &(negatedarrays[v]), ntermvars[v]) ); /*lint !e866 */
3177
3178 /* get binary representatives of binary variables in non-linear terms */
3179 SCIP_CALL( SCIPgetBinvarRepresentatives(scip, ntermvars[v], termvars[v], activetermvars[v], negatedarrays[v]) );
3180 }
3181 else
3182 {
3183 SCIP_CALL( SCIPduplicateBufferArray(scip, &(activetermvars[v]), termvars[v], ntermvars[v]) ); /*lint !e866 */
3184 SCIP_CALL( SCIPallocBufferArray(scip, &(negatedarrays[v]), ntermvars[v]) ); /*lint !e866 */
3185 BMSclearMemoryArray(negatedarrays[v], ntermvars[v]); /*lint !e866 */
3186 }
3187 }
3188 }
3189 else
3190 {
3191 activetermvars = NULL;
3192 negatedarrays = NULL;
3193 }
3194
3195 mult = 1;
3196 retcode = SCIP_OKAY;
3197
3198 /* print row(s) in OPB format */
3199 if( SCIPisEQ(scip, lhs, rhs) )
3200 {
3201 assert( !SCIPisInfinity(scip, rhs) );
3202
3203 /* equality constraint */
3204 retcode = printPBRow(scip, file, "=", activelinvars, activelinvals, nactivelinvars, activetermvars,
3205 ntermvars, termvals, ntermvals, negatedarrays, indvar, rhs - activelinconstant, &mult, multisymbol);
3206 }
3207 else
3208 {
3209 if( !SCIPisInfinity(scip, -lhs) )
3210 {
3211 /* print inequality ">=" */
3212 retcode = printPBRow(scip, file, ">=", activelinvars, activelinvals, nactivelinvars, activetermvars,
3213 ntermvars, termvals, ntermvals, negatedarrays, indvar, lhs - activelinconstant, &mult, multisymbol);
3214 }
3215
3216 if( !SCIPisInfinity(scip, rhs) )
3217 {
3218 mult *= -1;
3219
3220 /* print inequality ">=" and multiplying all coefficients by -1 */
3221 /* coverity[var_deref_model] */
3222 retcode = printPBRow(scip, file, ">=", activelinvars, activelinvals, nactivelinvars, activetermvars,
3223 ntermvars, termvals, ntermvals, negatedarrays, indvar, rhs - activelinconstant, &mult, multisymbol);
3224 }
3225 }
3226
3227 /* free buffers for non-linear arrays */
3228 if( ntermvals > 0 )
3229 {
3230 assert(negatedarrays != NULL);
3231 assert(activetermvars != NULL);
3232
3233 for( v = 0; v < ntermvals; ++v )
3234 {
3235 assert(negatedarrays[v] != NULL);
3236 assert(activetermvars[v] != NULL);
3237 SCIPfreeBufferArray(scip, &(negatedarrays[v]));
3238 SCIPfreeBufferArray(scip, &(activetermvars[v]));
3239 }
3240 SCIPfreeBufferArray(scip, &negatedarrays);
3241 SCIPfreeBufferArray(scip, &activetermvars);
3242 }
3243
3244 /* free buffer for linear arrays */
3245 if( nactivelinvars > 0 )
3246 {
3247 SCIPfreeBufferArray(scip, &activelinvars);
3248 SCIPfreeBufferArray(scip, &activelinvals);
3249 }
3250
3251 return retcode;
3252 }
3253
3254 /** determine total number of linear constraints split into lhs/rhs */
3255 static
3256 void determineTotalNumberLinearConss(
3257 SCIP*const scip, /**< SCIP data structure */
3258 SCIP_CONS**const conss, /**< array with constraints of the problem */
3259 int const nconss, /**< number of constraints in the problem */
3260 int* nlinearconss, /**< pointer to store the total number of linear constraints */
3261 int* nsplitlinearconss /**< pointer to store the total number of linear constraints split into lhs/rhs */
3262 )
3263 {
3264 SCIP_CONSHDLR* conshdlr;
3265 const char* conshdlrname;
3266 SCIP_CONS* cons;
3267 int c;
3268
3269 assert(scip != NULL);
3270 assert(conss != NULL || nconss == 0);
3271 assert(nlinearconss != NULL);
3272 assert(nsplitlinearconss != NULL);
3273
3274 *nlinearconss = 0;
3275 *nsplitlinearconss = 0;
3276
3277 /* loop over all constraints */
3278 for( c = 0; c < nconss; ++c )
3279 {
3280 cons = conss[c];
3281 assert(cons != NULL);
3282 conshdlr = SCIPconsGetHdlr(cons); /*lint !e613*/
3283 assert(conshdlr != NULL);
3284
3285 conshdlrname = SCIPconshdlrGetName(conshdlr);
3286
3287 if( strcmp(conshdlrname, "linear") == 0 )
3288 {
3289 if( ! SCIPisInfinity(scip, SCIPgetLhsLinear(scip, cons)) )
3290 ++(*nsplitlinearconss);
3291
3292 if( ! SCIPisInfinity(scip, SCIPgetRhsLinear(scip, cons)) )
3293 ++(*nsplitlinearconss);
3294
3295 ++(*nlinearconss);
3296 }
3297
3298 if( strcmp(conshdlrname, "varbound") == 0 )
3299 {
3300 if( ! SCIPisInfinity(scip, SCIPgetLhsVarbound(scip, cons)) )
3301 ++(*nsplitlinearconss);
3302
3303 if( ! SCIPisInfinity(scip, SCIPgetRhsVarbound(scip, cons)) )
3304 ++(*nsplitlinearconss);
3305
3306 ++(*nlinearconss);
3307 }
3308 }
3309 }
3310
3311 /** write constraints */
3312 static
3313 SCIP_RETCODE writeOpbConstraints(
3314 SCIP*const scip, /**< SCIP data structure */
3315 FILE*const file, /**< output file, or NULL if standard output should be used */
3316 SCIP_CONS**const conss, /**< array with constraints of the problem */
3317 int const nconss, /**< number of constraints in the problem */
3318 SCIP_VAR**const vars, /**< array with active (binary) variables */
3319 int const nvars, /**< number of active variables in the problem */
3320 SCIP_VAR** const resvars, /**< array of resultant variables */
3321 int const nresvars, /**< number of resultant variables */
3322 SCIP_VAR**const*const andvars, /**< corresponding array of and-variables */
3323 int const*const nandvars, /**< array of numbers of corresponding and-variables */
3324 char const*const multisymbol, /**< the multiplication symbol to use between coefficient and variable */
3325 SCIP_Bool const existandconshdlr, /**< does and-constrainthandler exist? */
3326 SCIP_Bool const existands, /**< does some and-constraints exist? */
3327 SCIP_Bool const transformed /**< TRUE iff problem is the transformed problem */
3328 )
3329 {
3330 SCIP_CONSHDLR* conshdlr;
3331 const char* conshdlrname;
3332 SCIP_CONS* cons;
3333 SCIP_VAR** consvars;
3334 SCIP_Real* consvals;
3335 SCIP_RETCODE retcode;
3336 int nconsvars;
3337 int v, c;
3338 SCIP_HASHMAP* linconssofindicatorsmap = NULL;
3339 SCIP_HASHMAP* linconssofpbsmap = NULL;
3340
3341 assert(scip != NULL);
3342 assert(file != NULL);
3343 assert(conss != NULL || nconss == 0);
3344 assert(vars != NULL || nvars == 0);
3345 assert(resvars != NULL || nresvars == 0);
3346 assert(andvars != NULL || nandvars == 0);
3347 assert(multisymbol != NULL);
3348
3349 if( transformed )
3350 {
3351 conshdlr = SCIPfindConshdlr(scip, "indicator");
3352
3353 /* find artificial linear constraints which correspond to indicator constraints to avoid double printing */
3354 if( conshdlr != NULL )
3355 {
3356 SCIP_CONS** indconss;
3357 int nindconss;
3358
3359 indconss = SCIPconshdlrGetConss(conshdlr);
3360 nindconss = SCIPconshdlrGetNConss(conshdlr);
3361 assert(indconss != NULL || nindconss == 0);
3362
3363 if( nindconss > 0 )
3364 {
3365 SCIP_CONS* lincons;
3366
3367 /* create the linear constraint of indicator constraints hash map */
3368 SCIP_CALL( SCIPhashmapCreate(&linconssofindicatorsmap, SCIPblkmem(scip), nindconss) );
3369 assert(indconss != NULL);
3370
3371 for( c = 0; c < nindconss; ++c )
3372 {
3373 assert(indconss[c] != NULL);
3374 lincons = SCIPgetLinearConsIndicator(indconss[c]);
3375 assert(lincons != NULL);
3376
3377 /* insert constraint into mapping between */
3378 SCIP_CALL( SCIPhashmapInsert(linconssofindicatorsmap, (void*)lincons, (void*)lincons) );
3379 }
3380 }
3381 }
3382
3383 conshdlr = SCIPfindConshdlr(scip, "pseudoboolean");
3384
3385 /* find artifical linear constraints which correspond to indicator constraints to avoid double printing */
3386 if( conshdlr != NULL )
3387 {
3388 SCIP_CONS** pbconss;
3389 int npbconss;
3390
3391 pbconss = SCIPconshdlrGetConss(conshdlr);
3392 npbconss = SCIPconshdlrGetNConss(conshdlr);
3393 assert(pbconss != NULL || npbconss == 0);
3394
3395 if( npbconss > 0 )
3396 {
3397 SCIP_CONS* lincons;
3398
3399 /* create the linear constraint of indicator constraints hash map */
3400 SCIP_CALL( SCIPhashmapCreate(&linconssofpbsmap, SCIPblkmem(scip), npbconss) );
3401
3402 for( c = 0; c < npbconss; ++c )
3403 {
3404 assert(pbconss[c] != NULL); /*lint !e613*/
3405 lincons = SCIPgetLinearConsPseudoboolean(scip, pbconss[c]); /*lint !e613*/
3406 assert(lincons != NULL);
3407
3408 /* insert constraint into mapping between */
3409 SCIP_CALL( SCIPhashmapInsert(linconssofpbsmap, (void*)lincons, (void*)lincons) );
3410 }
3411 }
3412 }
3413 }
3414 /* in original space we cannot ask the constraint handler for its constraints, therefore we have to loop over all
3415 * original to check for artificial linear once
3416 */
3417 else
3418 {
3419 SCIP_CONS* lincons;
3420 SCIP_Bool pbhashmapcreated = FALSE;
3421 SCIP_Bool indhashmapcreated = FALSE;
3422
3423 /* loop over all constraint for printing */
3424 for( c = 0; c < nconss; ++c )
3425 {
3426 conshdlr = SCIPconsGetHdlr(conss[c]); /*lint !e613*/
3427 assert(conshdlr != NULL);
3428
3429 conshdlrname = SCIPconshdlrGetName(conshdlr);
3430
3431 if( strcmp(conshdlrname, "pseudoboolean") == 0 )
3432 {
3433 if( !pbhashmapcreated )
3434 {
3435 /* create the linear constraint of indicator constraints hash map */
3436 SCIP_CALL( SCIPhashmapCreate(&linconssofpbsmap, SCIPblkmem(scip), nconss) );
3437 pbhashmapcreated = TRUE;
3438 }
3439
3440 lincons = SCIPgetLinearConsPseudoboolean(scip, conss[c]); /*lint !e613*/
3441 assert(lincons != NULL);
3442
3443 /* insert constraint into mapping between */
3444 SCIP_CALL( SCIPhashmapInsert(linconssofpbsmap, (void*)lincons, (void*)lincons) );
3445 }
3446 else if( strcmp(conshdlrname, "indicator") == 0 )
3447 {
3448 if( !indhashmapcreated )
3449 {
3450 /* create the linear constraint of indicator constraints hash map */
3451 SCIP_CALL( SCIPhashmapCreate(&linconssofindicatorsmap, SCIPblkmem(scip), nconss) );
3452 indhashmapcreated = TRUE;
3453 }
3454
3455 lincons = SCIPgetLinearConsIndicator(conss[c]); /*lint !e613*/
3456 assert(lincons != NULL);
3457
3458 /* insert constraint into mapping between */
3459 SCIP_CALL( SCIPhashmapInsert(linconssofindicatorsmap, (void*)lincons, (void*)lincons) );
3460 }
3461 }
3462 }
3463
3464 retcode = SCIP_OKAY;
3465 cons = NULL;
3466
3467 /* loop over all constraint for printing */
3468 for( c = 0; c < nconss && retcode == SCIP_OKAY; ++c )
3469 {
3470 SCIP_CONS* artcons;
3471
3472 artcons = NULL;
3473
3474 cons = conss[c]; /*lint !e613 */
3475 assert(cons != NULL);
3476
3477 conshdlr = SCIPconsGetHdlr(cons);
3478 assert(conshdlr != NULL);
3479
3480 conshdlrname = SCIPconshdlrGetName(conshdlr);
3481 assert(transformed == SCIPconsIsTransformed(cons));
3482
3483 /* in case the transformed is written only constraint are posted which are enabled in the current node */
3484 assert(!transformed || SCIPconsIsEnabled(cons));
3485
3486 if( linconssofpbsmap != NULL )
3487 artcons = (SCIP_CONS*) SCIPhashmapGetImage(linconssofpbsmap, (void*)cons);
3488 if( artcons == NULL && linconssofindicatorsmap != NULL )
3489 artcons = (SCIP_CONS*) SCIPhashmapGetImage(linconssofindicatorsmap, (void*)cons);
3490
3491 if( artcons == NULL )
3492 {
3493 if( strcmp(conshdlrname, "linear") == 0 )
3494 {
3495 if( SCIPgetNVarsLinear(scip, cons) == 0 )
3496 {
3497 if( SCIPisGT(scip, SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons)) )
3498 {
3499 SCIPerrorMessage("Cannot print empty violated constraint %s, %g <= %g is not fulfilled\n",
3500 SCIPconsGetName(cons), SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons));
3501 }
3502 continue;
3503 }
3504
3505 if( existands )
3506 {
3507 retcode = printNonLinearCons(scip, file,
3508 SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons), SCIPgetNVarsLinear(scip, cons),
3509 SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons), resvars, nresvars, andvars, nandvars,
3510 0LL, transformed, multisymbol);
3511 }
3512 else
3513 {
3514 retcode = printLinearCons(scip, file,
3515 SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons), SCIPgetNVarsLinear(scip, cons),
3516 SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons), 0LL, transformed, multisymbol);
3517 }
3518 }
3519 else if( strcmp(conshdlrname, "setppc") == 0 )
3520 {
3521 consvars = SCIPgetVarsSetppc(scip, cons);
3522 nconsvars = SCIPgetNVarsSetppc(scip, cons);
3523
3524 if( nconsvars == 0 )
3525 continue;
3526
3527 switch( SCIPgetTypeSetppc(scip, cons) )
3528 {
3529 case SCIP_SETPPCTYPE_PARTITIONING :
3530 if( existands )
3531 {
3532 retcode = printNonLinearCons(scip, file, consvars, NULL, nconsvars, 1.0, 1.0, resvars, nresvars,
3533 andvars, nandvars, 0LL, transformed, multisymbol);
3534 }
3535 else
3536 {
3537 retcode = printLinearCons(scip, file,
3538 consvars, NULL, nconsvars, 1.0, 1.0, 0LL, transformed, multisymbol);
3539 }
3540 break;
3541 case SCIP_SETPPCTYPE_PACKING :
3542 if( existands )
3543 {
3544 retcode = printNonLinearCons(scip, file,
3545 consvars, NULL, nconsvars, -SCIPinfinity(scip), 1.0, resvars, nresvars, andvars, nandvars,
3546 0LL, transformed, multisymbol);
3547 }
3548 else
3549 {
3550 retcode = printLinearCons(scip, file,
3551 consvars, NULL, nconsvars, -SCIPinfinity(scip), 1.0, 0LL, transformed, multisymbol);
3552 }
3553 break;
3554 case SCIP_SETPPCTYPE_COVERING :
3555 if( existands )
3556 {
3557 retcode = printNonLinearCons(scip, file,
3558 consvars, NULL, nconsvars, 1.0, SCIPinfinity(scip), resvars, nresvars, andvars, nandvars,
3559 0LL, transformed, multisymbol);
3560 }
3561 else
3562 {
3563 retcode = printLinearCons(scip, file,
3564 consvars, NULL, nconsvars, 1.0, SCIPinfinity(scip), 0LL, transformed, multisymbol);
3565 }
3566 break;
3567 }
3568 }
3569 else if( strcmp(conshdlrname, "logicor") == 0 )
3570 {
3571 if( SCIPgetNVarsLogicor(scip, cons) == 0 )
3572 continue;
3573
3574 if( existands )
3575 {
3576 retcode = printNonLinearCons(scip, file,
3577 SCIPgetVarsLogicor(scip, cons), NULL, SCIPgetNVarsLogicor(scip, cons), 1.0, SCIPinfinity(scip),
3578 resvars, nresvars, andvars, nandvars, 0LL, transformed, multisymbol);
3579 }
3580 else
3581 {
3582 retcode = printLinearCons(scip, file,
3583 SCIPgetVarsLogicor(scip, cons), NULL, SCIPgetNVarsLogicor(scip, cons),
3584 1.0, SCIPinfinity(scip), 0LL, transformed, multisymbol);
3585 }
3586 }
3587 else if( strcmp(conshdlrname, "knapsack") == 0 )
3588 {
3589 SCIP_Longint* weights;
3590
3591 consvars = SCIPgetVarsKnapsack(scip, cons);
3592 nconsvars = SCIPgetNVarsKnapsack(scip, cons);
3593
3594 if( nconsvars == 0 )
3595 continue;
3596
3597 /* copy Longint array to SCIP_Real array */
3598 weights = SCIPgetWeightsKnapsack(scip, cons);
3599 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) );
3600 for( v = 0; v < nconsvars; ++v )
3601 consvals[v] = (SCIP_Real)weights[v];
3602
3603 if( existands )
3604 {
3605 retcode = printNonLinearCons(scip, file, consvars, consvals, nconsvars, -SCIPinfinity(scip),
3606 (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), resvars, nresvars, andvars, nandvars,
3607 0LL, transformed, multisymbol);
3608 }
3609 else
3610 {
3611 retcode = printLinearCons(scip, file, consvars, consvals, nconsvars, -SCIPinfinity(scip),
3612 (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), 0LL, transformed, multisymbol);
3613 }
3614
3615 SCIPfreeBufferArray(scip, &consvals);
3616 }
3617 else if( strcmp(conshdlrname, "varbound") == 0 )
3618 {
3619 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) );
3620 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) );
3621
3622 consvars[0] = SCIPgetVarVarbound(scip, cons);
3623 consvars[1] = SCIPgetVbdvarVarbound(scip, cons);
3624
3625 consvals[0] = 1.0;
3626 consvals[1] = SCIPgetVbdcoefVarbound(scip, cons);
3627
3628 if( existands )
3629 {
3630 retcode = printNonLinearCons(scip, file, consvars, consvals, 2, SCIPgetLhsVarbound(scip, cons),
3631 SCIPgetRhsVarbound(scip, cons), resvars, nresvars, andvars, nandvars, 0LL, transformed, multisymbol);
3632 }
3633 else
3634 {
3635 retcode = printLinearCons(scip, file, consvars, consvals, 2, SCIPgetLhsVarbound(scip, cons),
3636 SCIPgetRhsVarbound(scip, cons), 0LL, transformed, multisymbol);
3637 }
3638
3639 SCIPfreeBufferArray(scip, &consvars);
3640 SCIPfreeBufferArray(scip, &consvals);
3641 }
3642 else if( strcmp(conshdlrname, "pseudoboolean") == 0 )
3643 {
3644 SCIP_VAR*** termvars;
3645 int* ntermvars;
3646 int termvarssize;
3647 SCIP_CONS** andconss;
3648 SCIP_Real* andcoefs ;
3649 SCIP_VAR** linvars;
3650 SCIP_Real* lincoefs ;
3651 int nlinvars;
3652 int t;
3653
3654 /* get the required array size for the variables array and for the number of variables in each variable array */
3655 termvarssize = SCIPgetNAndsPseudoboolean(scip, cons);
3656 assert(termvarssize >= 0);
3657
3658 /* allocate temporary memory */
3659 SCIP_CALL( SCIPallocBufferArray(scip, &andconss, termvarssize) );
3660 SCIP_CALL( SCIPallocBufferArray(scip, &termvars, termvarssize) );
3661 SCIP_CALL( SCIPallocBufferArray(scip, &andcoefs, termvarssize) );
3662 SCIP_CALL( SCIPallocBufferArray(scip, &ntermvars, termvarssize) );
3663
3664 /* get all corresponding and-constraints and therefor all variables */
3665 SCIP_CALL( SCIPgetAndDatasPseudoboolean(scip, cons, andconss, andcoefs, &termvarssize) );
3666 for( t = termvarssize - 1; t >= 0; --t )
3667 {
3668 termvars[t] = SCIPgetVarsAnd(scip, andconss[t]);
3669 ntermvars[t] = SCIPgetNVarsAnd(scip, andconss[t]);
3670 }
3671
3672 /* gets number of linear variables without artificial terms variables of pseudoboolean constraint */
3673 nlinvars = SCIPgetNLinVarsWithoutAndPseudoboolean(scip, cons);
3674
3675 /* allocate temporary memory */
3676 SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nlinvars) );
3677 SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nlinvars) );
3678
3679 /* gets linear constraint of pseudoboolean constraint */
3680 SCIP_CALL( SCIPgetLinDatasWithoutAndPseudoboolean(scip, cons, linvars, lincoefs, &nlinvars) );
3681
3682 retcode = printPseudobooleanCons(scip, file, linvars, lincoefs, nlinvars,
3683 termvars, ntermvars, andcoefs, termvarssize, SCIPgetIndVarPseudoboolean(scip, cons),
3684 SCIPgetLhsPseudoboolean(scip, cons), SCIPgetRhsPseudoboolean(scip, cons), transformed, multisymbol);
3685
3686 /* free temporary memory */
3687 SCIPfreeBufferArray(scip, &lincoefs);
3688 SCIPfreeBufferArray(scip, &linvars);
3689 SCIPfreeBufferArray(scip, &ntermvars);
3690 SCIPfreeBufferArray(scip, &andcoefs);
3691 SCIPfreeBufferArray(scip, &termvars);
3692 SCIPfreeBufferArray(scip, &andconss);
3693 }
3694 else if( strcmp(conshdlrname, "indicator") == 0 )
3695 {
3696 SCIP_CONS* lincons;
3697 SCIP_VAR* indvar;
3698 SCIP_VAR* slackvar;
3699 SCIP_Longint weight;
3700
3701 /* get artificial binary indicator variables */
3702 indvar = SCIPgetBinaryVarIndicator(cons);
3703 assert(indvar != NULL);
3704
3705 if( SCIPvarGetStatus(indvar) == SCIP_VARSTATUS_NEGATED )
3706 {
3707 indvar = SCIPvarGetNegationVar(indvar);
3708 assert(indvar != NULL);
3709 assert(SCIPvarGetStatus(indvar) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(indvar) != SCIP_VARSTATUS_MULTAGGR);
3710
3711 /* get the soft cost of this constraint */
3712 weight = (SCIP_Longint) SCIPvarGetObj(indvar);
3713 }
3714 else
3715 {
3716 assert(SCIPvarGetStatus(indvar) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(indvar) != SCIP_VARSTATUS_MULTAGGR);
3717
3718 /* get the soft cost of this constraint */
3719 weight = -(SCIP_Longint) SCIPvarGetObj(indvar);
3720 }
3721
3722 /* get artificial slack variable */
3723 slackvar = SCIPgetSlackVarIndicator(cons);
3724 assert(slackvar != NULL);
3725
3726 /* only need to print indicator constraints with weights on their indicator variable */
3727 if( weight != 0 )
3728 {
3729 SCIP_VAR** scipvarslinear;
3730 SCIP_Real* scipvalslinear;
3731 SCIP_Bool cont;
3732 int nonbinarypos;
3733
3734 lincons = SCIPgetLinearConsIndicator(cons);
3735 assert(lincons != NULL);
3736
3737 nconsvars = SCIPgetNVarsLinear(scip, lincons);
3738 scipvarslinear = SCIPgetVarsLinear(scip, lincons);
3739 scipvalslinear = SCIPgetValsLinear(scip, lincons);
3740
3741 /* allocate temporary memory */
3742 SCIP_CALL( SCIPduplicateBufferArray(scip, &consvars, scipvarslinear, nconsvars) );
3743 SCIP_CALL( SCIPduplicateBufferArray(scip, &consvals, scipvalslinear, nconsvars) );
3744
3745 nonbinarypos = -1;
3746 cont = FALSE;
3747
3748 /* find non-binary variable */
3749 for( v = 0; v < nconsvars; ++v )
3750 {
3751 if( SCIPvarGetType(consvars[v]) != SCIP_VARTYPE_BINARY )
3752 {
3753 if( consvars[v] == slackvar )
3754 {
3755 assert(nonbinarypos == -1);
3756 nonbinarypos = v;
3757 }
3758 else
3759 {
3760 SCIPwarningMessage(scip, "cannot print linear constraint <%s> of indicator constraint <%s> because it has more than one non-binary variable\n", SCIPconsGetName(lincons), SCIPconsGetName(cons) );
3761 SCIPinfoMessage(scip, file, "* ");
3762 SCIP_CALL( SCIPprintCons(scip, cons, file) );
3763 SCIPinfoMessage(scip, file, ";\n");
3764 cont = TRUE;
3765 break;
3766 }
3767 }
3768 }
3769
3770 /* if we have not found any non-binary variable we do not print the constraint, maybe we should ??? */
3771 if( nonbinarypos == -1 )
3772 {
3773 SCIPwarningMessage(scip, "cannot print linear constraint <%s> of indicator constraint <%s> because it has no slack variable\n", SCIPconsGetName(lincons), SCIPconsGetName(cons) );
3774 SCIPinfoMessage(scip, file, "* ");
3775 SCIP_CALL( SCIPprintCons(scip, cons, file) );
3776 SCIPinfoMessage(scip, file, ";\n");
3777
3778 /* free temporary memory */
3779 SCIPfreeBufferArray(scip, &consvals);
3780 SCIPfreeBufferArray(scip, &consvars);
3781 continue;
3782 }
3783
3784 /* if the constraint has more than two non-binary variables is not printable and we go to the next */
3785 if( cont )
3786 {
3787 /* free temporary memory */
3788 SCIPfreeBufferArray(scip, &consvals);
3789 SCIPfreeBufferArray(scip, &consvars);
3790 continue;
3791 }
3792
3793 assert(0 <= nonbinarypos && nonbinarypos < nconsvars);
3794
3795 /* remove slackvariable in linear constraint for printing */
3796 --nconsvars;
3797 consvars[nonbinarypos] = consvars[nconsvars];
3798 consvals[nonbinarypos] = consvals[nconsvars];
3799
3800 if( existands )
3801 {
3802 retcode = printNonLinearCons(scip, file,
3803 consvars, consvals, nconsvars, SCIPgetLhsLinear(scip, lincons), SCIPgetRhsLinear(scip, lincons),
3804 resvars, nresvars, andvars, nandvars,
3805 weight, transformed, multisymbol);
3806 }
3807 else
3808 {
3809 retcode = printLinearCons(scip, file,
3810 consvars, consvals, nconsvars, SCIPgetLhsLinear(scip, lincons), SCIPgetRhsLinear(scip, lincons),
3811 weight, transformed, multisymbol);
3812 }
3813
3814 /* free temporary memory */
3815 SCIPfreeBufferArray(scip, &consvals);
3816 SCIPfreeBufferArray(scip, &consvars);
3817 }
3818 else
3819 {
3820 SCIPwarningMessage(scip, "indicator constraint <%s> will not be printed because the indicator variable has no objective value(= weight of this soft constraint)\n", SCIPconsGetName(cons) );
3821 SCIPinfoMessage(scip, file, "* ");
3822 SCIP_CALL( SCIPprintCons(scip, cons, file) );
3823 SCIPinfoMessage(scip, file, ";\n");
3824 }
3825 }
3826 else if( strcmp(conshdlrname, "and") == 0 )
3827 {
3828 /* all resultants of the and constraint will be replaced by all corresponding variables of this constraint,
3829 * so no and-constraint will be printed directly */
3830 assert(existandconshdlr);
3831 }
3832 else
3833 {
3834 SCIPwarningMessage(scip, "constraint handler <%s> cannot print requested format\n", conshdlrname );
3835 SCIPinfoMessage(scip, file, "* ");
3836 SCIP_CALL( SCIPprintCons(scip, cons, file) );
3837 SCIPinfoMessage(scip, file, ";\n");
3838 }
3839 }
3840 }
3841
3842 if( retcode == SCIP_INVALIDDATA )
3843 {
3844 assert(cons != NULL);
3845
3846 SCIPerrorMessage("Cannot print constraint %s with non-integral coefficient or sides in opb-format\n",
3847 SCIPconsGetName(cons));
3848 SCIP_CALL( SCIPprintCons(scip, cons, stderr) );
3849 SCIPinfoMessage(scip, file, ";\n");
3850 }
3851
3852 if( linconssofpbsmap != NULL )
3853 {
3854 /* free hash map */
3855 SCIPhashmapFree(&linconssofpbsmap);
3856 }
3857 if( linconssofindicatorsmap != NULL )
3858 {
3859 /* free hash map */
3860 SCIPhashmapFree(&linconssofindicatorsmap);
3861 }
3862
3863 return retcode;
3864 }
3865
3866 /* write fixed variables (unless already done because they are an and resultant or and variable) */
3867 static
3868 SCIP_RETCODE writeOpbFixedVars(
3869 SCIP*const scip, /**< SCIP data structure */
3870 FILE*const file, /**< output file, or NULL if standard output should be used */
3871 SCIP_VAR** vars, /**< array with active (binary) variables */
3872 int nvars, /**< number of active variables in the problem */
3873 SCIP_HASHTABLE*const printedfixing, /**< hashmap to store if a fixed variable was already printed */
3874 char const*const multisymbol, /**< the multiplication symbol to use between coefficient and variable */
3875 SCIP_Bool const transformed /**< TRUE iff problem is the transformed problem */
3876 )
3877 {
3878 char linebuffer[OPB_MAX_LINELEN+1];
3879 char buffer[OPB_MAX_LINELEN];
3880 int linecnt;
3881 int v;
3882
3883 assert(scip != NULL);
3884 assert(file != NULL);
3885 assert(vars != NULL || nvars == 0);
3886 assert(printedfixing != NULL);
3887 assert(multisymbol != NULL);
3888
3889 clearBuffer(linebuffer, &linecnt);
3890
3891 /* print variables which are fixed */
3892 for( v = 0; v < nvars; ++v )
3893 {
3894 SCIP_VAR* var;
3895 SCIP_Real lb;
3896 SCIP_Real ub;
3897 SCIP_Bool neg = FALSE;
3898
3899 assert( vars != NULL );
3900 var = vars[v];
3901
3902 if( transformed )
3903 {
3904 /* in case the transformed is written only local bounds are posted which are valid in the current node */
3905 lb = SCIPvarGetLbLocal(var);
3906 ub = SCIPvarGetUbLocal(var);
3907 }
3908 else
3909 {
3910 lb = SCIPvarGetLbOriginal(var);
3911 ub = SCIPvarGetUbOriginal(var);
3912 }
3913 assert(lb > -0.5 && ub < 1.5);
3914 assert(SCIPisFeasIntegral(scip, lb));
3915 assert(SCIPisFeasIntegral(scip, ub));
3916
3917 /* print fixed and-resultants */
3918 if( lb > 0.5 || ub < 0.5 )
3919 {
3920 if( transformed ) {
3921 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &neg) );
3922 }
3923
3924 if( SCIPhashtableExists(printedfixing, (void*)var) )
3925 continue;
3926
3927 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "+1%s%s%s = %g ;\n", multisymbol, neg ? "~" : "", strstr(SCIPvarGetName(neg ? SCIPvarGetNegationVar(var) : var), "x"), lb);
3928 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
3929
3930 /* add variable to the hashmap */
3931 SCIP_CALL( SCIPhashtableInsert(printedfixing, (void*)var) );
3932 }
3933 }
3934
3935 writeBuffer(scip, file, linebuffer, &linecnt);
3936
3937 return SCIP_OKAY;
3938 }
3939
3940 /* write and constraints of inactive but relevant and-resultants and and variables which are fixed to one */
3941 static
3942 SCIP_RETCODE writeOpbRelevantAnds(
3943 SCIP*const scip, /**< SCIP data structure */
3944 FILE*const file, /**< output file, or NULL if standard output should be used */
3945 SCIP_VAR**const resvars, /**< array of resultant variables */
3946 int const nresvars, /**< number of resultant variables */
3947 SCIP_VAR**const*const andvars, /**< corresponding array of and-variables */
3948 int const*const nandvars, /**< array of numbers of corresponding and-variables */
3949 SCIP_HASHTABLE*const printedfixing, /**< hashmap to store if a fixed variable was already printed */
3950 char const*const multisymbol, /**< the multiplication symbol to use between coefficient and variable */
3951 SCIP_Bool const transformed /**< TRUE iff problem is the transformed problem */
3952 )
3953 {
3954 SCIP_VAR* resvar;
3955 SCIP_Longint rhslhs;
3956 char linebuffer[OPB_MAX_LINELEN+1];
3957 char buffer[OPB_MAX_LINELEN];
3958 int linecnt;
3959 int r, v;
3960
3961 assert(scip != NULL);
3962 assert(file != NULL);
3963 assert(resvars != NULL || nresvars == 0);
3964 assert(nandvars != NULL || nresvars == 0);
3965 assert(andvars != NULL || nandvars == NULL);
3966 assert(multisymbol != NULL);
3967
3968 clearBuffer(linebuffer, &linecnt);
3969
3970 /* print and-variables which are fixed */
3971 /* @todo remove this block here and the hashtable and let writeOpbFixedVars() do the job? */
3972 for( r = nresvars - 1; r >= 0; --r )
3973 {
3974 SCIP_VAR* var;
3975 SCIP_Bool neg;
3976 SCIP_Real lb;
3977 SCIP_Real ub;
3978
3979 assert( resvars != NULL );
3980 resvar = resvars[r];
3981
3982 if( transformed )
3983 {
3984 /* in case the transformed is written only local bounds are posted which are valid in the current node */
3985 lb = SCIPvarGetLbLocal(resvar);
3986 ub = SCIPvarGetUbLocal(resvar);
3987 }
3988 else
3989 {
3990 lb = SCIPvarGetLbOriginal(resvar);
3991 ub = SCIPvarGetUbOriginal(resvar);
3992 }
3993
3994 /* print fixed and-resultants */
3995 if( lb > 0.5 || ub < 0.5 )
3996 {
3997 /* coverity[copy_paste_error] */
3998 SCIP_CALL( SCIPgetBinvarRepresentative(scip, resvar, &var, &neg) );
3999
4000 assert(SCIPisFeasIntegral(scip, lb));
4001 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "+1%s%s%s = %g ;\n", multisymbol, neg ? "~" : "", strstr(SCIPvarGetName(neg ? SCIPvarGetNegationVar(var) : var), "x"), lb);
4002 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
4003
4004 /* add variable to the hashmap */
4005 SCIP_CALL( SCIPhashtableInsert(printedfixing, (void*)var) );
4006 }
4007
4008 assert( andvars != NULL && nandvars != NULL );
4009 assert( andvars[r] != NULL || nandvars[r] == 0 );
4010
4011 /* print fixed and-variables */
4012 for( v = nandvars[r] - 1; v >= 0; --v ) /*lint !e613 */
4013 {
4014 assert( andvars[r] != NULL );
4015 assert( andvars[r][v] != NULL );
4016
4017 if( transformed )
4018 {
4019 /* in case the transformed is written only local bounds are posted which are valid in the current node */
4020 lb = SCIPvarGetLbLocal(andvars[r][v]);
4021 ub = SCIPvarGetUbLocal(andvars[r][v]);
4022 }
4023 else
4024 {
4025 lb = SCIPvarGetLbOriginal(andvars[r][v]);
4026 ub = SCIPvarGetUbOriginal(andvars[r][v]);
4027 }
4028
4029 if( lb > 0.5 || ub < 0.5 )
4030 {
4031 SCIP_CALL( SCIPgetBinvarRepresentative(scip, andvars[r][v], &var, &neg) ); /*lint !e613 */
4032
4033 assert(SCIPisFeasIntegral(scip, lb));
4034 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "+1%s%s%s = %g ;\n", multisymbol, neg ? "~" : "", strstr(SCIPvarGetName(neg ? SCIPvarGetNegationVar(var) : var), "x"), lb);
4035 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
4036
4037 /* add variable to the hashmap */
4038 SCIP_CALL( SCIPhashtableInsert(printedfixing, (void*)var) );
4039 }
4040 }
4041 }
4042
4043 /* print and-constraints with fixed and-resultant to zero and all and-constraints with
4044 * aggregated resultant, otherwise we would loose this information
4045 */
4046 for( r = nresvars - 1; r >= 0; --r )
4047 {
4048 assert( resvars != NULL );
4049 resvar = resvars[r];
4050 rhslhs = (SCIPvarGetUbLocal(resvar) < 0.5) ? 0 : ((SCIPvarGetLbLocal(resvar) > 0.5) ? 1 : -1);
4051
4052 /* if and resultant is fixed to 0 and at least one and-variable is fixed to zero, we don't print this redundant constraint */
4053 if( rhslhs == 0 )
4054 {
4055 SCIP_Bool cont;
4056
4057 cont = FALSE;
4058
4059 assert( andvars != NULL && nandvars != NULL );
4060 assert( andvars[r] != NULL || nandvars[r] == 0 );
4061
4062 /* if resultant variable and one other and variable is already zero, so we did not need to print this and
4063 * constraint because all other variables are free
4064 */
4065 for( v = nandvars[r] - 1; v >= 0; --v ) /*lint !e613 */
4066 {
4067 assert( andvars[r] != NULL );
4068 assert( andvars[r][v] != NULL );
4069
4070 if( SCIPvarGetUbLocal(andvars[r][v]) < 0.5 ) /*lint !e613 */
4071 {
4072 cont = TRUE;
4073 break;
4074 }
4075 }
4076
4077 if( cont )
4078 continue;
4079 }
4080 /* if and resultant is fixed to 1 and all and-variable are fixed to 1 too, we don't print this redundant constraint */
4081 else if( rhslhs == 1 )
4082 {
4083 SCIP_Bool cont;
4084
4085 cont = TRUE;
4086
4087 assert( andvars != NULL && nandvars != NULL );
4088 assert( andvars[r] != NULL || nandvars[r] == 0 );
4089
4090 /* if all variables are already fixed to one, we do not need to print this and constraint */
4091 for( v = nandvars[r] - 1; v >= 0; --v )
4092 {
4093 assert( andvars[r] != NULL );
4094 assert( andvars[r][v] != NULL );
4095
4096 if( SCIPvarGetLbLocal(andvars[r][v]) < 0.5 ) /*lint !e613 */
4097 {
4098 cont = FALSE;
4099 break;
4100 }
4101 }
4102
4103 if( cont )
4104 continue;
4105 }
4106
4107 /* print and with fixed or aggregated and-resultant */
4108 /* rhslhs equals to 0 means the and constraint is relevant due to it's not clear on which values the and variables are
4109 * rhslhs equals to 1 means the and constraint is irrelevant cause all and variables have to be 1 too
4110 * rhslhs equals to -1 means the and constraint is relevant cause the variable is only aggregated */
4111 if( !SCIPvarIsActive(resvar) )
4112 {
4113 SCIP_VAR* var;
4114 SCIP_Bool neg;
4115 SCIP_Bool firstprinted;
4116
4117 firstprinted = FALSE;
4118
4119 assert( andvars != NULL && nandvars != NULL );
4120 assert( andvars[r] != NULL || nandvars[r] == 0 );
4121
4122 for( v = nandvars[r] - 1; v >= 0; --v )
4123 {
4124 assert( andvars[r] != NULL );
4125 assert( andvars[r][v] != NULL );
4126
4127 SCIP_CALL( SCIPgetBinvarRepresentative(scip, andvars[r][v], &var, &neg) ); /*lint !e613 */
4128
4129 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%s%s%s", (firstprinted) ? multisymbol : "", neg ? "~" : "", strstr(SCIPvarGetName(neg ? SCIPvarGetNegationVar(var) : var), "x"));
4130 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
4131
4132 firstprinted = TRUE;
4133 }
4134
4135 /* if the resultant is aggregated we need to print his binary representation */
4136 if( rhslhs == -1 )
4137 {
4138 int pos;
4139
4140 assert(transformed);
4141
4142 SCIP_CALL( SCIPgetBinvarRepresentative(scip, resvar, &resvar, &neg) );
4143
4144 #ifndef NDEBUG
4145 if( neg )
4146 assert(SCIPvarIsActive(SCIPvarGetNegationVar(resvar)));
4147 else
4148 assert(SCIPvarIsActive(resvar));
4149 #endif
4150
4151 /* replace and-resultant with corresponding variables */
4152 if( SCIPsortedvecFindPtr((void**)resvars, SCIPvarComp, neg ? SCIPvarGetNegationVar(resvar) : resvar, nresvars, &pos) )
4153 {
4154 SCIP_Bool negated;
4155 int a;
4156
4157 assert(andvars != NULL);
4158 assert(nandvars != NULL);
4159 assert(pos >= 0 && nandvars[pos] > 0 && andvars[pos] != NULL);
4160 assert(andvars[pos][nandvars[pos] - 1] != NULL);
4161
4162 negated = SCIPvarIsNegated(andvars[pos][nandvars[pos] - 1]);
4163
4164 /* print and-vars */
4165 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, neg ? " +1%s%s%s" : " -1%s%s%s", multisymbol, negated ? "~" : "",
4166 strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(andvars[pos][nandvars[pos] - 1]) : andvars[pos][nandvars[pos] - 1]), "x"));
4167 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
4168
4169 for(a = nandvars[pos] - 2; a >= 0; --a )
4170 {
4171 negated = SCIPvarIsNegated(andvars[pos][a]);
4172
4173 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, "%s%s%s", multisymbol, negated ? "~" : "", strstr(SCIPvarGetName(negated ? SCIPvarGetNegationVar(andvars[pos][a]) : andvars[pos][a]), "x"));
4174 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
4175 }
4176
4177 appendBuffer(scip, file, linebuffer, &linecnt, " ");
4178
4179 if( neg )
4180 rhslhs = 1;
4181 else
4182 rhslhs = 0;
4183 }
4184 else
4185 {
4186 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, " -1%s%s%s", multisymbol, neg ? "~" : "",
4187 strstr(SCIPvarGetName(neg ? SCIPvarGetNegationVar(resvar) : resvar), "x"));
4188 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
4189
4190 rhslhs = 0;
4191 }
4192 }
4193
4194 /* print rhslhs */
4195 (void) SCIPsnprintf(buffer, OPB_MAX_LINELEN, " = %" SCIP_LONGINT_FORMAT " ;\n", rhslhs);
4196 appendBuffer(scip, file, linebuffer, &linecnt, buffer);
4197
4198 writeBuffer(scip, file, linebuffer, &linecnt);
4199 }
4200 }
4201
4202 return SCIP_OKAY;
4203 }
4204
4205 /* writes problem to file */
4206 static
4207 SCIP_RETCODE writeOpb(
4208 SCIP* scip, /**< SCIP data structure */
4209 FILE* file, /**< output file, or NULL if standard output should be used */
4210 const char* name, /**< problem name */
4211 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */
4212 SCIP_OBJSENSE objsense, /**< objective sense */
4213 SCIP_Real objscale, /**< scalar applied to objective function; external objective value is
4214 * extobj = objsense * objscale * (intobj + objoffset) */
4215 SCIP_Real objoffset, /**< objective offset from bound shifting and fixing */
4216 SCIP_VAR** vars, /**< array with active (binary) variables */
4217 int nvars, /**< number of active variables in the problem */
4218 SCIP_CONS** conss, /**< array with constraints of the problem */
4219 int nconss, /**< number of constraints in the problem */
4220 SCIP_VAR** const resvars, /**< array of resultant variables */
4221 int const nresvars, /**< number of resultant variables */
4222 SCIP_VAR**const*const andvars, /**< corresponding array of and-variables */
4223 int const*const nandvars, /**< array of numbers of corresponding and-variables */
4224 SCIP_Bool const existandconshdlr, /**< does and-constrainthandler exist? */
4225 SCIP_Bool const existands, /**< does some and-constraints exist? */
4226 SCIP_RESULT* result /**< pointer to store the result of the file writing call */
4227 )
4228 {
4229 char multisymbol[OPB_MAX_LINELEN];
4230 SCIP_HASHTABLE* printedfixing;
4231 SCIP_Bool usesymbol;
4232 SCIP_RETCODE retcode;
4233 int nlinearconss;
4234 int nsplitlinearconss;
4235
4236 assert( scip != NULL );
4237 assert( vars != NULL || nvars == 0 );
4238 assert( conss != NULL || nconss == 0 );
4239 assert( result != NULL );
4240
4241 /* check if should use a multipliers symbol star '*' between coefficients and variables */
4242 SCIP_CALL( SCIPgetBoolParam(scip, "reading/" READER_NAME "/multisymbol", &usesymbol) );
4243 (void) SCIPsnprintf(multisymbol, OPB_MAX_LINELEN, "%s", usesymbol ? " * " : " ");
4244
4245 /* determine how many linear constraints are split */
4246 determineTotalNumberLinearConss(scip, conss, nconss, &nlinearconss, &nsplitlinearconss);
4247
4248 /* print statistics as comment to file */
4249 SCIPinfoMessage(scip, file, "* SCIP STATISTICS\n");
4250 SCIPinfoMessage(scip, file, "* Problem name : %s\n", name);
4251 SCIPinfoMessage(scip, file, "* Variables : %d (all binary)\n", nvars);
4252 SCIPinfoMessage(scip, file, "* Constraints : %d\n", nconss - nlinearconss + nsplitlinearconss);
4253
4254 /* create a hash table */
4255 SCIP_CALL( SCIPhashtableCreate(&printedfixing, SCIPblkmem(scip), nvars,
4256 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
4257
4258 /* write objective function */
4259 SCIP_CALL( writeOpbObjective(scip, file, vars, nvars, resvars, nresvars, andvars, nandvars,
4260 objsense, objscale, objoffset, multisymbol, existands, transformed) );
4261
4262 /* write constraints */
4263 retcode = writeOpbConstraints(scip, file, conss, nconss, vars, nvars, resvars, nresvars, andvars, nandvars,
4264 multisymbol, existandconshdlr, existands, transformed);
4265
4266 if( existands && (retcode == SCIP_OKAY) )
4267 {
4268 /* write and constraints of inactive but relevant and-resultants and and-variables which are fixed to one
4269 with no fixed and resultant */
4270 SCIP_CALL( writeOpbRelevantAnds(scip, file, resvars, nresvars, andvars, nandvars, printedfixing, multisymbol, transformed) );
4271 }
4272
4273 /* write fixed variables */
4274 SCIP_CALL( writeOpbFixedVars(scip, file, vars, nvars, printedfixing, multisymbol, transformed) );
4275
4276 SCIPhashtableFree(&printedfixing);
4277
4278 *result = SCIP_SUCCESS;
4279
4280 return retcode;
4281 }
4282
4283
4284 /*
4285 * extern methods
4286 */
4287
4288 /** reads problem from file */
4289 SCIP_RETCODE SCIPreadOpb(
4290 SCIP* scip, /**< SCIP data structure */
4291 SCIP_READER* reader, /**< the file reader itself */
4292 const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */
4293 SCIP_RESULT* result /**< pointer to store the result of the file reading call */
4294 )
4295 { /*lint --e{715}*/
4296 OPBINPUT opbinput;
4297 SCIP_RETCODE retcode;
4298 int i;
4299
4300 assert(scip != NULL); /* for lint */
4301 assert(reader != NULL);
4302
4303 /* initialize OPB input data */
4304 opbinput.file = NULL;
4305 opbinput.linebuf[0] = '\0';
4306 SCIP_CALL( SCIPallocBufferArray(scip, &opbinput.token, OPB_MAX_LINELEN) );
4307 opbinput.token[0] = '\0';
4308 SCIP_CALL( SCIPallocBufferArray(scip, &opbinput.tokenbuf, OPB_MAX_LINELEN) );
4309 opbinput.tokenbuf[0] = '\0';
4310 for( i = 0; i < OPB_MAX_PUSHEDTOKENS; ++i )
4311 {
4312 SCIP_CALL( SCIPallocBufferArray(scip, &(opbinput.pushedtokens[i]), OPB_MAX_LINELEN) ); /*lint !e866 */
4313 }
4314
4315 opbinput.npushedtokens = 0;
4316 opbinput.linenumber = 1;
4317 opbinput.bufpos = 0;
4318 opbinput.linepos = 0;
4319 opbinput.objsense = SCIP_OBJSENSE_MINIMIZE;
4320 opbinput.comment = FALSE;
4321 opbinput.endline = FALSE;
4322 opbinput.eof = FALSE;
4323 opbinput.haserror = FALSE;
4324 opbinput.nproblemcoeffs = 0;
4325 opbinput.wbo = FALSE;
4326 opbinput.topcost = -SCIPinfinity(scip);
4327 opbinput.nindvars = 0;
4328 #if GENCONSNAMES == TRUE
4329 opbinput.consnumber = 0;
4330 #endif
4331
4332 /* read the file */
4333 retcode = readOPBFile(scip, &opbinput, filename);
4334
4335 /* free dynamically allocated memory */
4336 for( i = OPB_MAX_PUSHEDTOKENS - 1; i >= 0; --i )
4337 {
4338 SCIPfreeBufferArrayNull(scip, &(opbinput.pushedtokens[i]));
4339 }
4340 SCIPfreeBufferArrayNull(scip, &opbinput.tokenbuf);
4341 SCIPfreeBufferArrayNull(scip, &opbinput.token);
4342
4343 if( retcode == SCIP_PLUGINNOTFOUND )
4344 retcode = SCIP_READERROR;
4345
4346 SCIP_CALL( retcode );
4347
4348 if( opbinput.nproblemcoeffs > 0 )
4349 {
4350 SCIPwarningMessage(scip, "there might be <%d> coefficients or weight out of range!\n", opbinput.nproblemcoeffs);
4351 }
4352
4353 /* evaluate the result */
4354 if( opbinput.haserror )
4355 return SCIP_READERROR;
4356 else
4357 {
4358 /* set objective sense */
4359 SCIP_CALL( SCIPsetObjsense(scip, opbinput.objsense) );
4360 *result = SCIP_SUCCESS;
4361 }
4362
4363 return SCIP_OKAY;
4364 }
4365
4366 /** writes problem to file */
4367 SCIP_RETCODE SCIPwriteOpb(
4368 SCIP* scip, /**< SCIP data structure */
4369 FILE* file, /**< output file, or NULL if standard output should be used */
4370 const char* name, /**< problem name */
4371 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */
4372 SCIP_OBJSENSE objsense, /**< objective sense */
4373 SCIP_Real objscale, /**< scalar applied to objective function; external objective value is
4374 * extobj = objsense * objscale * (intobj + objoffset) */
4375 SCIP_Real objoffset, /**< objective offset from bound shifting and fixing */
4376 SCIP_VAR** vars, /**< array with active variables ordered binary, integer, implicit, continuous */
4377 int nvars, /**< number of active variables in the problem */
4378 int nbinvars, /**< number of binary variables */
4379 int nintvars, /**< number of general integer variables */
4380 int nimplvars, /**< number of implicit integer variables */
4381 int ncontvars, /**< number of continuous variables */
4382 SCIP_VAR** fixedvars, /**< array with fixed variables */
4383 int nfixedvars, /**< number of fixed and aggregated variables in the problem */
4384 SCIP_CONS** conss, /**< array with constraints of the problem */
4385 int nconss, /**< number of constraints in the problem */
4386 SCIP_Bool genericnames, /**< should generic variable and constraint names be used */
4387 SCIP_RESULT* result /**< pointer to store the result of the file writing call */
4388 )
4389 { /*lint --e{715}*/
4390 SCIP_RETCODE retcode = SCIP_OKAY;
4391
4392 if( nvars != nbinvars && (nintvars > 0 || SCIPfindConshdlr(scip, "indicator") != NULL
4393 || ncontvars + nimplvars != SCIPconshdlrGetNConss(SCIPfindConshdlr(scip, "indicator"))) )
4394 {
4395 SCIPwarningMessage(scip, "only binary problems can be written in OPB format.\n");
4396 *result = SCIP_DIDNOTRUN;
4397 }
4398 else
4399 {
4400 SCIP_VAR*** andvars;
4401 SCIP_VAR** resvars;
4402 int* nandvars;
4403 SCIP_Bool existands;
4404 SCIP_Bool existandconshdlr;
4405 int nresvars;
4406 int v;
4407
4408 /* computes all and-resultants and their corresponding constraint variables */
4409 /* coverity[leaked_storage] */
4410 SCIP_CALL( computeAndConstraintInfos(scip, transformed, &resvars, &nresvars, &andvars, &nandvars, &existandconshdlr, &existands) );
4411
4412 if( genericnames )
4413 {
4414 #ifndef NDEBUG
4415 /* check for correct names for opb-format */
4416 int idx;
4417 int pos;
4418
4419 for( v = nvars - 1; v >= 0; --v )
4420 {
4421 if( existands )
4422 {
4423 /* and variables are artificial */
4424 if( SCIPsortedvecFindPtr((void**)resvars, SCIPvarComp, vars[v], nresvars, &pos) )
4425 continue;
4426 }
4427
4428 assert(sscanf(SCIPvarGetName(vars[v]), "x%d", &idx) == 1);
4429 }
4430 #endif
4431 retcode = writeOpb(scip, file, name, transformed, objsense, objscale, objoffset, vars,
4432 nvars, conss, nconss, resvars, nresvars, andvars, nandvars, existandconshdlr, existands, result);
4433 }
4434 else
4435 {
4436 SCIP_Bool printed;
4437 int idx;
4438 int pos;
4439
4440 printed = FALSE;
4441
4442 /* check if there are already generic names for all (not fixed variables)*/
4443 for( v = nvars - 1; v >= 0; --v )
4444 if( !existands || !SCIPsortedvecFindPtr((void**)resvars, SCIPvarComp, vars[v], nresvars, &pos) )
4445 {
4446 if( sscanf(SCIPvarGetName(vars[v]), transformed ? "t_x%d" : "x%d", &idx) != 1 && strstr(SCIPvarGetName(vars[v]), INDICATORVARNAME) == NULL && strstr(SCIPvarGetName(vars[v]), INDICATORSLACKVARNAME) == NULL )
4447 {
4448 SCIPwarningMessage(scip, "At least following variable name isn't allowed in opb format.\n");
4449 SCIP_CALL( SCIPprintVar(scip, vars[v], NULL) );
4450 SCIPwarningMessage(scip, "OPB format needs generic variable names!\n");
4451
4452 if( transformed )
4453 {
4454 SCIPwarningMessage(scip, "write transformed problem with generic variable names.\n");
4455 SCIP_CALL( SCIPprintTransProblem(scip, file, "opb", TRUE) );
4456 }
4457 else
4458 {
4459 SCIPwarningMessage(scip, "write original problem with generic variable names.\n");
4460 SCIP_CALL( SCIPprintOrigProblem(scip, file, "opb", TRUE) );
4461 }
4462 printed = TRUE;
4463 break;
4464 }
4465 }
4466
4467 if( !printed )
4468 {
4469 /* check if there are already generic names for all (fixed variables)*/
4470 for( v = nfixedvars - 1; v >= 0; --v )
4471 if( !existands || !SCIPsortedvecFindPtr((void**)resvars, SCIPvarComp, vars[v], nresvars, &pos) )
4472 {
4473 /* coverity[secure_coding] */
4474 if( sscanf(SCIPvarGetName(fixedvars[v]), transformed ? "t_x%d" : "x%d", &idx) != 1 && strstr(SCIPvarGetName(fixedvars[v]), INDICATORVARNAME) == NULL && strstr(SCIPvarGetName(fixedvars[v]), INDICATORSLACKVARNAME) == NULL )
4475 {
4476 SCIPwarningMessage(scip, "At least following variable name isn't allowed in opb format.\n");
4477 SCIP_CALL( SCIPprintVar(scip, fixedvars[v], NULL) );
4478 SCIPwarningMessage(scip, "OPB format needs generic variable names!\n");
4479
4480 if( transformed )
4481 {
4482 SCIPwarningMessage(scip, "write transformed problem with generic variable names.\n");
4483 SCIP_CALL( SCIPprintTransProblem(scip, file, "opb", TRUE) );
4484 }
4485 else
4486 {
4487 SCIPwarningMessage(scip, "write original problem with generic variable names.\n");
4488 SCIP_CALL( SCIPprintOrigProblem(scip, file, "opb", TRUE) );
4489 }
4490 printed = TRUE;
4491 break;
4492 }
4493 }
4494 }
4495
4496 if( !printed )
4497 {
4498 #ifndef NDEBUG
4499 for( v = nvars - 1; v >= 0; --v )
4500 {
4501 if( existands )
4502 {
4503 if( SCIPsortedvecFindPtr((void**)resvars, SCIPvarComp, vars[v], nresvars, &pos) )
4504 continue;
4505 }
4506
4507 assert(sscanf(SCIPvarGetName(vars[v]), transformed ? "t_x%d" : "x%d", &idx) == 1 || strstr(SCIPvarGetName(vars[v]), INDICATORVARNAME) != NULL || strstr(SCIPvarGetName(vars[v]), INDICATORSLACKVARNAME) != NULL );
4508 }
4509 #endif
4510 retcode = writeOpb(scip, file, name, transformed, objsense, objscale, objoffset, vars,
4511 nvars, conss, nconss, resvars, nresvars, andvars, nandvars, existandconshdlr, existands, result);
4512 }
4513 }
4514
4515 if( existands )
4516 {
4517 /* free temporary buffers */
4518 assert(resvars != NULL);
4519 assert(andvars != NULL);
4520 assert(nandvars != NULL);
4521
4522 for( v = nresvars - 1; v >= 0; --v )
4523 {
4524 assert(andvars[v] != NULL);
4525 SCIPfreeMemoryArray(scip, &andvars[v]);
4526 }
4527 SCIPfreeMemoryArray(scip, &nandvars);
4528 SCIPfreeMemoryArray(scip, &andvars);
4529 SCIPfreeMemoryArray(scip, &resvars);
4530 }
4531
4532 *result = SCIP_SUCCESS;
4533 }
4534
4535 if( retcode == SCIP_INVALIDDATA )
4536 return SCIP_WRITEERROR;
4537
4538 return retcode;
4539 }
4540
4541 /*
4542 * Callback methods of reader
4543 */
4544
4545 /** copy method for reader plugins (called when SCIP copies plugins) */
4546 static
4547 SCIP_DECL_READERCOPY(readerCopyOpb)
4548 { /*lint --e{715}*/
4549 assert(scip != NULL);
4550 assert(reader != NULL);
4551 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
4552
4553 /* call inclusion method of reader */
4554 SCIP_CALL( SCIPincludeReaderOpb(scip) );
4555
4556 return SCIP_OKAY;
4557 }
4558
4559
4560 /** problem reading method of reader */
4561 static
4562 SCIP_DECL_READERREAD(readerReadOpb)
4563 { /*lint --e{715}*/
4564
4565 SCIP_CALL( SCIPreadOpb(scip, reader, filename, result) );
4566
4567 return SCIP_OKAY;
4568 }
4569
4570
4571 /** problem writing method of reader */
4572 static
4573 SCIP_DECL_READERWRITE(readerWriteOpb)
4574 { /*lint --e{715}*/
4575
4576 SCIP_CALL( SCIPwriteOpb(scip, file, name, transformed, objsense, objscale, objoffset, vars,
4577 nvars, nbinvars, nintvars, nimplvars, ncontvars, fixedvars, nfixedvars, conss, nconss, genericnames, result) );
4578
4579 return SCIP_OKAY;
4580 }
4581
4582 /*
4583 * reader specific interface methods
4584 */
4585
4586 /** includes the opb file reader in SCIP */
4587 SCIP_RETCODE SCIPincludeReaderOpb(
4588 SCIP* scip /**< SCIP data structure */
4589 )
4590 {
4591 SCIP_READER* reader;
4592
4593 /* include reader */
4594 SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, NULL) );
4595
4596 /* set non fundamental callbacks via setter functions */
4597 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyOpb) );
4598 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadOpb) );
4599 SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteOpb) );
4600
4601 /* add opb reader parameters */
4602 SCIP_CALL( SCIPaddBoolParam(scip,
4603 "reading/" READER_NAME "/dynamicconss", "should model constraints be subject to aging?",
4604 NULL, FALSE, FALSE/*TRUE*/, NULL, NULL) ); /* have to be FALSE, otherwise an error might inccur in restart during branch and bound */
4605 SCIP_CALL( SCIPaddBoolParam(scip,
4606 "reading/" READER_NAME "/multisymbol", "use '*' between coefficients and variables by writing to problem?",
4607 NULL, TRUE, FALSE, NULL, NULL) );
4608
4609 return SCIP_OKAY;
4610 }
4611