1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2 /* */ 3 /* This file is part of the program and library */ 4 /* SCIP --- Solving Constraint Integer Programs */ 5 /* */ 6 /* Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB) */ 7 /* */ 8 /* Licensed under the Apache License, Version 2.0 (the "License"); */ 9 /* you may not use this file except in compliance with the License. */ 10 /* You may obtain a copy of the License at */ 11 /* */ 12 /* http://www.apache.org/licenses/LICENSE-2.0 */ 13 /* */ 14 /* Unless required by applicable law or agreed to in writing, software */ 15 /* distributed under the License is distributed on an "AS IS" BASIS, */ 16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ 17 /* See the License for the specific language governing permissions and */ 18 /* limitations under the License. */ 19 /* */ 20 /* You should have received a copy of the Apache-2.0 license */ 21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */ 22 /* */ 23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 24 25 /**@file reader_pip.c 26 * @ingroup DEFPLUGINS_READER 27 * @brief file reader for polynomial mixed-integer programs in PIP format 28 * @author Stefan Vigerske 29 * @author Marc Pfetsch 30 */ 31 32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 33 34 #include <ctype.h> 35 36 #include "blockmemshell/memory.h" 37 #include "scip/reader_pip.h" 38 #include "scip/cons_and.h" 39 #include "scip/cons_nonlinear.h" 40 #include "scip/cons_knapsack.h" 41 #include "scip/cons_linear.h" 42 #include "scip/cons_logicor.h" 43 #include "scip/cons_setppc.h" 44 #include "scip/cons_varbound.h" 45 #include "scip/expr_sum.h" 46 #include "scip/expr_var.h" 47 #include "scip/pub_cons.h" 48 #include "scip/pub_expr.h" 49 #include "scip/pub_fileio.h" 50 #include "scip/pub_message.h" 51 #include "scip/pub_misc.h" 52 #include "scip/pub_nlp.h" 53 #include "scip/pub_reader.h" 54 #include "scip/pub_var.h" 55 #include "scip/scip_cons.h" 56 #include "scip/scip_mem.h" 57 #include "scip/scip_message.h" 58 #include "scip/scip_numerics.h" 59 #include "scip/scip_param.h" 60 #include "scip/scip_prob.h" 61 #include "scip/scip_reader.h" 62 #include "scip/scip_var.h" 63 #include <stdlib.h> 64 #include <string.h> 65 #include <ctype.h> 66 67 #if !defined(_WIN32) && !defined(_WIN64) 68 #include <strings.h> /*lint --e{766}*/ /* needed for strncasecmp() */ 69 #endif 70 71 #define READER_NAME "pipreader" 72 #define READER_DESC "file reader for polynomial mixed-integer programs in PIP format" 73 #define READER_EXTENSION "pip" 74 75 76 /* 77 * Data structures 78 */ 79 #define PIP_MAX_LINELEN 65536 80 #define PIP_MAX_PUSHEDTOKENS 2 81 #define PIP_INIT_MONOMIALSSIZE 128 82 #define PIP_INIT_FACTORSSIZE 16 83 #define PIP_MAX_PRINTLEN 561 /**< the maximum length of any line is 560 + '\\0' = 561*/ 84 #define PIP_MAX_NAMELEN 256 /**< the maximum length for any name is 255 + '\\0' = 256 */ 85 #define PIP_PRINTLEN 100 86 87 /** Section in PIP File */ 88 enum PipSection 89 { 90 PIP_START, 91 PIP_OBJECTIVE, 92 PIP_CONSTRAINTS, 93 PIP_BOUNDS, 94 PIP_GENERALS, 95 PIP_BINARIES, 96 PIP_END 97 }; 98 typedef enum PipSection PIPSECTION; 99 100 enum PipExpType 101 { 102 PIP_EXP_NONE, 103 PIP_EXP_UNSIGNED, 104 PIP_EXP_SIGNED 105 }; 106 typedef enum PipExpType PIPEXPTYPE; 107 108 enum PipSense 109 { 110 PIP_SENSE_NOTHING, 111 PIP_SENSE_LE, 112 PIP_SENSE_GE, 113 PIP_SENSE_EQ 114 }; 115 typedef enum PipSense PIPSENSE; 116 117 /** PIP reading data */ 118 struct PipInput 119 { 120 SCIP_FILE* file; 121 char linebuf[PIP_MAX_LINELEN+1]; 122 char probname[PIP_MAX_LINELEN]; 123 char objname[PIP_MAX_LINELEN]; 124 char* token; 125 char* tokenbuf; 126 char* pushedtokens[PIP_MAX_PUSHEDTOKENS]; 127 int npushedtokens; 128 int linenumber; 129 int linepos; 130 PIPSECTION section; 131 SCIP_OBJSENSE objsense; 132 SCIP_Bool initialconss; /**< should model constraints be marked as initial? */ 133 SCIP_Bool dynamicconss; /**< should model constraints be subject to aging? */ 134 SCIP_Bool dynamiccols; /**< should columns be added and removed dynamically to the LP? */ 135 SCIP_Bool dynamicrows; /**< should rows be added and removed dynamically to the LP? */ 136 SCIP_Bool haserror; 137 }; 138 typedef struct PipInput PIPINPUT; 139 140 static const char delimchars[] = " \f\n\r\t\v"; 141 static const char tokenchars[] = "-+:<>=*^"; 142 static const char commentchars[] = "\\"; 143 static const char namechars[] = "!#$%&;?@_"; /* and characters and numbers */ 144 145 146 /* 147 * Local methods (for reading) 148 */ 149 150 /** issues an error message and marks the PIP data to have errors */ 151 static 152 void syntaxError( 153 SCIP* scip, /**< SCIP data structure */ 154 PIPINPUT* pipinput, /**< PIP reading data */ 155 const char* msg /**< error message */ 156 ) 157 { 158 char formatstr[256]; 159 160 assert(pipinput != NULL); 161 162 SCIPerrorMessage("Syntax error in line %d: %s ('%s')\n", pipinput->linenumber, msg, pipinput->token); 163 if( pipinput->linebuf[strlen(pipinput->linebuf)-1] == '\n' ) 164 { 165 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, " input: %s", pipinput->linebuf); 166 } 167 else 168 { 169 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, " input: %s\n", pipinput->linebuf); 170 } 171 (void) SCIPsnprintf(formatstr, 256, " %%%ds\n", pipinput->linepos); 172 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, formatstr, "^"); 173 pipinput->section = PIP_END; 174 pipinput->haserror = TRUE; 175 } 176 177 /** returns whether a syntax error was detected */ 178 static 179 SCIP_Bool hasError( 180 PIPINPUT* pipinput /**< PIP reading data */ 181 ) 182 { 183 assert(pipinput != NULL); 184 185 return pipinput->haserror; 186 } 187 188 /** returns whether the given character is a token delimiter */ 189 static 190 SCIP_Bool isDelimChar( 191 char c /**< input character */ 192 ) 193 { 194 return (c == '\0') || (strchr(delimchars, c) != NULL); 195 } 196 197 /** returns whether the given character is a single token */ 198 static 199 SCIP_Bool isTokenChar( 200 char c /**< input character */ 201 ) 202 { 203 return (strchr(tokenchars, c) != NULL); 204 } 205 206 /** returns whether the current character is member of a value string */ 207 static 208 SCIP_Bool isValueChar( 209 char c, /**< input character */ 210 char nextc, /**< next input character */ 211 SCIP_Bool firstchar, /**< is the given character the first char of the token? */ 212 SCIP_Bool* hasdot, /**< pointer to update the dot flag */ 213 PIPEXPTYPE* exptype /**< pointer to update the exponent type */ 214 ) 215 { 216 assert(hasdot != NULL); 217 assert(exptype != NULL); 218 219 if( isdigit((unsigned char)c) ) 220 return TRUE; 221 else if( (*exptype == PIP_EXP_NONE) && !(*hasdot) && (c == '.') && isdigit((unsigned char)nextc) ) 222 { 223 *hasdot = TRUE; 224 return TRUE; 225 } 226 else if( !firstchar && (*exptype == PIP_EXP_NONE) && (c == 'e' || c == 'E') ) 227 { 228 if( nextc == '+' || nextc == '-' ) 229 { 230 *exptype = PIP_EXP_SIGNED; 231 return TRUE; 232 } 233 else if( isdigit((unsigned char)nextc) ) 234 { 235 *exptype = PIP_EXP_UNSIGNED; 236 return TRUE; 237 } 238 } 239 else if( (*exptype == PIP_EXP_SIGNED) && (c == '+' || c == '-') ) 240 { 241 *exptype = PIP_EXP_UNSIGNED; 242 return TRUE; 243 } 244 245 return FALSE; 246 } 247 248 /** reads the next line from the input file into the line buffer; skips comments; 249 * returns whether a line could be read 250 */ 251 static 252 SCIP_Bool getNextLine( 253 SCIP* scip, /**< SCIP data structure */ 254 PIPINPUT* pipinput /**< PIP reading data */ 255 ) 256 { 257 int i; 258 259 assert(scip != NULL); /* for lint */ 260 assert(pipinput != NULL); 261 262 /* clear the line */ 263 BMSclearMemoryArray(pipinput->linebuf, PIP_MAX_LINELEN); 264 265 /* read next line */ 266 pipinput->linepos = 0; 267 pipinput->linebuf[PIP_MAX_LINELEN-2] = '\0'; 268 if( SCIPfgets(pipinput->linebuf, (int) sizeof(pipinput->linebuf), pipinput->file) == NULL ) 269 return FALSE; 270 pipinput->linenumber++; 271 if( pipinput->linebuf[PIP_MAX_LINELEN-2] != '\0' ) 272 { 273 SCIPerrorMessage("Error: line %d exceeds %d characters\n", pipinput->linenumber, PIP_MAX_LINELEN-2); 274 pipinput->haserror = TRUE; 275 return FALSE; 276 } 277 pipinput->linebuf[PIP_MAX_LINELEN-1] = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */ 278 279 /* skip characters after comment symbol */ 280 for( i = 0; commentchars[i] != '\0'; ++i ) 281 { 282 char* commentstart; 283 284 commentstart = strchr(pipinput->linebuf, commentchars[i]); 285 if( commentstart != NULL ) 286 { 287 *commentstart = '\0'; 288 *(commentstart+1) = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */ 289 } 290 } 291 292 return TRUE; 293 } 294 295 /** swaps the addresses of two pointers */ 296 static 297 void swapPointers( 298 char** pointer1, /**< first pointer */ 299 char** pointer2 /**< second pointer */ 300 ) 301 { 302 char* tmp; 303 304 tmp = *pointer1; 305 *pointer1 = *pointer2; 306 *pointer2 = tmp; 307 } 308 309 /** reads the next token from the input file into the token buffer; returns whether a token was read */ 310 static 311 SCIP_Bool getNextToken( 312 SCIP* scip, /**< SCIP data structure */ 313 PIPINPUT* pipinput /**< PIP reading data */ 314 ) 315 { 316 SCIP_Bool hasdot; 317 PIPEXPTYPE exptype; 318 char* buf; 319 int tokenlen; 320 321 assert(pipinput != NULL); 322 assert(pipinput->linepos < PIP_MAX_LINELEN); 323 324 /* check the token stack */ 325 if( pipinput->npushedtokens > 0 ) 326 { 327 swapPointers(&pipinput->token, &pipinput->pushedtokens[pipinput->npushedtokens-1]); 328 pipinput->npushedtokens--; 329 SCIPdebugMsg(scip, "(line %d) read token again: '%s'\n", pipinput->linenumber, pipinput->token); 330 return TRUE; 331 } 332 333 /* skip delimiters */ 334 buf = pipinput->linebuf; 335 while( isDelimChar(buf[pipinput->linepos]) ) 336 { 337 if( buf[pipinput->linepos] == '\0' ) 338 { 339 if( !getNextLine(scip, pipinput) ) 340 { 341 pipinput->section = PIP_END; 342 SCIPdebugMsg(scip, "(line %d) end of file\n", pipinput->linenumber); 343 return FALSE; 344 } 345 assert(pipinput->linepos == 0); 346 } 347 else 348 pipinput->linepos++; 349 } 350 assert(pipinput->linepos < PIP_MAX_LINELEN); 351 assert(!isDelimChar(buf[pipinput->linepos])); 352 353 /* check if the token is a value */ 354 hasdot = FALSE; 355 exptype = PIP_EXP_NONE; 356 if( isValueChar(buf[pipinput->linepos], buf[pipinput->linepos+1], TRUE, &hasdot, &exptype) ) 357 { 358 /* read value token */ 359 tokenlen = 0; 360 do 361 { 362 assert(tokenlen < PIP_MAX_LINELEN); 363 assert(!isDelimChar(buf[pipinput->linepos])); 364 pipinput->token[tokenlen] = buf[pipinput->linepos]; 365 tokenlen++; 366 pipinput->linepos++; 367 } 368 while( isValueChar(buf[pipinput->linepos], buf[pipinput->linepos+1], FALSE, &hasdot, &exptype) ); 369 } 370 else 371 { 372 /* read non-value token */ 373 tokenlen = 0; 374 do 375 { 376 assert(tokenlen < PIP_MAX_LINELEN); 377 pipinput->token[tokenlen] = buf[pipinput->linepos]; 378 tokenlen++; 379 pipinput->linepos++; 380 if( tokenlen == 1 && isTokenChar(pipinput->token[0]) ) 381 break; 382 } 383 while( !isDelimChar(buf[pipinput->linepos]) && !isTokenChar(buf[pipinput->linepos]) ); 384 385 /* if the token is an equation sense '<', '>', or '=', skip a following '=' 386 * if the token is an equality token '=' and the next character is a '<' or '>', replace the token by the inequality sense 387 */ 388 if( tokenlen >= 1 389 && (pipinput->token[tokenlen-1] == '<' || pipinput->token[tokenlen-1] == '>' || pipinput->token[tokenlen-1] == '=') 390 && buf[pipinput->linepos] == '=' ) 391 { 392 pipinput->linepos++; 393 } 394 else if( pipinput->token[tokenlen-1] == '=' && (buf[pipinput->linepos] == '<' || buf[pipinput->linepos] == '>') ) 395 { 396 pipinput->token[tokenlen-1] = buf[pipinput->linepos]; 397 pipinput->linepos++; 398 } 399 } 400 assert(tokenlen < PIP_MAX_LINELEN); 401 pipinput->token[tokenlen] = '\0'; 402 403 SCIPdebugMsg(scip, "(line %d) read token: '%s'\n", pipinput->linenumber, pipinput->token); 404 405 return TRUE; 406 } 407 408 /** puts the current token on the token stack, such that it is read at the next call to getNextToken() */ 409 static 410 void pushToken( 411 PIPINPUT* pipinput /**< PIP reading data */ 412 ) 413 { 414 assert(pipinput != NULL); 415 assert(pipinput->npushedtokens < PIP_MAX_PUSHEDTOKENS); 416 417 swapPointers(&pipinput->pushedtokens[pipinput->npushedtokens], &pipinput->token); 418 pipinput->npushedtokens++; 419 } 420 421 /** puts the buffered token on the token stack, such that it is read at the next call to getNextToken() */ 422 static 423 void pushBufferToken( 424 PIPINPUT* pipinput /**< PIP reading data */ 425 ) 426 { 427 assert(pipinput != NULL); 428 assert(pipinput->npushedtokens < PIP_MAX_PUSHEDTOKENS); 429 430 swapPointers(&pipinput->pushedtokens[pipinput->npushedtokens], &pipinput->tokenbuf); 431 pipinput->npushedtokens++; 432 } 433 434 /** swaps the current token with the token buffer */ 435 static 436 void swapTokenBuffer( 437 PIPINPUT* pipinput /**< PIP reading data */ 438 ) 439 { 440 assert(pipinput != NULL); 441 442 swapPointers(&pipinput->token, &pipinput->tokenbuf); 443 } 444 445 /** checks whether the current token is a section identifier, and if yes, switches to the corresponding section */ 446 static 447 SCIP_Bool isNewSection( 448 SCIP* scip, /**< SCIP data structure */ 449 PIPINPUT* pipinput /**< PIP reading data */ 450 ) 451 { 452 SCIP_Bool iscolon; 453 454 assert(pipinput != NULL); 455 456 /* remember first token by swapping the token buffer */ 457 swapTokenBuffer(pipinput); 458 459 /* look at next token: if this is a ':', the first token is a name and no section keyword */ 460 iscolon = FALSE; 461 if( getNextToken(scip, pipinput) ) 462 { 463 iscolon = (strcmp(pipinput->token, ":") == 0); 464 pushToken(pipinput); 465 } 466 467 /* reinstall the previous token by swapping back the token buffer */ 468 swapTokenBuffer(pipinput); 469 470 /* check for ':' */ 471 if( iscolon ) 472 return FALSE; 473 474 if( strcasecmp(pipinput->token, "MINIMIZE") == 0 475 || strcasecmp(pipinput->token, "MINIMUM") == 0 476 || strcasecmp(pipinput->token, "MIN") == 0 ) 477 { 478 SCIPdebugMsg(scip, "(line %d) new section: OBJECTIVE\n", pipinput->linenumber); 479 pipinput->section = PIP_OBJECTIVE; 480 pipinput->objsense = SCIP_OBJSENSE_MINIMIZE; 481 return TRUE; 482 } 483 484 if( strcasecmp(pipinput->token, "MAXIMIZE") == 0 485 || strcasecmp(pipinput->token, "MAXIMUM") == 0 486 || strcasecmp(pipinput->token, "MAX") == 0 ) 487 { 488 SCIPdebugMsg(scip, "(line %d) new section: OBJECTIVE\n", pipinput->linenumber); 489 pipinput->section = PIP_OBJECTIVE; 490 pipinput->objsense = SCIP_OBJSENSE_MAXIMIZE; 491 return TRUE; 492 } 493 494 if( strcasecmp(pipinput->token, "SUBJECT") == 0 ) 495 { 496 /* check if the next token is 'TO' */ 497 swapTokenBuffer(pipinput); 498 if( getNextToken(scip, pipinput) ) 499 { 500 if( strcasecmp(pipinput->token, "TO") == 0 ) 501 { 502 SCIPdebugMsg(scip, "(line %d) new section: CONSTRAINTS\n", pipinput->linenumber); 503 pipinput->section = PIP_CONSTRAINTS; 504 return TRUE; 505 } 506 else 507 pushToken(pipinput); 508 } 509 swapTokenBuffer(pipinput); 510 } 511 512 if( strcasecmp(pipinput->token, "SUCH") == 0 ) 513 { 514 /* check if the next token is 'THAT' */ 515 swapTokenBuffer(pipinput); 516 if( getNextToken(scip, pipinput) ) 517 { 518 if( strcasecmp(pipinput->token, "THAT") == 0 ) 519 { 520 SCIPdebugMsg(scip, "(line %d) new section: CONSTRAINTS\n", pipinput->linenumber); 521 pipinput->section = PIP_CONSTRAINTS; 522 return TRUE; 523 } 524 else 525 pushToken(pipinput); 526 } 527 swapTokenBuffer(pipinput); 528 } 529 530 if( strcasecmp(pipinput->token, "st") == 0 531 || strcasecmp(pipinput->token, "S.T.") == 0 532 || strcasecmp(pipinput->token, "ST.") == 0 ) 533 { 534 SCIPdebugMsg(scip, "(line %d) new section: CONSTRAINTS\n", pipinput->linenumber); 535 pipinput->section = PIP_CONSTRAINTS; 536 return TRUE; 537 } 538 539 if( strcasecmp(pipinput->token, "BOUNDS") == 0 540 || strcasecmp(pipinput->token, "BOUND") == 0 ) 541 { 542 SCIPdebugMsg(scip, "(line %d) new section: BOUNDS\n", pipinput->linenumber); 543 pipinput->section = PIP_BOUNDS; 544 return TRUE; 545 } 546 547 if( strcasecmp(pipinput->token, "GENERAL") == 0 548 || strcasecmp(pipinput->token, "GENERALS") == 0 549 || strcasecmp(pipinput->token, "GEN") == 0 550 || strcasecmp(pipinput->token, "INTEGER") == 0 551 || strcasecmp(pipinput->token, "INTEGERS") == 0 552 || strcasecmp(pipinput->token, "INT") == 0 ) 553 { 554 SCIPdebugMsg(scip, "(line %d) new section: GENERALS\n", pipinput->linenumber); 555 pipinput->section = PIP_GENERALS; 556 return TRUE; 557 } 558 559 if( strcasecmp(pipinput->token, "BINARY") == 0 560 || strcasecmp(pipinput->token, "BINARIES") == 0 561 || strcasecmp(pipinput->token, "BIN") == 0 ) 562 { 563 SCIPdebugMsg(scip, "(line %d) new section: BINARIES\n", pipinput->linenumber); 564 pipinput->section = PIP_BINARIES; 565 return TRUE; 566 } 567 568 if( strcasecmp(pipinput->token, "END") == 0 ) 569 { 570 SCIPdebugMsg(scip, "(line %d) new section: END\n", pipinput->linenumber); 571 pipinput->section = PIP_END; 572 return TRUE; 573 } 574 575 return FALSE; 576 } 577 578 /** returns whether the current token is a sign */ 579 static 580 SCIP_Bool isSign( 581 PIPINPUT* pipinput, /**< PIP reading data */ 582 int* sign /**< pointer to update the sign */ 583 ) 584 { 585 assert(pipinput != NULL); 586 assert(sign != NULL); 587 assert(*sign == +1 || *sign == -1); 588 589 if( pipinput->token[1] == '\0' ) 590 { 591 if( *pipinput->token == '+' ) 592 return TRUE; 593 else if( *pipinput->token == '-' ) 594 { 595 *sign *= -1; 596 return TRUE; 597 } 598 } 599 600 return FALSE; 601 } 602 603 /** returns whether the current token is a value */ 604 static 605 SCIP_Bool isValue( 606 SCIP* scip, /**< SCIP data structure */ 607 PIPINPUT* pipinput, /**< PIP reading data */ 608 SCIP_Real* value /**< pointer to store the value (unchanged, if token is no value) */ 609 ) 610 { 611 assert(pipinput != NULL); 612 assert(value != NULL); 613 614 if( strcasecmp(pipinput->token, "INFINITY") == 0 || strcasecmp(pipinput->token, "INF") == 0 ) 615 { 616 *value = SCIPinfinity(scip); 617 return TRUE; 618 } 619 else 620 { 621 double val; 622 char* endptr; 623 624 val = strtod(pipinput->token, &endptr); 625 if( endptr != pipinput->token && *endptr == '\0' ) 626 { 627 *value = val; 628 return TRUE; 629 } 630 } 631 632 return FALSE; 633 } 634 635 /** returns whether the current token is an equation sense */ 636 static 637 SCIP_Bool isSense( 638 PIPINPUT* pipinput, /**< PIP reading data */ 639 PIPSENSE* sense /**< pointer to store the equation sense, or NULL */ 640 ) 641 { 642 assert(pipinput != NULL); 643 644 if( strcmp(pipinput->token, "<") == 0 ) 645 { 646 if( sense != NULL ) 647 *sense = PIP_SENSE_LE; 648 return TRUE; 649 } 650 else if( strcmp(pipinput->token, ">") == 0 ) 651 { 652 if( sense != NULL ) 653 *sense = PIP_SENSE_GE; 654 return TRUE; 655 } 656 else if( strcmp(pipinput->token, "=") == 0 ) 657 { 658 if( sense != NULL ) 659 *sense = PIP_SENSE_EQ; 660 return TRUE; 661 } 662 663 return FALSE; 664 } 665 666 /** returns the variable with the given name, or creates a new variable if it does not exist */ 667 static 668 SCIP_RETCODE getVariable( 669 SCIP* scip, /**< SCIP data structure */ 670 char* name, /**< name of the variable */ 671 SCIP_Bool dynamiccols, /**< should columns be added and removed dynamically to the LP? */ 672 SCIP_VAR** var, /**< pointer to store the variable */ 673 SCIP_Bool* created /**< pointer to store whether a new variable was created, or NULL */ 674 ) 675 { 676 assert(name != NULL); 677 assert(var != NULL); 678 679 *var = SCIPfindVar(scip, name); 680 if( *var == NULL ) 681 { 682 SCIP_VAR* newvar; 683 684 /* create new variable of the given name */ 685 SCIPdebugMsg(scip, "creating new variable: <%s>\n", name); 686 SCIP_CALL( SCIPcreateVar(scip, &newvar, name, 0.0, SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS, 687 !dynamiccols, dynamiccols, NULL, NULL, NULL, NULL, NULL) ); 688 SCIP_CALL( SCIPaddVar(scip, newvar) ); 689 *var = newvar; 690 691 /* because the variable was added to the problem, it is captured by SCIP and we can safely release it right now 692 * without making the returned *var invalid 693 */ 694 SCIP_CALL( SCIPreleaseVar(scip, &newvar) ); 695 696 if( created != NULL ) 697 *created = TRUE; 698 } 699 else if( created != NULL ) 700 *created = FALSE; 701 702 return SCIP_OKAY; 703 } 704 705 /** reads the header of the file */ 706 static 707 SCIP_RETCODE readStart( 708 SCIP* scip, /**< SCIP data structure */ 709 PIPINPUT* pipinput /**< PIP reading data */ 710 ) 711 { 712 assert(pipinput != NULL); 713 714 /* everything before first section is treated as comment */ 715 do 716 { 717 /* get token */ 718 if( !getNextToken(scip, pipinput) ) 719 return SCIP_OKAY; 720 } 721 while( !isNewSection(scip, pipinput) ); 722 723 return SCIP_OKAY; 724 } 725 726 /** ensure that an array of monomials can hold a minimum number of entries */ 727 static 728 SCIP_RETCODE ensureMonomialsSize( 729 SCIP* scip, /**< SCIP data structure */ 730 SCIP_EXPR*** monomials, /**< pointer to current array of monomials */ 731 SCIP_Real** monomialscoef, /**< pointer to current array of monomial coefficients */ 732 int* monomialssize, /**< current size of monomials array at input; new size at exit */ 733 int minnmonomials /**< required minimal size of monomials array */ 734 ) 735 { 736 int newsize; 737 738 assert(scip != NULL); 739 assert(monomials != NULL); 740 assert(monomialscoef != NULL); 741 assert(monomialssize != NULL); 742 assert(*monomials != NULL || *monomialssize == 0); 743 744 if( minnmonomials <= *monomialssize ) 745 return SCIP_OKAY; 746 747 newsize = SCIPcalcMemGrowSize(scip, minnmonomials); 748 749 if( *monomials != NULL ) 750 { 751 SCIP_CALL( SCIPreallocBufferArray(scip, monomials, newsize) ); 752 } 753 else 754 { 755 SCIP_CALL( SCIPallocBufferArray(scip, monomials, newsize) ); 756 } 757 if( *monomialscoef != NULL ) 758 { 759 SCIP_CALL( SCIPreallocBufferArray(scip, monomialscoef, newsize) ); 760 } 761 else 762 { 763 SCIP_CALL( SCIPallocBufferArray(scip, monomialscoef, newsize) ); 764 } 765 *monomialssize = newsize; 766 767 return SCIP_OKAY; 768 } 769 770 /** ensure that arrays of exponents and variable indices can hold a minimum number of entries */ 771 static 772 SCIP_RETCODE ensureFactorsSize( 773 SCIP* scip, /**< SCIP data structure */ 774 SCIP_VAR*** vars, /**< pointer to current array of variables */ 775 SCIP_Real** exponents, /**< pointer to current array of exponents */ 776 int* factorssize, /**< current size of arrays at input; new size at exit */ 777 int minnfactors /**< required minimal size of arrays */ 778 ) 779 { 780 int newsize; 781 782 assert(scip != NULL); 783 assert(vars != NULL); 784 assert(exponents != NULL); 785 assert(factorssize != NULL); 786 assert(*exponents != NULL || *factorssize == 0); 787 assert(*vars != NULL || *factorssize == 0); 788 789 if( minnfactors <= *factorssize ) 790 return SCIP_OKAY; 791 792 newsize = SCIPcalcMemGrowSize(scip, minnfactors); 793 794 if( *exponents != NULL ) 795 { 796 SCIP_CALL( SCIPreallocBufferArray(scip, exponents, newsize) ); 797 SCIP_CALL( SCIPreallocBufferArray(scip, vars, newsize) ); 798 } 799 else 800 { 801 SCIP_CALL( SCIPallocBufferArray(scip, exponents, newsize) ); 802 SCIP_CALL( SCIPallocBufferArray(scip, vars, newsize) ); 803 } 804 *factorssize = newsize; 805 806 return SCIP_OKAY; 807 } 808 809 /** reads an objective or constraint with name and coefficients */ 810 static 811 SCIP_RETCODE readPolynomial( 812 SCIP* scip, /**< SCIP data structure */ 813 PIPINPUT* pipinput, /**< PIP reading data */ 814 char* name, /**< pointer to store the name of the line; must be at least of size 815 * PIP_MAX_LINELEN */ 816 SCIP_EXPR** expr, /**< pointer to store the constraint function as expression */ 817 SCIP_Bool* islinear, /**< pointer to store polynomial is linear */ 818 SCIP_Bool* newsection /**< pointer to store whether a new section was encountered */ 819 ) 820 { 821 SCIP_Bool havesign; 822 SCIP_Bool havevalue; 823 SCIP_Real coef; 824 int coefsign; 825 int nextcoefsign; 826 int monomialdegree; 827 int i; 828 829 SCIP_VAR** vars; 830 SCIP_Real constant; 831 832 SCIP_EXPR** monomials; 833 SCIP_Real* monomialscoef; 834 int monomialssize; 835 int nmonomials; 836 837 int nfactors; 838 int factorssize; 839 SCIP_Real* exponents; 840 841 assert(scip != NULL); 842 assert(pipinput != NULL); 843 assert(name != NULL); 844 assert(expr != NULL); 845 assert(islinear != NULL); 846 assert(newsection != NULL); 847 848 *name = '\0'; 849 *expr = NULL; 850 *islinear = TRUE; 851 *newsection = FALSE; 852 853 /* read the first token, which may be the name of the line */ 854 if( getNextToken(scip, pipinput) ) 855 { 856 /* check if we reached a new section */ 857 if( isNewSection(scip, pipinput) ) 858 { 859 *newsection = TRUE; 860 return SCIP_OKAY; 861 } 862 863 /* remember the token in the token buffer */ 864 swapTokenBuffer(pipinput); 865 866 /* get the next token and check, whether it is a colon */ 867 if( getNextToken(scip, pipinput) ) 868 { 869 if( strcmp(pipinput->token, ":") == 0 ) 870 { 871 /* the second token was a colon: the first token is the line name */ 872 (void)SCIPstrncpy(name, pipinput->tokenbuf, PIP_MAX_LINELEN); 873 SCIPdebugMsg(scip, "(line %d) read constraint name: '%s'\n", pipinput->linenumber, name); 874 } 875 else 876 { 877 /* the second token was no colon: push the tokens back onto the token stack and parse them as coefficients */ 878 pushToken(pipinput); 879 pushBufferToken(pipinput); 880 } 881 } 882 else 883 { 884 /* there was only one token left: push it back onto the token stack and parse it as coefficient */ 885 pushBufferToken(pipinput); 886 } 887 } 888 889 /* initialize buffer for storing the monomials */ 890 monomialssize = PIP_INIT_MONOMIALSSIZE; 891 SCIP_CALL( SCIPallocBufferArray(scip, &monomials, monomialssize) ); 892 SCIP_CALL( SCIPallocBufferArray(scip, &monomialscoef, monomialssize) ); 893 894 /* initialize buffer for storing the factors in a monomial */ 895 factorssize = PIP_INIT_FACTORSSIZE; 896 SCIP_CALL( SCIPallocBufferArray(scip, &exponents, factorssize) ); 897 SCIP_CALL( SCIPallocBufferArray(scip, &vars, factorssize) ); 898 899 /* read the coefficients */ 900 coefsign = +1; 901 nextcoefsign = +1; 902 coef = 1.0; 903 havesign = FALSE; 904 havevalue = FALSE; 905 nmonomials = 0; 906 nfactors = 0; 907 monomialdegree = 0; 908 constant = 0.0; 909 while( getNextToken(scip, pipinput) ) 910 { 911 SCIP_VAR* var; 912 SCIP_Bool issense; 913 SCIP_Bool issign; 914 SCIP_Bool isnewsection; 915 SCIP_Real exponent; 916 917 issign = FALSE; /* fix compiler warning */ 918 issense = FALSE; /* fix lint warning */ 919 if( (isnewsection = isNewSection(scip, pipinput)) || /*lint !e820*/ 920 (issense = isSense(pipinput, NULL)) || /*lint !e820*/ 921 ((nfactors > 0 || havevalue) && (issign = isSign(pipinput, &nextcoefsign))) ) /*lint !e820*/ 922 { 923 /* finish the current monomial */ 924 if( nfactors > 0 ) 925 { 926 if( coefsign * coef != 0.0 ) 927 { 928 SCIP_CALL( ensureMonomialsSize(scip, &monomials, &monomialscoef, &monomialssize, nmonomials + 1) ); 929 SCIP_CALL( SCIPcreateExprMonomial(scip, &monomials[nmonomials], nfactors, vars, exponents, NULL, NULL) ); 930 monomialscoef[nmonomials] = coefsign * coef; 931 ++nmonomials; 932 } 933 } 934 else if( havevalue ) 935 { 936 constant += coefsign * coef; 937 } 938 939 if( monomialdegree > 1 ) 940 *islinear = FALSE; 941 942 /* reset variables */ 943 nfactors = 0; 944 coef = 1.0; 945 coefsign = +1; 946 havesign = FALSE; 947 havevalue = FALSE; 948 monomialdegree = 0; 949 950 if( isnewsection ) 951 { 952 *newsection = TRUE; 953 break; 954 } 955 956 if( issense ) 957 { 958 /* put the sense back onto the token stack */ 959 pushToken(pipinput); 960 break; 961 } 962 963 if( issign ) 964 { 965 coefsign = nextcoefsign; 966 SCIPdebugMsg(scip, "(line %d) read coefficient sign: %+d\n", pipinput->linenumber, coefsign); 967 havesign = TRUE; 968 nextcoefsign = +1; 969 continue; 970 } 971 } 972 973 /* check if we read a sign */ 974 if( isSign(pipinput, &coefsign) ) 975 { 976 SCIPdebugMsg(scip, "(line %d) read coefficient sign: %+d\n", pipinput->linenumber, coefsign); 977 978 if( nfactors > 0 || havevalue ) 979 { 980 syntaxError(scip, pipinput, "sign can only be at beginning of monomial"); 981 goto TERMINATE_READPOLYNOMIAL; 982 } 983 984 havesign = TRUE; 985 continue; 986 } 987 988 /* check if we are in between factors of a monomial */ 989 if( strcmp(pipinput->token, "*") == 0 ) 990 { 991 if( nfactors == 0 ) 992 { 993 syntaxError(scip, pipinput, "cannot have '*' before first variable in monomial"); 994 goto TERMINATE_READPOLYNOMIAL; 995 } 996 997 continue; 998 } 999 1000 /* all but the first monomial need a sign */ 1001 if( nmonomials > 0 && !havesign ) 1002 { 1003 syntaxError(scip, pipinput, "expected sign ('+' or '-') or sense ('<' or '>')"); 1004 goto TERMINATE_READPOLYNOMIAL; 1005 } 1006 1007 /* check if we are at an exponent for the last variable */ 1008 if( strcmp(pipinput->token, "^") == 0 ) 1009 { 1010 if( !getNextToken(scip, pipinput) || !isValue(scip, pipinput, &exponent) ) 1011 { 1012 syntaxError(scip, pipinput, "expected exponent value after '^'"); 1013 goto TERMINATE_READPOLYNOMIAL; 1014 } 1015 if( nfactors == 0 ) 1016 { 1017 syntaxError(scip, pipinput, "cannot have '^' before first variable in monomial"); 1018 goto TERMINATE_READPOLYNOMIAL; 1019 } 1020 exponents[nfactors-1] = exponent; /*lint !e530*/ 1021 if( SCIPisIntegral(scip, exponent) && exponent > 0.0 ) /*lint !e530*/ 1022 monomialdegree += (int)exponent - 1; /*lint !e530*//* -1, because we added +1 when we put the variable into varidxs */ 1023 else 1024 *islinear = FALSE; 1025 1026 SCIPdebugMsg(scip, "(line %d) read exponent value %g for variable %s\n", pipinput->linenumber, exponent, 1027 SCIPvarGetName(vars[nfactors-1])); 1028 continue; 1029 } 1030 1031 /* check if we read a value */ 1032 if( isValue(scip, pipinput, &coef) ) 1033 { 1034 SCIPdebugMsg(scip, "(line %d) read coefficient value: %g with sign %+d\n", pipinput->linenumber, coef, coefsign); 1035 1036 if( havevalue ) 1037 { 1038 syntaxError(scip, pipinput, "two consecutive values"); 1039 goto TERMINATE_READPOLYNOMIAL; 1040 } 1041 1042 if( nfactors > 0 ) 1043 { 1044 syntaxError(scip, pipinput, "coefficients can only be at the beginning of a monomial"); 1045 goto TERMINATE_READPOLYNOMIAL; 1046 } 1047 1048 havevalue = TRUE; 1049 continue; 1050 } 1051 1052 /* the token is a variable name: get the corresponding variable (or create a new one) */ 1053 SCIP_CALL( getVariable(scip, pipinput->token, pipinput->dynamiccols, &var, NULL) ); 1054 1055 /* ensure that there is enough memory to store all factors */ 1056 SCIP_CALL( ensureFactorsSize(scip, &vars, &exponents, &factorssize, nfactors + 1) ); 1057 1058 /* create and store corresponding variable expression */ 1059 vars[nfactors] = var; 1060 exponents[nfactors] = 1.0; 1061 ++nfactors; 1062 ++monomialdegree; 1063 } 1064 1065 if( nfactors > 0 ) 1066 { 1067 syntaxError(scip, pipinput, "string ended before monomial has finished"); 1068 goto TERMINATE_READPOLYNOMIAL; 1069 } 1070 1071 /* create sum expression consisting of all monomial expressions */ 1072 SCIP_CALL( SCIPcreateExprSum(scip, expr, nmonomials, monomials, monomialscoef, constant, NULL, NULL) ); 1073 1074 /* release monomial expressions */ 1075 for( i = 0; i < nmonomials; ++i ) 1076 { 1077 assert(monomials[i] != NULL); 1078 SCIP_CALL( SCIPreleaseExpr(scip, &monomials[i]) ); 1079 } 1080 1081 #ifdef SCIP_DEBUG 1082 SCIPdebugMsg(scip, "read polynomial: "); 1083 SCIP_CALL( SCIPprintExpr(scip, *expr, NULL) ); 1084 SCIPinfoMessage(scip, NULL, "\n"); 1085 #endif 1086 1087 TERMINATE_READPOLYNOMIAL: 1088 SCIPfreeBufferArray(scip, &vars); 1089 SCIPfreeBufferArray(scip, &exponents); 1090 SCIPfreeBufferArray(scip, &monomialscoef); 1091 SCIPfreeBufferArray(scip, &monomials); 1092 1093 return SCIP_OKAY; 1094 } 1095 1096 /** reads the objective section */ 1097 static 1098 SCIP_RETCODE readObjective( 1099 SCIP* scip, /**< SCIP data structure */ 1100 PIPINPUT* pipinput /**< PIP reading data */ 1101 ) 1102 { 1103 char name[PIP_MAX_LINELEN]; 1104 SCIP_EXPR* expr; 1105 SCIP_Bool linear; 1106 SCIP_Bool newsection; 1107 SCIP_Bool initial; 1108 SCIP_Bool separate; 1109 SCIP_Bool enforce; 1110 SCIP_Bool check; 1111 SCIP_Bool propagate; 1112 SCIP_Bool local; 1113 SCIP_Bool modifiable; 1114 SCIP_Bool dynamic; 1115 SCIP_Bool removable; 1116 1117 assert(pipinput != NULL); 1118 1119 /* determine settings; note that reading/{initialconss,dynamicconss,dynamicrows,dynamiccols} apply only to model 1120 * constraints and variables, not to an auxiliary objective constraint (otherwise it can happen that an auxiliary 1121 * objective variable is loose with infinite best bound, triggering the problem that an LP that is unbounded because 1122 * of loose variables with infinite best bound cannot be solved) 1123 */ 1124 initial = TRUE; 1125 separate = TRUE; 1126 enforce = TRUE; 1127 check = TRUE; 1128 propagate = TRUE; 1129 local = FALSE; 1130 modifiable = FALSE; 1131 dynamic = FALSE; 1132 removable = FALSE; 1133 1134 /* read the objective coefficients */ 1135 SCIP_CALL( readPolynomial(scip, pipinput, name, &expr, &linear, &newsection) ); 1136 if( !hasError(pipinput) && expr != NULL ) 1137 { 1138 SCIP_Real constant = SCIPgetConstantExprSum(expr); 1139 1140 /* always create a variable that represents the constant; otherwise, this might lead to numerical issues on 1141 * instances with a relatively large constant, e.g., popdynm* instances 1142 */ 1143 if( constant != 0.0 ) 1144 { 1145 SCIP_VAR* objconst; 1146 SCIP_CALL( SCIPcreateVarBasic(scip, &objconst, "objconst", 1.0, 1.0, constant, SCIP_VARTYPE_CONTINUOUS) ); 1147 SCIP_CALL( SCIPaddVar(scip, objconst) ); 1148 SCIP_CALL( SCIPreleaseVar(scip, &objconst) ); 1149 1150 /* remove the constant of the sum expression */ 1151 SCIPsetConstantExprSum(expr, 0.0); 1152 } 1153 1154 if( linear ) 1155 { 1156 int i; 1157 1158 /* set objective coefficients of variables */ 1159 for( i = 0; i < SCIPexprGetNChildren(expr); ++i ) 1160 { 1161 SCIP_EXPR* child; 1162 SCIP_VAR* var; 1163 SCIP_Real coef; 1164 1165 child = SCIPexprGetChildren(expr)[i]; 1166 assert(child != NULL); 1167 assert(SCIPisExprVar(scip, child)); 1168 1169 /* child has to be a variable expression, see SCIPcreateExprMonomial() */ 1170 var = SCIPgetVarExprVar(child); 1171 assert(var != NULL); 1172 coef = SCIPgetCoefsExprSum(expr)[i]; 1173 1174 /* adjust the objective coefficient */ 1175 SCIP_CALL( SCIPchgVarObj(scip, var, SCIPvarGetObj(var) + coef) ); 1176 } 1177 } 1178 else /* insert dummy variable and constraint to represent the nonlinear objective */ 1179 { 1180 SCIP_EXPR* nonlinobjvarexpr; 1181 SCIP_VAR* nonlinobjvar; 1182 SCIP_CONS* nonlinobjcons; 1183 SCIP_Real lhs; 1184 SCIP_Real rhs; 1185 1186 SCIP_CALL( SCIPcreateVar(scip, &nonlinobjvar, "nonlinobjvar", -SCIPinfinity(scip), SCIPinfinity(scip), 1.0, 1187 SCIP_VARTYPE_CONTINUOUS, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) ); 1188 SCIP_CALL( SCIPaddVar(scip, nonlinobjvar) ); 1189 1190 if ( pipinput->objsense == SCIP_OBJSENSE_MINIMIZE ) 1191 { 1192 lhs = -SCIPinfinity(scip); 1193 rhs = 0.0; 1194 } 1195 else 1196 { 1197 lhs = 0.0; 1198 rhs = SCIPinfinity(scip); 1199 } 1200 1201 /* add created objective variable */ 1202 SCIP_CALL( SCIPcreateExprVar(scip, &nonlinobjvarexpr, nonlinobjvar, NULL, NULL) ); 1203 SCIP_CALL( SCIPappendExprSumExpr(scip, expr, nonlinobjvarexpr, -1.0) ); 1204 SCIP_CALL( SCIPreleaseExpr(scip, &nonlinobjvarexpr) ); 1205 1206 /* create nonlinear constraint */ 1207 SCIP_CALL( SCIPcreateConsNonlinear(scip, &nonlinobjcons, "nonlinobj", expr, lhs, rhs, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) ); 1208 1209 SCIP_CALL( SCIPaddCons(scip, nonlinobjcons) ); 1210 SCIPdebugMsg(scip, "(line %d) added constraint <%s> to represent nonlinear objective: ", pipinput->linenumber, SCIPconsGetName(nonlinobjcons)); 1211 SCIPdebugPrintCons(scip, nonlinobjcons, NULL); 1212 1213 SCIP_CALL( SCIPreleaseCons(scip, &nonlinobjcons) ); 1214 SCIP_CALL( SCIPreleaseVar(scip, &nonlinobjvar) ); 1215 } 1216 } 1217 1218 /* release expression */ 1219 if( expr != NULL ) 1220 { 1221 SCIP_CALL( SCIPreleaseExpr(scip, &expr) ); 1222 } 1223 1224 return SCIP_OKAY; 1225 } 1226 1227 /** reads the constraints section */ 1228 static 1229 SCIP_RETCODE readConstraints( 1230 SCIP* scip, /**< SCIP data structure */ 1231 PIPINPUT* pipinput /**< PIP reading data */ 1232 ) 1233 { 1234 char name[PIP_MAX_LINELEN]; 1235 SCIP_EXPR* expr; 1236 SCIP_CONS* cons = NULL; 1237 SCIP_Bool linear; 1238 1239 PIPSENSE sense; 1240 SCIP_Real sidevalue; 1241 SCIP_Real lhs; 1242 SCIP_Real rhs; 1243 SCIP_Bool newsection; 1244 SCIP_Bool initial; 1245 SCIP_Bool separate; 1246 SCIP_Bool enforce; 1247 SCIP_Bool check; 1248 SCIP_Bool propagate; 1249 SCIP_Bool local; 1250 SCIP_Bool modifiable; 1251 SCIP_Bool dynamic; 1252 SCIP_Bool removable; 1253 int sidesign; 1254 1255 assert(pipinput != NULL); 1256 1257 /* read polynomial */ 1258 SCIP_CALL( readPolynomial(scip, pipinput, name, &expr, &linear, &newsection) ); 1259 if ( hasError(pipinput) ) 1260 return SCIP_READERROR; 1261 if ( newsection ) 1262 { 1263 if ( expr != NULL ) 1264 syntaxError(scip, pipinput, "expected constraint sense '<=', '=', or '>='"); 1265 return SCIP_OKAY; 1266 } 1267 1268 /* read the constraint sense */ 1269 if ( !getNextToken(scip, pipinput) ) 1270 { 1271 syntaxError(scip, pipinput, "expected constraint sense."); 1272 return SCIP_READERROR; 1273 } 1274 if ( !isSense(pipinput, &sense) ) 1275 { 1276 syntaxError(scip, pipinput, "expected constraint sense '<=', '=', or '>='"); 1277 return SCIP_READERROR; 1278 } 1279 1280 /* read the right hand side */ 1281 sidesign = +1; 1282 if ( !getNextToken(scip, pipinput) ) 1283 { 1284 syntaxError(scip, pipinput, "missing right hand side"); 1285 return SCIP_READERROR; 1286 } 1287 if ( isSign(pipinput, &sidesign) ) 1288 { 1289 if( !getNextToken(scip, pipinput) ) 1290 { 1291 syntaxError(scip, pipinput, "missing value of right hand side"); 1292 return SCIP_READERROR; 1293 } 1294 } 1295 if ( !isValue(scip, pipinput, &sidevalue) ) 1296 { 1297 syntaxError(scip, pipinput, "expected value as right hand side"); 1298 return SCIP_READERROR; 1299 } 1300 sidevalue *= sidesign; 1301 1302 /* determine settings */ 1303 initial = pipinput->initialconss; 1304 separate = TRUE; 1305 enforce = TRUE; 1306 check = TRUE; 1307 propagate = TRUE; 1308 local = FALSE; 1309 modifiable = FALSE; 1310 dynamic = pipinput->dynamicconss; 1311 removable = pipinput->dynamicrows; 1312 1313 /* assign the left and right hand side, depending on the constraint sense */ 1314 switch ( sense ) /*lint !e530*/ 1315 { 1316 case PIP_SENSE_GE: 1317 lhs = sidevalue; 1318 rhs = SCIPinfinity(scip); 1319 break; 1320 case PIP_SENSE_LE: 1321 lhs = -SCIPinfinity(scip); 1322 rhs = sidevalue; 1323 break; 1324 case PIP_SENSE_EQ: 1325 lhs = sidevalue; 1326 rhs = sidevalue; 1327 break; 1328 case PIP_SENSE_NOTHING: 1329 default: 1330 SCIPerrorMessage("invalid constraint sense <%d>\n", sense); 1331 return SCIP_INVALIDDATA; 1332 } 1333 1334 /* linear constraint function */ 1335 if( linear ) 1336 { 1337 SCIP_VAR** vars; 1338 SCIP_Real* coefs; 1339 SCIP_Real constant; 1340 int nchildren; 1341 int i; 1342 1343 nchildren = SCIPexprGetNChildren(expr); 1344 constant = SCIPgetConstantExprSum(expr); 1345 coefs = SCIPgetCoefsExprSum(expr); 1346 1347 /* allocate memory to store variables */ 1348 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren) ); 1349 1350 /* collect variables */ 1351 for( i = 0; i < nchildren; ++i ) 1352 { 1353 SCIP_EXPR* child = SCIPexprGetChildren(expr)[i]; 1354 assert(child != NULL); 1355 assert(SCIPisExprVar(scip, child)); 1356 1357 vars[i] = SCIPgetVarExprVar(child); 1358 assert(vars[i] != NULL); 1359 } 1360 1361 /* adjust lhs and rhs */ 1362 if( !SCIPisInfinity(scip, -lhs) ) 1363 lhs -= constant; 1364 if( !SCIPisInfinity(scip, rhs) ) 1365 rhs -= constant; 1366 1367 /* create linear constraint */ 1368 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nchildren, vars, coefs, lhs, rhs, initial, separate, enforce, 1369 check, propagate, local, modifiable, dynamic, removable, FALSE) ); 1370 1371 /* free memory */ 1372 SCIPfreeBufferArray(scip, &vars); 1373 } 1374 else /* nonlinear constraint function */ 1375 { 1376 SCIP_CALL( SCIPcreateConsNonlinear(scip, &cons, name, expr, lhs, rhs, initial, separate, enforce, check, propagate, 1377 local, modifiable, dynamic, removable) ); 1378 } 1379 1380 /* add and release constraint */ 1381 assert(cons != NULL); 1382 SCIP_CALL( SCIPaddCons(scip, cons) ); 1383 SCIPdebugMsg(scip, "(line %d) created constraint: ", pipinput->linenumber); 1384 SCIPdebugPrintCons(scip, cons, NULL); 1385 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 1386 1387 /* release expression */ 1388 if( expr != NULL ) 1389 { 1390 SCIP_CALL( SCIPreleaseExpr(scip, &expr) ); 1391 } 1392 1393 return SCIP_OKAY; 1394 } 1395 1396 /** reads the bounds section */ 1397 static 1398 SCIP_RETCODE readBounds( 1399 SCIP* scip, /**< SCIP data structure */ 1400 PIPINPUT* pipinput /**< PIP reading data */ 1401 ) 1402 { 1403 assert(pipinput != NULL); 1404 1405 while( getNextToken(scip, pipinput) ) 1406 { 1407 SCIP_VAR* var; 1408 SCIP_Real value; 1409 SCIP_Real lb; 1410 SCIP_Real ub; 1411 int sign; 1412 SCIP_Bool hassign; 1413 PIPSENSE leftsense; 1414 1415 /* check if we reached a new section */ 1416 if( isNewSection(scip, pipinput) ) 1417 return SCIP_OKAY; 1418 1419 /* default bounds are [0,+inf] */ 1420 lb = 0.0; 1421 ub = SCIPinfinity(scip); 1422 leftsense = PIP_SENSE_NOTHING; 1423 1424 /* check if the first token is a sign */ 1425 sign = +1; 1426 hassign = isSign(pipinput, &sign); 1427 if( hassign && !getNextToken(scip, pipinput) ) 1428 { 1429 syntaxError(scip, pipinput, "expected value"); 1430 return SCIP_OKAY; 1431 } 1432 1433 /* the first token must be either a value or a variable name */ 1434 if( isValue(scip, pipinput, &value) ) 1435 { 1436 /* first token is a value: the second token must be a sense */ 1437 if( !getNextToken(scip, pipinput) || !isSense(pipinput, &leftsense) ) 1438 { 1439 syntaxError(scip, pipinput, "expected bound sense '<=', '=', or '>='"); 1440 return SCIP_OKAY; 1441 } 1442 1443 /* update the bound corresponding to the sense */ 1444 switch( leftsense ) 1445 { 1446 case PIP_SENSE_GE: 1447 ub = sign * value; 1448 break; 1449 case PIP_SENSE_LE: 1450 lb = sign * value; 1451 break; 1452 case PIP_SENSE_EQ: 1453 lb = sign * value; 1454 ub = sign * value; 1455 break; 1456 case PIP_SENSE_NOTHING: 1457 default: 1458 SCIPerrorMessage("invalid bound sense <%d>\n", leftsense); 1459 return SCIP_INVALIDDATA; 1460 } 1461 } 1462 else if( hassign ) 1463 { 1464 syntaxError(scip, pipinput, "expected value"); 1465 return SCIP_OKAY; 1466 } 1467 else 1468 pushToken(pipinput); 1469 1470 /* the next token must be a variable name */ 1471 if( !getNextToken(scip, pipinput) ) 1472 { 1473 syntaxError(scip, pipinput, "expected variable name"); 1474 return SCIP_OKAY; 1475 } 1476 SCIP_CALL( getVariable(scip, pipinput->token, pipinput->dynamiccols, &var, NULL) ); 1477 1478 /* the next token might be another sense, or the word "free" */ 1479 if( getNextToken(scip, pipinput) ) 1480 { 1481 PIPSENSE rightsense; 1482 1483 if( isSense(pipinput, &rightsense) ) 1484 { 1485 /* check, if the senses fit */ 1486 if( leftsense == PIP_SENSE_NOTHING 1487 || (leftsense == PIP_SENSE_LE && rightsense == PIP_SENSE_LE) 1488 || (leftsense == PIP_SENSE_GE && rightsense == PIP_SENSE_GE) ) 1489 { 1490 if( !getNextToken(scip, pipinput) ) 1491 { 1492 syntaxError(scip, pipinput, "expected value or sign"); 1493 return SCIP_OKAY; 1494 } 1495 1496 /* check if the next token is a sign */ 1497 sign = +1; 1498 hassign = isSign(pipinput, &sign); 1499 if( hassign && !getNextToken(scip, pipinput) ) 1500 { 1501 syntaxError(scip, pipinput, "expected value"); 1502 return SCIP_OKAY; 1503 } 1504 1505 /* the next token must be a value */ 1506 if( !isValue(scip, pipinput, &value) ) 1507 { 1508 syntaxError(scip, pipinput, "expected value"); 1509 return SCIP_OKAY; 1510 } 1511 1512 /* update the bound corresponding to the sense */ 1513 switch( rightsense ) 1514 { 1515 case PIP_SENSE_GE: 1516 lb = sign * value; 1517 break; 1518 case PIP_SENSE_LE: 1519 ub = sign * value; 1520 break; 1521 case PIP_SENSE_EQ: 1522 lb = sign * value; 1523 ub = sign * value; 1524 break; 1525 case PIP_SENSE_NOTHING: 1526 default: 1527 SCIPerrorMessage("invalid bound sense <%d>\n", leftsense); 1528 return SCIP_INVALIDDATA; 1529 } 1530 } 1531 else 1532 { 1533 syntaxError(scip, pipinput, "the two bound senses do not fit"); 1534 return SCIP_OKAY; 1535 } 1536 } 1537 else if( strcasecmp(pipinput->token, "FREE") == 0 ) 1538 { 1539 if( leftsense != PIP_SENSE_NOTHING ) 1540 { 1541 syntaxError(scip, pipinput, "variable with bound is marked as 'free'"); 1542 return SCIP_OKAY; 1543 } 1544 lb = -SCIPinfinity(scip); 1545 ub = SCIPinfinity(scip); 1546 } 1547 else 1548 { 1549 /* the token was no sense: push it back to the token stack */ 1550 pushToken(pipinput); 1551 } 1552 } 1553 1554 /* change the bounds of the variable if bounds have been given (do not destroy earlier specification of bounds) */ 1555 if ( lb != 0.0 ) 1556 SCIP_CALL( SCIPchgVarLb(scip, var, lb) ); 1557 /*lint --e{777}*/ 1558 if ( ub != SCIPinfinity(scip) ) 1559 SCIP_CALL( SCIPchgVarUb(scip, var, ub) ); 1560 SCIPdebugMsg(scip, "(line %d) new bounds: <%s>[%g,%g]\n", pipinput->linenumber, SCIPvarGetName(var), 1561 SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)); 1562 } 1563 1564 return SCIP_OKAY; 1565 } 1566 1567 /** reads the generals section */ 1568 static 1569 SCIP_RETCODE readGenerals( 1570 SCIP* scip, /**< SCIP data structure */ 1571 PIPINPUT* pipinput /**< PIP reading data */ 1572 ) 1573 { 1574 assert(pipinput != NULL); 1575 1576 while( getNextToken(scip, pipinput) ) 1577 { 1578 SCIP_VAR* var; 1579 SCIP_Bool created; 1580 SCIP_Bool infeasible; 1581 1582 /* check if we reached a new section */ 1583 if( isNewSection(scip, pipinput) ) 1584 return SCIP_OKAY; 1585 1586 /* the token must be the name of an existing variable */ 1587 SCIP_CALL( getVariable(scip, pipinput->token, pipinput->dynamiccols, &var, &created) ); 1588 if( created ) 1589 { 1590 syntaxError(scip, pipinput, "unknown variable in generals section"); 1591 return SCIP_OKAY; 1592 } 1593 1594 /* mark the variable to be integral */ 1595 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_INTEGER, &infeasible) ); 1596 /* don't assert feasibility here because the presolver will and should detect a infeasibility */ 1597 } 1598 1599 return SCIP_OKAY; 1600 } 1601 1602 /** reads the binaries section */ 1603 static 1604 SCIP_RETCODE readBinaries( 1605 SCIP* scip, /**< SCIP data structure */ 1606 PIPINPUT* pipinput /**< PIP reading data */ 1607 ) 1608 { 1609 assert(pipinput != NULL); 1610 1611 while( getNextToken(scip, pipinput) ) 1612 { 1613 SCIP_VAR* var; 1614 SCIP_Bool created; 1615 SCIP_Bool infeasible; 1616 1617 /* check if we reached a new section */ 1618 if( isNewSection(scip, pipinput) ) 1619 return SCIP_OKAY; 1620 1621 /* the token must be the name of an existing variable */ 1622 SCIP_CALL( getVariable(scip, pipinput->token, pipinput->dynamiccols, &var, &created) ); 1623 if( created ) 1624 { 1625 syntaxError(scip, pipinput, "unknown variable in binaries section"); 1626 return SCIP_OKAY; 1627 } 1628 1629 /* mark the variable to be binary and change its bounds appropriately */ 1630 if( SCIPvarGetLbGlobal(var) < 0.0 ) 1631 { 1632 SCIP_CALL( SCIPchgVarLb(scip, var, 0.0) ); 1633 } 1634 if( SCIPvarGetUbGlobal(var) > 1.0 ) 1635 { 1636 SCIP_CALL( SCIPchgVarUb(scip, var, 1.0) ); 1637 } 1638 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) ); 1639 /* don't assert feasibility here because the presolver will and should detect a infeasibility */ 1640 } 1641 1642 return SCIP_OKAY; 1643 } 1644 1645 /** reads a PIP file 1646 */ 1647 static 1648 SCIP_RETCODE readPIPFile( 1649 SCIP* scip, /**< SCIP data structure */ 1650 PIPINPUT* pipinput, /**< PIP reading data */ 1651 const char* filename /**< name of the input file */ 1652 ) 1653 { 1654 assert(pipinput != NULL); 1655 1656 /* open file */ 1657 pipinput->file = SCIPfopen(filename, "r"); 1658 if( pipinput->file == NULL ) 1659 { 1660 SCIPerrorMessage("cannot open file <%s> for reading\n", filename); 1661 SCIPprintSysError(filename); 1662 return SCIP_NOFILE; 1663 } 1664 1665 /* create problem */ 1666 SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); 1667 1668 /* parse the file */ 1669 pipinput->section = PIP_START; 1670 while( pipinput->section != PIP_END && !hasError(pipinput) ) 1671 { 1672 switch( pipinput->section ) 1673 { 1674 case PIP_START: 1675 SCIP_CALL( readStart(scip, pipinput) ); 1676 break; 1677 1678 case PIP_OBJECTIVE: 1679 SCIP_CALL( readObjective(scip, pipinput) ); 1680 break; 1681 1682 case PIP_CONSTRAINTS: 1683 SCIP_CALL( readConstraints(scip, pipinput) ); 1684 break; 1685 1686 case PIP_BOUNDS: 1687 SCIP_CALL( readBounds(scip, pipinput) ); 1688 break; 1689 1690 case PIP_GENERALS: 1691 SCIP_CALL( readGenerals(scip, pipinput) ); 1692 break; 1693 1694 case PIP_BINARIES: 1695 SCIP_CALL( readBinaries(scip, pipinput) ); 1696 break; 1697 1698 case PIP_END: /* this is already handled in the while() loop */ 1699 default: 1700 SCIPerrorMessage("invalid PIP file section <%d>\n", pipinput->section); 1701 return SCIP_INVALIDDATA; 1702 } 1703 } 1704 1705 /* close file */ 1706 SCIPfclose(pipinput->file); 1707 1708 return SCIP_OKAY; 1709 } 1710 1711 1712 /* 1713 * Local methods (for writing) 1714 */ 1715 1716 /** hash key retrieval function for variables */ 1717 static 1718 SCIP_DECL_HASHGETKEY(hashGetKeyVar) 1719 { /*lint --e{715}*/ 1720 return elem; 1721 } 1722 1723 /** returns TRUE iff the indices of both variables are equal */ 1724 static 1725 SCIP_DECL_HASHKEYEQ(hashKeyEqVar) 1726 { /*lint --e{715}*/ 1727 if ( key1 == key2 ) 1728 return TRUE; 1729 return FALSE; 1730 } 1731 1732 /** returns the hash value of the key */ 1733 static 1734 SCIP_DECL_HASHKEYVAL(hashKeyValVar) 1735 { /*lint --e{715}*/ 1736 assert( SCIPvarGetIndex((SCIP_VAR*) key) >= 0 ); 1737 return (unsigned int) SCIPvarGetIndex((SCIP_VAR*) key); 1738 } 1739 1740 /** transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant */ 1741 static 1742 SCIP_RETCODE getActiveVariables( 1743 SCIP* scip, /**< SCIP data structure */ 1744 SCIP_VAR*** vars, /**< pointer to vars array to get active variables for */ 1745 SCIP_Real** scalars, /**< pointer to scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */ 1746 int* nvars, /**< pointer to number of variables and values in vars and vals array */ 1747 SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */ 1748 SCIP_Bool transformed /**< transformed constraint? */ 1749 ) 1750 { 1751 int requiredsize; 1752 int v; 1753 1754 assert(scip != NULL); 1755 assert(vars != NULL); 1756 assert(scalars != NULL); 1757 assert(nvars != NULL); 1758 assert(*vars != NULL || *nvars == 0); 1759 assert(*scalars != NULL || *nvars == 0); 1760 assert(constant != NULL); 1761 1762 if( transformed ) 1763 { 1764 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); 1765 1766 if( requiredsize > *nvars ) 1767 { 1768 SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) ); 1769 SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) ); 1770 1771 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); 1772 assert( requiredsize <= *nvars ); 1773 } 1774 } 1775 else 1776 { 1777 if( *nvars > 0 && ( *vars == NULL || *scalars == NULL ) ) /*lint !e774 !e845*/ 1778 { 1779 SCIPerrorMessage("Null pointer in PIP reader\n"); /* should not happen */ 1780 SCIPABORT(); 1781 return SCIP_INVALIDDATA; /*lint !e527*/ 1782 } 1783 1784 for( v = 0; v < *nvars; ++v ) 1785 { 1786 SCIP_CALL( SCIPvarGetOrigvarSum(&(*vars)[v], &(*scalars)[v], constant) ); 1787 1788 /* negated variables with an original counterpart may also be returned by SCIPvarGetOrigvarSum(); 1789 * make sure we get the original variable in that case 1790 */ 1791 if( SCIPvarGetStatus((*vars)[v]) == SCIP_VARSTATUS_NEGATED ) 1792 { 1793 (*vars)[v] = SCIPvarGetNegatedVar((*vars)[v]); 1794 *constant += (*scalars)[v]; 1795 (*scalars)[v] *= -1.0; 1796 } 1797 } 1798 } 1799 return SCIP_OKAY; 1800 } 1801 1802 /** checks whether a given expression is a signomial 1803 * 1804 * assumes simplified expression 1805 */ 1806 static 1807 SCIP_Bool isExprSignomial( 1808 SCIP* scip, /**< SCIP data structure */ 1809 SCIP_EXPR* expr /**< expression */ 1810 ) 1811 { 1812 assert(scip != NULL); 1813 assert(expr != NULL); 1814 1815 if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) ) 1816 return TRUE; 1817 1818 if( SCIPisExprPower(scip, expr) && SCIPisExprVar(scip, SCIPexprGetChildren(expr)[0]) ) 1819 return TRUE; 1820 1821 if( SCIPisExprProduct(scip, expr) ) 1822 { 1823 SCIP_EXPR* child; 1824 int c; 1825 1826 for( c = 0; c < SCIPexprGetNChildren(expr); ++c ) 1827 { 1828 child = SCIPexprGetChildren(expr)[c]; 1829 1830 if( SCIPisExprVar(scip, child) ) 1831 continue; 1832 1833 if( SCIPisExprPower(scip, child) && SCIPisExprVar(scip, SCIPexprGetChildren(child)[0]) ) 1834 continue; 1835 1836 /* the pip format does not allow constants here */ 1837 1838 return FALSE; 1839 } 1840 1841 return TRUE; 1842 } 1843 1844 return FALSE; 1845 } 1846 1847 /** checks whether a given expression is a sum of signomials (i.e., like a polynomial, but negative and fractional exponents allowed) 1848 * 1849 * assumes simplified expression; 1850 * does not check whether variables in powers with fractional exponent are nonnegative; 1851 * does not check whether variables in powers with negative exponent are bounded away from zero (the format specification does not require that, too) 1852 */ 1853 static 1854 SCIP_Bool isExprPolynomial( 1855 SCIP* scip, /**< SCIP data structure */ 1856 SCIP_EXPR* expr /**< expression */ 1857 ) 1858 { 1859 int c; 1860 1861 assert(scip != NULL); 1862 assert(expr != NULL); 1863 1864 if( !SCIPisExprSum(scip, expr) ) 1865 return isExprSignomial(scip, expr); 1866 1867 /* check whether every term of sum is signomial */ 1868 for( c = 0; c < SCIPexprGetNChildren(expr); ++c ) 1869 if( !isExprSignomial(scip, SCIPexprGetChildren(expr)[c]) ) 1870 return FALSE; 1871 1872 return TRUE; 1873 } 1874 1875 /** clears the given line buffer */ 1876 static 1877 void clearLine( 1878 char* linebuffer, /**< line */ 1879 int* linecnt /**< number of characters in line */ 1880 ) 1881 { 1882 assert( linebuffer != NULL ); 1883 assert( linecnt != NULL ); 1884 1885 (*linecnt) = 0; 1886 linebuffer[0] = '\0'; 1887 } 1888 1889 /** ends the given line with '\\0' and prints it to the given file stream */ 1890 static 1891 void endLine( 1892 SCIP* scip, /**< SCIP data structure */ 1893 FILE* file, /**< output file (or NULL for standard output) */ 1894 char* linebuffer, /**< line */ 1895 int* linecnt /**< number of characters in line */ 1896 ) 1897 { 1898 assert( scip != NULL ); 1899 assert( linebuffer != NULL ); 1900 assert( linecnt != NULL ); 1901 assert( 0 <= *linecnt && *linecnt < PIP_MAX_PRINTLEN ); 1902 1903 if( (*linecnt) > 0 ) 1904 { 1905 linebuffer[(*linecnt)] = '\0'; 1906 SCIPinfoMessage(scip, file, "%s\n", linebuffer); 1907 clearLine(linebuffer, linecnt); 1908 } 1909 } 1910 1911 /** appends extension to line and prints it to the give file stream if the 1912 * line exceeded the length given in the define PIP_PRINTLEN */ 1913 static 1914 void appendLine( 1915 SCIP* scip, /**< SCIP data structure */ 1916 FILE* file, /**< output file (or NULL for standard output) */ 1917 char* linebuffer, /**< line */ 1918 int* linecnt, /**< number of characters in line */ 1919 const char* extension /**< string to extent the line */ 1920 ) 1921 { 1922 assert( scip != NULL ); 1923 assert( linebuffer != NULL ); 1924 assert( linecnt != NULL ); 1925 assert( extension != NULL ); 1926 assert( strlen(linebuffer) + strlen(extension) < PIP_MAX_PRINTLEN ); 1927 1928 /* NOTE: avoid 1929 * sprintf(linebuffer, "%s%s", linebuffer, extension); 1930 * because of overlapping memory areas in memcpy used in sprintf. 1931 */ 1932 (void) strncat(linebuffer, extension, PIP_MAX_PRINTLEN - strlen(linebuffer)); 1933 1934 (*linecnt) += (int) strlen(extension); 1935 1936 SCIPdebugMsg(scip, "linebuffer <%s>, length = %lu\n", linebuffer, (unsigned long)strlen(linebuffer)); 1937 1938 if( (*linecnt) > PIP_PRINTLEN ) 1939 endLine(scip, file, linebuffer, linecnt); 1940 } 1941 1942 1943 /** print linear or quadratic row in PIP format to file stream */ 1944 static 1945 SCIP_RETCODE printRow( 1946 SCIP* scip, /**< SCIP data structure */ 1947 FILE* file, /**< output file (or NULL for standard output) */ 1948 const char* rowname, /**< row name */ 1949 const char* rownameextension, /**< row name extension */ 1950 const char* type, /**< row type ("=", "<=", or ">=") */ 1951 SCIP_VAR** linvars, /**< array of linear variables */ 1952 SCIP_Real* linvals, /**< array of linear coefficient values */ 1953 int nlinvars, /**< number of linear variables */ 1954 SCIP_EXPR* quadexpr, /**< quadratic expression */ 1955 SCIP_Real rhs, /**< right hand side */ 1956 SCIP_Bool transformed /**< transformed constraint? */ 1957 ) 1958 { 1959 int v; 1960 char linebuffer[PIP_MAX_PRINTLEN+1] = { '\0' }; 1961 int linecnt; 1962 1963 char varname[PIP_MAX_NAMELEN]; 1964 char varname2[PIP_MAX_NAMELEN]; 1965 char consname[PIP_MAX_NAMELEN + 1]; /* an extra character for ':' */ 1966 char buffer[PIP_MAX_PRINTLEN]; 1967 1968 assert( scip != NULL ); 1969 assert( strcmp(type, "=") == 0 || strcmp(type, "<=") == 0 || strcmp(type, ">=") == 0 ); 1970 assert( nlinvars == 0 || (linvars != NULL && linvals != NULL) ); 1971 1972 clearLine(linebuffer, &linecnt); 1973 1974 /* start each line with a space */ 1975 appendLine(scip, file, linebuffer, &linecnt, " "); 1976 1977 /* print row name */ 1978 if ( strlen(rowname) > 0 || strlen(rownameextension) > 0 ) 1979 { 1980 (void) SCIPsnprintf(consname, PIP_MAX_NAMELEN + 1, "%s%s:", rowname, rownameextension); 1981 appendLine(scip, file, linebuffer, &linecnt, consname); 1982 } 1983 1984 /* print coefficients */ 1985 for( v = 0; v < nlinvars; ++v ) 1986 { 1987 SCIP_VAR* var; 1988 1989 assert(linvars != NULL); /* for lint */ 1990 assert(linvals != NULL); 1991 1992 var = linvars[v]; 1993 assert( var != NULL ); 1994 1995 /* we start a new line; therefore we tab this line */ 1996 if ( linecnt == 0 ) 1997 appendLine(scip, file, linebuffer, &linecnt, " "); 1998 1999 (void) SCIPsnprintf(varname, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var)); 2000 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %+.15g %s", linvals[v], varname); 2001 2002 appendLine(scip, file, linebuffer, &linecnt, buffer); 2003 } 2004 2005 /* print quadratic part */ 2006 if( quadexpr != NULL ) 2007 { 2008 SCIP_EXPR** linexprs; 2009 SCIP_VAR** activevars; 2010 SCIP_Real* activevals; 2011 SCIP_Real* lincoefs; 2012 SCIP_Real constant; 2013 SCIP_Real activeconstant = 0.0; 2014 int nbilinexprterms; 2015 int nactivevars; 2016 int nquadexprs; 2017 int nlinexprs; 2018 2019 /* get data from the quadratic expression */ 2020 SCIPexprGetQuadraticData(quadexpr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprterms, 2021 NULL, NULL); 2022 2023 /* allocate memory to store active linear variables */ 2024 SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nlinexprs) ); 2025 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, lincoefs, nlinexprs) ); 2026 nactivevars = nlinexprs; 2027 2028 for( v = 0; v < nlinexprs; ++v ) 2029 { 2030 assert(linexprs != NULL && linexprs[v] != NULL); 2031 assert(SCIPisExprVar(scip, linexprs[v])); 2032 2033 activevars[v] = SCIPgetVarExprVar(linexprs[v]); 2034 assert(activevars[v] != NULL); 2035 } 2036 2037 /* get active variables */ 2038 SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activeconstant, transformed) ); 2039 constant += activeconstant; 2040 2041 /* print linear coefficients of linear variables */ 2042 for( v = 0; v < nactivevars; ++v ) 2043 { 2044 SCIP_VAR* var; 2045 2046 assert(activevars != NULL); /* for lint */ 2047 assert(activevals != NULL); 2048 2049 var = activevars[v]; 2050 assert( var != NULL ); 2051 2052 /* we start a new line; therefore we tab this line */ 2053 if( linecnt == 0 ) 2054 appendLine(scip, file, linebuffer, &linecnt, " "); 2055 2056 (void) SCIPsnprintf(varname, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var)); 2057 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %+.15g %s", activevals[v], varname); 2058 2059 appendLine(scip, file, linebuffer, &linecnt, buffer); 2060 } 2061 2062 /* free memory for active linear variables */ 2063 SCIPfreeBufferArray(scip, &activevals); 2064 SCIPfreeBufferArray(scip, &activevars); 2065 2066 /* adjust rhs if there is a constant */ 2067 if( constant != 0.0 && !SCIPisInfinity(scip, rhs) ) 2068 rhs -= constant; 2069 2070 /* print linear coefficients of quadratic variables */ 2071 for( v = 0; v < nquadexprs; ++v ) 2072 { 2073 SCIP_EXPR* expr; 2074 SCIP_VAR* var; 2075 SCIP_Real lincoef; 2076 2077 /* get linear coefficient and variable of quadratic term */ 2078 SCIPexprGetQuadraticQuadTerm(quadexpr, v, &expr, &lincoef, NULL, NULL, NULL, NULL); 2079 assert(expr != NULL); 2080 assert(SCIPisExprVar(scip, expr)); 2081 2082 var = SCIPgetVarExprVar(expr); 2083 assert(var != NULL); 2084 2085 if( lincoef == 0.0 ) 2086 continue; 2087 2088 /* we start a new line; therefore we tab this line */ 2089 if( linecnt == 0 ) 2090 appendLine(scip, file, linebuffer, &linecnt, " "); 2091 2092 (void) SCIPsnprintf(varname, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var)); 2093 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %+.15g %s", lincoef, varname); 2094 2095 appendLine(scip, file, linebuffer, &linecnt, buffer); 2096 } 2097 2098 /* print square terms */ 2099 for( v = 0; v < nquadexprs; ++v ) 2100 { 2101 SCIP_EXPR* expr; 2102 SCIP_VAR* var; 2103 SCIP_Real sqrcoef; 2104 2105 /* get square coefficient and variable of quadratic term */ 2106 SCIPexprGetQuadraticQuadTerm(quadexpr, v, &expr, NULL, &sqrcoef, NULL, NULL, NULL); 2107 assert(expr != NULL); 2108 assert(SCIPisExprVar(scip, expr)); 2109 2110 var = SCIPgetVarExprVar(expr); 2111 assert(var != NULL); 2112 2113 if( sqrcoef == 0.0 ) 2114 continue; 2115 2116 /* we start a new line; therefore we tab this line */ 2117 if( linecnt == 0 ) 2118 appendLine(scip, file, linebuffer, &linecnt, " "); 2119 2120 (void) SCIPsnprintf(varname, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var)); 2121 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %+.15g %s^2", sqrcoef, varname); 2122 2123 appendLine(scip, file, linebuffer, &linecnt, buffer); 2124 } 2125 2126 /* print bilinear terms */ 2127 for( v = 0; v < nbilinexprterms; ++v ) 2128 { 2129 SCIP_EXPR* expr1; 2130 SCIP_EXPR* expr2; 2131 SCIP_VAR* var1; 2132 SCIP_VAR* var2; 2133 SCIP_Real bilincoef; 2134 2135 /* get coefficient and variables of bilinear */ 2136 SCIPexprGetQuadraticBilinTerm(quadexpr, v, &expr1, &expr2, &bilincoef, NULL, NULL); 2137 assert(expr1 != NULL); 2138 assert(SCIPisExprVar(scip, expr1)); 2139 assert(expr2 != NULL); 2140 assert(SCIPisExprVar(scip, expr2)); 2141 2142 var1 = SCIPgetVarExprVar(expr1); 2143 assert(var1 != NULL); 2144 var2 = SCIPgetVarExprVar(expr2); 2145 assert(var2 != NULL); 2146 2147 /* we start a new line; therefore we tab this line */ 2148 if( linecnt == 0 ) 2149 appendLine(scip, file, linebuffer, &linecnt, " "); 2150 2151 (void) SCIPsnprintf(varname, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var1)); 2152 (void) SCIPsnprintf(varname2, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var2)); 2153 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %+.15g %s * %s", bilincoef, varname, varname2); 2154 2155 appendLine(scip, file, linebuffer, &linecnt, buffer); 2156 } 2157 } 2158 2159 /* print right hand side */ 2160 if( SCIPisZero(scip, rhs) ) 2161 rhs = 0.0; 2162 2163 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %s %+.15g", type, rhs); 2164 2165 /* we start a new line; therefore we tab this line */ 2166 if (linecnt == 0 ) 2167 appendLine(scip, file, linebuffer, &linecnt, " "); 2168 appendLine(scip, file, linebuffer, &linecnt, buffer); 2169 2170 endLine(scip, file, linebuffer, &linecnt); 2171 2172 return SCIP_OKAY; 2173 } 2174 2175 /** print signomial in PIP format to file stream */ 2176 static 2177 void printSignomial( 2178 SCIP* scip, /**< SCIP data structure */ 2179 FILE* file, /**< output file (or NULL for standard output) */ 2180 char* linebuffer, /**< line buffer to append to */ 2181 int* linecnt, /**< count on line buffer use */ 2182 SCIP_EXPR* expr, /**< sigomial expression */ 2183 SCIP_Real coef, /**< coefficient */ 2184 SCIP_Bool needsign /**< whether a sign needs to be ensured */ 2185 ) 2186 { 2187 char buffer[PIP_MAX_PRINTLEN]; 2188 SCIP_EXPR* child; 2189 int c; 2190 2191 assert(isExprSignomial(scip, expr)); 2192 2193 if( SCIPisExprProduct(scip, expr) ) 2194 coef *= SCIPgetCoefExprProduct(expr); 2195 2196 if( SCIPisExprValue(scip, expr) ) 2197 coef *= SCIPgetValueExprValue(expr); 2198 2199 if( REALABS(coef) != 1.0 ) 2200 { 2201 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, needsign ? " %+.15g " : " %.15g ", coef); 2202 appendLine(scip, file, linebuffer, linecnt, buffer); 2203 } 2204 else if( coef == 1.0 && needsign ) 2205 { 2206 appendLine(scip, file, linebuffer, linecnt, " + "); 2207 } 2208 else if( coef == -1.0 ) 2209 { 2210 appendLine(scip, file, linebuffer, linecnt, " - "); 2211 } 2212 else 2213 { 2214 appendLine(scip, file, linebuffer, linecnt, " "); 2215 } 2216 2217 if( SCIPisExprVar(scip, expr) ) 2218 { 2219 appendLine(scip, file, linebuffer, linecnt, SCIPvarGetName(SCIPgetVarExprVar(expr))); 2220 return; 2221 } 2222 2223 if( SCIPisExprValue(scip, expr) ) 2224 { 2225 if( REALABS(coef) == 1.0 ) 2226 { 2227 /* in this case, we will have printed only a sign or space above, so print also a 1.0 */ 2228 appendLine(scip, file, linebuffer, linecnt, "1.0"); 2229 } 2230 return; 2231 } 2232 2233 if( SCIPisExprPower(scip, expr) ) 2234 { 2235 assert(SCIPisExprVar(scip, SCIPexprGetChildren(expr)[0])); 2236 2237 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, "%s^%.15g", SCIPvarGetName(SCIPgetVarExprVar(SCIPexprGetChildren(expr)[0])), SCIPgetExponentExprPow(expr)); 2238 appendLine(scip, file, linebuffer, linecnt, buffer); 2239 2240 return; 2241 } 2242 2243 assert(SCIPisExprProduct(scip, expr)); 2244 for( c = 0; c < SCIPexprGetNChildren(expr); ++c ) 2245 { 2246 child = SCIPexprGetChildren(expr)[c]; 2247 2248 if( c > 0 ) 2249 appendLine(scip, file, linebuffer, linecnt, " "); 2250 2251 if( SCIPisExprVar(scip, child) ) 2252 { 2253 appendLine(scip, file, linebuffer, linecnt, SCIPvarGetName(SCIPgetVarExprVar(child))); 2254 continue; 2255 } 2256 2257 assert(SCIPisExprPower(scip, child)); 2258 assert(SCIPisExprVar(scip, SCIPexprGetChildren(child)[0])); 2259 2260 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, "%s^%.15g", SCIPvarGetName(SCIPgetVarExprVar(SCIPexprGetChildren(child)[0])), SCIPgetExponentExprPow(child)); 2261 appendLine(scip, file, linebuffer, linecnt, buffer); 2262 } 2263 } 2264 2265 /** print polynomial row in PIP format to file stream */ 2266 static 2267 void printRowNl( 2268 SCIP* scip, /**< SCIP data structure */ 2269 FILE* file, /**< output file (or NULL for standard output) */ 2270 const char* rowname, /**< row name */ 2271 const char* rownameextension, /**< row name extension */ 2272 const char* type, /**< row type ("=", "<=", or ">=") */ 2273 SCIP_EXPR* expr, /**< polynomial expression */ 2274 SCIP_Real rhs /**< right hand side */ 2275 ) 2276 { 2277 char consname[PIP_MAX_NAMELEN + 1]; /* an extra character for ':' */ 2278 char buffer[PIP_MAX_PRINTLEN]; 2279 char linebuffer[PIP_MAX_PRINTLEN+1] = { '\0' }; 2280 int linecnt; 2281 2282 assert(scip != NULL); 2283 assert(strcmp(type, "=") == 0 || strcmp(type, "<=") == 0 || strcmp(type, ">=") == 0); 2284 assert(expr != NULL); 2285 2286 clearLine(linebuffer, &linecnt); 2287 2288 /* start each line with a space */ 2289 appendLine(scip, file, linebuffer, &linecnt, " "); 2290 2291 /* print row name */ 2292 if( strlen(rowname) > 0 || strlen(rownameextension) > 0 ) 2293 { 2294 (void) SCIPsnprintf(consname, PIP_MAX_NAMELEN + 1, "%s%s:", rowname, rownameextension); 2295 appendLine(scip, file, linebuffer, &linecnt, consname); 2296 } 2297 2298 if( SCIPisExprSum(scip, expr) ) 2299 { 2300 int c; 2301 SCIP_Bool needsign = FALSE; 2302 2303 if( SCIPgetConstantExprSum(expr) != 0.0 ) 2304 { 2305 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %+.15g", SCIPgetConstantExprSum(expr)); 2306 appendLine(scip, file, linebuffer, &linecnt, buffer); 2307 2308 needsign = TRUE; 2309 } 2310 2311 for( c = 0; c < SCIPexprGetNChildren(expr); ++c ) 2312 { 2313 printSignomial(scip, file, linebuffer, &linecnt, SCIPexprGetChildren(expr)[c], SCIPgetCoefsExprSum(expr)[c], needsign); 2314 needsign = TRUE; 2315 } 2316 } 2317 else 2318 { 2319 printSignomial(scip, file, linebuffer, &linecnt, expr, 1.0, FALSE); 2320 } 2321 2322 /* print right hand side */ 2323 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %s %+.15g", type, rhs); 2324 2325 /* we start a new line; therefore we tab this line */ 2326 if( linecnt == 0 ) 2327 appendLine(scip, file, linebuffer, &linecnt, " "); 2328 appendLine(scip, file, linebuffer, &linecnt, buffer); 2329 2330 endLine(scip, file, linebuffer, &linecnt); 2331 } 2332 2333 /** print "and" constraint as row in PIP format to file stream */ 2334 static 2335 void printRowAnd( 2336 SCIP* scip, /**< SCIP data structure */ 2337 FILE* file, /**< output file (or NULL for standard output) */ 2338 const char* rowname, /**< row name */ 2339 SCIP_CONS* cons /**< "and" constraint */ 2340 ) 2341 { 2342 char linebuffer[PIP_MAX_PRINTLEN+1] = { '\0' }; 2343 int linecnt; 2344 int i; 2345 2346 assert(scip != NULL); 2347 assert(rowname != NULL); 2348 assert(cons != NULL); 2349 2350 clearLine(linebuffer, &linecnt); 2351 2352 /* start each line with a space */ 2353 appendLine(scip, file, linebuffer, &linecnt, " "); 2354 2355 /* print row name */ 2356 if( strlen(rowname) > 0 ) 2357 { 2358 appendLine(scip, file, linebuffer, &linecnt, rowname); 2359 appendLine(scip, file, linebuffer, &linecnt, ":"); 2360 } 2361 2362 for( i = 0; i < SCIPgetNVarsAnd(scip, cons); ++i ) 2363 { 2364 appendLine(scip, file, linebuffer, &linecnt, " "); 2365 appendLine(scip, file, linebuffer, &linecnt, SCIPvarGetName(SCIPgetVarsAnd(scip, cons)[i])); 2366 } 2367 2368 appendLine(scip, file, linebuffer, &linecnt, " - "); 2369 appendLine(scip, file, linebuffer, &linecnt, SCIPvarGetName(SCIPgetResultantAnd(scip, cons))); 2370 2371 /* we start a new line; therefore we tab this line */ 2372 if( linecnt == 0 ) 2373 appendLine(scip, file, linebuffer, &linecnt, " "); 2374 2375 /* print right hand side */ 2376 appendLine(scip, file, linebuffer, &linecnt, " = 0"); 2377 2378 endLine(scip, file, linebuffer, &linecnt); 2379 } 2380 2381 /** prints given (linear or) quadratic constraint information in LP format to file stream */ 2382 static 2383 SCIP_RETCODE printQuadraticCons( 2384 SCIP* scip, /**< SCIP data structure */ 2385 FILE* file, /**< output file (or NULL for standard output) */ 2386 const char* rowname, /**< name of the row */ 2387 SCIP_VAR** linvars, /**< array of linear variables */ 2388 SCIP_Real* linvals, /**< array of linear coefficients values (or NULL if all linear coefficient values are 1) */ 2389 int nlinvars, /**< number of linear variables */ 2390 SCIP_EXPR* quadexpr, /**< quadratic expression (or NULL if nlinvars > 0) */ 2391 SCIP_Real lhs, /**< left hand side */ 2392 SCIP_Real rhs, /**< right hand side */ 2393 SCIP_Bool transformed /**< transformed constraint? */ 2394 ) 2395 { 2396 int v; 2397 SCIP_VAR** activevars = NULL; 2398 SCIP_Real* activevals = NULL; 2399 int nactivevars; 2400 SCIP_Real activeconstant = 0.0; 2401 2402 assert( scip != NULL ); 2403 assert( rowname != NULL ); 2404 2405 assert( nlinvars == 0 || linvars != NULL ); 2406 assert( quadexpr == NULL || nlinvars == 0); 2407 assert( lhs <= rhs ); 2408 2409 if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) ) 2410 return SCIP_OKAY; 2411 2412 nactivevars = nlinvars; 2413 if( nlinvars > 0 ) 2414 { 2415 /* duplicate variable and value array */ 2416 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, linvars, nactivevars ) ); 2417 if( linvals != NULL ) 2418 { 2419 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, linvals, nactivevars ) ); 2420 } 2421 else 2422 { 2423 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) ); 2424 2425 for( v = 0; v < nactivevars; ++v ) 2426 activevals[v] = 1.0; 2427 } 2428 2429 /* retransform given variables to active variables */ 2430 SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activeconstant, transformed) ); 2431 } 2432 2433 /* print row(s) in LP format */ 2434 if( SCIPisEQ(scip, lhs, rhs) ) 2435 { 2436 assert( !SCIPisInfinity(scip, rhs) ); 2437 2438 /* equal constraint */ 2439 SCIP_CALL( printRow(scip, file, rowname, "", "=", activevars, activevals, nactivevars, quadexpr, 2440 rhs - activeconstant, transformed) ); 2441 } 2442 else 2443 { 2444 if( !SCIPisInfinity(scip, -lhs) ) 2445 { 2446 /* print inequality ">=" */ 2447 SCIP_CALL( printRow(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", ">=", activevars, 2448 activevals, nactivevars, quadexpr, lhs - activeconstant, transformed) ); 2449 } 2450 if( !SCIPisInfinity(scip, rhs) ) 2451 { 2452 /* print inequality "<=" */ 2453 SCIP_CALL( printRow(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "<=", activevars, 2454 activevals, nactivevars, quadexpr, rhs - activeconstant, transformed) ); 2455 } 2456 } 2457 2458 if( nlinvars > 0 ) 2459 { 2460 /* free buffer arrays */ 2461 SCIPfreeBufferArray(scip, &activevars); 2462 SCIPfreeBufferArray(scip, &activevals); 2463 } 2464 2465 return SCIP_OKAY; 2466 } 2467 2468 /** prints given nonlinear constraint information in LP format to file stream */ 2469 static 2470 SCIP_RETCODE printNonlinearCons( 2471 SCIP* scip, /**< SCIP data structure */ 2472 FILE* file, /**< output file (or NULL for standard output) */ 2473 const char* rowname, /**< name of the row */ 2474 SCIP_EXPR* expr, /**< polynomial expression */ 2475 SCIP_Real lhs, /**< left hand side */ 2476 SCIP_Real rhs /**< right hand side */ 2477 ) 2478 { 2479 assert(scip != NULL); 2480 assert(rowname != NULL); 2481 assert(expr != NULL); 2482 assert(lhs <= rhs); 2483 2484 if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) ) 2485 return SCIP_OKAY; 2486 2487 /* print row(s) in LP format */ 2488 if( SCIPisEQ(scip, lhs, rhs) ) 2489 { 2490 assert( !SCIPisInfinity(scip, rhs) ); 2491 2492 /* equal constraint */ 2493 printRowNl(scip, file, rowname, "", "=", expr, rhs); 2494 } 2495 else 2496 { 2497 if( !SCIPisInfinity(scip, -lhs) ) 2498 { 2499 /* print inequality ">=" */ 2500 printRowNl(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", ">=", expr, lhs); 2501 } 2502 if( !SCIPisInfinity(scip, rhs) ) 2503 { 2504 /* print inequality "<=" */ 2505 printRowNl(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "<=", expr, rhs); 2506 } 2507 } 2508 2509 return SCIP_OKAY; 2510 } 2511 2512 /** check whether given variables are aggregated and put them into an array without duplication */ 2513 static 2514 SCIP_RETCODE collectAggregatedVars( 2515 int nvars, /**< number of active variables in the problem */ 2516 SCIP_VAR** vars, /**< variable array */ 2517 int* nAggregatedVars, /**< number of aggregated variables on output */ 2518 SCIP_VAR*** aggregatedVars, /**< array storing the aggregated variables on output */ 2519 SCIP_HASHTABLE** varAggregated /**< hashtable for checking duplicates */ 2520 ) 2521 { 2522 int j; 2523 2524 /* check variables */ 2525 for (j = 0; j < nvars; ++j) 2526 { 2527 SCIP_VARSTATUS status; 2528 SCIP_VAR* var; 2529 2530 var = vars[j]; 2531 status = SCIPvarGetStatus(var); 2532 2533 /* collect aggregated variables in a list */ 2534 if( status >= SCIP_VARSTATUS_AGGREGATED ) 2535 { 2536 assert( status == SCIP_VARSTATUS_AGGREGATED || 2537 status == SCIP_VARSTATUS_MULTAGGR || 2538 status == SCIP_VARSTATUS_NEGATED ); 2539 2540 if ( ! SCIPhashtableExists(*varAggregated, (void*) var) ) 2541 { 2542 (*aggregatedVars)[(*nAggregatedVars)++] = var; 2543 SCIP_CALL( SCIPhashtableInsert(*varAggregated, (void*) var) ); 2544 } 2545 } 2546 } 2547 2548 return SCIP_OKAY; 2549 } 2550 2551 2552 /** print aggregated variable-constraints */ 2553 static 2554 SCIP_RETCODE printAggregatedCons( 2555 SCIP* scip, /**< SCIP data structure */ 2556 FILE* file, /**< output file (or NULL for standard output) */ 2557 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */ 2558 int nvars, /**< number of active variables in the problem */ 2559 int nAggregatedVars, /**< number of aggregated variables */ 2560 SCIP_VAR** aggregatedVars /**< array storing the aggregated variables */ 2561 ) 2562 { 2563 int j; 2564 2565 SCIP_VAR** activevars; 2566 SCIP_Real* activevals; 2567 int nactivevars; 2568 SCIP_Real activeconstant = 0.0; 2569 char consname[PIP_MAX_NAMELEN]; 2570 2571 assert( scip != NULL ); 2572 2573 /* write aggregation constraints */ 2574 SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nvars) ); 2575 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nvars) ); 2576 2577 for (j = 0; j < nAggregatedVars; ++j) 2578 { 2579 /* set up list to obtain substitution variables */ 2580 nactivevars = 1; 2581 2582 activevars[0] = aggregatedVars[j]; 2583 activevals[0] = 1.0; 2584 activeconstant = 0.0; 2585 2586 /* retransform given variables to active variables */ 2587 SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activeconstant, transformed) ); 2588 2589 activevals[nactivevars] = -1.0; 2590 activevars[nactivevars] = aggregatedVars[j]; 2591 ++nactivevars; 2592 2593 /* output constraint */ 2594 (void) SCIPsnprintf(consname, PIP_MAX_NAMELEN, "aggr_%s", SCIPvarGetName(aggregatedVars[j])); 2595 SCIP_CALL( printRow(scip, file, consname, "", "=", activevars, activevals, nactivevars, NULL, - activeconstant, 2596 transformed) ); 2597 } 2598 2599 /* free buffer arrays */ 2600 SCIPfreeBufferArray(scip, &activevars); 2601 SCIPfreeBufferArray(scip, &activevals); 2602 2603 return SCIP_OKAY; 2604 } 2605 2606 /** returns whether name is valid according to PIP specification 2607 * 2608 * Checks these two conditions from http://polip.zib.de/pipformat.php: 2609 * - Names/labels can contain at most 255 characters. 2610 * - Name/labels have to consist of the following characters: a-z, A-Z, 0-9, "!", "#", "$", "%", "&", ";", "?", "@", "_". They cannot start with a number. 2611 * 2612 * In addition checks that the length is not zero. 2613 */ 2614 static 2615 SCIP_Bool isNameValid( 2616 const char* name /**< name to check */ 2617 ) 2618 { 2619 size_t len; 2620 size_t i; 2621 2622 assert(name != NULL); 2623 2624 len = strlen(name); /*lint !e613*/ 2625 if( len > (size_t) PIP_MAX_NAMELEN || len == 0 ) 2626 return FALSE; 2627 2628 /* names cannot start with a number */ 2629 if( isdigit(name[0]) ) 2630 return FALSE; 2631 2632 for( i = 0; i < len; ++i ) 2633 { 2634 /* a-z, A-Z, 0-9 are ok */ 2635 if( isalnum(name[i]) ) 2636 continue; 2637 2638 /* characters in namechars are ok, too */ 2639 if( strchr(namechars, name[i]) != NULL ) 2640 continue; 2641 2642 return FALSE; 2643 } 2644 2645 return TRUE; 2646 } 2647 2648 2649 /** method check if the variable names are valid according to PIP specification */ 2650 static 2651 void checkVarnames( 2652 SCIP* scip, /**< SCIP data structure */ 2653 SCIP_VAR** vars, /**< array of variables */ 2654 int nvars /**< number of variables */ 2655 ) 2656 { 2657 int v; 2658 2659 assert(scip != NULL); 2660 assert(vars != NULL || nvars == 0); 2661 2662 /* check if the variable names are not too long and have only characters allowed by PIP */ 2663 for( v = 0; v < nvars; ++v ) 2664 { 2665 if( !isNameValid(SCIPvarGetName(vars[v])) ) 2666 { 2667 SCIPwarningMessage(scip, "variable name <%s> is not valid (too long or disallowed characters); PIP might be corrupted\n", SCIPvarGetName(vars[v])); 2668 return; 2669 } 2670 } 2671 } 2672 2673 /** method check if the constraint names are valid according to PIP specification */ 2674 static 2675 void checkConsnames( 2676 SCIP* scip, /**< SCIP data structure */ 2677 SCIP_CONS** conss, /**< array of constraints */ 2678 int nconss, /**< number of constraints */ 2679 SCIP_Bool transformed /**< TRUE iff problem is the transformed problem */ 2680 ) 2681 { 2682 int c; 2683 SCIP_CONS* cons; 2684 SCIP_CONSHDLR* conshdlr; 2685 const char* conshdlrname; 2686 2687 assert( scip != NULL ); 2688 assert( conss != NULL || nconss == 0 ); 2689 2690 for( c = 0; c < nconss; ++c ) 2691 { 2692 assert(conss != NULL); /* for lint */ 2693 cons = conss[c]; 2694 assert(cons != NULL ); 2695 2696 /* in case the transformed is written only constraints are posted which are enabled in the current node */ 2697 assert(!transformed || SCIPconsIsEnabled(cons)); 2698 2699 conshdlr = SCIPconsGetHdlr(cons); 2700 assert( conshdlr != NULL ); 2701 2702 conshdlrname = SCIPconshdlrGetName(conshdlr); 2703 assert( transformed == SCIPconsIsTransformed(cons) ); 2704 2705 if( !isNameValid(SCIPconsGetName(cons)) ) 2706 { 2707 SCIPwarningMessage(scip, "constraint name <%s> is not valid (too long or unallowed characters); PIP might be corrupted\n", SCIPconsGetName(cons)); 2708 return; 2709 } 2710 2711 if( strcmp(conshdlrname, "linear") == 0 ) 2712 { 2713 SCIP_Real lhs = SCIPgetLhsLinear(scip, cons); 2714 SCIP_Real rhs = SCIPgetRhsLinear(scip, cons); 2715 2716 /* for ranged constraints, we need to be able to append _lhs and _rhs to the constraint name, so need additional 4 characters */ 2717 if( !SCIPisEQ(scip, lhs, rhs) && strlen(SCIPconsGetName(conss[c])) > (size_t) PIP_MAX_NAMELEN - 4 ) 2718 { 2719 SCIPwarningMessage(scip, "name of ranged constraint <%s> has to be cut down to %d characters;\n", SCIPconsGetName(conss[c]), 2720 PIP_MAX_NAMELEN - 1); 2721 return; 2722 } 2723 } 2724 } 2725 } 2726 2727 /** writes problem to file 2728 * @todo add writing cons_pseudoboolean 2729 */ 2730 SCIP_RETCODE SCIPwritePip( 2731 SCIP* scip, /**< SCIP data structure */ 2732 FILE* file, /**< output file, or NULL if standard output should be used */ 2733 const char* name, /**< problem name */ 2734 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */ 2735 SCIP_OBJSENSE objsense, /**< objective sense */ 2736 SCIP_Real objscale, /**< scalar applied to objective function; external objective value is 2737 * extobj = objsense * objscale * (intobj + objoffset) */ 2738 SCIP_Real objoffset, /**< objective offset from bound shifting and fixing */ 2739 SCIP_VAR** vars, /**< array with active variables ordered binary, integer, implicit, continuous */ 2740 int nvars, /**< number of active variables in the problem */ 2741 int nbinvars, /**< number of binary variables */ 2742 int nintvars, /**< number of general integer variables */ 2743 int nimplvars, /**< number of implicit integer variables */ 2744 int ncontvars, /**< number of continuous variables */ 2745 SCIP_CONS** conss, /**< array with constraints of the problem */ 2746 int nconss, /**< number of constraints in the problem */ 2747 SCIP_RESULT* result /**< pointer to store the result of the file writing call */ 2748 ) 2749 { 2750 int c; 2751 int v; 2752 2753 int linecnt; 2754 char linebuffer[PIP_MAX_PRINTLEN+1]; 2755 2756 char varname[PIP_MAX_NAMELEN]; 2757 char buffer[PIP_MAX_PRINTLEN]; 2758 2759 SCIP_CONSHDLR* conshdlr; 2760 const char* conshdlrname; 2761 SCIP_CONS* cons; 2762 SCIP_CONS** consNonlinear; 2763 int nConsNonlinear; 2764 SCIP_CONS** consAnd; 2765 int nConsAnd; 2766 char consname[PIP_MAX_NAMELEN]; 2767 2768 SCIP_VAR** aggregatedVars; 2769 int nAggregatedVars; 2770 SCIP_HASHTABLE* varAggregated; 2771 2772 SCIP_VAR** tmpvars; 2773 int tmpvarssize; 2774 2775 SCIP_VAR** consvars; 2776 SCIP_Real* consvals; 2777 int nconsvars; 2778 2779 SCIP_VAR* var; 2780 SCIP_Real lb; 2781 SCIP_Real ub; 2782 2783 assert( scip != NULL ); 2784 2785 nAggregatedVars = 0; 2786 nConsNonlinear = 0; 2787 nConsAnd = 0; 2788 2789 /* check if the variable names are not to long */ 2790 checkVarnames(scip, vars, nvars); 2791 2792 /* check if the constraint names are to long */ 2793 checkConsnames(scip, conss, nconss, transformed); 2794 2795 /* print statistics as comment to file */ 2796 SCIPinfoMessage(scip, file, "\\ SCIP STATISTICS\n"); 2797 SCIPinfoMessage(scip, file, "\\ Problem name : %s\n", name); 2798 SCIPinfoMessage(scip, file, "\\ Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n", 2799 nvars, nbinvars, nintvars, nimplvars, ncontvars); 2800 SCIPinfoMessage(scip, file, "\\ Constraints : %d\n", nconss); 2801 2802 /* print objective sense */ 2803 SCIPinfoMessage(scip, file, "%s\n", objsense == SCIP_OBJSENSE_MINIMIZE ? "Minimize" : "Maximize"); 2804 2805 clearLine(linebuffer, &linecnt); 2806 appendLine(scip, file, linebuffer, &linecnt, " Obj:"); 2807 2808 for (v = 0; v < nvars; ++v) 2809 { 2810 var = vars[v]; 2811 2812 #ifndef NDEBUG 2813 /* in case the original problem has to be posted the variables have to be either "original" or "negated" */ 2814 if ( !transformed ) 2815 assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED ); 2816 #endif 2817 2818 if ( SCIPisZero(scip, SCIPvarGetObj(var)) ) 2819 continue; 2820 2821 /* we start a new line; therefore we tab this line */ 2822 if ( linecnt == 0 ) 2823 appendLine(scip, file, linebuffer, &linecnt, " "); 2824 2825 (void) SCIPsnprintf(varname, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var)); 2826 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %+.15g %s", objscale * SCIPvarGetObj(var), varname ); 2827 2828 appendLine(scip, file, linebuffer, &linecnt, buffer); 2829 } 2830 2831 if( ! SCIPisZero(scip, objoffset) ) 2832 { 2833 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %+.15g", objscale * objoffset); 2834 appendLine(scip, file, linebuffer, &linecnt, buffer); 2835 } 2836 2837 endLine(scip, file, linebuffer, &linecnt); 2838 2839 /* print "Subject to" section */ 2840 SCIPinfoMessage(scip, file, "Subject to\n"); 2841 2842 /* collect quadratic, nonlinear, absolute power, and, and bivariate constraints in arrays */ 2843 SCIP_CALL( SCIPallocBufferArray(scip, &consNonlinear, nconss) ); 2844 SCIP_CALL( SCIPallocBufferArray(scip, &consAnd, nconss) ); 2845 2846 tmpvarssize = SCIPgetNTotalVars(scip); 2847 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, tmpvarssize) ); 2848 2849 for (c = 0; c < nconss; ++c) 2850 { 2851 cons = conss[c]; 2852 assert( cons != NULL); 2853 2854 /* in case the transformed is written only constraints are posted which are enabled in the current node */ 2855 assert(!transformed || SCIPconsIsEnabled(cons)); 2856 2857 conshdlr = SCIPconsGetHdlr(cons); 2858 assert( conshdlr != NULL ); 2859 2860 (void) SCIPsnprintf(consname, PIP_MAX_NAMELEN, "%s", SCIPconsGetName(cons)); 2861 conshdlrname = SCIPconshdlrGetName(conshdlr); 2862 assert( transformed == SCIPconsIsTransformed(cons) ); 2863 2864 if( strcmp(conshdlrname, "linear") == 0 ) 2865 { 2866 SCIP_CALL( printQuadraticCons(scip, file, consname, 2867 SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons), SCIPgetNVarsLinear(scip, cons), 2868 NULL, SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons), transformed) ); 2869 } 2870 else if( strcmp(conshdlrname, "setppc") == 0 ) 2871 { 2872 consvars = SCIPgetVarsSetppc(scip, cons); 2873 nconsvars = SCIPgetNVarsSetppc(scip, cons); 2874 2875 switch( SCIPgetTypeSetppc(scip, cons) ) 2876 { 2877 case SCIP_SETPPCTYPE_PARTITIONING : 2878 SCIP_CALL( printQuadraticCons(scip, file, consname, 2879 consvars, NULL, nconsvars, NULL, 1.0, 1.0, transformed) ); 2880 break; 2881 case SCIP_SETPPCTYPE_PACKING : 2882 SCIP_CALL( printQuadraticCons(scip, file, consname, 2883 consvars, NULL, nconsvars, NULL, -SCIPinfinity(scip), 1.0, transformed) ); 2884 break; 2885 case SCIP_SETPPCTYPE_COVERING : 2886 SCIP_CALL( printQuadraticCons(scip, file, consname, 2887 consvars, NULL, nconsvars, NULL, 1.0, SCIPinfinity(scip), transformed) ); 2888 break; 2889 } 2890 } 2891 else if ( strcmp(conshdlrname, "logicor") == 0 ) 2892 { 2893 SCIP_CALL( printQuadraticCons(scip, file, consname, 2894 SCIPgetVarsLogicor(scip, cons), NULL, SCIPgetNVarsLogicor(scip, cons), 2895 NULL, 1.0, SCIPinfinity(scip), transformed) ); 2896 } 2897 else if ( strcmp(conshdlrname, "knapsack") == 0 ) 2898 { 2899 SCIP_Longint* weights; 2900 2901 consvars = SCIPgetVarsKnapsack(scip, cons); 2902 nconsvars = SCIPgetNVarsKnapsack(scip, cons); 2903 2904 /* copy Longint array to SCIP_Real array */ 2905 weights = SCIPgetWeightsKnapsack(scip, cons); 2906 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) ); 2907 for( v = 0; v < nconsvars; ++v ) 2908 consvals[v] = (SCIP_Real)weights[v]; 2909 2910 SCIP_CALL( printQuadraticCons(scip, file, consname, consvars, consvals, nconsvars, 2911 NULL, -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), transformed) ); 2912 2913 SCIPfreeBufferArray(scip, &consvals); 2914 } 2915 else if ( strcmp(conshdlrname, "varbound") == 0 ) 2916 { 2917 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) ); 2918 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) ); 2919 2920 consvars[0] = SCIPgetVarVarbound(scip, cons); 2921 consvars[1] = SCIPgetVbdvarVarbound(scip, cons); 2922 2923 consvals[0] = 1.0; 2924 consvals[1] = SCIPgetVbdcoefVarbound(scip, cons); 2925 2926 SCIP_CALL( printQuadraticCons(scip, file, consname, consvars, consvals, 2, NULL, 2927 SCIPgetLhsVarbound(scip, cons), SCIPgetRhsVarbound(scip, cons), transformed) ); 2928 2929 SCIPfreeBufferArray(scip, &consvars); 2930 SCIPfreeBufferArray(scip, &consvals); 2931 } 2932 else if( strcmp(conshdlrname, "nonlinear") == 0 ) 2933 { 2934 SCIP_Bool ispolynomial; 2935 SCIP_Bool isquadratic; 2936 SCIP_EXPR* simplifiedexpr = NULL; 2937 2938 ispolynomial = isExprPolynomial(scip, SCIPgetExprNonlinear(cons)); 2939 if( !ispolynomial ) 2940 { 2941 /* simplify expression and check again if polynomial 2942 * simplifying the expr owned by the cons can have undesired sideffects onto the consdata (the varhashmap can get messed up), so we copy first 2943 */ 2944 SCIP_EXPR* exprcopy; 2945 SCIP_Bool changed; 2946 SCIP_Bool infeasible; 2947 2948 SCIP_CALL( SCIPduplicateExpr(scip, SCIPgetExprNonlinear(cons), &exprcopy, NULL, NULL, NULL, NULL) ); 2949 SCIP_CALL( SCIPsimplifyExpr(scip, exprcopy, &simplifiedexpr, &changed, &infeasible, NULL, NULL) ); 2950 SCIP_CALL( SCIPreleaseExpr(scip, &exprcopy) ); 2951 2952 ispolynomial = isExprPolynomial(scip, simplifiedexpr); 2953 } 2954 2955 /* nonlinear constraints that are not polynomial cannot be printed as PIP */ 2956 if( !ispolynomial ) 2957 { 2958 SCIPwarningMessage(scip, "nonlinear constraint <%s> is not polynomial\n", SCIPconsGetName(cons)); 2959 SCIPinfoMessage(scip, file, "\\ "); 2960 SCIP_CALL( SCIPprintCons(scip, cons, file) ); 2961 SCIPinfoMessage(scip, file, ";\n"); 2962 2963 SCIP_CALL( SCIPreleaseExpr(scip, &simplifiedexpr) ); 2964 return SCIP_OKAY; 2965 } 2966 2967 /* check whether constraint is even quadratic 2968 * (we could also skip this and print as polynomial, but the code exists already) 2969 */ 2970 SCIP_CALL( SCIPcheckExprQuadratic(scip, simplifiedexpr != NULL ? simplifiedexpr : SCIPgetExprNonlinear(cons), &isquadratic) ); 2971 if( isquadratic ) 2972 isquadratic = SCIPexprAreQuadraticExprsVariables(simplifiedexpr != NULL ? simplifiedexpr : SCIPgetExprNonlinear(cons)); 2973 2974 if( isquadratic ) 2975 { 2976 SCIP_CALL( printQuadraticCons(scip, file, consname, NULL, NULL, 0, simplifiedexpr != NULL ? simplifiedexpr : SCIPgetExprNonlinear(cons), 2977 SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), transformed) ); 2978 } 2979 else 2980 { 2981 SCIP_CALL( printNonlinearCons(scip, file, consname, simplifiedexpr != NULL ? simplifiedexpr : SCIPgetExprNonlinear(cons), SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons)) ); 2982 } 2983 2984 consNonlinear[nConsNonlinear++] = cons; 2985 2986 if( simplifiedexpr != NULL ) 2987 { 2988 SCIP_CALL( SCIPreleaseExpr(scip, &simplifiedexpr) ); 2989 } 2990 } 2991 else if( strcmp(conshdlrname, "and") == 0 ) 2992 { 2993 printRowAnd(scip, file, consname, cons); 2994 2995 consAnd[nConsAnd++] = cons; 2996 } 2997 else 2998 { 2999 SCIPwarningMessage(scip, "constraint handler <%s> cannot print requested format\n", conshdlrname ); 3000 SCIPinfoMessage(scip, file, "\\ "); 3001 SCIP_CALL( SCIPprintCons(scip, cons, file) ); 3002 SCIPinfoMessage(scip, file, ";\n"); 3003 } 3004 } 3005 3006 /* create hashtable for storing aggregated variables */ 3007 SCIP_CALL( SCIPallocBufferArray(scip, &aggregatedVars, nvars) ); 3008 SCIP_CALL( SCIPhashtableCreate(&varAggregated, SCIPblkmem(scip), nvars/10, hashGetKeyVar, hashKeyEqVar, hashKeyValVar, NULL) ); 3009 3010 /* check for aggregated variables in nonlinear constraints and output aggregations as linear constraints */ 3011 for( c = 0; c < nConsNonlinear; ++c ) 3012 { 3013 SCIP_Bool success; 3014 int ntmpvars; 3015 3016 /* get variables of the nonlinear constraint */ 3017 SCIP_CALL( SCIPgetConsNVars(scip, consNonlinear[c], &ntmpvars, &success) ); 3018 assert(success); 3019 if( ntmpvars > tmpvarssize ) 3020 { 3021 tmpvarssize = SCIPcalcMemGrowSize(scip, ntmpvars); 3022 SCIP_CALL( SCIPreallocBufferArray(scip, &tmpvars, tmpvarssize) ); 3023 } 3024 SCIP_CALL( SCIPgetConsVars(scip, consNonlinear[c], tmpvars, tmpvarssize, &success) ); 3025 assert(success); 3026 3027 SCIP_CALL( collectAggregatedVars(ntmpvars, tmpvars, &nAggregatedVars, &aggregatedVars, &varAggregated) ); 3028 } 3029 3030 /* check for aggregated variables in and constraints and output aggregations as linear constraints */ 3031 for (c = 0; c < nConsAnd; ++c) 3032 { 3033 SCIP_VAR* resultant; 3034 3035 cons = consAnd[c]; 3036 3037 SCIP_CALL( collectAggregatedVars(SCIPgetNVarsAnd(scip, cons), SCIPgetVarsAnd(scip, cons), &nAggregatedVars, &aggregatedVars, &varAggregated) ); 3038 3039 resultant = SCIPgetResultantAnd(scip, cons); 3040 SCIP_CALL( collectAggregatedVars(1, &resultant, &nAggregatedVars, &aggregatedVars, &varAggregated) ); 3041 } 3042 3043 /* print aggregation constraints */ 3044 SCIP_CALL( printAggregatedCons(scip, file, transformed, nvars, nAggregatedVars, aggregatedVars) ); 3045 3046 /* print "Bounds" section */ 3047 SCIPinfoMessage(scip, file, "Bounds\n"); 3048 for (v = 0; v < nvars; ++v) 3049 { 3050 var = vars[v]; 3051 assert( var != NULL ); 3052 (void) SCIPsnprintf(varname, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var) ); 3053 3054 if( transformed ) 3055 { 3056 /* in case the transformed is written only local bounds are posted which are valid in the current node */ 3057 lb = SCIPvarGetLbLocal(var); 3058 ub = SCIPvarGetUbLocal(var); 3059 } 3060 else 3061 { 3062 lb = SCIPvarGetLbOriginal(var); 3063 ub = SCIPvarGetUbOriginal(var); 3064 } 3065 3066 if ( SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub) ) 3067 SCIPinfoMessage(scip, file, " %s free\n", varname); 3068 else 3069 { 3070 /* print lower bound */ 3071 if ( SCIPisInfinity(scip, -lb) ) 3072 SCIPinfoMessage(scip, file, " -inf <= "); 3073 else 3074 { 3075 if ( SCIPisZero(scip, lb) ) 3076 { 3077 /* variables are nonnegative by default - so we skip these variables */ 3078 if ( SCIPisInfinity(scip, ub) ) 3079 continue; 3080 lb = 0.0; 3081 } 3082 3083 SCIPinfoMessage(scip, file, " %.15g <= ", lb); 3084 } 3085 /* print variable name */ 3086 SCIPinfoMessage(scip, file, "%s", varname); 3087 3088 /* print upper bound as far this one is not infinity */ 3089 if( !SCIPisInfinity(scip, ub) ) 3090 SCIPinfoMessage(scip, file, " <= %.15g", ub); 3091 3092 SCIPinfoMessage(scip, file, "\n"); 3093 } 3094 } 3095 3096 /* output aggregated variables as 'free' */ 3097 for (v = 0; v < nAggregatedVars; ++v) 3098 { 3099 var = aggregatedVars[v]; 3100 assert( var != NULL ); 3101 (void) SCIPsnprintf(varname, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var) ); 3102 3103 SCIPinfoMessage(scip, file, " %s free\n", varname); 3104 } 3105 3106 /* free space */ 3107 SCIPfreeBufferArray(scip, &aggregatedVars); 3108 SCIPhashtableFree(&varAggregated); 3109 3110 /* print binaries section */ 3111 if ( nbinvars > 0 ) 3112 { 3113 SCIPinfoMessage(scip, file, "Binaries\n"); 3114 3115 clearLine(linebuffer, &linecnt); 3116 3117 for (v = 0; v < nvars; ++v) 3118 { 3119 var = vars[v]; 3120 assert( var != NULL ); 3121 3122 if ( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY ) 3123 { 3124 (void) SCIPsnprintf(varname, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var) ); 3125 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %s", varname); 3126 appendLine(scip, file, linebuffer, &linecnt, buffer); 3127 } 3128 } 3129 3130 endLine(scip, file, linebuffer, &linecnt); 3131 } 3132 3133 /* print generals section */ 3134 if ( nintvars > 0 ) 3135 { 3136 SCIPinfoMessage(scip, file, "Generals\n"); 3137 3138 for (v = 0; v < nvars; ++v) 3139 { 3140 var = vars[v]; 3141 assert( var != NULL ); 3142 3143 if ( SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER ) 3144 { 3145 (void) SCIPsnprintf(varname, PIP_MAX_NAMELEN, "%s", SCIPvarGetName(var) ); 3146 (void) SCIPsnprintf(buffer, PIP_MAX_PRINTLEN, " %s", varname); 3147 appendLine(scip, file, linebuffer, &linecnt, buffer); 3148 } 3149 } 3150 endLine(scip, file, linebuffer, &linecnt); 3151 } 3152 3153 /* free space */ 3154 SCIPfreeBufferArray(scip, &tmpvars); 3155 SCIPfreeBufferArray(scip, &consNonlinear); 3156 SCIPfreeBufferArray(scip, &consAnd); 3157 3158 /* end of lp format */ 3159 SCIPinfoMessage(scip, file, "%s\n", "End"); 3160 3161 *result = SCIP_SUCCESS; 3162 3163 return SCIP_OKAY; 3164 } 3165 3166 /* 3167 * Callback methods of reader 3168 */ 3169 3170 /** copy method for reader plugins (called when SCIP copies plugins) */ 3171 static 3172 SCIP_DECL_READERCOPY(readerCopyPip) 3173 { /*lint --e{715}*/ 3174 assert(scip != NULL); 3175 assert(reader != NULL); 3176 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); 3177 3178 /* call inclusion method of reader */ 3179 SCIP_CALL( SCIPincludeReaderPip(scip) ); 3180 3181 return SCIP_OKAY; 3182 } 3183 3184 3185 /** problem reading method of reader */ 3186 static 3187 SCIP_DECL_READERREAD(readerReadPip) 3188 { /*lint --e{715}*/ 3189 3190 SCIP_CALL( SCIPreadPip(scip, reader, filename, result) ); 3191 3192 return SCIP_OKAY; 3193 } 3194 3195 3196 /** problem writing method of reader */ 3197 static 3198 SCIP_DECL_READERWRITE(readerWritePip) 3199 { /*lint --e{715}*/ 3200 SCIP_CALL( SCIPwritePip(scip, file, name, transformed, objsense, objscale, objoffset, vars, 3201 nvars, nbinvars, nintvars, nimplvars, ncontvars, conss, nconss, result) ); 3202 3203 return SCIP_OKAY; 3204 } 3205 3206 3207 /* 3208 * reader specific interface methods 3209 */ 3210 3211 /** includes the pip file reader in SCIP */ 3212 SCIP_RETCODE SCIPincludeReaderPip( 3213 SCIP* scip /**< SCIP data structure */ 3214 ) 3215 { 3216 SCIP_READER* reader; 3217 3218 /* include reader */ 3219 SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, NULL) ); 3220 3221 /* set non fundamental callbacks via setter functions */ 3222 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyPip) ); 3223 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadPip) ); 3224 SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWritePip) ); 3225 3226 return SCIP_OKAY; 3227 } 3228 3229 3230 /** reads problem from file */ 3231 SCIP_RETCODE SCIPreadPip( 3232 SCIP* scip, /**< SCIP data structure */ 3233 SCIP_READER* reader, /**< the file reader itself */ 3234 const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */ 3235 SCIP_RESULT* result /**< pointer to store the result of the file reading call */ 3236 ) 3237 { /*lint --e{715}*/ 3238 PIPINPUT pipinput; 3239 SCIP_RETCODE retcode; 3240 int i; 3241 3242 assert(scip != NULL); /* for lint */ 3243 assert(reader != NULL); 3244 3245 /* initialize PIP input data */ 3246 pipinput.file = NULL; 3247 pipinput.linebuf[0] = '\0'; 3248 pipinput.probname[0] = '\0'; 3249 pipinput.objname[0] = '\0'; 3250 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &pipinput.token, PIP_MAX_LINELEN) ); /*lint !e506*/ 3251 pipinput.token[0] = '\0'; 3252 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &pipinput.tokenbuf, PIP_MAX_LINELEN) ); /*lint !e506*/ 3253 pipinput.tokenbuf[0] = '\0'; 3254 for( i = 0; i < PIP_MAX_PUSHEDTOKENS; ++i ) 3255 { 3256 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &((pipinput.pushedtokens)[i]), PIP_MAX_LINELEN) ); /*lint !e866 !e506*/ 3257 } 3258 3259 pipinput.npushedtokens = 0; 3260 pipinput.linenumber = 0; 3261 pipinput.linepos = 0; 3262 pipinput.section = PIP_START; 3263 pipinput.objsense = SCIP_OBJSENSE_MINIMIZE; 3264 pipinput.haserror = FALSE; 3265 3266 SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &(pipinput.initialconss)) ); 3267 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &(pipinput.dynamicconss)) ); 3268 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &(pipinput.dynamiccols)) ); 3269 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &(pipinput.dynamicrows)) ); 3270 3271 /* read the file */ 3272 retcode = readPIPFile(scip, &pipinput, filename); 3273 3274 /* free dynamically allocated memory */ 3275 for( i = PIP_MAX_PUSHEDTOKENS - 1; i >= 0 ; --i ) 3276 { 3277 SCIPfreeBlockMemoryArray(scip, &pipinput.pushedtokens[i], PIP_MAX_LINELEN); 3278 } 3279 SCIPfreeBlockMemoryArray(scip, &pipinput.tokenbuf, PIP_MAX_LINELEN); 3280 SCIPfreeBlockMemoryArray(scip, &pipinput.token, PIP_MAX_LINELEN); 3281 3282 if( retcode == SCIP_PLUGINNOTFOUND ) 3283 retcode = SCIP_READERROR; 3284 3285 /* evaluate the result */ 3286 if( pipinput.haserror ) 3287 retcode = SCIP_READERROR; 3288 else 3289 { 3290 /* set objective sense */ 3291 SCIP_CALL( SCIPsetObjsense(scip, pipinput.objsense) ); 3292 *result = SCIP_SUCCESS; 3293 } 3294 3295 SCIP_CALL( retcode ); 3296 3297 return SCIP_OKAY; 3298 } 3299