Scippy

    SCIP

    Solving Constraint Integer Programs

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