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_diff.c 26 * @ingroup DEFPLUGINS_READER 27 * @brief DIFF file reader 28 * @author Jakob Witzig 29 * 30 * This reader allows to parse a new objective function in the style of CPLEX .lp files. 31 * 32 * The lp format is defined within the CPLEX documentation. 33 * 34 * An example of a *.diff file looks like this: 35 * 36 * Minimize 37 * obj: - STM6 + STM7 38 * 39 * Here is the objective sense set to minimize the function -STM6 + STM7. 40 */ 41 42 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 43 44 #include <ctype.h> 45 #include "scip/pub_fileio.h" 46 #include "scip/pub_message.h" 47 #include "scip/pub_misc.h" 48 #include "scip/pub_reader.h" 49 #include "scip/pub_var.h" 50 #include "scip/reader_diff.h" 51 #include "scip/scip_general.h" 52 #include "scip/scip_mem.h" 53 #include "scip/scip_message.h" 54 #include "scip/scip_numerics.h" 55 #include "scip/scip_prob.h" 56 #include "scip/scip_reader.h" 57 #include "scip/scip_solve.h" 58 #include <stdlib.h> 59 #include <string.h> 60 61 #if !defined(_WIN32) && !defined(_WIN64) 62 #include <strings.h> /*lint --e{766}*/ /* needed for strncasecmp() */ 63 #endif 64 65 #define READER_NAME "diffreader" 66 #define READER_DESC "file reader for changes in the LP file" 67 #define READER_EXTENSION "diff" 68 69 /* 70 * Data structures 71 */ 72 #define LP_MAX_LINELEN 65536 73 #define LP_MAX_PUSHEDTOKENS 2 74 #define LP_INIT_COEFSSIZE 8192 75 76 /** Section in LP File */ 77 enum LpSection 78 { 79 LP_START, LP_OBJECTIVE, LP_END 80 }; 81 typedef enum LpSection LPSECTION; 82 83 enum LpExpType 84 { 85 LP_EXP_NONE, LP_EXP_UNSIGNED, LP_EXP_SIGNED 86 }; 87 typedef enum LpExpType LPEXPTYPE; 88 89 enum LpSense 90 { 91 LP_SENSE_LE, LP_SENSE_GE, LP_SENSE_EQ 92 }; 93 typedef enum LpSense LPSENSE; 94 95 /** LP reading data */ 96 struct LpInput 97 { 98 SCIP_FILE* file; 99 char* linebuf; 100 char probname[LP_MAX_LINELEN]; 101 char objname[LP_MAX_LINELEN]; 102 char* token; 103 char* tokenbuf; 104 char* pushedtokens[LP_MAX_PUSHEDTOKENS]; 105 int npushedtokens; 106 int linenumber; 107 int linepos; 108 int linebufsize; 109 LPSECTION section; 110 SCIP_OBJSENSE objsense; 111 SCIP_Bool haserror; 112 }; 113 typedef struct LpInput LPINPUT; 114 115 static const char commentchars[] = "\\"; 116 117 118 /* 119 * Local methods (for reading) 120 */ 121 122 /** issues an error message and marks the LP data to have errors */ 123 static 124 void syntaxError( 125 SCIP* scip, /**< SCIP data structure */ 126 LPINPUT* lpinput, /**< LP reading data */ 127 const char* msg /**< error message */ 128 ) 129 { 130 char formatstr[256]; 131 132 assert(lpinput != NULL); 133 134 SCIPerrorMessage("Syntax error in line %d ('%s'): %s \n", lpinput->linenumber, lpinput->token, msg); 135 if( lpinput->linebuf[lpinput->linebufsize - 1] == '\n' ) 136 { 137 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, " input: %s", lpinput->linebuf); 138 } 139 else 140 { 141 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, " input: %s\n", lpinput->linebuf); 142 } 143 (void) SCIPsnprintf(formatstr, 256, " %%%ds\n", lpinput->linepos); 144 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, (const char*)formatstr, "^"); 145 lpinput->section = LP_END; 146 lpinput->haserror = TRUE; 147 } 148 149 /** returns whether a syntax error was detected */ 150 static 151 SCIP_Bool hasError( 152 LPINPUT* lpinput /**< LP reading data */ 153 ) 154 { 155 assert(lpinput != NULL); 156 157 return lpinput->haserror; 158 } 159 160 /** returns whether the given character is a token delimiter */ 161 static 162 SCIP_Bool isDelimChar( 163 char c /**< input character */ 164 ) 165 { 166 switch (c) 167 { 168 case ' ': 169 case '\f': 170 case '\n': 171 case '\r': 172 case '\t': 173 case '\v': 174 case '\0': 175 return TRUE; 176 default: 177 return FALSE; 178 } 179 } 180 181 /** returns whether the given character is a single token */ 182 static 183 SCIP_Bool isTokenChar( 184 char c /**< input character */ 185 ) 186 { 187 switch (c) 188 { 189 case '-': 190 case '+': 191 case ':': 192 case '<': 193 case '>': 194 case '=': 195 case '[': 196 case ']': 197 case '*': 198 case '^': 199 return TRUE; 200 default: 201 return FALSE; 202 } 203 } 204 205 /** returns whether the current character is member of a value string */ 206 static 207 SCIP_Bool isValueChar( 208 char c, /**< input character */ 209 char nextc, /**< next input character */ 210 SCIP_Bool firstchar, /**< is the given character the first char of the token? */ 211 SCIP_Bool* hasdot, /**< pointer to update the dot flag */ 212 LPEXPTYPE* exptype /**< pointer to update the exponent type */ 213 ) 214 { 215 assert(hasdot != NULL); 216 assert(exptype != NULL); 217 218 if( isdigit((unsigned char)c) ) 219 return TRUE; 220 else if( (*exptype == LP_EXP_NONE) && !(*hasdot) && (c == '.') && isdigit((unsigned char)nextc) ) 221 { 222 *hasdot = TRUE; 223 return TRUE; 224 } 225 else if( !firstchar && (*exptype == LP_EXP_NONE) && (c == 'e' || c == 'E') ) 226 { 227 if( nextc == '+' || nextc == '-' ) 228 { 229 *exptype = LP_EXP_SIGNED; 230 return TRUE; 231 } 232 else if( isdigit((unsigned char)nextc) ) 233 { 234 *exptype = LP_EXP_UNSIGNED; 235 return TRUE; 236 } 237 } 238 else if( (*exptype == LP_EXP_SIGNED) && (c == '+' || c == '-') ) 239 { 240 *exptype = LP_EXP_UNSIGNED; 241 return TRUE; 242 } 243 244 return FALSE; 245 } 246 247 /** reads the next line from the input file into the line buffer; skips comments; 248 * returns whether a line could be read 249 */ 250 static 251 SCIP_Bool getNextLine( 252 SCIP* scip, /**< SCIP data structure */ 253 LPINPUT* lpinput /**< LP reading data */ 254 ) 255 { 256 int i; 257 258 assert(lpinput != NULL); 259 260 /* read next line */ 261 lpinput->linepos = 0; 262 lpinput->linebuf[lpinput->linebufsize - 2] = '\0'; 263 264 if( SCIPfgets(lpinput->linebuf, lpinput->linebufsize, lpinput->file) == NULL ) 265 { 266 /* clear the line, this is really necessary here! */ 267 BMSclearMemoryArray(lpinput->linebuf, lpinput->linebufsize); 268 269 return FALSE; 270 } 271 272 lpinput->linenumber++; 273 274 /* if line is too long for our buffer reallocate buffer */ 275 while( lpinput->linebuf[lpinput->linebufsize - 2] != '\0' ) 276 { 277 int newsize; 278 279 newsize = SCIPcalcMemGrowSize(scip, lpinput->linebufsize + 1); 280 SCIP_CALL_ABORT( SCIPreallocBlockMemoryArray(scip, &lpinput->linebuf, lpinput->linebufsize, newsize) ); 281 282 lpinput->linebuf[newsize-2] = '\0'; 283 if ( SCIPfgets(lpinput->linebuf + lpinput->linebufsize - 1, newsize - lpinput->linebufsize + 1, lpinput->file) == NULL ) 284 return FALSE; 285 lpinput->linebufsize = newsize; 286 } 287 lpinput->linebuf[lpinput->linebufsize - 1] = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */ 288 289 /* skip characters after comment symbol */ 290 for( i = 0; commentchars[i] != '\0'; ++i ) 291 { 292 char* commentstart; 293 294 commentstart = strchr(lpinput->linebuf, commentchars[i]); 295 if( commentstart != NULL ) 296 { 297 *commentstart = '\0'; 298 *(commentstart+1) = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */ 299 300 break; 301 } 302 } 303 304 return TRUE; 305 } 306 307 /** swaps the addresses of two pointers */ 308 static 309 void swapPointers( 310 char** pointer1, /**< first pointer */ 311 char** pointer2 /**< second pointer */ 312 ) 313 { 314 char* tmp; 315 316 tmp = *pointer1; 317 *pointer1 = *pointer2; 318 *pointer2 = tmp; 319 } 320 321 /** reads the next token from the input file into the token buffer; returns whether a token was read */ 322 static 323 SCIP_Bool getNextToken( 324 SCIP* scip, /**< SCIP data structure */ 325 LPINPUT* lpinput /**< LP reading data */ 326 ) 327 { 328 SCIP_Bool hasdot; 329 LPEXPTYPE exptype; 330 char* buf; 331 int tokenlen; 332 333 assert(lpinput != NULL); 334 assert(lpinput->linepos < lpinput->linebufsize); 335 336 /* check the token stack */ 337 if( lpinput->npushedtokens > 0 ) 338 { 339 swapPointers(&lpinput->token, &lpinput->pushedtokens[lpinput->npushedtokens-1]); 340 lpinput->npushedtokens--; 341 342 SCIPdebugMsg(scip, "(line %d) read token again: '%s'\n", lpinput->linenumber, lpinput->token); 343 return TRUE; 344 } 345 346 /* skip delimiters */ 347 buf = lpinput->linebuf; 348 while( isDelimChar(buf[lpinput->linepos]) ) 349 { 350 if( buf[lpinput->linepos] == '\0' ) 351 { 352 if( !getNextLine(scip, lpinput) ) 353 { 354 lpinput->section = LP_END; 355 SCIPdebugMsg(scip, "(line %d) end of file\n", lpinput->linenumber); 356 return FALSE; 357 } 358 assert(lpinput->linepos == 0); 359 /* update buf, because the linebuffer may have been reallocated */ 360 buf = lpinput->linebuf; 361 } 362 else 363 lpinput->linepos++; 364 } 365 assert(lpinput->linepos < lpinput->linebufsize); 366 assert(!isDelimChar(buf[lpinput->linepos])); 367 assert(buf[lpinput->linepos] != '\0'); /* '\0' is a delim-char, so this assert is redundant, but it helps to suppress a scan-build warning */ 368 369 /* check if the token is a value */ 370 hasdot = FALSE; 371 exptype = LP_EXP_NONE; 372 if( isValueChar(buf[lpinput->linepos], buf[lpinput->linepos+1], TRUE, &hasdot, &exptype) ) 373 { 374 /* read value token */ 375 tokenlen = 0; 376 do 377 { 378 assert(tokenlen < LP_MAX_LINELEN); 379 assert(!isDelimChar(buf[lpinput->linepos])); 380 lpinput->token[tokenlen] = buf[lpinput->linepos]; 381 tokenlen++; 382 lpinput->linepos++; 383 } 384 while( isValueChar(buf[lpinput->linepos], buf[lpinput->linepos+1], FALSE, &hasdot, &exptype) ); 385 } 386 else 387 { 388 /* read non-value token */ 389 tokenlen = 0; 390 do 391 { 392 assert(tokenlen < LP_MAX_LINELEN); 393 lpinput->token[tokenlen] = buf[lpinput->linepos]; 394 tokenlen++; 395 lpinput->linepos++; 396 if( tokenlen == 1 && isTokenChar(lpinput->token[0]) ) 397 break; 398 } 399 while( !isDelimChar(buf[lpinput->linepos]) && !isTokenChar(buf[lpinput->linepos]) ); 400 401 /* if the token is a power sign '^', skip a following '2' 402 * if the token is an equation sense '<', '>', or '=', skip a following '=' 403 * if the token is an equality token '=' and the next character is a '<' or '>', replace the token by the inequality sense 404 */ 405 if( tokenlen >= 1 && lpinput->token[tokenlen-1] == '^' && buf[lpinput->linepos] == '2' ) 406 { 407 lpinput->linepos++; 408 } 409 if( tokenlen >= 1 410 && (lpinput->token[tokenlen-1] == '<' || lpinput->token[tokenlen-1] == '>' || lpinput->token[tokenlen-1] == '=') 411 && buf[lpinput->linepos] == '=' ) 412 { 413 lpinput->linepos++; 414 } 415 else if( lpinput->token[tokenlen-1] == '=' && (buf[lpinput->linepos] == '<' || buf[lpinput->linepos] == '>') ) 416 { 417 lpinput->token[tokenlen-1] = buf[lpinput->linepos]; 418 lpinput->linepos++; 419 } 420 } 421 assert(tokenlen < LP_MAX_LINELEN); 422 lpinput->token[tokenlen] = '\0'; 423 424 SCIPdebugMsg(scip, "(line %d) read token: '%s'\n", lpinput->linenumber, lpinput->token); 425 426 return TRUE; 427 } 428 429 /** puts the current token on the token stack, such that it is read at the next call to getNextToken() */ 430 static 431 void pushToken( 432 LPINPUT* lpinput /**< LP reading data */ 433 ) 434 { 435 assert(lpinput != NULL); 436 assert(lpinput->npushedtokens < LP_MAX_PUSHEDTOKENS); 437 438 swapPointers(&lpinput->pushedtokens[lpinput->npushedtokens], &lpinput->token); 439 lpinput->npushedtokens++; 440 } 441 442 /** puts the buffered token on the token stack, such that it is read at the next call to getNextToken() */ 443 static 444 void pushBufferToken( 445 LPINPUT* lpinput /**< LP reading data */ 446 ) 447 { 448 assert(lpinput != NULL); 449 assert(lpinput->npushedtokens < LP_MAX_PUSHEDTOKENS); 450 451 swapPointers(&lpinput->pushedtokens[lpinput->npushedtokens], &lpinput->tokenbuf); 452 lpinput->npushedtokens++; 453 } 454 455 /** swaps the current token with the token buffer */ 456 static 457 void swapTokenBuffer( 458 LPINPUT* lpinput /**< LP reading data */ 459 ) 460 { 461 assert(lpinput != NULL); 462 463 swapPointers(&lpinput->token, &lpinput->tokenbuf); 464 } 465 466 /** checks whether the current token is a section identifier, and if yes, switches to the corresponding section */ 467 static 468 SCIP_Bool isNewSection( 469 SCIP* scip, /**< SCIP data structure */ 470 LPINPUT* lpinput /**< LP reading data */ 471 ) 472 { 473 SCIP_Bool iscolon; 474 size_t len; 475 476 assert(lpinput != NULL); 477 478 /* remember first token by swapping the token buffer */ 479 swapTokenBuffer(lpinput); 480 481 /* look at next token: if this is a ':', the first token is a name and no section keyword */ 482 iscolon = FALSE; 483 if( getNextToken(scip, lpinput) ) 484 { 485 iscolon = (*lpinput->token == ':'); 486 pushToken(lpinput); 487 } 488 489 /* reinstall the previous token by swapping back the token buffer */ 490 swapTokenBuffer(lpinput); 491 492 /* check for ':' */ 493 if( iscolon ) 494 return FALSE; 495 496 len = strlen(lpinput->token); 497 assert(len < LP_MAX_LINELEN); 498 499 /* the section keywords are at least 2 characters up to 8 or exactly 15 characters long */ 500 if( len > 1 && (len < 9 || len == 15) ) 501 { 502 char token[16]; 503 int c = 0; 504 505 while( lpinput->token[c] != '\0' ) 506 { 507 token[c] = toupper(lpinput->token[c]); /*lint !e734*/ 508 ++c; 509 assert(c < 16); 510 } 511 token[c] = '\0'; 512 513 if( (len == 3 && strcmp(token, "MIN") == 0) 514 || (len == 7 && strcmp(token, "MINIMUM") == 0) 515 || (len == 8 && strcmp(token, "MINIMIZE") == 0) ) 516 { 517 SCIPdebugMsg(scip, "(line %d) new section: OBJECTIVE\n", lpinput->linenumber); 518 lpinput->section = LP_OBJECTIVE; 519 lpinput->objsense = SCIP_OBJSENSE_MINIMIZE; 520 return TRUE; 521 } 522 523 if( (len == 3 && strcmp(token, "MAX") == 0) 524 || (len == 7 && strcmp(token, "MAXIMUM") == 0) 525 || (len == 8 && strcmp(token, "MAXIMIZE") == 0) ) 526 { 527 SCIPdebugMsg(scip, "(line %d) new section: OBJECTIVE\n", lpinput->linenumber); 528 lpinput->section = LP_OBJECTIVE; 529 lpinput->objsense = SCIP_OBJSENSE_MAXIMIZE; 530 return TRUE; 531 } 532 533 if( len == 3 && strcmp(token, "END") == 0 ) 534 { 535 SCIPdebugMsg(scip, "(line %d) new section: END\n", lpinput->linenumber); 536 lpinput->section = LP_END; 537 return TRUE; 538 } 539 } 540 541 return FALSE; 542 } 543 544 /** returns whether the current token is a sign */ 545 static 546 SCIP_Bool isSign( 547 LPINPUT* lpinput, /**< LP reading data */ 548 int* sign /**< pointer to update the sign */ 549 ) 550 { 551 assert(lpinput != NULL); 552 assert(sign != NULL); 553 assert(*sign == +1 || *sign == -1); 554 555 if( lpinput->token[1] == '\0' ) 556 { 557 if( *lpinput->token == '+' ) 558 return TRUE; 559 else if( *lpinput->token == '-' ) 560 { 561 *sign *= -1; 562 return TRUE; 563 } 564 } 565 566 return FALSE; 567 } 568 569 /** returns whether the current token is a value */ 570 static 571 SCIP_Bool isValue( 572 SCIP* scip, /**< SCIP data structure */ 573 LPINPUT* lpinput, /**< LP reading data */ 574 SCIP_Real* value /**< pointer to store the value (unchanged, if token is no value) */ 575 ) 576 { 577 assert(lpinput != NULL); 578 assert(value != NULL); 579 580 if( strcasecmp(lpinput->token, "INFINITY") == 0 || strcasecmp(lpinput->token, "INF") == 0 ) 581 { 582 *value = SCIPinfinity(scip); 583 return TRUE; 584 } 585 else 586 { 587 double val; 588 char* endptr; 589 590 val = strtod(lpinput->token, &endptr); 591 if( endptr != lpinput->token && *endptr == '\0' ) 592 { 593 *value = val; 594 return TRUE; 595 } 596 } 597 598 return FALSE; 599 } 600 601 /** returns whether the current token is an equation sense */ 602 static 603 SCIP_Bool isSense( 604 LPINPUT* lpinput, /**< LP reading data */ 605 LPSENSE* sense /**< pointer to store the equation sense, or NULL */ 606 ) 607 { 608 assert(lpinput != NULL); 609 610 if( strcmp(lpinput->token, "<") == 0 ) 611 { 612 if( sense != NULL ) 613 *sense = LP_SENSE_LE; 614 return TRUE; 615 } 616 else if( strcmp(lpinput->token, ">") == 0 ) 617 { 618 if( sense != NULL ) 619 *sense = LP_SENSE_GE; 620 return TRUE; 621 } 622 else if( strcmp(lpinput->token, "=") == 0 ) 623 { 624 if( sense != NULL ) 625 *sense = LP_SENSE_EQ; 626 return TRUE; 627 } 628 629 return FALSE; 630 } 631 632 /** returns the variable with the given name, or creates a new variable if it does not exist */ 633 static 634 SCIP_RETCODE getVariable( 635 SCIP* scip, /**< SCIP data structure */ 636 char* name, /**< name of the variable */ 637 SCIP_VAR** var /**< pointer to store the variable */ 638 ) 639 { 640 assert(name != NULL); 641 assert(var != NULL); 642 643 *var = SCIPfindVar(scip, name); 644 645 if( *var == NULL ) 646 return SCIP_READERROR; 647 648 return SCIP_OKAY; 649 } 650 651 /** reads the header of the file */ 652 static 653 SCIP_RETCODE readStart( 654 SCIP* scip, /**< SCIP data structure */ 655 LPINPUT* lpinput /**< LP reading data */ 656 ) 657 { 658 assert(lpinput != NULL); 659 660 /* everything before first section is treated as comment */ 661 do 662 { 663 /* get token */ 664 if( !getNextToken(scip, lpinput) ) 665 return SCIP_OKAY; 666 } 667 while( !isNewSection(scip, lpinput) ); 668 669 return SCIP_OKAY; 670 } 671 672 /** reads an objective or constraint with name and coefficients */ 673 static 674 SCIP_RETCODE readCoefficients( 675 SCIP* scip, /**< SCIP data structure */ 676 LPINPUT* lpinput, /**< LP reading data */ 677 SCIP_Bool isobjective, /**< indicates whether we are currently reading the coefficients of the objective */ 678 char* name, /**< pointer to store the name of the line; must be at least of size 679 * LP_MAX_LINELEN */ 680 int* coefssize, /**< size of vars and coefs arrays */ 681 SCIP_VAR*** vars, /**< pointer to store the array with variables (must be freed by caller) */ 682 SCIP_Real** coefs, /**< pointer to store the array with coefficients (must be freed by caller) */ 683 int* ncoefs, /**< pointer to store the number of coefficients */ 684 SCIP_Bool* newsection /**< pointer to store whether a new section was encountered */ 685 ) 686 { 687 SCIP_Bool havesign; 688 SCIP_Bool havevalue; 689 SCIP_Real coef; 690 int coefsign; 691 692 assert(lpinput != NULL); 693 assert(name != NULL); 694 assert(coefssize != NULL); 695 assert(vars != NULL); 696 assert(coefs != NULL); 697 assert(ncoefs != NULL); 698 assert(newsection != NULL); 699 700 *coefssize = 0; 701 *vars = NULL; 702 *coefs = NULL; 703 *name = '\0'; 704 *ncoefs = 0; 705 *newsection = FALSE; 706 707 /* read the first token, which may be the name of the line */ 708 if( getNextToken(scip, lpinput) ) 709 { 710 /* check if we reached a new section */ 711 if( isNewSection(scip, lpinput) ) 712 { 713 *newsection = TRUE; 714 return SCIP_OKAY; 715 } 716 717 /* remember the token in the token buffer */ 718 swapTokenBuffer(lpinput); 719 720 /* get the next token and check, whether it is a colon */ 721 if( getNextToken(scip, lpinput) ) 722 { 723 if( strcmp(lpinput->token, ":") == 0 ) 724 { 725 /* the second token was a colon: the first token is the line name */ 726 (void)SCIPmemccpy(name, lpinput->tokenbuf, '\0', LP_MAX_LINELEN); 727 728 name[LP_MAX_LINELEN - 1] = '\0'; 729 SCIPdebugMsg(scip, "(line %d) read constraint name: '%s'\n", lpinput->linenumber, name); 730 } 731 else 732 { 733 /* the second token was no colon: push the tokens back onto the token stack and parse them as coefficients */ 734 pushToken(lpinput); 735 pushBufferToken(lpinput); 736 } 737 } 738 else 739 { 740 /* there was only one token left: push it back onto the token stack and parse it as coefficient */ 741 pushBufferToken(lpinput); 742 } 743 } 744 745 /* initialize buffers for storing the coefficients */ 746 *coefssize = LP_INIT_COEFSSIZE; 747 SCIP_CALL( SCIPallocBlockMemoryArray(scip, vars, *coefssize) ); 748 SCIP_CALL( SCIPallocBlockMemoryArray(scip, coefs, *coefssize) ); 749 750 /* read the coefficients */ 751 coefsign = +1; 752 coef = 1.0; 753 havesign = FALSE; 754 havevalue = FALSE; 755 *ncoefs = 0; 756 while( getNextToken(scip, lpinput) ) 757 { 758 SCIP_VAR* var; 759 760 /* check if we read a sign */ 761 if( isSign(lpinput, &coefsign) ) 762 { 763 SCIPdebugMsg(scip, "(line %d) read coefficient sign: %+d\n", lpinput->linenumber, coefsign); 764 havesign = TRUE; 765 continue; 766 } 767 768 /* check if we read a value */ 769 if( isValue(scip, lpinput, &coef) ) 770 { 771 SCIPdebugMsg(scip, "(line %d) read coefficient value: %g with sign %+d\n", lpinput->linenumber, coef, coefsign); 772 if( havevalue ) 773 { 774 syntaxError(scip, lpinput, "two consecutive values."); 775 return SCIP_OKAY; 776 } 777 havevalue = TRUE; 778 continue; 779 } 780 781 /* check if we reached an equation sense */ 782 if( isSense(lpinput, NULL) ) 783 { 784 if( isobjective ) 785 { 786 syntaxError(scip, lpinput, "no sense allowed in objective"); 787 return SCIP_OKAY; 788 } 789 790 /* put the sense back onto the token stack */ 791 pushToken(lpinput); 792 break; 793 } 794 795 /* check if we reached a new section, that will be only allowed when having no current sign and value and if we 796 * are not in the quadratic part 797 */ 798 if( (isobjective || (!havevalue && !havesign)) && isNewSection(scip, lpinput) ) 799 { 800 if( havesign && !havevalue ) 801 { 802 SCIPwarningMessage(scip, "skipped single sign %c without value or variable in objective\n", coefsign == 1 ? '+' : '-'); 803 } 804 else if( isobjective && havevalue && !SCIPisZero(scip, coef) ) 805 { 806 SCIPwarningMessage(scip, "constant term %+g in objective is skipped\n", coef * coefsign); 807 } 808 809 *newsection = TRUE; 810 return SCIP_OKAY; 811 } 812 813 /* check if we start a quadratic part */ 814 if( *lpinput->token == '[' ) 815 { 816 syntaxError(scip, lpinput, "diff reader does not support quadratic objective function."); 817 return SCIP_READERROR; 818 } 819 820 /* all but the first coefficient need a sign */ 821 if( *ncoefs > 0 && !havesign ) 822 { 823 syntaxError(scip, lpinput, "expected sign ('+' or '-') or sense ('<' or '>')."); 824 return SCIP_OKAY; 825 } 826 827 /* check if the last variable should be squared */ 828 if( *lpinput->token == '^' ) 829 { 830 syntaxError(scip, lpinput, "diff reader does not support quadratic objective function."); 831 return SCIP_READERROR; 832 } 833 else 834 { 835 /* the token is a variable name: get the corresponding variable */ 836 SCIP_CALL( getVariable(scip, lpinput->token, &var) ); 837 } 838 839 /* insert the linear coefficient */ 840 SCIPdebugMsg(scip, "(line %d) read linear coefficient: %+g<%s>\n", lpinput->linenumber, coefsign * coef, SCIPvarGetName(var)); 841 if( !SCIPisZero(scip, coef) ) 842 { 843 /* resize the vars and coefs array if needed */ 844 if( *ncoefs >= *coefssize ) 845 { 846 int oldcoefssize; 847 848 oldcoefssize = *coefssize; 849 *coefssize *= 2; 850 *coefssize = MAX(*coefssize, (*ncoefs)+1); 851 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, vars, oldcoefssize, *coefssize) ); 852 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, coefs, oldcoefssize, *coefssize) ); 853 } 854 assert(*ncoefs < *coefssize); 855 856 /* add coefficient */ 857 (*vars)[*ncoefs] = var; 858 (*coefs)[*ncoefs] = coefsign * coef; 859 (*ncoefs)++; 860 } 861 862 /* reset the flags and coefficient value for the next coefficient */ 863 coefsign = +1; 864 coef = 1.0; 865 havesign = FALSE; 866 havevalue = FALSE; 867 } 868 869 return SCIP_OKAY; 870 } 871 872 /** reads the objective section */ 873 static 874 SCIP_RETCODE readObjective( 875 SCIP* scip, /**< SCIP data structure */ 876 LPINPUT* lpinput /**< LP reading data */ 877 ) 878 { 879 char name[LP_MAX_LINELEN]; 880 SCIP_VAR** vars; 881 SCIP_Real* coefs; 882 SCIP_Bool newsection; 883 int coefssize; 884 int ncoefs; 885 886 assert(lpinput != NULL); 887 888 /* read the objective coefficients */ 889 SCIP_CALL( readCoefficients(scip, lpinput, TRUE, name, &coefssize, &vars, &coefs, &ncoefs, &newsection) ); 890 891 /* change the objective function */ 892 SCIP_CALL( SCIPchgReoptObjective(scip, lpinput->objsense, vars, coefs, ncoefs) ); 893 894 /* free memory */ 895 SCIPfreeBlockMemoryArrayNull(scip, &coefs, coefssize); 896 SCIPfreeBlockMemoryArrayNull(scip, &vars, coefssize); 897 898 return SCIP_OKAY; /*lint !e438*/ 899 } 900 901 /** reads a diff file */ 902 static 903 SCIP_RETCODE readDiffFile( 904 SCIP* scip, /**< SCIP data structure */ 905 LPINPUT* lpinput, /**< LP reading data */ 906 const char* filename /**< name of the input file */ 907 ) 908 { 909 assert(lpinput != NULL); 910 911 /* open file */ 912 lpinput->file = SCIPfopen(filename, "r"); 913 if( lpinput->file == NULL ) 914 { 915 SCIPerrorMessage("cannot open file <%s> for reading\n", filename); 916 SCIPprintSysError(filename); 917 return SCIP_NOFILE; 918 } 919 920 /* free transformed problem */ 921 if( SCIPisReoptEnabled(scip) && SCIPgetStage(scip) > SCIP_STAGE_PROBLEM ) 922 { 923 SCIP_CALL( SCIPfreeReoptSolve(scip) ); 924 } 925 else 926 { 927 SCIP_CALL( SCIPfreeTransform(scip) ); 928 } 929 930 /* parse the file */ 931 lpinput->section = LP_START; 932 while( lpinput->section != LP_END && !hasError(lpinput) ) 933 { 934 switch( lpinput->section ) 935 { 936 case LP_START: 937 SCIP_CALL( readStart(scip, lpinput) ); 938 break; 939 940 case LP_OBJECTIVE: 941 SCIP_CALL( readObjective(scip, lpinput) ); 942 break; 943 944 case LP_END: /* this is already handled in the while() loop */ 945 default: 946 SCIPerrorMessage("invalid Diff file section <%d>\n", lpinput->section); 947 return SCIP_INVALIDDATA; 948 } 949 } 950 951 /* close file */ 952 SCIPfclose(lpinput->file); 953 954 return SCIP_OKAY; 955 } 956 957 /* 958 * Callback methods of reader 959 */ 960 961 /** copy method for reader plugins (called when SCIP copies plugins) */ 962 static 963 SCIP_DECL_READERCOPY(readerCopyDiff) 964 { /*lint --e{715}*/ 965 assert(scip != NULL); 966 assert(reader != NULL); 967 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); 968 969 /* call inclusion method of reader */ 970 SCIP_CALL( SCIPincludeReaderDiff(scip) ); 971 972 return SCIP_OKAY; 973 } 974 975 /** destructor of reader to free user data (called when SCIP is exiting) */ 976 static 977 SCIP_DECL_READERFREE(readerFreeDiff) 978 { /*lint --e{715}*/ 979 return SCIP_OKAY; 980 } 981 982 /** problem reading method of reader */ 983 static 984 SCIP_DECL_READERREAD(readerReadDiff) 985 { /*lint --e{715}*/ 986 987 SCIP_CALL( SCIPreadDiff(scip, reader, filename, result) ); 988 989 return SCIP_OKAY; 990 } 991 992 /* 993 * reader specific interface methods 994 */ 995 996 /** includes the lp file reader in SCIP */ 997 SCIP_RETCODE SCIPincludeReaderDiff( 998 SCIP* scip /**< SCIP data structure */ 999 ) 1000 { 1001 SCIP_READER* reader; 1002 1003 /* include reader */ 1004 SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, NULL) ); 1005 1006 /* set non fundamental callbacks via setter functions */ 1007 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyDiff) ); 1008 SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeDiff) ); 1009 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadDiff) ); 1010 1011 return SCIP_OKAY; 1012 } 1013 1014 1015 /** reads problem from file */ 1016 SCIP_RETCODE SCIPreadDiff( 1017 SCIP* scip, /**< SCIP data structure */ 1018 SCIP_READER* reader, /**< the file reader itself */ 1019 const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */ 1020 SCIP_RESULT* result /**< pointer to store the result of the file reading call */ 1021 ) 1022 { /*lint --e{715}*/ 1023 LPINPUT lpinput; 1024 int i; 1025 1026 assert(scip != NULL); 1027 assert(reader != NULL); 1028 1029 /* initialize LP input data */ 1030 lpinput.file = NULL; 1031 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lpinput.linebuf, LP_MAX_LINELEN) ); 1032 lpinput.linebuf[0] = '\0'; 1033 lpinput.linebufsize = LP_MAX_LINELEN; 1034 lpinput.probname[0] = '\0'; 1035 lpinput.objname[0] = '\0'; 1036 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lpinput.token, LP_MAX_LINELEN) ); /*lint !e506*/ 1037 lpinput.token[0] = '\0'; 1038 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lpinput.tokenbuf, LP_MAX_LINELEN) ); /*lint !e506*/ 1039 lpinput.tokenbuf[0] = '\0'; 1040 for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i ) 1041 { 1042 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(lpinput.pushedtokens[i]), LP_MAX_LINELEN) ); /*lint !e866 !e506*/ 1043 } 1044 1045 lpinput.npushedtokens = 0; 1046 lpinput.linenumber = 0; 1047 lpinput.linepos = 0; 1048 lpinput.section = LP_START; 1049 lpinput.objsense = SCIP_OBJSENSE_MINIMIZE; 1050 lpinput.haserror = FALSE; 1051 1052 /* read the file */ 1053 SCIP_CALL( readDiffFile(scip, &lpinput, filename) ); 1054 1055 /* free dynamically allocated memory */ 1056 for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i ) 1057 { 1058 SCIPfreeBlockMemoryArray(scip, &lpinput.pushedtokens[i], LP_MAX_LINELEN); 1059 } 1060 SCIPfreeBlockMemoryArray(scip, &lpinput.tokenbuf, LP_MAX_LINELEN); 1061 SCIPfreeBlockMemoryArray(scip, &lpinput.token, LP_MAX_LINELEN); 1062 SCIPfreeBlockMemoryArray(scip, &lpinput.linebuf, lpinput.linebufsize); 1063 1064 /* evaluate the result */ 1065 if( lpinput.haserror ) 1066 return SCIP_READERROR; 1067 1068 *result = SCIP_SUCCESS; 1069 1070 return SCIP_OKAY; 1071 } 1072