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_fzn.c 26 * @ingroup DEFPLUGINS_READER 27 * @brief FlatZinc file reader 28 * @author Timo Berthold 29 * @author Stefan Heinz 30 * 31 * FlatZinc is a low-level solver input language that is the target language for MiniZinc. It is designed to be easy to 32 * translate into the form required by a solver. For more details see https://www.minizinc.org. The format is described 33 * at https://github.com/MiniZinc/minizinc-doc/blob/develop/en/fzn-spec.rst. 34 * 35 * @todo Support more general constraint types 36 */ 37 38 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 39 40 #include "blockmemshell/memory.h" 41 #include <ctype.h> 42 #include "scip/cons_nonlinear.h" 43 #include "scip/cons_and.h" 44 #include "scip/cons_cumulative.h" 45 #include "scip/cons_knapsack.h" 46 #include "scip/cons_linear.h" 47 #include "scip/cons_logicor.h" 48 #include "scip/cons_or.h" 49 #include "scip/cons_setppc.h" 50 #include "scip/cons_varbound.h" 51 #include "scip/cons_xor.h" 52 #include "scip/pub_cons.h" 53 #include "scip/pub_fileio.h" 54 #include "scip/pub_message.h" 55 #include "scip/pub_misc.h" 56 #include "scip/pub_misc_sort.h" 57 #include "scip/pub_reader.h" 58 #include "scip/pub_var.h" 59 #include "scip/reader_fzn.h" 60 #include "scip/scip_cons.h" 61 #include "scip/scip_mem.h" 62 #include "scip/scip_message.h" 63 #include "scip/scip_numerics.h" 64 #include "scip/scip_param.h" 65 #include "scip/scip_prob.h" 66 #include "scip/scip_reader.h" 67 #include "scip/scip_sol.h" 68 #include "scip/scip_solvingstats.h" 69 #include "scip/scip_var.h" 70 #include <stdlib.h> 71 #include <string.h> 72 73 #ifdef ALLDIFFERENT 74 #include "scip/cons_alldifferent.h" 75 #endif 76 77 #define READER_NAME "fznreader" 78 #define READER_DESC "file reader for FlatZinc format" 79 #define READER_EXTENSION "fzn" 80 81 82 #define FZN_BUFFERLEN 65536 /**< size of the line buffer for reading or writing */ 83 #define FZN_INIT_LINELEN 65536 /**< initial size of the line buffer for reading */ 84 #define FZN_MAX_PUSHEDTOKENS 1 85 86 /* 87 * Data structures 88 */ 89 90 /** number types */ 91 enum FznNumberType 92 { 93 FZN_BOOL, 94 FZN_INT, 95 FZN_FLOAT 96 }; 97 typedef enum FznNumberType FZNNUMBERTYPE; 98 99 /** Expression type in FlatZinc File */ 100 enum FznExpType 101 { 102 FZN_EXP_NONE, 103 FZN_EXP_UNSIGNED, 104 FZN_EXP_SIGNED 105 }; 106 typedef enum FznExpType FZNEXPTYPE; 107 108 /* structures to store the dimension information */ 109 struct Dimensions 110 { 111 int* lbs; /**< lower bounds */ 112 int* ubs; /**< upper bounds */ 113 int ndims; /**< number of dimensions */ 114 int size; /**< size of lbs and ubs */ 115 }; 116 typedef struct Dimensions DIMENSIONS; 117 118 /** FlatZinc constant */ 119 struct FznConstant 120 { 121 const char* name; /**< constant name */ 122 FZNNUMBERTYPE type; /**< constant type */ 123 SCIP_Real value; /**< constant value */ 124 }; 125 typedef struct FznConstant FZNCONSTANT; 126 127 /** structure to store information for an array variable */ 128 struct ConstArray 129 { 130 FZNCONSTANT** constants; /**< array of constants */ 131 char* name; /**< name of constant array */ 132 int nconstants; /**< number of constants */ 133 FZNNUMBERTYPE type; /**< constant type */ 134 }; 135 typedef struct ConstArray CONSTARRAY; 136 137 /** structure to store information for an array variable */ 138 struct VarArray 139 { 140 SCIP_VAR** vars; /**< variable belonging to the variable array */ 141 char* name; /**< name of the array variable */ 142 DIMENSIONS* info; /**< dimension information */ 143 int nvars; /**< number of variables */ 144 FZNNUMBERTYPE type; /**< variable type */ 145 }; 146 typedef struct VarArray VARARRAY; 147 148 /** data for FlatZinc reader */ 149 struct SCIP_ReaderData 150 { 151 VARARRAY** vararrays; /**< variable arrays to output */ 152 int nvararrays; /**< number of variables */ 153 int vararrayssize; /**< size of variable array */ 154 }; 155 156 /** tries to creates and adds a constraint; sets parameter created to TRUE if method was successful 157 * 158 * input: 159 * - scip : SCIP main data structure 160 * - fzninput, : FZN reading data 161 * - fname, : functions identifier name 162 * - ftokens, : function identifier tokens 163 * - nftokens, : number of function identifier tokes 164 * 165 * output 166 * - created : pointer to store whether a constraint was created or not 167 */ 168 #define CREATE_CONSTRAINT(x) SCIP_RETCODE x (SCIP* scip, FZNINPUT* fzninput, const char* fname, char** ftokens, int nftokens, SCIP_Bool* created) 169 170 171 /** FlatZinc reading data */ 172 struct FznInput 173 { 174 SCIP_FILE* file; 175 SCIP_HASHTABLE* varHashtable; 176 SCIP_HASHTABLE* constantHashtable; 177 FZNCONSTANT** constants; 178 char* linebuf; 179 char* token; 180 char* pushedtokens[FZN_MAX_PUSHEDTOKENS]; 181 int npushedtokens; 182 int linenumber; 183 int linepos; 184 int linebufsize; 185 int bufpos; 186 int nconstants; 187 int sconstants; 188 SCIP_OBJSENSE objsense; 189 SCIP_Bool hasdot; /**< if the current token is a number, this bool tells if it contains a dot */ 190 SCIP_Bool comment; /**< current buffer contains everything until a comment starts */ 191 SCIP_Bool haserror; /**< a error was detected during parsing */ 192 SCIP_Bool valid; 193 SCIP_Bool initialconss; /**< should model constraints be marked as initial? */ 194 SCIP_Bool dynamicconss; /**< should model constraints be subject to aging? */ 195 SCIP_Bool dynamiccols; /**< should columns be added and removed dynamically to the LP? */ 196 SCIP_Bool dynamicrows; /**< should rows be added and removed dynamically to the LP? */ 197 198 VARARRAY** vararrays; /**< variable arrays */ 199 int nvararrays; /**< number of variables */ 200 int vararrayssize; /**< size of variable array */ 201 202 CONSTARRAY** constarrays; /**< constant arrays */ 203 int nconstarrays; /**< number of constant arrays */ 204 int constarrayssize; /**< size of constant array */ 205 }; 206 typedef struct FznInput FZNINPUT; 207 208 /** FlatZinc writing data */ 209 struct FznOutput 210 { 211 char* varbuffer; /* buffer for auxiliary variables (float representatives of discrete variables) */ 212 int varbufferlen; /* current length of the above buffer */ 213 int varbufferpos; /* current filling position in the above buffer */ 214 char* castbuffer; /* buffer for int2float conversion constraints */ 215 int castbufferlen; /* current length of the above buffer */ 216 int castbufferpos; /* current filling position in the above buffer */ 217 char* consbuffer; /* buffer for all problem constraints */ 218 int consbufferlen; /* current length of the above buffer */ 219 int consbufferpos; /* current filling position in the above buffer */ 220 int ndiscretevars; /* number of discrete variables in the problem */ 221 SCIP_Bool* varhasfloat; /* array which indicates, whether a discrete variable already has a float representative */ 222 }; 223 typedef struct FznOutput FZNOUTPUT; 224 225 static const char delimchars[] = " \f\n\r\t\v"; 226 static const char tokenchars[] = ":<>=;{}[],()"; 227 static const char commentchars[] = "%"; 228 229 /* 230 * Hash functions 231 */ 232 233 /** gets the key (i.e. the name) of the given variable */ 234 static 235 SCIP_DECL_HASHGETKEY(hashGetKeyVar) 236 { /*lint --e{715}*/ 237 SCIP_VAR* var = (SCIP_VAR*) elem; 238 239 assert(var != NULL); 240 return (void*) SCIPvarGetName(var); 241 } 242 243 /** gets the key (i.e. the name) of the flatzinc constant */ 244 static 245 SCIP_DECL_HASHGETKEY(hashGetKeyConstant) 246 { /*lint --e{715}*/ 247 FZNCONSTANT* constant = (FZNCONSTANT*) elem; 248 249 assert(constant != NULL); 250 return (void*) constant->name; 251 } 252 253 /** comparison method for sorting variable arrays w.r.t. to their name */ 254 static 255 SCIP_DECL_SORTPTRCOMP(vararraysComp) 256 { 257 return strcmp( ((VARARRAY*)elem1)->name, ((VARARRAY*)elem2)->name ); 258 } 259 260 261 /** frees a given buffer char* array */ 262 static 263 void freeStringBufferArray( 264 SCIP* scip, /**< SCIP data structure */ 265 char** array, /**< buffer array to free */ 266 int nelements /**< number of elements */ 267 ) 268 { 269 int i; 270 271 for( i = nelements - 1; i >= 0; --i ) 272 SCIPfreeBufferArray(scip, &array[i]); 273 274 SCIPfreeBufferArray(scip, &array); 275 } 276 277 /** returns whether the given character is a token delimiter */ 278 static 279 SCIP_Bool isDelimChar( 280 char c /**< input character */ 281 ) 282 { 283 return (c == '\0') || (strchr(delimchars, c) != NULL); 284 } 285 286 /** returns whether the given character is a single token */ 287 static 288 SCIP_Bool isTokenChar( 289 char c /**< input character */ 290 ) 291 { 292 return (strchr(tokenchars, c) != NULL); 293 } 294 295 /** check if the current token is equal to give char */ 296 static 297 SCIP_Bool isChar( 298 const char* token, /**< token to be checked */ 299 char c /**< char to compare */ 300 ) 301 { 302 if( strlen(token) == 1 && *token == c ) 303 return TRUE; 304 305 return FALSE; 306 } 307 308 /** check if the current token is Bool expression, this means false or true */ 309 static 310 SCIP_Bool isBoolExp( 311 const char* name, /**< name to check */ 312 SCIP_Bool* value /**< pointer to store the Bool value */ 313 ) 314 { 315 /* check the name */ 316 if( strlen(name) == 4 && strncmp(name, "true", 4) == 0 ) 317 { 318 *value = TRUE; 319 return TRUE; 320 } 321 else if( strlen(name) == 1 && strncmp(name, "1", 1) == 0 ) 322 { 323 /* we also allow 1 as true */ 324 *value = TRUE; 325 return TRUE; 326 } 327 else if( strlen(name) == 5 && strncmp(name, "false", 5) == 0 ) 328 { 329 *value = FALSE; 330 return TRUE; 331 } 332 else if( strlen(name) == 1 && strncmp(name, "0", 1) == 0 ) 333 { 334 /* we also allow 0 as false */ 335 *value = FALSE; 336 return TRUE; 337 } 338 339 return FALSE; 340 } 341 342 343 /** check if the current token is an identifier, this means [A-Za-z][A-Za-z0-9_]* */ 344 static 345 SCIP_Bool isIdentifier( 346 const char* name /**< name to check */ 347 ) 348 { 349 int i; 350 351 /* check if the identifier starts with a letter */ 352 if( strlen(name) == 0 || !isalpha((unsigned char)name[0]) ) 353 return FALSE; 354 355 i = 1; 356 while( name[i] ) 357 { 358 if( !isalnum((unsigned char)name[i]) && name[i] != '_' ) 359 return FALSE; 360 i++; 361 } 362 363 return TRUE; 364 } 365 366 /** returns whether the current character is member of a value string */ 367 static 368 SCIP_Bool isValueChar( 369 char c, /**< input character */ 370 char nextc, /**< next input character */ 371 SCIP_Bool firstchar, /**< is the given character the first char of the token? */ 372 SCIP_Bool* hasdot, /**< pointer to update the dot flag */ 373 FZNEXPTYPE* exptype /**< pointer to update the exponent type */ 374 ) 375 { 376 assert(hasdot != NULL); 377 assert(exptype != NULL); 378 379 if( isdigit((unsigned char)c) ) 380 return TRUE; 381 else if( firstchar && (c == '+' || c == '-') ) 382 return TRUE; 383 else if( (*exptype == FZN_EXP_NONE) && !(*hasdot) && (c == '.') && (isdigit((unsigned char)nextc))) 384 { 385 *hasdot = TRUE; 386 return TRUE; 387 } 388 else if( !firstchar && (*exptype == FZN_EXP_NONE) && (c == 'e' || c == 'E') ) 389 { 390 if( nextc == '+' || nextc == '-' ) 391 { 392 *exptype = FZN_EXP_SIGNED; 393 return TRUE; 394 } 395 else if( isdigit((unsigned char)nextc) ) 396 { 397 *exptype = FZN_EXP_UNSIGNED; 398 return TRUE; 399 } 400 } 401 else if( (*exptype == FZN_EXP_SIGNED) && (c == '+' || c == '-') ) 402 { 403 *exptype = FZN_EXP_UNSIGNED; 404 return TRUE; 405 } 406 407 return FALSE; 408 } 409 410 /** compares two token if they are equal */ 411 static 412 SCIP_Bool equalTokens( 413 const char* token1, /**< first token */ 414 const char* token2 /**< second token */ 415 ) 416 { 417 assert(token1 != NULL); 418 assert(token2 != NULL); 419 420 if( strlen(token1) != strlen(token2) ) 421 return FALSE; 422 423 return !strncmp(token1, token2, strlen(token2) ); 424 } 425 426 /** reads the next line from the input file into the line buffer; skips comments; 427 * returns whether a line could be read 428 */ 429 static 430 SCIP_Bool getNextLine( 431 SCIP* scip, /**< SCIP data structure */ 432 FZNINPUT* fzninput /**< FZN reading data */ 433 ) 434 { 435 int i; 436 437 assert(fzninput != NULL); 438 439 /* clear the line */ 440 BMSclearMemoryArray(fzninput->linebuf, fzninput->linebufsize); 441 fzninput->linebuf[fzninput->linebufsize - 2] = '\0'; 442 443 fzninput->linepos = 0; 444 fzninput->bufpos = 0; 445 446 if( SCIPfgets(fzninput->linebuf, fzninput->linebufsize, fzninput->file) == NULL ) 447 return FALSE; 448 449 fzninput->linenumber++; 450 451 if( fzninput->linebuf[fzninput->linebufsize - 2] != '\0' ) 452 { 453 int newsize; 454 455 newsize = SCIPcalcMemGrowSize(scip, fzninput->linebufsize + 1); 456 SCIP_CALL_ABORT( SCIPreallocBlockMemoryArray(scip, &fzninput->linebuf, fzninput->linebufsize, newsize) ); 457 458 fzninput->linebuf[newsize-2] = '\0'; 459 if ( SCIPfgets(fzninput->linebuf + fzninput->linebufsize - 1, newsize - fzninput->linebufsize + 1, fzninput->file) == NULL ) 460 return FALSE; 461 fzninput->linebufsize = newsize; 462 } 463 464 fzninput->linebuf[fzninput->linebufsize - 1] = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */ 465 fzninput->comment = FALSE; 466 467 /* skip characters after comment symbol */ 468 for( i = 0; commentchars[i] != '\0'; ++i ) 469 { 470 char* commentstart; 471 472 commentstart = strchr(fzninput->linebuf, commentchars[i]); 473 if( commentstart != NULL ) 474 { 475 *commentstart = '\0'; 476 *(commentstart+1) = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */ 477 fzninput->comment = TRUE; 478 break; 479 } 480 } 481 482 return TRUE; 483 } 484 485 486 /** reads the next token from the input file into the token buffer; returns whether a token was read */ 487 static 488 SCIP_Bool getNextToken( 489 SCIP* scip, /**< SCIP data structure */ 490 FZNINPUT* fzninput /**< FZN reading data */ 491 ) 492 { 493 SCIP_Bool hasdot; 494 FZNEXPTYPE exptype; 495 char* buf; 496 int tokenlen; 497 498 assert(fzninput != NULL); 499 assert(fzninput->bufpos < fzninput->linebufsize); 500 501 /* if the current line got marked as comment get the next line */ 502 if( fzninput->comment && !getNextLine(scip, fzninput) ) 503 { 504 SCIPdebugMsg(scip, "(line %d) end of file\n", fzninput->linenumber); 505 return FALSE; 506 } 507 508 /* check the token stack */ 509 if( fzninput->npushedtokens > 0 ) 510 { 511 SCIPswapPointers((void**)&fzninput->token, (void**)&fzninput->pushedtokens[fzninput->npushedtokens-1]); 512 fzninput->npushedtokens--; 513 SCIPdebugMsg(scip, "(line %d) read token again: '%s'\n", fzninput->linenumber, fzninput->token); 514 return TRUE; 515 } 516 517 /* skip delimiters */ 518 buf = fzninput->linebuf; 519 while( isDelimChar(buf[fzninput->bufpos]) ) 520 { 521 if( buf[fzninput->bufpos] == '\0' ) 522 { 523 if( !getNextLine(scip, fzninput) ) 524 { 525 SCIPdebugMsg(scip, "(line %d) end of file\n", fzninput->linenumber); 526 return FALSE; 527 } 528 assert(fzninput->bufpos == 0); 529 /* update buf, because the linebuffer may have been reallocated */ 530 buf = fzninput->linebuf; 531 } 532 else 533 { 534 fzninput->bufpos++; 535 fzninput->linepos++; 536 } 537 } 538 assert(fzninput->bufpos < fzninput->linebufsize); 539 assert(!isDelimChar(buf[fzninput->bufpos])); 540 541 hasdot = FALSE; 542 exptype = FZN_EXP_NONE; 543 544 if( buf[fzninput->bufpos] == '.' && buf[fzninput->bufpos+1] == '.') 545 { 546 /* found <..> which only occurs in Ranges and is a "keyword" */ 547 tokenlen = 2; 548 fzninput->bufpos += 2; 549 fzninput->linepos += 2; 550 fzninput->token[0] = '.'; 551 fzninput->token[1] = '.'; 552 } 553 else if( isValueChar(buf[fzninput->bufpos], buf[fzninput->bufpos+1], TRUE, &hasdot, &exptype) ) 554 { 555 /* read value token */ 556 tokenlen = 0; 557 do 558 { 559 assert(tokenlen < fzninput->linebufsize); 560 assert(!isDelimChar(buf[fzninput->bufpos])); 561 fzninput->token[tokenlen] = buf[fzninput->bufpos]; 562 tokenlen++; 563 fzninput->bufpos++; 564 fzninput->linepos++; 565 assert(fzninput->bufpos < fzninput->linebufsize); 566 } 567 while( isValueChar(buf[fzninput->bufpos], buf[fzninput->bufpos+1], FALSE, &hasdot, &exptype) ); 568 569 fzninput->hasdot = hasdot; 570 } 571 else 572 { 573 /* read non-value token */ 574 tokenlen = 0; 575 do 576 { 577 assert(tokenlen < fzninput->linebufsize); 578 fzninput->token[tokenlen] = buf[fzninput->bufpos]; 579 tokenlen++; 580 fzninput->bufpos++; 581 fzninput->linepos++; 582 583 /* check for annotations */ 584 if(tokenlen == 1 && fzninput->token[0] == ':' && buf[fzninput->bufpos] == ':') 585 { 586 fzninput->token[tokenlen] = buf[fzninput->bufpos]; 587 tokenlen++; 588 fzninput->bufpos++; 589 fzninput->linepos++; 590 break; 591 } 592 593 if( tokenlen == 1 && isTokenChar(fzninput->token[0]) ) 594 break; 595 } 596 while( !isDelimChar(buf[fzninput->bufpos]) && !isTokenChar(buf[fzninput->bufpos]) ); 597 } 598 599 assert(tokenlen < fzninput->linebufsize); 600 fzninput->token[tokenlen] = '\0'; 601 602 SCIPdebugMsg(scip, "(line %d) read token: '%s'\n", fzninput->linenumber, fzninput->token); 603 604 return TRUE; 605 } 606 607 /** puts the current token on the token stack, such that it is read at the next call to getNextToken() */ 608 static 609 void pushToken( 610 FZNINPUT* fzninput /**< FZN reading data */ 611 ) 612 { 613 assert(fzninput != NULL); 614 assert(fzninput->npushedtokens < FZN_MAX_PUSHEDTOKENS); 615 616 SCIPswapPointers((void**)&fzninput->pushedtokens[fzninput->npushedtokens], (void**)&fzninput->token); 617 fzninput->npushedtokens++; 618 } 619 620 /** checks whether the current token is a semicolon which closes a statement */ 621 static 622 SCIP_Bool isEndStatement( 623 FZNINPUT* fzninput /**< FZN reading data */ 624 ) 625 { 626 assert(fzninput != NULL); 627 628 return isChar(fzninput->token, ';'); 629 } 630 631 /** returns whether the current token is a value */ 632 static 633 SCIP_Bool isValue( 634 const char* token, /**< token to check */ 635 SCIP_Real* value /**< pointer to store the value (unchanged, if token is no value) */ 636 ) 637 { 638 double val; 639 char* endptr; 640 641 assert(value != NULL); 642 643 val = strtod(token, &endptr); 644 if( endptr != token && *endptr == '\0' ) 645 { 646 *value = val; 647 return TRUE; 648 } 649 650 return FALSE; 651 } 652 653 /* 654 * Local methods (for reading) 655 */ 656 657 /** issues an error message and marks the FlatZinc data to have errors */ 658 static 659 void syntaxError( 660 SCIP* scip, /**< SCIP data structure */ 661 FZNINPUT* fzninput, /**< FZN reading data */ 662 const char* msg /**< error message */ 663 ) 664 { 665 assert(fzninput != NULL); 666 assert(scip != NULL); 667 668 SCIPerrorMessage("Syntax error in line %d: %s found <%s>\n", fzninput->linenumber, msg, fzninput->token); 669 SCIPerrorMessage(" input: %s\n", fzninput->linebuf); 670 671 fzninput->haserror = TRUE; 672 } 673 674 /** returns whether a syntax error was detected */ 675 static 676 SCIP_Bool hasError( 677 FZNINPUT* fzninput /**< FZN reading data */ 678 ) 679 { 680 assert(fzninput != NULL); 681 682 return (fzninput->haserror || !fzninput->valid); 683 } 684 685 /** create reader data */ 686 static 687 SCIP_RETCODE readerdataCreate( 688 SCIP* scip, /**< SCIP data structure */ 689 SCIP_READERDATA** readerdata /**< pointer to reader data */ 690 ) 691 { 692 SCIP_CALL( SCIPallocBlockMemory(scip, readerdata) ); 693 694 (*readerdata)->vararrays = NULL; 695 (*readerdata)->nvararrays = 0; 696 (*readerdata)->vararrayssize = 0; 697 698 return SCIP_OKAY; 699 } 700 701 /** ensure the size if the variable array */ 702 static 703 SCIP_RETCODE ensureVararrySize( 704 SCIP* scip, /**< SCIP data structure */ 705 SCIP_READERDATA* readerdata /**< reader data */ 706 ) 707 { 708 int nvararrays; 709 int vararrayssize; 710 711 nvararrays = readerdata->nvararrays; 712 vararrayssize = readerdata->vararrayssize; 713 714 if( vararrayssize == nvararrays ) 715 { 716 if( vararrayssize == 0 ) 717 { 718 vararrayssize = 100; 719 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &readerdata->vararrays, vararrayssize) ); 720 } 721 else 722 { 723 vararrayssize *= 2; 724 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &readerdata->vararrays, readerdata->vararrayssize, vararrayssize) ); 725 } 726 } 727 728 readerdata->vararrayssize = vararrayssize; 729 730 return SCIP_OKAY; 731 } 732 733 /** ensure the size if the variable array */ 734 static 735 SCIP_RETCODE ensureVararrySizeFznInput( 736 SCIP* scip, /**< SCIP data structure */ 737 FZNINPUT* fzninput /**< FZN reading data */ 738 ) 739 { 740 int nvararrays; 741 int vararrayssize; 742 743 nvararrays = fzninput->nvararrays; 744 vararrayssize = fzninput->vararrayssize; 745 746 if( vararrayssize == nvararrays ) 747 { 748 if( vararrayssize == 0 ) 749 { 750 vararrayssize = 100; 751 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &fzninput->vararrays, vararrayssize) ); 752 } 753 else 754 { 755 vararrayssize *= 2; 756 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &fzninput->vararrays, fzninput->vararrayssize, vararrayssize) ); 757 } 758 } 759 760 fzninput->vararrayssize = vararrayssize; 761 762 return SCIP_OKAY; 763 } 764 765 /** ensure the size if the variable array */ 766 static 767 SCIP_RETCODE ensureConstarrySizeFznInput( 768 SCIP* scip, /**< SCIP data structure */ 769 FZNINPUT* fzninput /**< FZN reading data */ 770 ) 771 { 772 int nconstarrays; 773 int constarrayssize; 774 775 nconstarrays = fzninput->nconstarrays; 776 constarrayssize = fzninput->constarrayssize; 777 778 if( constarrayssize == nconstarrays ) 779 { 780 if( constarrayssize == 0 ) 781 { 782 constarrayssize = 100; 783 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &fzninput->constarrays, constarrayssize) ); 784 } 785 else 786 { 787 constarrayssize *= 2; 788 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &fzninput->constarrays, fzninput->constarrayssize, constarrayssize) ); 789 } 790 } 791 792 fzninput->constarrayssize = constarrayssize; 793 794 return SCIP_OKAY; 795 } 796 797 /** print given value in FlatZinc format to given stream */ 798 static 799 void printValue( 800 SCIP* scip, /**< SCIP data structure */ 801 FILE* file, /**< output file (or NULL for standard output) */ 802 SCIP_Real value, /**< value to print */ 803 FZNNUMBERTYPE type /**< FlatZinc number type */ 804 ) 805 { 806 switch( type ) 807 { 808 case FZN_BOOL: 809 if( value < 0.5 ) 810 SCIPinfoMessage(scip, file, "false"); 811 else 812 SCIPinfoMessage(scip, file, "true"); 813 break; 814 case FZN_INT: 815 { 816 SCIP_Longint longvalue; 817 longvalue = SCIPconvertRealToLongint(scip, value); 818 SCIPinfoMessage(scip, file, "%" SCIP_LONGINT_FORMAT "", longvalue); 819 break; 820 } 821 case FZN_FLOAT: 822 if( SCIPisIntegral(scip, value) ) 823 { 824 printValue(scip, file, value, FZN_INT); 825 826 /* add a ".0" to be type save */ 827 SCIPinfoMessage(scip, file, ".0"); 828 } 829 else 830 { 831 SCIPinfoMessage(scip, file, "%.1f", value); 832 } 833 break; 834 } 835 } 836 837 /* 838 * Local methods (for VARARRAY) 839 */ 840 841 /** free dimension structure */ 842 static 843 SCIP_RETCODE copyDimensions( 844 SCIP* scip, /**< SCIP data structure */ 845 DIMENSIONS** target, /**< pointer to dimension target structure */ 846 DIMENSIONS* source /**< dimension source */ 847 ) 848 { 849 if( source != NULL ) 850 { 851 SCIP_CALL( SCIPallocBlockMemory(scip, target) ); 852 853 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->lbs, source->lbs, source->ndims) ); 854 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->ubs, source->ubs, source->ndims) ); 855 (*target)->ndims = source->ndims; 856 (*target)->size = source->ndims; 857 } 858 else 859 *target = NULL; 860 861 return SCIP_OKAY; 862 } 863 864 /** create variable array data structure */ 865 static 866 SCIP_RETCODE createVararray( 867 SCIP* scip, /**< SCIP data structure */ 868 VARARRAY** vararray, /**< pointer to variable array */ 869 const char* name, /**< name of the variable array */ 870 SCIP_VAR** vars, /**< array of variables */ 871 int nvars, /**< number of variables */ 872 FZNNUMBERTYPE type, /**< variable type */ 873 DIMENSIONS* info /**< dimension information for output */ 874 ) 875 { 876 /* allocate memory for the new vararray struct */ 877 SCIP_CALL( SCIPallocBlockMemory(scip, vararray) ); 878 879 /* copy variable pointers */ 880 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*vararray)->vars, vars, nvars) ); 881 882 /* copy variable array name */ 883 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*vararray)->name, name, strlen(name)+1) ); 884 885 SCIP_CALL( copyDimensions(scip, &(*vararray)->info, info) ); 886 887 (*vararray)->nvars = nvars; 888 (*vararray)->type = type; 889 890 return SCIP_OKAY; 891 } 892 893 /** free dimension structure */ 894 static 895 void freeDimensions( 896 SCIP* scip, /**< SCIP data structure */ 897 DIMENSIONS** dim /**< pointer to dimension structure */ 898 ) 899 { 900 if( *dim != NULL ) 901 { 902 SCIPfreeBlockMemoryArrayNull(scip, &(*dim)->lbs, (*dim)->size); 903 SCIPfreeBlockMemoryArrayNull(scip, &(*dim)->ubs, (*dim)->size); 904 SCIPfreeBlockMemory(scip, dim); 905 } 906 } 907 908 /** free variable array data structure */ 909 static 910 void freeVararray( 911 SCIP* scip, /**< SCIP data structure */ 912 VARARRAY** vararray /**< pointer to variable array */ 913 ) 914 { 915 freeDimensions(scip, &(*vararray)->info); 916 917 SCIPfreeBlockMemoryArray(scip, &(*vararray)->name, strlen((*vararray)->name) + 1); 918 SCIPfreeBlockMemoryArray(scip, &(*vararray)->vars, (*vararray)->nvars); 919 920 SCIPfreeBlockMemory(scip, vararray); 921 } 922 923 /** searches the variable array data base if a constant array exists with the given name; if it exists it is returned */ 924 static 925 VARARRAY* findVararray( 926 FZNINPUT* fzninput, /**< FZN reading data */ 927 const char* name /**< variable array name */ 928 ) 929 { 930 VARARRAY* vararray; 931 int c; 932 933 /* search in constants array list for a constants array with the given name */ 934 for( c = 0; c < fzninput->nvararrays; ++c ) 935 { 936 vararray = fzninput->vararrays[c]; 937 938 if( equalTokens(name, vararray->name) ) 939 return vararray; 940 } 941 942 return NULL; 943 } 944 945 /* 946 * Local methods (for CONSTARRAY) 947 */ 948 949 /** create constant array data structure */ 950 static 951 SCIP_RETCODE createConstarray( 952 SCIP* scip, /**< SCIP data structure */ 953 CONSTARRAY** constarray, /**< pointer to constant array */ 954 const char* name, /**< name of the variable array */ 955 FZNCONSTANT** constants, /**< array of constants */ 956 int nconstants, /**< number of constants */ 957 FZNNUMBERTYPE type /**< constant type */ 958 ) 959 { 960 SCIPdebugMsg(scip, "create constant array <%s>\n", name); 961 962 /* allocate memory for the new constarray struct */ 963 SCIP_CALL( SCIPallocBlockMemory(scip, constarray) ); 964 965 /* copy constant values */ 966 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*constarray)->constants, constants, nconstants) ); 967 968 /* copy constant array name */ 969 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*constarray)->name, name, strlen(name)+1) ); 970 971 (*constarray)->nconstants = nconstants; 972 (*constarray)->type = type; 973 974 return SCIP_OKAY; 975 } 976 977 /** free constant array data structure */ 978 static 979 void freeConstarray( 980 SCIP* scip, /**< SCIP data structure */ 981 CONSTARRAY** constarray /**< pointer to constant array */ 982 ) 983 { 984 SCIPdebugMsg(scip, "free constant array <%s>\n", (*constarray)->name); 985 986 /* free variable pointers */ 987 SCIPfreeBlockMemoryArray(scip, &(*constarray)->constants, (*constarray)->nconstants); 988 989 /* free variable array name */ 990 SCIPfreeBlockMemoryArray(scip, &(*constarray)->name, strlen((*constarray)->name) + 1); 991 992 /* allocate memory for the new vararray struct */ 993 SCIPfreeBlockMemory(scip, constarray); 994 } 995 996 /** searches the constant array data base if a constant array exists with the given name; if it exists it is returned */ 997 static 998 CONSTARRAY* findConstarray( 999 FZNINPUT* fzninput, /**< FZN reading data */ 1000 const char* name /**< constant array name */ 1001 ) 1002 { 1003 CONSTARRAY* constarray; 1004 int c; 1005 1006 /* search in constants array list for a constants array with the given name */ 1007 for( c = 0; c < fzninput->nconstarrays; ++c ) 1008 { 1009 constarray = fzninput->constarrays[c]; 1010 1011 if( equalTokens(name, constarray->name) ) 1012 return constarray; 1013 } 1014 1015 return NULL; 1016 } 1017 1018 /** add variable to the reader data */ 1019 static 1020 SCIP_RETCODE readerdataAddOutputvar( 1021 SCIP* scip, /**< SCIP data structure */ 1022 SCIP_READERDATA* readerdata, /**< reader data */ 1023 SCIP_VAR* var, /**< variable to add to the reader data */ 1024 FZNNUMBERTYPE type /**< variable type */ 1025 ) 1026 { 1027 DIMENSIONS* info; 1028 const char* name; 1029 VARARRAY* vararray; 1030 int nvararrays; 1031 1032 nvararrays = readerdata->nvararrays; 1033 1034 SCIP_CALL( ensureVararrySize(scip, readerdata) ); 1035 assert(nvararrays < readerdata->vararrayssize); 1036 1037 /* get variable name */ 1038 name = SCIPvarGetName(var); 1039 1040 /* allocate memory for the new vararray struct */ 1041 SCIP_CALL( SCIPallocBlockMemory(scip, &vararray) ); 1042 1043 /* copy variable pointers */ 1044 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &vararray->vars, &var, 1) ); 1045 1046 /* copy variable array name */ 1047 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &vararray->name, name, strlen(name)+1) ); 1048 1049 SCIP_CALL( SCIPallocBlockMemory(scip, &info) ); 1050 info->lbs = NULL; 1051 info->ubs = NULL; 1052 info->ndims = 0; 1053 info->size = 0; 1054 1055 vararray->info = info; 1056 vararray->nvars = 1; 1057 vararray->type = type; 1058 1059 readerdata->vararrays[nvararrays] = vararray; 1060 readerdata->nvararrays++; 1061 1062 return SCIP_OKAY; 1063 } 1064 1065 /** add variable to the reader data */ 1066 static 1067 SCIP_RETCODE readerdataAddOutputvararray( 1068 SCIP* scip, /**< SCIP data structure */ 1069 SCIP_READERDATA* readerdata, /**< reader data */ 1070 const char* name, /**< name of the variable array */ 1071 SCIP_VAR** vars, /**< array of variable to add to the reader data */ 1072 int nvars, /**< number of variables */ 1073 FZNNUMBERTYPE type, /**< variable type */ 1074 DIMENSIONS* info /**< dimension information for output */ 1075 ) 1076 { 1077 VARARRAY* vararray; 1078 int nvararrays; 1079 1080 nvararrays = readerdata->nvararrays; 1081 1082 SCIP_CALL( ensureVararrySize(scip, readerdata) ); 1083 assert(nvararrays < readerdata->vararrayssize); 1084 1085 /* create variable array data structure */ 1086 SCIP_CALL( createVararray(scip, &vararray, name, vars, nvars, type, info) ); 1087 1088 readerdata->vararrays[nvararrays] = vararray; 1089 readerdata->nvararrays++; 1090 1091 return SCIP_OKAY; 1092 } 1093 1094 /** add variable to the input data */ 1095 static 1096 SCIP_RETCODE fzninputAddVararray( 1097 SCIP* scip, /**< SCIP data structure */ 1098 FZNINPUT* fzninput, /**< FZN reading data */ 1099 const char* name, /**< name of the variable array */ 1100 SCIP_VAR** vars, /**< array of variables */ 1101 int nvars, /**< number of variables */ 1102 FZNNUMBERTYPE type, /**< variable type */ 1103 DIMENSIONS* info /**< dimension information for output */ 1104 ) 1105 { 1106 VARARRAY* vararray; 1107 int nvararrays; 1108 1109 nvararrays = fzninput->nvararrays; 1110 1111 SCIP_CALL( ensureVararrySizeFznInput(scip, fzninput) ); 1112 assert(nvararrays < fzninput->vararrayssize); 1113 1114 /* create variable array data structure */ 1115 SCIP_CALL( createVararray(scip, &vararray, name, vars, nvars, type, info) ); 1116 1117 fzninput->vararrays[nvararrays] = vararray; 1118 fzninput->nvararrays++; 1119 1120 return SCIP_OKAY; 1121 } 1122 1123 /** add variable to the reader data */ 1124 static 1125 SCIP_RETCODE fzninputAddConstarray( 1126 SCIP* scip, /**< SCIP data structure */ 1127 FZNINPUT* fzninput, /**< FZN reading data */ 1128 const char* name, /**< name of the variable array */ 1129 FZNCONSTANT** constants, /**< array of constants */ 1130 int nconstants, /**< number of constants */ 1131 FZNNUMBERTYPE type /**< variable type */ 1132 ) 1133 { 1134 CONSTARRAY* constarray; 1135 int nconstarrays; 1136 1137 nconstarrays = fzninput->nconstarrays; 1138 1139 SCIP_CALL( ensureConstarrySizeFznInput(scip, fzninput) ); 1140 assert(nconstarrays < fzninput->constarrayssize); 1141 1142 /* create constant array structure */ 1143 SCIP_CALL( createConstarray(scip, &constarray, name, constants, nconstants, type) ); 1144 1145 fzninput->constarrays[nconstarrays] = constarray; 1146 fzninput->nconstarrays++; 1147 1148 return SCIP_OKAY; 1149 } 1150 1151 /** creates, adds, and releases a quadratic constraint */ 1152 static 1153 SCIP_RETCODE createQuadraticCons( 1154 SCIP* scip, /**< SCIP data structure */ 1155 const char* name, /**< name of constraint */ 1156 int nlinvars, /**< number of linear terms (n) */ 1157 SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */ 1158 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */ 1159 int nquadterms, /**< number of quadratic terms (m) */ 1160 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */ 1161 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */ 1162 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */ 1163 SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */ 1164 SCIP_Real rhs, /**< right hand side of quadratic equation (u) */ 1165 SCIP_Bool initialconss, /**< should model constraints be marked as initial? */ 1166 SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */ 1167 SCIP_Bool dynamicrows /**< should rows be added and removed dynamically to the LP? */ 1168 ) 1169 { 1170 SCIP_CONS* cons; 1171 1172 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, &cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, 1173 quadvars2, quadcoefs, lhs, rhs, initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, 1174 dynamicrows) ); 1175 1176 SCIPdebugPrintCons(scip, cons, NULL); 1177 1178 SCIP_CALL( SCIPaddCons(scip, cons) ); 1179 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 1180 1181 return SCIP_OKAY; 1182 } 1183 1184 /** creates, adds, and releases a linear constraint */ 1185 static 1186 SCIP_RETCODE createLinearCons( 1187 SCIP* scip, /**< SCIP data structure */ 1188 const char* name, /**< name of constraint */ 1189 int nvars, /**< number of nonzeros in the constraint */ 1190 SCIP_VAR** vars, /**< array with variables of constraint entries */ 1191 SCIP_Real* vals, /**< array with coefficients of constraint entries */ 1192 SCIP_Real lhs, /**< left hand side of constraint */ 1193 SCIP_Real rhs, /**< right hand side of constraint */ 1194 SCIP_Bool initialconss, /**< should model constraints be marked as initial? */ 1195 SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */ 1196 SCIP_Bool dynamicrows /**< should rows be added and removed dynamically to the LP? */ 1197 ) 1198 { 1199 SCIP_CONS* cons; 1200 1201 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nvars, vars, vals, lhs, rhs, 1202 initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); 1203 1204 SCIPdebugPrintCons(scip, cons, NULL); 1205 1206 SCIP_CALL( SCIPaddCons(scip, cons) ); 1207 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 1208 1209 return SCIP_OKAY; 1210 } 1211 1212 /** create a linking between the two given identifiers */ 1213 static 1214 SCIP_RETCODE createLinking( 1215 SCIP* scip, /**< SCIP data structure */ 1216 FZNINPUT* fzninput, /**< FZN reading data */ 1217 const char* consname, /**< name of constraint */ 1218 const char* name1, /**< name of first identifier */ 1219 const char* name2, /**< name of second identifier */ 1220 SCIP_Real lhs, /**< left hand side of the linking */ 1221 SCIP_Real rhs /**< right hand side of the linking */ 1222 ) 1223 { 1224 SCIP_VAR** vars; 1225 SCIP_Real vals[] = {0.0,0.0}; 1226 SCIP_Real value1; 1227 SCIP_Real value2; 1228 int nvars; 1229 1230 nvars = 0; 1231 value1 = 0.0; 1232 value2 = 0.0; 1233 1234 SCIP_CALL( SCIPallocBufferArray(scip, &vars, 2) ); 1235 1236 vars[nvars] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) name1); 1237 if( vars[nvars] != NULL ) 1238 { 1239 vals[nvars] = 1.0; 1240 nvars++; 1241 } 1242 else if( !isValue(name1, &value1) ) 1243 { 1244 FZNCONSTANT* constant; 1245 1246 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) name1); 1247 assert(constant != NULL); 1248 1249 value1 = constant->value; 1250 } 1251 1252 vars[nvars] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) name2); 1253 if( vars[nvars] != NULL ) 1254 { 1255 vals[nvars] = -1.0; 1256 nvars++; 1257 } 1258 else if( !isValue(name2, &value2) ) 1259 { 1260 FZNCONSTANT* constant; 1261 1262 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) name2); 1263 assert(constant != NULL); 1264 1265 value2 = constant->value; 1266 } 1267 1268 if( !SCIPisInfinity(scip, -lhs) ) 1269 lhs += (value2 - value1); 1270 1271 if( !SCIPisInfinity(scip, rhs) ) 1272 rhs += (value2 - value1); 1273 1274 SCIP_CALL( createLinearCons(scip, consname, nvars, vars, vals, lhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) ); 1275 1276 SCIPfreeBufferArray(scip, &vars); 1277 1278 return SCIP_OKAY; 1279 } 1280 1281 /** parse array index expression */ 1282 static 1283 void parseArrayIndex( 1284 SCIP* scip, /**< SCIP data structure */ 1285 FZNINPUT* fzninput, /**< FZN reading data */ 1286 int* idx /**< pointer to store the array index */ 1287 ) 1288 { 1289 SCIP_Real value; 1290 1291 assert( isChar(fzninput->token, '[') ); 1292 1293 /* parse array index expression */ 1294 if( !getNextToken(scip, fzninput) || isEndStatement(fzninput) ) 1295 { 1296 syntaxError(scip, fzninput, "expecting array index expression"); 1297 return; 1298 } 1299 1300 if( isIdentifier(fzninput->token) ) 1301 { 1302 FZNCONSTANT* constant; 1303 1304 /* identifier has to be one of a constant */ 1305 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, fzninput->token); 1306 1307 if( constant == NULL ) 1308 syntaxError(scip, fzninput, "unknown index name"); 1309 else 1310 { 1311 assert(constant->type == FZN_INT); 1312 *idx = (int) constant->value; 1313 } 1314 } 1315 else if( isValue(fzninput->token, &value) ) 1316 { 1317 assert( fzninput->hasdot == FALSE ); 1318 *idx = (int) value; 1319 } 1320 else 1321 syntaxError(scip, fzninput, "expecting array index expression"); 1322 } 1323 1324 /** unroll assignment if it is an array access one */ 1325 static 1326 void flattenAssignment( 1327 SCIP* scip, /**< SCIP data structure */ 1328 FZNINPUT* fzninput, /**< FZN reading data */ 1329 char* assignment /**< assignment to unroll */ 1330 ) 1331 { 1332 assert(scip != NULL); 1333 assert(fzninput != NULL); 1334 1335 SCIPdebugMsg(scip, "parse assignment expression\n"); 1336 1337 if( !getNextToken(scip, fzninput) || isEndStatement(fzninput) ) 1338 { 1339 syntaxError(scip, fzninput, "expecting more tokens"); 1340 return; 1341 } 1342 1343 if( isIdentifier(fzninput->token) ) 1344 { 1345 char name[FZN_BUFFERLEN]; 1346 int idx; 1347 1348 (void) SCIPsnprintf(name, FZN_BUFFERLEN, "%s", fzninput->token); 1349 1350 if( !getNextToken(scip, fzninput) ) 1351 { 1352 syntaxError(scip, fzninput, "expecting at least a semicolon to close the statement"); 1353 return; 1354 } 1355 1356 /* check if it is an array access expression */ 1357 if( isChar(fzninput->token, '[') ) 1358 { 1359 idx = -1; 1360 parseArrayIndex(scip, fzninput, &idx); 1361 1362 assert(idx >= 0); 1363 1364 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ']') ) 1365 { 1366 syntaxError(scip, fzninput, "expecting token <]>"); 1367 return; 1368 } 1369 1370 /* put constant name or variable name together */ 1371 (void) SCIPsnprintf(assignment, FZN_BUFFERLEN, "%s[%d]", name, idx); 1372 } 1373 else 1374 { 1375 (void) SCIPsnprintf(assignment, FZN_BUFFERLEN, "%s", name); 1376 1377 /* push the current token back for latter evaluations */ 1378 pushToken(fzninput); 1379 } 1380 } 1381 else 1382 (void) SCIPsnprintf(assignment, FZN_BUFFERLEN, "%s", fzninput->token); 1383 } 1384 1385 /** computes w.r.t. to the given side value and relation the left and right side for a SCIP linear constraint */ 1386 static 1387 void computeLinearConsSides( 1388 SCIP* scip, /**< SCIP data structure */ 1389 FZNINPUT* fzninput, /**< FZN reading data */ 1390 const char* name, /**< name of the relation */ 1391 SCIP_Real sidevalue, /**< parsed side value */ 1392 SCIP_Real* lhs, /**< pointer to left hand side */ 1393 SCIP_Real* rhs /**< pointer to right hand side */ 1394 ) 1395 { 1396 SCIPdebugMsg(scip, "check relation <%s>\n", name); 1397 1398 /* compute left and right hand side of the linear constraint */ 1399 if( equalTokens(name, "eq") ) 1400 { 1401 *lhs = sidevalue; 1402 *rhs = sidevalue; 1403 } 1404 else if( equalTokens(name, "ge") ) 1405 { 1406 *lhs = sidevalue; 1407 } 1408 else if( equalTokens(name, "le") ) 1409 { 1410 *rhs = sidevalue; 1411 } 1412 else if( equalTokens(name, "gt") ) 1413 { 1414 /* greater than only works if there are not continuous variables are involved */ 1415 *lhs = sidevalue + 1.0; 1416 } 1417 else if( equalTokens(name, "lt") ) 1418 { 1419 /* less than only works if there are not continuous variables are involved */ 1420 *rhs = sidevalue - 1.0; 1421 } 1422 else 1423 syntaxError(scip, fzninput, "unknown relation in constraint identifier name"); 1424 1425 SCIPdebugMsg(scip, "lhs = %g, rhs = %g\n", *lhs, *rhs); 1426 } 1427 1428 /** parse a list of elements which is separates by a comma */ 1429 static 1430 SCIP_RETCODE parseList( 1431 SCIP* scip, /**< SCIP data structure */ 1432 FZNINPUT* fzninput, /**< FZN reading data */ 1433 char*** elements, /**< pointer to char* array for storing the elements of the list */ 1434 int* nelements, /**< pointer to store the number of elements */ 1435 int selements /**< size of the elements char* array */ 1436 ) 1437 { 1438 char assignment[FZN_BUFFERLEN]; 1439 assert(selements > 0); 1440 1441 /* check if the list is not empty */ 1442 if( getNextToken(scip, fzninput) && !isChar(fzninput->token, ']') ) 1443 { 1444 /* push back token */ 1445 pushToken(fzninput); 1446 1447 /* loop through the array */ 1448 do 1449 { 1450 if(selements == *nelements) 1451 { 1452 selements *= 2; 1453 SCIP_CALL( SCIPreallocBufferArray(scip, elements, selements) ); 1454 } 1455 1456 /* parse and flatten assignment */ 1457 flattenAssignment(scip, fzninput, assignment); 1458 1459 if( hasError(fzninput) ) 1460 break; 1461 1462 /* store assignment */ 1463 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*elements)[(*nelements)], assignment, (int) strlen(assignment) + 1) ); /*lint !e866*/ 1464 1465 (*nelements)++; 1466 } 1467 while( getNextToken(scip, fzninput) && isChar(fzninput->token, ',') ); 1468 } 1469 else 1470 { 1471 SCIPdebugMsg(scip, "list is empty\n"); 1472 } 1473 1474 /* push back ']' which closes the list */ 1475 pushToken(fzninput); 1476 1477 return SCIP_OKAY; 1478 } 1479 1480 /** parse range expression */ 1481 static 1482 void parseRange( 1483 SCIP* scip, /**< SCIP data structure */ 1484 FZNINPUT* fzninput, /**< FZN reading data */ 1485 FZNNUMBERTYPE* type, /**< pointer to store the number type */ 1486 SCIP_Real* lb, /**< pointer to store the lower bound */ 1487 SCIP_Real* ub /**< pointer to store the upper bound */ 1488 ) 1489 { 1490 if( !getNextToken(scip, fzninput) ) 1491 { 1492 syntaxError(scip, fzninput, "expected left side of range"); 1493 return; 1494 } 1495 1496 /* current token should be the lower bound */ 1497 if( !isValue(fzninput->token, lb) ) 1498 { 1499 syntaxError(scip, fzninput, "expected lower bound value"); 1500 return; 1501 } 1502 1503 /* check if we have a float notation or an integer notation which defines the type of the variable */ 1504 if( fzninput->hasdot || !SCIPisIntegral(scip, *lb) ) 1505 *type = FZN_FLOAT; 1506 else 1507 *type = FZN_INT; 1508 1509 /* parse next token which should be <..> */ 1510 if( !getNextToken(scip, fzninput) || !equalTokens(fzninput->token, "..") ) 1511 { 1512 syntaxError(scip, fzninput, "expected <..>"); 1513 return; 1514 } 1515 1516 /* parse upper bound */ 1517 if( !getNextToken(scip, fzninput) || !isValue(fzninput->token, ub) ) 1518 { 1519 syntaxError(scip, fzninput, "expected upper bound value"); 1520 return; 1521 } 1522 1523 /* check if upper bound notation fits which lower bound notation */ 1524 if( fzninput->hasdot != (*type == FZN_FLOAT) ) 1525 { 1526 SCIPwarningMessage(scip, "lower bound and upper bound mismatch in value type, assume %s variable type\n", 1527 fzninput->hasdot ? "an integer" : "a continuous"); 1528 } 1529 } 1530 1531 /** parse dimension information */ 1532 static 1533 SCIP_RETCODE parseOutputDimensioninfo( 1534 SCIP* scip, /**< SCIP data structure */ 1535 FZNINPUT* fzninput, /**< FZN reading data */ 1536 DIMENSIONS** info /**< pointer to store the output dimension information if one */ 1537 ) 1538 { 1539 FZNNUMBERTYPE type; 1540 SCIP_Real lb; 1541 SCIP_Real ub; 1542 int nelements; 1543 int size; 1544 1545 nelements = 0; 1546 size = 100; 1547 1548 SCIP_CALL( SCIPallocBlockMemory(scip, info) ); 1549 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*info)->lbs, size) ); 1550 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*info)->ubs, size) ); 1551 (*info)->size = size; 1552 1553 /* check for bracket */ 1554 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '(') ) 1555 { 1556 syntaxError(scip, fzninput, "expecting <(> after <output_array>"); 1557 return SCIP_OKAY; 1558 } 1559 1560 while( getNextToken(scip, fzninput) && !isChar(fzninput->token, ']') ) 1561 { 1562 parseRange(scip, fzninput, &type, &lb, &ub); 1563 1564 if( fzninput->haserror ) 1565 return SCIP_OKAY; 1566 1567 assert(type == FZN_INT); 1568 1569 if( nelements == size ) 1570 { 1571 size *= 2; 1572 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(*info)->lbs, (*info)->size, size) ); 1573 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(*info)->ubs, (*info)->size, size) ); 1574 (*info)->size = size; 1575 } 1576 1577 /* we assume integer bounds */ 1578 (*info)->lbs[nelements] = (int) lb; 1579 (*info)->ubs[nelements] = (int) ub; 1580 nelements++; 1581 } 1582 1583 (*info)->ndims = nelements; 1584 1585 /* check for colon */ 1586 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ')') ) 1587 syntaxError(scip, fzninput, "expecting <)>"); 1588 1589 return SCIP_OKAY; 1590 } 1591 1592 /** parse identifier name without annotations */ 1593 static 1594 SCIP_RETCODE parseName( 1595 SCIP* scip, /**< SCIP data structure */ 1596 FZNINPUT* fzninput, /**< FZN reading data */ 1597 char* name, /**< pointer to store the name */ 1598 SCIP_Bool* output, /**< pointer to store if the name has the annotations to output */ 1599 DIMENSIONS** info /**< pointer to store the output dimension information if one */ 1600 ) 1601 { 1602 if( output != NULL ) 1603 (*output) = FALSE; 1604 1605 /* check for colon */ 1606 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ':') ) 1607 { 1608 syntaxError(scip, fzninput, "expecting colon <:>"); 1609 return SCIP_OKAY; 1610 } 1611 1612 /* parse identifier name */ 1613 if( !getNextToken(scip, fzninput) || !isIdentifier(fzninput->token) ) 1614 { 1615 syntaxError(scip, fzninput, "expecting identifier name"); 1616 return SCIP_OKAY; 1617 } 1618 1619 /* copy identifier name */ 1620 (void)SCIPsnprintf(name, FZN_BUFFERLEN-1, "%s", (const char*)fzninput->token); 1621 1622 /* search for an assignment; therefore, skip annotations */ 1623 do 1624 { 1625 if( !getNextToken(scip, fzninput) ) 1626 { 1627 syntaxError(scip, fzninput, "expected at least a semicolon to close statement"); 1628 return SCIP_OKAY; 1629 } 1630 1631 /* check if the name has the annotation to be part of the output */ 1632 if( equalTokens(fzninput->token, "output_var") && output != NULL ) 1633 (*output) = TRUE; 1634 else if( equalTokens(fzninput->token, "output_array") && output != NULL) 1635 { 1636 (*output) = TRUE; 1637 assert(info != NULL); 1638 SCIP_CALL( parseOutputDimensioninfo(scip, fzninput, info) ); 1639 } 1640 1641 if( isEndStatement(fzninput) ) 1642 break; 1643 } 1644 while( !isChar(fzninput->token, '=') ); 1645 1646 /* push back '=' or ';' */ 1647 pushToken(fzninput); 1648 1649 return SCIP_OKAY; 1650 } 1651 1652 /** parse variable/constant (array) type (integer, float, bool, or set) */ 1653 static 1654 void parseType( 1655 SCIP* scip, /**< SCIP data structure */ 1656 FZNINPUT* fzninput, /**< FZN reading data */ 1657 FZNNUMBERTYPE* type, /**< pointer to store the number type */ 1658 SCIP_Real* lb, /**< pointer to store the lower bound */ 1659 SCIP_Real* ub /**< pointer to store the lower bound */ 1660 ) 1661 { 1662 if( !getNextToken(scip, fzninput) || isEndStatement(fzninput) ) 1663 { 1664 syntaxError(scip, fzninput, "missing token"); 1665 return; 1666 } 1667 1668 *lb = -SCIPinfinity(scip); 1669 *ub = SCIPinfinity(scip); 1670 1671 /* parse variable type or bounds */ 1672 if( equalTokens(fzninput->token, "bool") ) 1673 { 1674 *type = FZN_BOOL; 1675 *lb = 0.0; 1676 *ub = 1.0; 1677 } 1678 else if( equalTokens(fzninput->token, "float") ) 1679 *type = FZN_FLOAT; 1680 else if( equalTokens(fzninput->token, "int") ) 1681 *type = FZN_INT; 1682 else if( equalTokens(fzninput->token, "set") || isChar(fzninput->token, '{') ) 1683 { 1684 SCIPwarningMessage(scip, "sets are not supported yet\n"); 1685 fzninput->valid = FALSE; 1686 return; 1687 } 1688 else 1689 { 1690 /* the type is not explicitly given; it is given through the a range 1691 * expression; therefore, push back the current token since it 1692 * belongs to the range expression */ 1693 pushToken(fzninput); 1694 parseRange(scip, fzninput, type, lb, ub); 1695 1696 if( fzninput->haserror ) 1697 return; 1698 } 1699 1700 SCIPdebugMsg(scip, "range = [%g,%g]\n", *lb, *ub); 1701 1702 assert(*lb <= *ub); 1703 } 1704 1705 /** applies assignment */ 1706 static 1707 SCIP_RETCODE applyVariableAssignment( 1708 SCIP* scip, /**< SCIP data structure */ 1709 FZNINPUT* fzninput, /**< FZN reading data */ 1710 SCIP_VAR* var, /**< variable to assign something */ 1711 FZNNUMBERTYPE type, /**< number type */ 1712 const char* assignment /**< assignment */ 1713 ) 1714 { 1715 FZNCONSTANT* constant; 1716 SCIP_VAR* linkVar; 1717 SCIP_Bool boolvalue; 1718 SCIP_Real realvalue; 1719 SCIP_Real fixvalue; 1720 SCIP_Real vals[] = {1.0,-1.0}; 1721 1722 linkVar = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) assignment); 1723 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) assignment); 1724 1725 realvalue = SCIP_INVALID; 1726 boolvalue = FALSE; 1727 1728 if( linkVar == NULL ) 1729 { 1730 if( isBoolExp(assignment, &boolvalue) && type == FZN_BOOL ) 1731 fixvalue = (SCIP_Real) boolvalue; 1732 else if( isValue(assignment, &realvalue) && type != FZN_BOOL ) 1733 fixvalue = realvalue; 1734 else if( constant != NULL ) 1735 fixvalue = constant->value; 1736 else 1737 { 1738 syntaxError(scip, fzninput, "assignment is not recognizable"); 1739 return SCIP_OKAY; 1740 } 1741 1742 /* create fixing constraint */ 1743 SCIP_CALL( createLinearCons(scip, "fixing", 1, &var, vals, fixvalue, fixvalue, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) ); 1744 } 1745 else 1746 { 1747 SCIP_VAR** vars; 1748 1749 SCIP_CALL( SCIPallocBufferArray(scip, &vars, 2) ); 1750 vars[0] = var; 1751 vars[1] = linkVar; 1752 1753 SCIP_CALL( createLinearCons(scip, "link", 2, vars, vals, 0.0, 0.0, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) ); 1754 1755 SCIPfreeBufferArray(scip, &vars); 1756 } 1757 1758 return SCIP_OKAY; 1759 } 1760 1761 /** applies constant assignment expression */ 1762 static 1763 SCIP_RETCODE createConstantAssignment( 1764 SCIP* scip, /**< SCIP data structure */ 1765 FZNCONSTANT** constant, /**< pointer to constant */ 1766 FZNINPUT* fzninput, /**< FZN reading data */ 1767 const char* name, /**< constant name */ 1768 FZNNUMBERTYPE type, /**< number type */ 1769 const char* assignment /**< assignment to apply */ 1770 ) 1771 { 1772 SCIP_Bool boolvalue; 1773 SCIP_Real realvalue; 1774 SCIP_Real value; 1775 1776 (*constant) = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) assignment); 1777 realvalue = SCIP_INVALID; 1778 boolvalue = FALSE; 1779 1780 if( *constant != NULL ) 1781 { 1782 /* check if the constant type fits */ 1783 if( type != (*constant)->type ) 1784 { 1785 syntaxError(scip, fzninput, "type error"); 1786 return SCIP_OKAY; 1787 } 1788 1789 value = (*constant)->value; 1790 } 1791 else if( isBoolExp(assignment, &boolvalue) && type == FZN_BOOL ) 1792 { 1793 value = (SCIP_Real) boolvalue; 1794 } 1795 else if( isValue(assignment, &realvalue) && type != FZN_BOOL ) 1796 { 1797 value = realvalue; 1798 } 1799 else 1800 { 1801 syntaxError(scip, fzninput, "assignment is not recognizable"); 1802 return SCIP_OKAY; 1803 } 1804 1805 /* get buffer memory for FZNCONSTANT struct */ 1806 SCIP_CALL( SCIPallocBuffer(scip, constant) ); 1807 1808 (*constant)->type = type; 1809 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*constant)->name, name, (int) strlen(name) + 1) ); 1810 (*constant)->value = value; 1811 1812 /* store constant */ 1813 if( fzninput->sconstants == fzninput->nconstants ) 1814 { 1815 assert(fzninput->sconstants > 0); 1816 fzninput->sconstants *= 2; 1817 SCIP_CALL( SCIPreallocBufferArray(scip, &fzninput->constants, fzninput->sconstants) ); 1818 } 1819 1820 assert(fzninput->sconstants > fzninput->nconstants); 1821 fzninput->constants[fzninput->nconstants] = *constant; 1822 fzninput->nconstants++; 1823 1824 SCIP_CALL( SCIPhashtableInsert(fzninput->constantHashtable, (void*) (*constant)) ); 1825 1826 return SCIP_OKAY; 1827 } 1828 1829 /** parse array type ( (i) variable or constant; (ii) integer, float, bool, or set) */ 1830 static 1831 void parseArrayType( 1832 SCIP* scip, /**< SCIP data structure */ 1833 FZNINPUT* fzninput, /**< FZN reading data */ 1834 SCIP_Bool* isvararray, /**< pointer to store if it is a variable or constant array */ 1835 FZNNUMBERTYPE* type, /**< pointer to store number type */ 1836 SCIP_Real* lb, /**< pointer to store the lower bound */ 1837 SCIP_Real* ub /**< pointer to store the lower bound */ 1838 ) 1839 { 1840 if( !getNextToken(scip, fzninput) || !equalTokens(fzninput->token, "of") ) 1841 { 1842 syntaxError(scip, fzninput, "expected keyword <of>"); 1843 return; 1844 } 1845 1846 if( !getNextToken(scip, fzninput) ) 1847 { 1848 syntaxError(scip, fzninput, "expected more tokens"); 1849 return; 1850 } 1851 1852 /* check if it is a variable or constant array */ 1853 if( equalTokens(fzninput->token, "var") ) 1854 *isvararray = TRUE; 1855 else 1856 { 1857 /* push token back since it belongs to the type declaration */ 1858 pushToken(fzninput); 1859 *isvararray = FALSE; 1860 } 1861 1862 /* pares array type and range */ 1863 parseType(scip, fzninput, type, lb, ub); 1864 } 1865 1866 /** parse an array assignment */ 1867 static 1868 SCIP_RETCODE parseArrayAssignment( 1869 SCIP* scip, /**< SCIP data structure */ 1870 FZNINPUT* fzninput, /**< FZN reading data */ 1871 char*** elements, /**< pointer to string array to store the parsed elements */ 1872 int* nelements, /**< pointer to store the number of parsed elements */ 1873 int selements /**< size of the string array elements */ 1874 ) 1875 { 1876 assert(scip != NULL); 1877 assert(fzninput != NULL); 1878 assert(*nelements >= 0); 1879 assert(selements >= *nelements); 1880 1881 /* check for opening brackets */ 1882 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '[') ) 1883 { 1884 syntaxError(scip, fzninput, "expected token <[>"); 1885 return SCIP_OKAY; 1886 } 1887 1888 SCIP_CALL( parseList(scip, fzninput, elements, nelements, selements) ); 1889 1890 if( hasError(fzninput) ) 1891 return SCIP_OKAY; 1892 1893 /* check for closing brackets */ 1894 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ']') ) 1895 syntaxError(scip, fzninput, "expected token <]>"); 1896 1897 return SCIP_OKAY; 1898 } 1899 1900 /** parse array dimension */ 1901 static 1902 void parseArrayDimension( 1903 SCIP* scip, /**< SCIP data structure */ 1904 FZNINPUT* fzninput, /**< FZN reading data */ 1905 int* nelements /**< pointer to store the size of the array */ 1906 ) 1907 { 1908 FZNNUMBERTYPE type; 1909 SCIP_Real left; 1910 SCIP_Real right; 1911 1912 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '[') ) 1913 { 1914 syntaxError(scip, fzninput, "expected token <[> for array dimension"); 1915 return; 1916 } 1917 1918 /* get array dimension */ 1919 parseRange(scip, fzninput, &type, &left, &right); 1920 1921 if( fzninput->haserror ) 1922 return; 1923 1924 if( type != FZN_INT || left != 1.0 || right <= 0.0 ) 1925 { 1926 syntaxError(scip, fzninput, "invalid array dimension format"); 1927 return; 1928 } 1929 1930 *nelements = (int) right; 1931 1932 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ']') ) 1933 { 1934 syntaxError(scip, fzninput, "expected token <]> for array dimension"); 1935 return; 1936 } 1937 } 1938 1939 /** creates and adds a variable to SCIP and stores it for latter use in fzninput structure */ 1940 static 1941 SCIP_RETCODE createVariable( 1942 SCIP* scip, /**< SCIP data structure */ 1943 FZNINPUT* fzninput, /**< FZN reading data */ 1944 SCIP_VAR** var, /**< pointer to hold the created variable, or NULL */ 1945 const char* name, /**< name of the variable */ 1946 SCIP_Real lb, /**< lower bound of the variable */ 1947 SCIP_Real ub, /**< upper bound of the variable */ 1948 FZNNUMBERTYPE type /**< number type */ 1949 ) 1950 { 1951 SCIP_VAR* varcopy; 1952 SCIP_VARTYPE vartype; 1953 1954 assert(scip != NULL); 1955 assert(fzninput != NULL); 1956 assert(lb <= ub); 1957 1958 switch(type) 1959 { 1960 case FZN_BOOL: 1961 vartype = SCIP_VARTYPE_BINARY; 1962 break; 1963 case FZN_INT: 1964 vartype = SCIP_VARTYPE_INTEGER; 1965 break; 1966 case FZN_FLOAT: 1967 vartype = SCIP_VARTYPE_CONTINUOUS; 1968 break; 1969 default: 1970 syntaxError(scip, fzninput, "unknown variable type"); 1971 return SCIP_OKAY; 1972 } 1973 1974 /* create variable */ 1975 SCIP_CALL( SCIPcreateVar(scip, &varcopy, name, lb, ub, 0.0, vartype, !(fzninput->dynamiccols), fzninput->dynamiccols, NULL, NULL, NULL, NULL, NULL) ); 1976 SCIP_CALL( SCIPaddVar(scip, varcopy) ); 1977 1978 SCIPdebugMsg(scip, "created variable\n"); 1979 SCIPdebug( SCIP_CALL( SCIPprintVar(scip, varcopy, NULL) ) ); 1980 1981 /* variable name should not exist before */ 1982 assert(SCIPhashtableRetrieve(fzninput->varHashtable, varcopy) == NULL); 1983 1984 /* insert variable into the hashmap for later use in the constraint section */ 1985 SCIP_CALL( SCIPhashtableInsert(fzninput->varHashtable, varcopy) ); 1986 1987 /* copy variable pointer before releasing the variable to keep the pointer to the variable */ 1988 if( var != NULL ) 1989 *var = varcopy; 1990 1991 /* release variable */ 1992 SCIP_CALL( SCIPreleaseVar(scip, &varcopy) ); 1993 1994 return SCIP_OKAY; 1995 } 1996 1997 1998 /** parse variable array assignment and create the variables */ 1999 static 2000 SCIP_RETCODE parseVariableArray( 2001 SCIP* scip, /**< SCIP data structure */ 2002 SCIP_READERDATA* readerdata, /**< reader data */ 2003 FZNINPUT* fzninput, /**< FZN reading data */ 2004 const char* name, /**< array name */ 2005 int nvars, /**< number of variables */ 2006 FZNNUMBERTYPE type, /**< number type */ 2007 SCIP_Real lb, /**< lower bound of the variables */ 2008 SCIP_Real ub, /**< lower bound of the variables */ 2009 DIMENSIONS* info /**< dimension information */ 2010 ) 2011 { 2012 SCIP_VAR** vars; 2013 char varname[FZN_BUFFERLEN]; 2014 int v; 2015 2016 /* create variables and add them to the problem */ 2017 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) ); 2018 2019 for( v = 0; v < nvars; ++v ) 2020 { 2021 (void) SCIPsnprintf(varname, FZN_BUFFERLEN, "%s[%d]", name, v + 1); 2022 2023 /* create variable */ 2024 SCIP_CALL( createVariable(scip, fzninput, &vars[v], varname, lb, ub, type) ); 2025 } 2026 2027 if( !getNextToken(scip, fzninput) ) 2028 { 2029 syntaxError(scip, fzninput, "expected semicolon"); 2030 } 2031 else 2032 { 2033 if( isChar(fzninput->token, '=') ) 2034 { 2035 char** assigns; 2036 int nassigns; 2037 2038 SCIP_CALL( SCIPallocBufferArray(scip, &assigns, nvars) ); 2039 nassigns = 0; 2040 2041 SCIP_CALL( parseArrayAssignment(scip, fzninput, &assigns, &nassigns, nvars) ); 2042 2043 if(!hasError(fzninput) ) 2044 { 2045 for( v = 0; v < nvars && !hasError(fzninput); ++v ) 2046 { 2047 /* parse and apply assignment */ 2048 SCIP_CALL( applyVariableAssignment(scip, fzninput, vars[v], type, assigns[v]) ); 2049 } 2050 } 2051 2052 freeStringBufferArray(scip, assigns, nassigns); 2053 } 2054 else 2055 { 2056 /* push back the ';' */ 2057 assert( isEndStatement(fzninput) ); 2058 pushToken(fzninput); 2059 } 2060 2061 if( info != NULL ) 2062 { 2063 SCIP_CALL( readerdataAddOutputvararray(scip, readerdata, name, vars, nvars, type, info) ); 2064 } 2065 2066 /* add variable information to fzninput since this array name might be used later in the fzn file */ 2067 SCIP_CALL( fzninputAddVararray(scip, fzninput, name, vars, nvars, type, info) ); 2068 } 2069 2070 SCIPfreeBufferArray(scip, &vars); 2071 2072 return SCIP_OKAY; 2073 } 2074 2075 /** parse constant array assignment and create the constants */ 2076 static 2077 SCIP_RETCODE parseConstantArray( 2078 SCIP* scip, /**< SCIP data structure */ 2079 FZNINPUT* fzninput, /**< FZN reading data */ 2080 const char* name, /**< array name */ 2081 int nconstants, /**< number of constants */ 2082 FZNNUMBERTYPE type /**< number type */ 2083 ) 2084 { 2085 FZNCONSTANT** constants; 2086 char** assigns; 2087 char constantname[FZN_BUFFERLEN]; 2088 int nassigns; 2089 int c; 2090 2091 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '=') ) 2092 { 2093 syntaxError(scip, fzninput, "expected token <=>"); 2094 return SCIP_OKAY; 2095 } 2096 2097 SCIP_CALL( SCIPallocBufferArray(scip, &assigns, nconstants) ); 2098 SCIP_CALL( SCIPallocBufferArray(scip, &constants, nconstants) ); 2099 nassigns = 0; 2100 2101 SCIP_CALL( parseArrayAssignment(scip, fzninput, &assigns, &nassigns, nconstants) ); 2102 2103 if( !hasError(fzninput) ) 2104 { 2105 for( c = 0; c < nconstants; ++c ) 2106 { 2107 (void) SCIPsnprintf(constantname, FZN_BUFFERLEN, "%s[%d]", name, c + 1); 2108 SCIP_CALL( createConstantAssignment(scip, &constants[c], fzninput, constantname, type, assigns[c]) ); 2109 } 2110 2111 /* add variable information to fzninput since this array name might be used later in the fzn file */ 2112 SCIP_CALL( fzninputAddConstarray(scip, fzninput, name, constants, nconstants, type) ); 2113 } 2114 2115 SCIPfreeBufferArray(scip, &constants); 2116 freeStringBufferArray(scip, assigns, nassigns); 2117 2118 return SCIP_OKAY; 2119 } 2120 2121 /** parse predicate expression */ 2122 static 2123 SCIP_RETCODE parsePredicate( 2124 SCIP* scip, /**< SCIP data structure */ 2125 FZNINPUT* fzninput /**< FZN reading data */ 2126 ) 2127 { 2128 assert(scip != NULL); 2129 2130 /* mark predicate expression as comment such that it gets skipped */ 2131 fzninput->comment = TRUE; 2132 2133 return SCIP_OKAY; 2134 } 2135 2136 /** parse array expression */ 2137 static 2138 SCIP_RETCODE parseArray( 2139 SCIP* scip, /**< SCIP data structure */ 2140 SCIP_READERDATA* readerdata, /**< reader data */ 2141 FZNINPUT* fzninput /**< FZN reading data */ 2142 ) 2143 { 2144 FZNNUMBERTYPE type; 2145 DIMENSIONS* info; 2146 int nelements; 2147 SCIP_Real lb; 2148 SCIP_Real ub; 2149 SCIP_Bool isvararray; 2150 SCIP_Bool output; 2151 char name[FZN_BUFFERLEN]; 2152 2153 assert(scip != NULL); 2154 assert(fzninput != NULL); 2155 2156 info = NULL; 2157 isvararray = FALSE; 2158 nelements = -1; 2159 2160 SCIPdebugMsg(scip, "parse array expression\n"); 2161 2162 /* parse array dimension */ 2163 parseArrayDimension(scip, fzninput, &nelements); 2164 assert(hasError(fzninput) || nelements > 0); 2165 2166 if( hasError(fzninput) ) 2167 return SCIP_OKAY; 2168 2169 /* parse array type ( (i) variable or constant; (ii) integer, float, bool, or set) */ 2170 parseArrayType(scip, fzninput, &isvararray, &type, &lb, &ub); 2171 2172 if( hasError(fzninput) ) 2173 return SCIP_OKAY; 2174 2175 /* parse array name */ 2176 SCIP_CALL( parseName(scip, fzninput, name, &output, &info) ); 2177 assert(!output || info != NULL); 2178 2179 if( hasError(fzninput) ) 2180 return SCIP_OKAY; 2181 2182 SCIPdebugMsg(scip, "found <%s> array named <%s> of type <%s> and size <%d> with bounds [%g,%g] (output %u)\n", 2183 isvararray ? "variable" : "constant", name, 2184 type == FZN_BOOL ? "bool" : type == FZN_INT ? "integer" : "float", nelements, lb, ub, output); 2185 2186 if( isvararray ) 2187 SCIP_CALL( parseVariableArray(scip, readerdata, fzninput, name, nelements, type, lb, ub, info) ); 2188 else 2189 SCIP_CALL( parseConstantArray(scip, fzninput, name, nelements, type) ); 2190 2191 freeDimensions(scip, &info); 2192 2193 return SCIP_OKAY; 2194 } 2195 2196 /** parse variable expression */ 2197 static 2198 SCIP_RETCODE parseVariable( 2199 SCIP* scip, /**< SCIP data structure */ 2200 SCIP_READERDATA* readerdata, /**< reader data */ 2201 FZNINPUT* fzninput /**< FZN reading data */ 2202 ) 2203 { 2204 SCIP_VAR* var; 2205 FZNNUMBERTYPE type; 2206 SCIP_Real lb; 2207 SCIP_Real ub; 2208 SCIP_Bool output; 2209 char assignment[FZN_BUFFERLEN]; 2210 char name[FZN_BUFFERLEN]; 2211 2212 assert(scip != NULL); 2213 assert(fzninput != NULL); 2214 2215 SCIPdebugMsg(scip, "parse variable expression\n"); 2216 2217 /* pares variable type and range */ 2218 parseType(scip, fzninput, &type, &lb, &ub); 2219 2220 if( hasError(fzninput) ) 2221 return SCIP_OKAY; 2222 2223 /* parse variable name without annotations */ 2224 SCIP_CALL( parseName(scip, fzninput, name, &output, NULL) ); 2225 2226 if( hasError(fzninput) ) 2227 return SCIP_OKAY; 2228 2229 assert(type == FZN_BOOL || type == FZN_INT || type == FZN_FLOAT); 2230 2231 /* create variable */ 2232 SCIP_CALL( createVariable(scip, fzninput, &var, name, lb, ub, type) ); 2233 2234 /* check if the variable should be part of the output */ 2235 if( output ) 2236 { 2237 SCIP_CALL( readerdataAddOutputvar(scip, readerdata, var, type) ); 2238 } 2239 2240 if( !getNextToken(scip, fzninput) ) 2241 { 2242 syntaxError(scip, fzninput, "expected semicolon"); 2243 return SCIP_OKAY; 2244 } 2245 2246 if( isChar(fzninput->token, '=') ) 2247 { 2248 /* parse and flatten assignment */ 2249 flattenAssignment(scip, fzninput, assignment); 2250 2251 /* apply assignment */ 2252 SCIP_CALL( applyVariableAssignment(scip, fzninput, var, type, assignment) ); 2253 } 2254 else 2255 pushToken(fzninput); 2256 2257 return SCIP_OKAY; 2258 } 2259 2260 /** parse constant expression */ 2261 static 2262 SCIP_RETCODE parseConstant( 2263 SCIP* scip, /**< SCIP data structure */ 2264 FZNINPUT* fzninput, /**< FZN reading data */ 2265 FZNNUMBERTYPE type /**< constant type */ 2266 ) 2267 { 2268 FZNCONSTANT* constant; 2269 char name[FZN_BUFFERLEN]; 2270 char assignment[FZN_BUFFERLEN]; 2271 2272 assert(scip != NULL); 2273 assert(fzninput != NULL); 2274 assert(type == FZN_INT || type == FZN_FLOAT || type == FZN_BOOL); 2275 2276 SCIPdebugMsg(scip, "parse constant expression\n"); 2277 2278 /* parse name of the constant */ 2279 SCIP_CALL( parseName(scip, fzninput, name, NULL, NULL) ); 2280 2281 if( hasError(fzninput) ) 2282 return SCIP_OKAY; 2283 2284 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '=') ) 2285 { 2286 syntaxError(scip, fzninput, "expected token <=>"); 2287 return SCIP_OKAY; 2288 } 2289 2290 /* the assignment has to be an other constant or a suitable value */ 2291 flattenAssignment(scip, fzninput, assignment); 2292 2293 /* applies constant assignment and creates constant */ 2294 SCIP_CALL( createConstantAssignment(scip, &constant, fzninput, name, type, assignment) ); 2295 2296 return SCIP_OKAY; 2297 } 2298 2299 /** evaluates current token as constant */ 2300 static 2301 void parseValue( 2302 SCIP* scip, /**< SCIP data structure */ 2303 FZNINPUT* fzninput, /**< FZN reading data */ 2304 SCIP_Real* value, /**< pointer to store value */ 2305 const char* assignment /**< assignment to parse a value */ 2306 ) 2307 { 2308 if( isValue(assignment, value) ) 2309 return; 2310 2311 /* if it is an identifier name, it has to belong to a constant or fixed variable */ 2312 if( isIdentifier(assignment) ) 2313 { 2314 FZNCONSTANT* constant; 2315 2316 /* identifier has to be one of a constant */ 2317 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) assignment); 2318 2319 if( constant == NULL ) 2320 { 2321 SCIP_VAR* var; 2322 2323 var = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) assignment); 2324 2325 if( var == NULL ) 2326 syntaxError(scip, fzninput, "unknown constant name"); 2327 else 2328 { 2329 if( SCIPisEQ(scip, SCIPvarGetLbOriginal(var), SCIPvarGetUbOriginal(var)) ) 2330 (*value) = SCIPvarGetLbOriginal(var); 2331 else 2332 syntaxError(scip, fzninput, "expected fixed variable"); 2333 } 2334 } 2335 else 2336 (*value) = constant->value; 2337 } 2338 else 2339 syntaxError(scip, fzninput, "expected constant expression"); 2340 } 2341 2342 /** parse array expression containing constants */ 2343 static 2344 SCIP_RETCODE parseConstantArrayAssignment( 2345 SCIP* scip, /**< SCIP data structure */ 2346 FZNINPUT* fzninput, /**< FZN reading data */ 2347 SCIP_Real** vals, /**< pointer to value array */ 2348 int* nvals, /**< pointer to store the number if values */ 2349 int sizevals /**< size of the vals array */ 2350 ) 2351 { 2352 int c; 2353 2354 assert(*nvals <= sizevals); 2355 2356 /* check for next token */ 2357 if( !getNextToken(scip, fzninput) ) 2358 { 2359 syntaxError(scip, fzninput, "expected constant array"); 2360 return SCIP_OKAY; 2361 } 2362 2363 /* check if an array is given explicitly */ 2364 if( isChar(fzninput->token, '[') ) 2365 { 2366 char** elements; 2367 SCIP_Real value; 2368 int nelements; 2369 2370 SCIP_CALL( SCIPallocBufferArray(scip, &elements, sizevals) ); 2371 nelements = 0; 2372 2373 value = 0.0; 2374 2375 /* push back '[' which closes the list */ 2376 pushToken(fzninput); 2377 2378 /* pares array assignment */ 2379 SCIP_CALL( parseArrayAssignment(scip, fzninput, &elements, &nelements, sizevals) ); 2380 2381 if( sizevals <= *nvals + nelements ) 2382 { 2383 SCIP_CALL( SCIPreallocBufferArray(scip, vals, *nvals + nelements) ); 2384 } 2385 2386 for( c = 0; c < nelements && !hasError(fzninput); ++c ) 2387 { 2388 parseValue(scip, fzninput, &value, elements[c]); 2389 assert(!hasError(fzninput)); 2390 2391 (*vals)[(*nvals)] = value; 2392 (*nvals)++; 2393 } 2394 2395 freeStringBufferArray(scip, elements, nelements); 2396 } 2397 else 2398 { 2399 /* array is not given explicitly; therefore, check constant array data base if the given constant array name was 2400 * parsed before 2401 */ 2402 2403 CONSTARRAY* constarray; 2404 2405 constarray = findConstarray(fzninput, fzninput->token); 2406 2407 if( constarray != NULL ) 2408 { 2409 /* ensure variable array size */ 2410 if( sizevals <= *nvals + constarray->nconstants ) 2411 { 2412 SCIP_CALL( SCIPreallocBufferArray(scip, vals, *nvals + constarray->nconstants) ); 2413 } 2414 2415 for( c = 0; c < constarray->nconstants; ++c ) 2416 { 2417 (*vals)[(*nvals)] = constarray->constants[c]->value; 2418 (*nvals)++; 2419 } 2420 } 2421 else 2422 { 2423 /* there is no constant array with the given name; therefore check the variable array data base if such an 2424 * array exist with fixed variables 2425 */ 2426 2427 VARARRAY* vararray; 2428 2429 vararray = findVararray(fzninput, fzninput->token); 2430 2431 if( vararray == NULL ) 2432 { 2433 syntaxError(scip, fzninput, "unknown constants array name"); 2434 } 2435 else 2436 { 2437 /* ensure variable array size */ 2438 if( sizevals <= *nvals + vararray->nvars ) 2439 { 2440 SCIP_CALL( SCIPreallocBufferArray(scip, vals, *nvals + vararray->nvars) ); 2441 } 2442 2443 for( c = 0; c < vararray->nvars; ++c ) 2444 { 2445 SCIP_VAR* var; 2446 2447 var = vararray->vars[c]; 2448 assert(var != NULL); 2449 2450 if( SCIPisEQ(scip, SCIPvarGetLbOriginal(var), SCIPvarGetUbOriginal(var)) ) 2451 { 2452 (*vals)[(*nvals)] = SCIPvarGetLbOriginal(var); 2453 (*nvals)++; 2454 } 2455 else 2456 { 2457 syntaxError(scip, fzninput, "variable array contains unfixed variable"); 2458 break; 2459 } 2460 } 2461 } 2462 } 2463 } 2464 2465 return SCIP_OKAY; 2466 } 2467 2468 /** parse array expression containing variables */ 2469 static 2470 SCIP_RETCODE parseVariableArrayAssignment( 2471 SCIP* scip, /**< SCIP data structure */ 2472 FZNINPUT* fzninput, /**< FZN reading data */ 2473 SCIP_VAR*** vars, /**< pointer to variable array */ 2474 int* nvars, /**< pointer to store the number if variable */ 2475 int sizevars /**< size of the variable array */ 2476 ) 2477 { 2478 int v; 2479 2480 assert(*nvars <= sizevars); 2481 2482 /* check for next token */ 2483 if( !getNextToken(scip, fzninput) ) 2484 { 2485 syntaxError(scip, fzninput, "expected constant array"); 2486 return SCIP_OKAY; 2487 } 2488 2489 if( isChar(fzninput->token, '[') ) 2490 { 2491 char** elements; 2492 int nelements; 2493 2494 SCIP_CALL( SCIPallocBufferArray(scip, &elements, sizevars) ); 2495 nelements = 0; 2496 2497 /* push back '[' which closes the list */ 2498 pushToken(fzninput); 2499 2500 SCIP_CALL( parseArrayAssignment(scip, fzninput, &elements, &nelements, sizevars) ); 2501 2502 if( sizevars <= *nvars + nelements ) 2503 { 2504 SCIP_CALL( SCIPreallocBufferArray(scip, vars, *nvars + nelements) ); 2505 } 2506 2507 for( v = 0; v < nelements; ++v ) 2508 { 2509 (*vars)[(*nvars)] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, elements[v]); 2510 2511 if( (*vars)[(*nvars)] == NULL ) 2512 { 2513 /* since the given element does not correspond to a variable name 2514 * it might be the case that it is a constant which can be seen as 2515 * as a fixed variable 2516 */ 2517 2518 FZNCONSTANT* constant; 2519 SCIP_Real value; 2520 2521 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) elements[v]); 2522 2523 if( constant != NULL ) 2524 { 2525 assert(constant->type == FZN_FLOAT); 2526 value = constant->value; 2527 } 2528 else if(!isValue(elements[v], &value) ) 2529 { 2530 char* tmptoken; 2531 2532 tmptoken = fzninput->token; 2533 fzninput->token = elements[v]; 2534 syntaxError(scip, fzninput, "expected variable name or constant"); 2535 2536 fzninput->token = tmptoken; 2537 break; 2538 } 2539 2540 /* create a fixed variable */ 2541 SCIP_CALL( createVariable(scip, fzninput, &(*vars)[*nvars], elements[v], value, value, FZN_FLOAT) ); 2542 } 2543 2544 (*nvars)++; 2545 } 2546 2547 freeStringBufferArray(scip, elements, nelements); 2548 } 2549 else 2550 { 2551 VARARRAY* vararray; 2552 2553 vararray = findVararray(fzninput, fzninput->token); 2554 2555 if( vararray != NULL ) 2556 { 2557 assert(vararray != NULL); 2558 2559 /* ensure variable array size */ 2560 if( sizevars <= *nvars + vararray->nvars ) 2561 { 2562 SCIP_CALL( SCIPreallocBufferArray(scip, vars, *nvars + vararray->nvars) ); 2563 } 2564 2565 for( v = 0; v < vararray->nvars; ++v ) 2566 { 2567 (*vars)[(*nvars)] = vararray->vars[v]; 2568 (*nvars)++; 2569 } 2570 } 2571 else 2572 syntaxError(scip, fzninput, "unknown variable array name"); 2573 } 2574 2575 return SCIP_OKAY; 2576 } 2577 2578 /** parse linking statement */ 2579 static 2580 SCIP_RETCODE parseQuadratic( 2581 SCIP* scip, /**< SCIP data structure */ 2582 FZNINPUT* fzninput, /**< FZN reading data */ 2583 const char* name /**< name of constraint */ 2584 ) 2585 { 2586 char** elements; 2587 int nelements; 2588 2589 SCIP_CALL( SCIPallocBufferArray(scip, &elements, 3) ); 2590 nelements = 0; 2591 2592 /* parse the list of three elements */ 2593 SCIP_CALL( parseList(scip, fzninput, &elements, &nelements, 3) ); 2594 assert(nelements == 3); 2595 2596 if( !hasError(fzninput) ) 2597 { 2598 SCIP_VAR** vars; 2599 SCIP_Real* vals; 2600 SCIP_Real rhs; 2601 int v; 2602 2603 rhs = 0.0; 2604 2605 SCIP_CALL( SCIPallocBufferArray(scip, &vars, 3) ); 2606 SCIP_CALL( SCIPallocBufferArray(scip, &vals, 3) ); 2607 2608 for( v = 0; v < 3; ++v ) 2609 { 2610 /* collect variable if constraint identifier is a variable */ 2611 vars[v] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[v]); 2612 2613 /* parse the numeric value otherwise */ 2614 if( vars[v] == NULL ) 2615 { 2616 parseValue(scip, fzninput, &vals[v], elements[v]); 2617 assert(!hasError(fzninput)); 2618 } 2619 else 2620 vals[v] = SCIP_INVALID; 2621 } 2622 2623 /* the first two identifiers are proper variables => the constraints is indeed quadratic */ 2624 if( vars[0] != NULL && vars[1] != NULL ) 2625 { 2626 SCIP_Real quadval; 2627 quadval = 1.0; 2628 2629 /* we might have an additional linear term or just a constant */ 2630 if( vars[2] != NULL ) 2631 { 2632 SCIP_Real linval; 2633 linval = -1.0; 2634 2635 SCIP_CALL( createQuadraticCons(scip, name, 1, &vars[2], &linval, 1, &vars[0], &vars[1], &quadval, rhs, rhs, 2636 fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) ); 2637 } 2638 else 2639 { 2640 rhs += vals[2]; 2641 SCIP_CALL( createQuadraticCons(scip, name, 0, NULL, NULL, 1, &vars[0], &vars[1], &quadval, rhs, rhs, 2642 fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows)); 2643 } 2644 } 2645 else if( vars[0] != NULL || vars[1] != NULL ) 2646 { 2647 int nvars; 2648 nvars = 1; 2649 2650 /* the left hand side of x*y = z is linear (but not constant) */ 2651 if( vars[0] == NULL ) 2652 SCIPswapPointers((void**)&vars[0], (void**)&vars[1]); 2653 else 2654 SCIPswapPointers((void**)&vals[0], (void**)&vals[1]); 2655 2656 /* after swapping, the variable and the coefficient should stand in front */ 2657 assert(vars[0] != NULL && vals[0] != SCIP_INVALID ); /*lint !e777*/ 2658 2659 /* the right hand side might be a variable or a constant */ 2660 if( vars[2] != NULL ) 2661 { 2662 SCIPswapPointers((void**)&vars[1], (void**)&vars[2]); 2663 vals[1] = -1.0; 2664 nvars++; 2665 } 2666 else 2667 { 2668 assert(vals[2] != SCIP_INVALID); /*lint !e777*/ 2669 rhs += vals[2]; 2670 } 2671 2672 SCIP_CALL( createLinearCons(scip, name, nvars, vars, vals, rhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) ); 2673 } 2674 else 2675 { 2676 /* the left hand side of x*y = z is constant */ 2677 assert(vals[0] != SCIP_INVALID && vals[1] != SCIP_INVALID); /*lint !e777*/ 2678 2679 rhs = rhs - vals[0]*vals[1]; 2680 2681 /* the right hand side might be a variable or a constant */ 2682 if( vars[2] != NULL ) 2683 { 2684 SCIP_Real val; 2685 val = -1.0; 2686 SCIP_CALL( createLinearCons(scip, name, 1, &vars[2], &val, rhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) ); 2687 } 2688 else 2689 { 2690 assert(vals[2] != SCIP_INVALID); /*lint !e777*/ 2691 rhs += vals[2]; 2692 SCIP_CALL( createLinearCons(scip, name, 0, NULL, NULL, rhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) ); 2693 } 2694 } 2695 2696 /* free buffer arrays */ 2697 SCIPfreeBufferArray(scip, &vals); 2698 SCIPfreeBufferArray(scip, &vars); 2699 } 2700 2701 /* free elements array */ 2702 freeStringBufferArray(scip, elements, nelements); 2703 2704 return SCIP_OKAY; 2705 } 2706 2707 /** parse aggregation statement (plus, minus, negate) */ 2708 static 2709 SCIP_RETCODE parseAggregation( 2710 SCIP* scip, /**< SCIP data structure */ 2711 FZNINPUT* fzninput, /**< FZN reading data */ 2712 const char* name, /**< name of constraint */ 2713 const char* type /**< linear constraint type */ 2714 ) 2715 { 2716 /* here we take care of the three expression 2717 * 2718 * - int_plus(x1,x2,x3) -> x1 + x2 == x3 2719 * - int_minus(x1,x2,x3) -> x1 - x2 == x3 2720 * - int_negate(x1,x2) -> x1 + x2 == 0 2721 */ 2722 char** elements; 2723 int nelements; 2724 2725 SCIP_CALL( SCIPallocBufferArray(scip, &elements, 3) ); 2726 nelements = 0; 2727 2728 /* parse the list of three elements */ 2729 SCIP_CALL( parseList(scip, fzninput, &elements, &nelements, 3) ); 2730 assert(nelements == 3 || nelements == 2); 2731 2732 if( !hasError(fzninput) ) 2733 { 2734 SCIP_VAR** vars; 2735 SCIP_Real* vals; 2736 SCIP_Real value; 2737 SCIP_Real rhs; 2738 int nvars; 2739 2740 nvars = 0; 2741 rhs = 0.0; 2742 2743 SCIP_CALL( SCIPallocBufferArray(scip, &vars, 3) ); 2744 SCIP_CALL( SCIPallocBufferArray(scip, &vals, 3) ); 2745 2746 /* parse first element */ 2747 vars[nvars] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[0]); 2748 if( vars[nvars] == NULL ) 2749 { 2750 parseValue(scip, fzninput, &value, elements[0]); 2751 assert(!hasError(fzninput)); 2752 2753 rhs -= value; 2754 } 2755 else 2756 { 2757 vals[nvars] = 1.0; 2758 nvars++; 2759 } 2760 2761 /* parse second element */ 2762 vars[nvars] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[1]); 2763 if( vars[nvars] == NULL ) 2764 { 2765 parseValue(scip, fzninput, &value, elements[1]); 2766 assert(!hasError(fzninput)); 2767 2768 if( equalTokens(type, "minus") ) 2769 rhs += value; 2770 else 2771 rhs -= value; 2772 } 2773 else 2774 { 2775 if( equalTokens(type, "minus") ) 2776 { 2777 /* in case of minus the second element get a -1.0 as coefficient */ 2778 vals[nvars] = -1.0; 2779 } 2780 else 2781 vals[nvars] = 1.0; 2782 2783 nvars++; 2784 } 2785 2786 if( !equalTokens(type, "negate") ) 2787 { 2788 /* parse third element in case of "minus" or "plus" */ 2789 vars[nvars] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[2]); 2790 if( vars[nvars] == NULL ) 2791 { 2792 parseValue(scip, fzninput, &value, elements[2]); 2793 assert(!hasError(fzninput)); 2794 2795 rhs += value; 2796 } 2797 else 2798 { 2799 vals[nvars] = -1.0; 2800 nvars++; 2801 } 2802 } 2803 2804 SCIP_CALL( createLinearCons(scip, name, nvars, vars, vals, rhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) ); 2805 2806 /* free buffer arrays */ 2807 SCIPfreeBufferArray(scip, &vals); 2808 SCIPfreeBufferArray(scip, &vars); 2809 } 2810 2811 /* free elements array */ 2812 freeStringBufferArray(scip, elements, nelements); 2813 return SCIP_OKAY; 2814 } 2815 2816 /** parse linking statement */ 2817 static 2818 SCIP_RETCODE parseLinking( 2819 SCIP* scip, /**< SCIP data structure */ 2820 FZNINPUT* fzninput, /**< FZN reading data */ 2821 const char* name, /**< name of constraint */ 2822 const char* type, /**< linear constraint type */ 2823 SCIP_Real sidevalue /**< side value of constraint */ 2824 ) 2825 { 2826 char** names; 2827 SCIP_Real lhs = SCIP_INVALID; 2828 SCIP_Real rhs = SCIP_INVALID; 2829 int nnames; 2830 2831 nnames = 0; 2832 SCIP_CALL( SCIPallocBufferArray(scip, &names, 2) ); 2833 2834 SCIP_CALL( parseList(scip, fzninput, &names, &nnames, 2) ); 2835 assert(nnames == 2); 2836 2837 if( hasError(fzninput) ) 2838 goto TERMINATE; 2839 2840 /* compute left and right side */ 2841 computeLinearConsSides(scip, fzninput, type, sidevalue, &lhs, &rhs); 2842 2843 if( hasError(fzninput) ) 2844 goto TERMINATE; 2845 2846 SCIP_CALL( createLinking(scip, fzninput, name, names[0], names[1], lhs, rhs) ); 2847 2848 TERMINATE: 2849 freeStringBufferArray(scip, names, nnames); 2850 2851 return SCIP_OKAY; 2852 } 2853 2854 /** creates a linear constraint for an array operation */ 2855 static 2856 CREATE_CONSTRAINT(createCoercionOpCons) 2857 { /*lint --e{715}*/ 2858 assert(scip != NULL); 2859 assert(fzninput != NULL); 2860 2861 /* check if the function identifier name is array operation */ 2862 if( !equalTokens(fname, "int2float") && !equalTokens(fname, "bool2int") ) 2863 return SCIP_OKAY; 2864 2865 SCIP_CALL( parseLinking(scip, fzninput, fname, "eq", 0.0) ); 2866 2867 *created = TRUE; 2868 2869 return SCIP_OKAY; 2870 } 2871 2872 /** creates a linear constraint for an array operation */ 2873 static 2874 CREATE_CONSTRAINT(createSetOpCons) 2875 { /*lint --e{715}*/ 2876 assert(scip != NULL); 2877 assert(fzninput != NULL); 2878 2879 /* check if the function identifier name is array operation */ 2880 if( !equalTokens(ftokens[0], "set") ) 2881 return SCIP_OKAY; 2882 2883 fzninput->valid = FALSE; 2884 SCIPwarningMessage(scip, "Line %d: set operations are not supported yet.\n", fzninput->linenumber); 2885 2886 return SCIP_OKAY; 2887 } 2888 2889 /** creates linear constraint for an array operation */ 2890 static 2891 CREATE_CONSTRAINT(createArrayOpCons) 2892 { /*lint --e{715}*/ 2893 assert(scip != NULL); 2894 assert(fzninput != NULL); 2895 2896 /* check if the function identifier name is array operation */ 2897 if( !equalTokens(ftokens[0], "array") ) 2898 return SCIP_OKAY; 2899 2900 fzninput->valid = FALSE; 2901 SCIPwarningMessage(scip, "Line %d: array operations are not supported yet.\n", fzninput->linenumber); 2902 2903 return SCIP_OKAY; 2904 } 2905 2906 /** creates a linear constraint for a logical operation */ 2907 static 2908 CREATE_CONSTRAINT(createLogicalOpCons) 2909 { /*lint --e{715}*/ 2910 assert(scip != NULL); 2911 assert(fzninput != NULL); 2912 2913 /* check if the function identifier name is array operation */ 2914 if(nftokens < 2) 2915 return SCIP_OKAY; 2916 2917 if(equalTokens(ftokens[0], "bool") && nftokens == 2 ) 2918 { 2919 char** elements; 2920 int nelements; 2921 2922 /* the bool_eq constraint is processed in createComparisonOpCons() */ 2923 if( equalTokens(ftokens[1], "eq") || equalTokens(ftokens[1], "ge") || equalTokens(ftokens[1], "le") 2924 || equalTokens(ftokens[1], "lt") || equalTokens(ftokens[1], "gt") ) 2925 return SCIP_OKAY; 2926 2927 SCIP_CALL( SCIPallocBufferArray(scip, &elements, 3) ); 2928 nelements = 0; 2929 2930 SCIP_CALL( parseList(scip, fzninput, &elements, &nelements, 3) ); 2931 2932 if( !hasError(fzninput) ) 2933 { 2934 SCIP_CONS* cons; 2935 SCIP_VAR** vars; 2936 int v; 2937 int nvars; 2938 2939 if( equalTokens(ftokens[1], "ne") || equalTokens(ftokens[1], "not") ) 2940 nvars = 2; 2941 else 2942 nvars = 3; 2943 2944 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) ); 2945 2946 /* collect variable if constraint identifier is a variable */ 2947 for( v = 0; v < nvars; ++v ) 2948 { 2949 vars[v] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[v]); 2950 2951 if( vars[v] == NULL ) 2952 { 2953 syntaxError(scip, fzninput, "unknown variable identifier name"); 2954 goto TERMINATE; 2955 } 2956 } 2957 2958 if( equalTokens(ftokens[1], "ne" ) || equalTokens(ftokens[1], "not") ) 2959 { 2960 SCIP_Real vals[] = {1.0, 1.0}; 2961 2962 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, fname, 2, vars, vals, 1.0, 1.0, 2963 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) ); 2964 2965 *created = TRUE; 2966 } 2967 else if( equalTokens(ftokens[1], "or" ) ) 2968 { 2969 SCIP_CALL( SCIPcreateConsOr(scip, &cons, fname, vars[2], 2, vars, 2970 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) ); 2971 2972 *created = TRUE; 2973 } 2974 else if( equalTokens(ftokens[1], "and") ) 2975 { 2976 SCIP_CALL( SCIPcreateConsAnd(scip, &cons, fname, vars[2], 2, vars, 2977 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) ); 2978 2979 *created = TRUE; 2980 } 2981 else if( equalTokens(ftokens[1], "xor") ) 2982 { 2983 /* swap resultant to front */ 2984 SCIPswapPointers((void**)&vars[0], (void**)&vars[2]); 2985 2986 SCIP_CALL( SCIPcreateConsXor(scip, &cons, fname, FALSE, 3, vars, 2987 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) ); 2988 2989 *created = TRUE; 2990 } 2991 else 2992 { 2993 fzninput->valid = FALSE; 2994 SCIPwarningMessage(scip, "logical operation <%s> is not supported yet\n", fname); 2995 goto TERMINATE; 2996 } 2997 2998 SCIPdebugPrintCons(scip, cons, NULL); 2999 3000 SCIP_CALL( SCIPaddCons(scip, cons) ); 3001 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 3002 3003 TERMINATE: 3004 SCIPfreeBufferArray(scip, &vars); 3005 } 3006 3007 /* free elements array */ 3008 freeStringBufferArray(scip, elements, nelements); 3009 } 3010 else if(equalTokens(ftokens[1], "bool") && nftokens == 3 ) 3011 { 3012 SCIP_CONS* cons; 3013 SCIP_VAR** vars; 3014 SCIP_VAR* resvar; 3015 int nvars; 3016 char** elements; 3017 int nelements; 3018 int size; 3019 3020 if( !equalTokens(ftokens[2], "or" ) && !equalTokens(ftokens[2], "and" ) ) 3021 { 3022 fzninput->valid = FALSE; 3023 SCIPwarningMessage(scip, "logical operation <%s> is not supported yet\n", fname); 3024 return SCIP_OKAY; 3025 } 3026 3027 size = 10; 3028 nvars = 0; 3029 3030 SCIP_CALL( SCIPallocBufferArray(scip, &vars, size) ); 3031 SCIP_CALL( SCIPallocBufferArray(scip, &elements, 1) ); 3032 nelements = 0; 3033 3034 SCIPdebugMsg(scip, "found and constraint <%s>\n", fname); 3035 3036 /* parse operand variable array */ 3037 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, size) ); 3038 3039 /* check error and for the comma between the variable array and side value */ 3040 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') ) 3041 { 3042 if( hasError(fzninput) ) 3043 syntaxError(scip, fzninput, "unexpected error in fzn input"); 3044 else 3045 syntaxError(scip, fzninput, "expected token <,>"); 3046 3047 goto TERMINATE2; 3048 } 3049 3050 /* parse resultant variable array */ 3051 SCIP_CALL( parseList(scip, fzninput, &elements, &nelements, 1) ); 3052 resvar = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[0]); 3053 3054 /* check error and for the comma between the variable array and side value */ 3055 if( hasError(fzninput) || resvar == NULL ) 3056 { 3057 if( hasError(fzninput) ) 3058 syntaxError(scip, fzninput, "unexpected error in fzn input"); 3059 else 3060 syntaxError(scip, fzninput, "unknown variable identifier name"); 3061 goto TERMINATE2; 3062 } 3063 3064 /* create the constraint */ 3065 if( equalTokens(ftokens[2], "or" ) ) 3066 { 3067 SCIP_CALL( SCIPcreateConsOr(scip, &cons, fname, resvar, nvars, vars, 3068 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) ); 3069 } 3070 else 3071 { 3072 assert( equalTokens(ftokens[2], "and") ); 3073 3074 SCIP_CALL( SCIPcreateConsAnd(scip, &cons, fname, resvar, nvars, vars, 3075 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) ); 3076 } 3077 3078 SCIPdebugPrintCons(scip, cons, NULL); 3079 *created = TRUE; 3080 3081 SCIP_CALL( SCIPaddCons(scip, cons) ); 3082 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 3083 3084 TERMINATE2: 3085 /* free elements array */ 3086 freeStringBufferArray(scip, elements, nelements); 3087 SCIPfreeBufferArray(scip, &vars); 3088 } 3089 else if( equalTokens(ftokens[1], "bool") ) 3090 { 3091 fzninput->valid = FALSE; 3092 SCIPwarningMessage(scip, "logical operation <%s> is not supported yet\n", fname); 3093 return SCIP_OKAY; 3094 } 3095 3096 return SCIP_OKAY; 3097 } 3098 3099 /** creates a linear constraint for a comparison operation */ 3100 static 3101 CREATE_CONSTRAINT(createComparisonOpCons) 3102 { /*lint --e{715}*/ 3103 char assignment[FZN_BUFFERLEN]; 3104 3105 assert(scip != NULL); 3106 assert(fzninput != NULL); 3107 3108 /* check if the function name ends of "reif" (reified constraint) which SCIP does not support yet */ 3109 if( equalTokens(ftokens[nftokens - 1], "reif") ) 3110 { 3111 SCIPwarningMessage(scip, "Line %d: reified constraints are not supported.\n", fzninput->linenumber); 3112 fzninput->valid = FALSE; 3113 return SCIP_OKAY; 3114 } 3115 3116 /* the last token can be 3117 * 'eq' -- equal 3118 * 'ne' -- not equal 3119 * 'lt' -- less than 3120 * 'gt' -- greater than 3121 * 'le' -- less or equal than 3122 * 'ge' -- greater or equal than 3123 * => these are comparison constraints 3124 * 'plus' -- addition 3125 * 'minus' -- subtraction 3126 * 'negate' -- negation 3127 * => these are aggregation constraints 3128 * 'times' -- multiplication 3129 * => this is a nonlinear constraint 3130 */ 3131 if( strlen(ftokens[nftokens - 1]) != 2 && nftokens != 2 ) 3132 return SCIP_OKAY; 3133 3134 /* check if any sets are involved in the constraint */ 3135 if( equalTokens(ftokens[0], "set") ) 3136 { 3137 SCIPwarningMessage(scip, "constraints using sets are not supported\n"); 3138 fzninput->valid = FALSE; 3139 return SCIP_OKAY; 3140 } 3141 3142 /* check if the constraint is a 'not equal' one */ 3143 if( equalTokens(ftokens[nftokens - 1], "ne") ) 3144 { 3145 SCIPwarningMessage(scip, "constraints with 'not equal' relation are not supported\n"); 3146 fzninput->valid = FALSE; 3147 return SCIP_OKAY; 3148 } 3149 3150 /* check if the constraint contains float variable and coefficients and '<' or '>' relation */ 3151 if( equalTokens(ftokens[0], "float") && 3152 (equalTokens(ftokens[nftokens - 1], "lt") || equalTokens(ftokens[nftokens - 1], "gt") ) ) 3153 { 3154 SCIPwarningMessage(scip, "constraints with '<' or '>' relation and continuous variables are not supported\n"); 3155 fzninput->valid = FALSE; 3156 return SCIP_OKAY; 3157 } 3158 3159 if( equalTokens(ftokens[1], "lin") ) 3160 { 3161 SCIP_VAR** vars; 3162 SCIP_Real* vals; 3163 SCIP_Real sidevalue; 3164 int nvars; 3165 int nvals; 3166 int size; 3167 3168 assert(nftokens == 3); 3169 3170 size = 10; 3171 nvars = 0; 3172 nvals = 0; 3173 sidevalue = SCIP_INVALID; 3174 3175 SCIP_CALL( SCIPallocBufferArray(scip, &vars, size) ); 3176 SCIP_CALL( SCIPallocBufferArray(scip, &vals, size) ); 3177 3178 SCIPdebugMsg(scip, "found linear constraint <%s>\n", fname); 3179 3180 /* pares coefficients array */ 3181 SCIP_CALL( parseConstantArrayAssignment(scip, fzninput, &vals, &nvals, size) ); 3182 3183 /* check error and for the comma between the coefficient and variable array */ 3184 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') ) 3185 { 3186 if( !hasError(fzninput) ) 3187 syntaxError(scip, fzninput, "expected token <,>"); 3188 3189 goto TERMINATE; 3190 } 3191 3192 /* pares variable array */ 3193 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, size) ); 3194 3195 /* check error and for the comma between the variable array and side value */ 3196 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') ) 3197 { 3198 if( !hasError(fzninput) ) 3199 syntaxError(scip, fzninput, "expected token <,>"); 3200 3201 goto TERMINATE; 3202 } 3203 3204 /* pares sidevalue */ 3205 flattenAssignment(scip, fzninput, assignment); 3206 parseValue(scip, fzninput, &sidevalue, assignment); 3207 3208 if( !hasError(fzninput) ) 3209 { 3210 SCIP_Real lhs = -SCIPinfinity(scip); 3211 SCIP_Real rhs = SCIPinfinity(scip); 3212 3213 assert(sidevalue != SCIP_INVALID); /*lint !e777*/ 3214 3215 /* compute left and right side */ 3216 computeLinearConsSides(scip, fzninput, ftokens[2], sidevalue, &lhs, &rhs); 3217 3218 if( hasError(fzninput) ) 3219 goto TERMINATE; 3220 3221 SCIP_CALL( createLinearCons(scip, fname, nvars, vars, vals, lhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) ); 3222 } 3223 3224 TERMINATE: 3225 SCIPfreeBufferArray(scip, &vals); 3226 SCIPfreeBufferArray(scip, &vars); 3227 } 3228 else if( equalTokens(ftokens[1], "minus") || equalTokens(ftokens[1], "plus") || equalTokens(ftokens[1], "negate") ) 3229 { 3230 assert(nftokens == 2); 3231 SCIP_CALL( parseAggregation(scip, fzninput, fname, ftokens[1]) ); 3232 } 3233 else if( equalTokens(ftokens[1], "eq") || equalTokens(ftokens[1], "le") || equalTokens(ftokens[1], "ge") 3234 || equalTokens(ftokens[1], "lt") || equalTokens(ftokens[1], "gt") ) 3235 { 3236 assert(nftokens == 2); 3237 SCIP_CALL( parseLinking(scip, fzninput, fname, ftokens[1], 0.0) ); 3238 } 3239 else if( equalTokens(ftokens[1], "times") ) 3240 { 3241 assert(nftokens == 2); 3242 SCIP_CALL( parseQuadratic(scip, fzninput, fname) ); 3243 } 3244 else 3245 { 3246 syntaxError(scip, fzninput, "unknown constraint type"); 3247 } 3248 3249 *created = TRUE; 3250 3251 return SCIP_OKAY; 3252 } 3253 3254 /** creates an alldifferent constraint */ 3255 static 3256 CREATE_CONSTRAINT(createAlldifferentOpCons) 3257 { /*lint --e{715}*/ 3258 SCIP_VAR** vars; 3259 #ifdef ALLDIFFERENT 3260 SCIP_CONS* cons; 3261 #endif 3262 int nvars; 3263 int size; 3264 3265 assert(scip != NULL); 3266 assert(fzninput != NULL); 3267 3268 /* check if the function identifier name is array operation */ 3269 if( !equalTokens(ftokens[0], "all") || !equalTokens(ftokens[1], "different") ) 3270 return SCIP_OKAY; 3271 3272 size = 10; 3273 nvars = 0; 3274 SCIP_CALL( SCIPallocBufferArray(scip, &vars, size) ); 3275 3276 SCIPdebugMsg(scip, "parse alldifferent expression\n"); 3277 3278 /* pares variable array */ 3279 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, size) ); 3280 3281 #ifdef ALLDIFFERENT 3282 /* create alldifferent constraint */ 3283 SCIP_CALL( SCIPcreateConsAlldifferent(scip, &cons, fname, nvars, vars, 3284 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) ); 3285 3286 SCIPdebugPrintCons(scip, cons, NULL); 3287 3288 /* add and release the constraint to the problem */ 3289 SCIP_CALL( SCIPaddCons(scip, cons) ); 3290 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 3291 3292 *created = TRUE; 3293 #endif 3294 3295 SCIPfreeBufferArray(scip, &vars); 3296 3297 return SCIP_OKAY; 3298 } 3299 3300 /** creates an alldifferent constraint */ 3301 static 3302 CREATE_CONSTRAINT(createCumulativeOpCons) 3303 { /*lint --e{715}*/ 3304 SCIP_CONS* cons; 3305 SCIP_VAR** vars; 3306 SCIP_Real* vals = NULL; 3307 int* durations = NULL; 3308 int* demands = NULL; 3309 SCIP_Real val; 3310 int capacity; 3311 char assignment[FZN_BUFFERLEN]; 3312 3313 int nvars; 3314 int ndurations; 3315 int ndemads; 3316 int size; 3317 int i; 3318 3319 assert(scip != NULL); 3320 assert(fzninput != NULL); 3321 3322 /* check if the function identifier name is array operation */ 3323 if( !equalTokens(ftokens[0], "cumulative") ) 3324 return SCIP_OKAY; 3325 3326 size = 10; 3327 nvars = 0; 3328 ndurations = 0; 3329 ndemads = 0; 3330 3331 SCIPdebugMsg(scip, "parse cumulative expression\n"); 3332 3333 /* pares start time variable array */ 3334 SCIP_CALL( SCIPallocBufferArray(scip, &vars, size) ); 3335 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, size) ); 3336 3337 /* check error and for the comma between the variable array and side value */ 3338 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') ) 3339 { 3340 if( !hasError(fzninput) ) 3341 syntaxError(scip, fzninput, "expected token <,>"); 3342 3343 goto TERMINATE; 3344 } 3345 3346 /* pares job duration array */ 3347 SCIP_CALL( SCIPallocBufferArray(scip, &vals, size) ); 3348 SCIP_CALL( parseConstantArrayAssignment(scip, fzninput, &vals, &ndurations, size) ); 3349 3350 SCIP_CALL( SCIPallocBufferArray(scip, &durations, ndurations) ); 3351 for( i = 0; i < ndurations; ++i ) 3352 durations[i] = (int)vals[i]; 3353 3354 /* check error and for the comma between the variable array and side value */ 3355 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') ) 3356 { 3357 if( !hasError(fzninput) ) 3358 syntaxError(scip, fzninput, "expected token <,>"); 3359 3360 goto TERMINATE; 3361 } 3362 3363 /* pares job demand array */ 3364 SCIP_CALL( parseConstantArrayAssignment(scip, fzninput, &vals, &ndemads, size) ); 3365 3366 SCIP_CALL( SCIPallocBufferArray(scip, &demands, ndemads) ); 3367 for( i = 0; i < ndemads; ++i ) 3368 demands[i] = (int)vals[i]; 3369 3370 /* check error and for the comma between the variable array and side value */ 3371 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') ) 3372 { 3373 if( !hasError(fzninput) ) 3374 syntaxError(scip, fzninput, "expected token <,>"); 3375 3376 goto TERMINATE; 3377 } 3378 3379 /* parse cumulative capacity */ 3380 flattenAssignment(scip, fzninput, assignment); 3381 parseValue(scip, fzninput, &val, assignment); 3382 assert(!hasError(fzninput)); 3383 3384 capacity = (int)val; 3385 3386 assert(nvars == ndurations); 3387 assert(nvars == ndemads); 3388 3389 /* create cumulative constraint */ 3390 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, fname, nvars, vars, durations, demands, capacity, 3391 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) ); 3392 3393 SCIPdebugPrintCons(scip, cons, NULL); 3394 3395 /* add and release the constraint to the problem */ 3396 SCIP_CALL( SCIPaddCons(scip, cons) ); 3397 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 3398 3399 assert(!hasError(fzninput)); 3400 *created = TRUE; 3401 3402 TERMINATE: 3403 /* free buffers */ 3404 SCIPfreeBufferArrayNull(scip, &demands); 3405 SCIPfreeBufferArrayNull(scip, &durations); 3406 SCIPfreeBufferArrayNull(scip, &vals); 3407 SCIPfreeBufferArray(scip, &vars); 3408 3409 return SCIP_OKAY; 3410 } 3411 3412 /* function pointer array containing all function which can create a constraint */ 3413 static CREATE_CONSTRAINT((*constypes[])) = { 3414 createCoercionOpCons, 3415 createSetOpCons, 3416 createLogicalOpCons, 3417 createArrayOpCons, 3418 createComparisonOpCons, 3419 createAlldifferentOpCons, 3420 createCumulativeOpCons 3421 }; 3422 3423 /** size of the function pointer array */ 3424 static const int nconstypes = 7; 3425 3426 3427 /** parse constraint expression */ 3428 static 3429 SCIP_RETCODE parseConstraint( 3430 SCIP* scip, /**< SCIP data structure */ 3431 FZNINPUT* fzninput /**< FZN reading data */ 3432 ) 3433 { 3434 SCIP_VAR* var; 3435 char* tokens[4]; 3436 char* token; 3437 char* nexttoken; 3438 char name[FZN_BUFFERLEN]; 3439 char fname[FZN_BUFFERLEN]; 3440 SCIP_Bool created; 3441 int ntokens; 3442 int i; 3443 int c; 3444 3445 assert(scip != NULL); 3446 assert(fzninput != NULL); 3447 3448 SCIPdebugMsg(scip, "parse constraint expression\n"); 3449 3450 /* get next token already flatten */ 3451 flattenAssignment(scip, fzninput, name); 3452 3453 /* check if constraint identifier is a variable */ 3454 var = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) name); 3455 3456 if( var != NULL ) 3457 { 3458 SCIP_Real vals[] = {1.0}; 3459 3460 /* create fixing constraint */ 3461 SCIP_CALL( createLinearCons(scip, "fixing", 1, &var, vals, 1.0, 1.0, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) ); 3462 return SCIP_OKAY; 3463 } 3464 3465 /* check constraint identifier name */ 3466 if( !isIdentifier(name) ) 3467 { 3468 syntaxError(scip, fzninput, "expected constraint identifier name"); 3469 return SCIP_OKAY; 3470 } 3471 3472 /* check if we have a opening parenthesis */ 3473 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '(') ) 3474 { 3475 syntaxError(scip, fzninput, "expected token <(>"); 3476 return SCIP_OKAY; 3477 } 3478 3479 /* copy function name */ 3480 (void) SCIPsnprintf(fname, FZN_BUFFERLEN, "%s", name); 3481 3482 /* truncate the function identifier name in separate tokens */ 3483 token = SCIPstrtok(name, "_", &nexttoken); 3484 ntokens = 0; 3485 while( token != NULL ) 3486 { 3487 if( ntokens == 4 ) 3488 break; 3489 3490 SCIP_CALL( SCIPduplicateBufferArray(scip, &(tokens[ntokens]), token, (int) strlen(token) + 1) ); /*lint !e866*/ 3491 ntokens++; 3492 3493 token = SCIPstrtok(NULL, "_", &nexttoken); 3494 } 3495 3496 assert(token == NULL || tokens[0] != NULL); /*lint !e771*/ 3497 for( i = 0; i < ntokens; ++i ) 3498 { 3499 SCIPdebugMsgPrint(scip, "%s ", tokens[i]); 3500 } 3501 SCIPdebugMsgPrint(scip, "\n"); 3502 3503 created = FALSE; 3504 3505 /* loop over all methods which can create a constraint */ 3506 for( c = 0; c < nconstypes && !created && !hasError(fzninput); ++c ) 3507 { 3508 SCIP_CALL( constypes[c](scip, fzninput, fname, tokens, ntokens, &created) ); 3509 } 3510 3511 /* check if a constraint was created */ 3512 if( !hasError(fzninput) && !created ) 3513 { 3514 fzninput->valid = FALSE; 3515 SCIPwarningMessage(scip, "Line %d: Constraint <%s> is not supported yet.\n", fzninput->linenumber, fname); 3516 } 3517 3518 /* free memory */ 3519 for( i = ntokens - 1; i >= 0 ; --i ) 3520 { 3521 SCIPfreeBufferArray(scip, &tokens[i]); 3522 } 3523 3524 /* check for the closing parenthesis */ 3525 if( !hasError(fzninput) && ( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ')')) ) 3526 syntaxError(scip, fzninput, "expected token <)>"); 3527 3528 return SCIP_OKAY; 3529 } 3530 3531 /** parse solve item expression */ 3532 static 3533 SCIP_RETCODE parseSolveItem( 3534 SCIP* scip, /**< SCIP data structure */ 3535 FZNINPUT* fzninput /**< FZN reading data */ 3536 ) 3537 { 3538 assert(scip != NULL); 3539 assert(fzninput != NULL); 3540 3541 SCIPdebugMsg(scip, "parse solve item expression\n"); 3542 3543 if( !getNextToken(scip, fzninput) ) 3544 { 3545 syntaxError(scip, fzninput, "expected solving specification"); 3546 return SCIP_OKAY; 3547 } 3548 3549 /* check for annotations */ 3550 if( equalTokens(fzninput->token, "::") ) 3551 { 3552 /* skip the annotation */ 3553 do 3554 { 3555 if( !getNextToken(scip, fzninput) ) 3556 syntaxError(scip, fzninput, "expected more tokens"); 3557 } 3558 while( !equalTokens(fzninput->token, "satisfy") 3559 && !equalTokens(fzninput->token, "minimize") 3560 && !equalTokens(fzninput->token, "maximize") ); 3561 } 3562 3563 if( equalTokens(fzninput->token, "satisfy") ) 3564 { 3565 SCIPdebugMsg(scip, "detected a satisfiability problem\n"); 3566 } 3567 else 3568 { 3569 SCIP_VAR* var; 3570 FZNCONSTANT* constant; 3571 char name[FZN_BUFFERLEN]; 3572 3573 if( equalTokens(fzninput->token, "minimize") ) 3574 { 3575 fzninput->objsense = SCIP_OBJSENSE_MINIMIZE; 3576 SCIPdebugMsg(scip, "detected a minimization problem\n"); 3577 } 3578 else 3579 { 3580 assert(equalTokens(fzninput->token, "maximize")); 3581 fzninput->objsense = SCIP_OBJSENSE_MAXIMIZE; 3582 SCIPdebugMsg(scip, "detected a maximization problem\n"); 3583 } 3584 3585 /* parse objective coefficients */ 3586 3587 /* parse and flatten assignment */ 3588 flattenAssignment(scip, fzninput, name); 3589 3590 var = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) name); 3591 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) name); 3592 3593 if( var != NULL ) 3594 { 3595 SCIP_CALL(SCIPchgVarObj(scip, var, 1.0) ); 3596 } 3597 else if( constant != NULL ) 3598 { 3599 SCIPdebugMsg(scip, "optimizing a constant is equal to a satisfiability problem!\n"); 3600 } 3601 else if( equalTokens(name, "int_float_lin") ) 3602 { 3603 SCIP_VAR** vars; 3604 SCIP_Real* vals; 3605 int nvars; 3606 int nvals; 3607 int size; 3608 int v; 3609 3610 nvars = 0; 3611 nvals = 0; 3612 size = 10; 3613 3614 SCIP_CALL( SCIPallocBufferArray(scip, &vars, size) ); 3615 SCIP_CALL( SCIPallocBufferArray(scip, &vals, size) ); 3616 3617 SCIPdebugMsg(scip, "found linear objective\n"); 3618 3619 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '(') ) 3620 { 3621 syntaxError(scip, fzninput, "expected token <(>"); 3622 goto TERMINATE; 3623 } 3624 3625 /* pares coefficients array for integer variables */ 3626 SCIP_CALL( parseConstantArrayAssignment(scip, fzninput, &vals, &nvals, size) ); 3627 3628 /* check error and for the comma between the coefficient and variable array */ 3629 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') ) 3630 { 3631 if( !hasError(fzninput) ) 3632 syntaxError(scip, fzninput, "expected token <,>"); 3633 3634 goto TERMINATE; 3635 } 3636 3637 /* pares coefficients array for continuous variables */ 3638 SCIP_CALL( parseConstantArrayAssignment(scip, fzninput, &vals, &nvals, MAX(size, nvals)) ); 3639 3640 /* check error and for the comma between the coefficient and variable array */ 3641 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') ) 3642 { 3643 if( !hasError(fzninput) ) 3644 syntaxError(scip, fzninput, "expected token <,>"); 3645 3646 goto TERMINATE; 3647 } 3648 3649 /* pares integer variable array */ 3650 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, size) ); 3651 3652 /* check error and for the comma between the variable array and side value */ 3653 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') ) 3654 { 3655 if( !hasError(fzninput) ) 3656 syntaxError(scip, fzninput, "expected token <,>"); 3657 3658 goto TERMINATE; 3659 } 3660 3661 assert(nvars <= nvals); 3662 3663 /* pares continuous variable array */ 3664 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, MAX(size, nvars)) ); 3665 3666 /* check error and for the ')' */ 3667 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ')') ) 3668 { 3669 if( !hasError(fzninput) ) 3670 syntaxError(scip, fzninput, "expected token <)>"); 3671 3672 goto TERMINATE; 3673 } 3674 3675 assert( nvars == nvals ); 3676 3677 for( v = 0; v < nvars; ++v ) 3678 { 3679 SCIP_CALL(SCIPchgVarObj(scip, vars[v], vals[v]) ); 3680 } 3681 3682 TERMINATE: 3683 SCIPfreeBufferArray(scip, &vals); 3684 SCIPfreeBufferArray(scip, &vars); 3685 } 3686 else 3687 { 3688 syntaxError(scip, fzninput, "unknown identifier expression for a objective function"); 3689 } 3690 } 3691 3692 return SCIP_OKAY; 3693 } 3694 3695 /** reads a FlatZinc model */ 3696 static 3697 SCIP_RETCODE readFZNFile( 3698 SCIP* scip, /**< SCIP data structure */ 3699 SCIP_READERDATA* readerdata, /**< reader data */ 3700 FZNINPUT* fzninput, /**< FZN reading data */ 3701 const char* filename /**< name of the input file */ 3702 ) 3703 { 3704 assert(scip != NULL); 3705 assert(readerdata != NULL); 3706 assert(fzninput != NULL); 3707 3708 /* open file */ 3709 fzninput->file = SCIPfopen(filename, "r"); 3710 if( fzninput->file == NULL ) 3711 { 3712 SCIPerrorMessage("cannot open file <%s> for reading\n", filename); 3713 SCIPprintSysError(filename); 3714 return SCIP_NOFILE; 3715 } 3716 3717 /* create problem */ 3718 SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); 3719 3720 /* create two auxiliary variable for true and false values */ 3721 SCIP_CALL( createVariable(scip, fzninput, NULL, "true", 1.0, 1.0, FZN_BOOL) ); 3722 SCIP_CALL( createVariable(scip, fzninput, NULL, "false", 0.0, 0.0, FZN_BOOL) ); 3723 3724 /* parse through statements one-by-one */ 3725 while( !SCIPfeof( fzninput->file ) && !hasError(fzninput) ) 3726 { 3727 /* read the first token (keyword) of a new statement */ 3728 if( getNextToken(scip, fzninput) ) 3729 { 3730 if( equalTokens(fzninput->token, "predicate") ) 3731 { 3732 /* parse array expression containing constants or variables */ 3733 SCIP_CALL( parsePredicate(scip, fzninput) ); 3734 } 3735 else if( equalTokens(fzninput->token, "array") ) 3736 { 3737 /* parse array expression containing constants or variables */ 3738 SCIP_CALL( parseArray(scip, readerdata, fzninput) ); 3739 } 3740 else if( equalTokens(fzninput->token, "constraint") ) 3741 { 3742 /* parse a constraint */ 3743 SCIP_CALL( parseConstraint(scip, fzninput) ); 3744 } 3745 else if( equalTokens(fzninput->token, "int") ) 3746 { 3747 /* parse an integer constant */ 3748 SCIP_CALL( parseConstant(scip, fzninput, FZN_INT) ); 3749 } 3750 else if( equalTokens(fzninput->token, "float") ) 3751 { 3752 /* parse a float constant */ 3753 SCIP_CALL( parseConstant(scip, fzninput, FZN_FLOAT) ); 3754 } 3755 else if( equalTokens(fzninput->token, "bool") ) 3756 { 3757 /* parse a bool constant */ 3758 SCIP_CALL( parseConstant(scip, fzninput, FZN_BOOL) ); 3759 } 3760 else if( equalTokens(fzninput->token, "set") ) 3761 { 3762 /* deal with sets */ 3763 SCIPwarningMessage(scip, "sets are not supported yet\n"); 3764 fzninput->valid = FALSE; 3765 break; 3766 } 3767 else if( equalTokens(fzninput->token, "solve") ) 3768 { 3769 /* parse solve item (objective sense and objective function) */ 3770 SCIP_CALL( parseSolveItem(scip, fzninput) ); 3771 } 3772 else if( equalTokens(fzninput->token, "var") ) 3773 { 3774 /* parse variables */ 3775 SCIP_CALL( parseVariable(scip, readerdata, fzninput) ); 3776 } 3777 else if( equalTokens(fzninput->token, "output") ) 3778 { 3779 /* the output section is the last section in the flatzinc model and can be skipped */ 3780 SCIPdebugMsg(scip, "skip output section\n"); 3781 break; 3782 } 3783 else 3784 { 3785 FZNNUMBERTYPE type; 3786 SCIP_Real lb; 3787 SCIP_Real ub; 3788 3789 /* check if the new statement starts with a range expression 3790 * which indicates a constant; therefore, push back the current token 3791 * since it belongs to the range expression */ 3792 pushToken(fzninput); 3793 3794 /* parse range to detect constant type */ 3795 parseRange(scip, fzninput, &type, &lb, &ub); 3796 3797 if( hasError(fzninput) ) 3798 break; 3799 3800 /* parse the remaining constant statement */ 3801 SCIP_CALL( parseConstant(scip, fzninput, type) ); 3802 3803 if( hasError(fzninput) ) 3804 { 3805 SCIPwarningMessage(scip, "unknown keyword <%s> skip statement\n", fzninput->token); 3806 SCIPABORT(); 3807 return SCIP_OKAY; /*lint !e527*/ 3808 } 3809 } 3810 3811 if( hasError(fzninput) ) 3812 break; 3813 3814 /* if the current statement got marked as comment continue with the next line */ 3815 if( fzninput->comment ) 3816 continue; 3817 3818 /* each statement should be closed with a semicolon */ 3819 if( !getNextToken(scip, fzninput) ) 3820 syntaxError(scip, fzninput, "expected semicolon"); 3821 3822 /* check for annotations */ 3823 if( equalTokens(fzninput->token, "::") ) 3824 { 3825 /* skip the annotation */ 3826 do 3827 { 3828 if( !getNextToken(scip, fzninput) ) 3829 syntaxError(scip, fzninput, "expected more tokens"); 3830 } 3831 while( !isEndStatement(fzninput) ); 3832 } 3833 3834 if( !isEndStatement(fzninput) ) 3835 syntaxError(scip, fzninput, "expected semicolon"); 3836 } 3837 } 3838 3839 /* close file */ 3840 SCIPfclose(fzninput->file); 3841 3842 if( hasError(fzninput) ) 3843 { 3844 SCIP_CALL( SCIPfreeProb(scip) ); 3845 3846 /* create empty problem */ 3847 SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); 3848 } 3849 else 3850 { 3851 SCIP_CALL( SCIPsetObjsense(scip, fzninput->objsense) ); 3852 } 3853 3854 return SCIP_OKAY; 3855 } 3856 3857 3858 /* 3859 * Local methods (for writing) 3860 */ 3861 3862 /** transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant */ 3863 static 3864 SCIP_RETCODE getActiveVariables( 3865 SCIP* scip, /**< SCIP data structure */ 3866 SCIP_VAR*** vars, /**< pointer to vars array to get active variables for */ 3867 SCIP_Real** scalars, /**< pointer to scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */ 3868 int* nvars, /**< pointer to number of variables and values in vars and vals array */ 3869 SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */ 3870 SCIP_Bool transformed /**< transformed constraint? */ 3871 ) 3872 { 3873 int requiredsize; 3874 int v; 3875 3876 assert(scip != NULL); 3877 assert(vars != NULL); 3878 assert(scalars != NULL); 3879 assert(nvars != NULL); 3880 assert(*vars != NULL || *nvars == 0); 3881 assert(*scalars != NULL || *nvars == 0); 3882 assert(constant != NULL); 3883 3884 if( transformed ) 3885 { 3886 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); 3887 3888 if( requiredsize > *nvars ) 3889 { 3890 SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) ); 3891 SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) ); 3892 3893 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); 3894 assert( requiredsize <= *nvars ); 3895 } 3896 } 3897 else 3898 { 3899 if( *nvars > 0 && ( *vars == NULL || *scalars == NULL ) ) /*lint !e774 !e845*/ 3900 { 3901 SCIPerrorMessage("Null pointer in FZN reader\n"); /* should not happen */ 3902 SCIPABORT(); 3903 return SCIP_INVALIDDATA; /*lint !e527*/ 3904 } 3905 3906 for( v = 0; v < *nvars; ++v ) 3907 { 3908 SCIP_CALL( SCIPvarGetOrigvarSum(&(*vars)[v], &(*scalars)[v], constant) ); 3909 3910 /* negated variables with an original counterpart may also be returned by SCIPvarGetOrigvarSum(); 3911 * make sure we get the original variable in that case 3912 */ 3913 if( SCIPvarGetStatus((*vars)[v]) == SCIP_VARSTATUS_NEGATED ) 3914 { 3915 (*vars)[v] = SCIPvarGetNegatedVar((*vars)[v]); 3916 *constant += (*scalars)[v]; 3917 (*scalars)[v] *= -1.0; 3918 } 3919 } 3920 } 3921 return SCIP_OKAY; 3922 } 3923 3924 /** ends the given line with '\\0' and prints it to the given file stream */ 3925 static 3926 void writeBuffer( 3927 SCIP* scip, /**< SCIP data structure */ 3928 FILE* file, /**< output file (or NULL for standard output) */ 3929 char* buffer, /**< line */ 3930 int bufferpos /**< number of characters in buffer */ 3931 ) 3932 { 3933 assert( scip != NULL ); 3934 assert( buffer != NULL ); 3935 3936 if( bufferpos > 0 ) 3937 { 3938 buffer[bufferpos] = '\0'; 3939 3940 SCIPinfoMessage(scip, file, "%s", buffer); 3941 } 3942 } 3943 3944 /** appends extension to line and prints it to the give file stream if the line buffer get full */ 3945 static 3946 SCIP_RETCODE appendBuffer( 3947 SCIP* scip, /**< SCIP data structure */ 3948 char** buffer, /**< buffer which should be extended */ 3949 int* bufferlen, /**< length of the buffer */ 3950 int* bufferpos, /**< current position in the buffer */ 3951 const char* extension /**< string to extend the line */ 3952 ) 3953 { 3954 int newpos; 3955 int extlen; 3956 3957 assert( scip != NULL ); 3958 assert( buffer != NULL ); 3959 assert( bufferlen != NULL ); 3960 assert( bufferpos != NULL ); 3961 assert( extension != NULL ); 3962 3963 /* avoid overflow by reallocation */ 3964 extlen = (int)strlen(extension); 3965 newpos = (*bufferpos) + extlen; 3966 if( newpos >= (*bufferlen) ) 3967 { 3968 *bufferlen = MAX( newpos, 2 * (*bufferlen) ); 3969 3970 SCIP_CALL( SCIPreallocBufferArray(scip, buffer, (*bufferlen))); 3971 } 3972 3973 /* append extension to linebuffer (+1 because of '\0') */ 3974 (void)SCIPstrncpy((*buffer) + (*bufferpos), extension, extlen + 1); 3975 *bufferpos = newpos; 3976 3977 return SCIP_OKAY; 3978 } 3979 3980 /* Writes a real value to a string with full precision, if fractional and adds a ".0" if integral */ 3981 static 3982 void flattenFloat( 3983 SCIP* scip, /**< SCIP data structure */ 3984 SCIP_Real val, /**< value to flatten */ 3985 char* buffer /**< string buffer to print in */ 3986 ) 3987 { 3988 if( SCIPisIntegral(scip, val) ) 3989 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%.1f", SCIPround(scip, val)); 3990 else 3991 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%+.15g", val); 3992 } 3993 3994 /* print row in FZN format to file stream */ 3995 static 3996 SCIP_RETCODE printRow( 3997 SCIP* scip, /**< SCIP data structure */ 3998 FZNOUTPUT* fznoutput, /**< output data structure containing the buffers to write to */ 3999 const char* type, /**< row type ("eq", "le" or "ge") */ 4000 SCIP_VAR** vars, /**< array of variables */ 4001 SCIP_Real* vals, /**< array of values */ 4002 int nvars, /**< number of variables */ 4003 SCIP_Real rhs, /**< right hand side */ 4004 SCIP_Bool hasfloats /**< are there continuous variables or coefficients in the constraint? */ 4005 ) 4006 { 4007 SCIP_VAR* var; /* some variable */ 4008 int v; /* variable counter */ 4009 char buffer[FZN_BUFFERLEN]; 4010 char buffy[FZN_BUFFERLEN]; 4011 4012 assert( scip != NULL ); 4013 assert( vars != NULL || nvars == 0 ); 4014 assert( strcmp(type, "eq") == 0 || strcmp(type, "le") == 0 || strcmp(type, "ge") == 0 ); 4015 4016 /* Add a constraint of type float_lin or int_lin, depending on whether there are continuous variables or coefficients */ 4017 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), "constraint ") ); 4018 if( hasfloats ) 4019 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "float_lin_%s([", type); 4020 else 4021 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "int_lin_%s([", type); 4022 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), buffer) ); 4023 4024 /* print all coefficients but the last one */ 4025 for( v = 0; v < nvars-1; ++v ) 4026 { 4027 if( hasfloats ) 4028 { 4029 flattenFloat(scip, vals[v], buffy); 4030 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s, ", buffy); 4031 } 4032 else 4033 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%.f, ", vals[v]); 4034 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), buffer) ); 4035 } 4036 4037 /* print last coefficient */ 4038 if( nvars > 0 ) 4039 { 4040 if( hasfloats ) 4041 { 4042 flattenFloat(scip, vals[nvars-1], buffy); 4043 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s", buffy); 4044 } 4045 else 4046 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%.f", vals[nvars-1]); 4047 4048 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), buffer) ); 4049 } 4050 4051 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), "], [") ); 4052 4053 /* print all variables but the last one */ 4054 for( v = 0; v < nvars-1; ++v ) 4055 { 4056 var = vars[v]; /*lint !e613*/ 4057 assert( var != NULL ); 4058 4059 if( hasfloats ) 4060 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s%s, ", SCIPvarGetName(var), SCIPvarGetProbindex(var) < fznoutput->ndiscretevars ? "_float" : ""); 4061 else 4062 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s, ", SCIPvarGetName(var) ); 4063 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), buffer) ); 4064 } 4065 4066 /* print last variable */ 4067 if( nvars > 0 ) 4068 { 4069 assert(vars != NULL); /* for lint */ 4070 if( hasfloats ) 4071 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s%s",SCIPvarGetName(vars[nvars-1]), 4072 SCIPvarGetProbindex(vars[nvars-1]) < fznoutput->ndiscretevars ? "_float" : ""); /*lint !e613*/ 4073 else 4074 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s", SCIPvarGetName(vars[nvars-1])); /*lint !e613*/ 4075 4076 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos),buffer) ); 4077 } 4078 4079 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), "], ") ); 4080 4081 /* print right hand side */ 4082 if( SCIPisZero(scip, rhs) ) 4083 rhs = 0.0; 4084 4085 if( hasfloats ) 4086 { 4087 flattenFloat(scip, rhs, buffy); 4088 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s);\n", buffy); 4089 } 4090 else 4091 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%.f);\n", rhs); 4092 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos),buffer) ); 4093 4094 return SCIP_OKAY; 4095 } 4096 4097 /** prints given linear constraint information in FZN format to file stream */ 4098 static 4099 SCIP_RETCODE printLinearCons( 4100 SCIP* scip, /**< SCIP data structure */ 4101 FZNOUTPUT* fznoutput, /**< output data structure containing the buffers to write to */ 4102 SCIP_VAR** vars, /**< array of variables */ 4103 SCIP_Real* vals, /**< array of coefficients values (or NULL if all coefficient values are 1) */ 4104 int nvars, /**< number of variables */ 4105 SCIP_Real lhs, /**< left hand side */ 4106 SCIP_Real rhs, /**< right hand side */ 4107 SCIP_Bool transformed, /**< transformed constraint? */ 4108 SCIP_Bool mayhavefloats /**< may there be continuous variables in the constraint? */ 4109 ) 4110 { 4111 SCIP_VAR** activevars; /* active problem variables of a constraint */ 4112 SCIP_Real* activevals; /* coefficients in the active representation */ 4113 4114 SCIP_Real activeconstant; /* offset (e.g., due to fixings) in the active representation */ 4115 int nactivevars; /* number of active problem variables */ 4116 int v; /* variable counter */ 4117 4118 char buffer[FZN_BUFFERLEN]; 4119 SCIP_Bool hasfloats; 4120 4121 assert( scip != NULL ); 4122 assert( vars != NULL || nvars == 0 ); 4123 assert( fznoutput != NULL ); 4124 assert( lhs <= rhs ); 4125 4126 if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) ) 4127 return SCIP_OKAY; 4128 4129 /* duplicate variable and value array */ 4130 nactivevars = nvars; 4131 hasfloats = FALSE; 4132 activevars = NULL; 4133 activeconstant = 0.0; 4134 4135 if( vars != NULL ) 4136 { 4137 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars ) ); 4138 } 4139 4140 if( vals != NULL ) 4141 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars ) ); 4142 else 4143 { 4144 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) ); 4145 4146 for( v = 0; v < nactivevars; ++v ) 4147 activevals[v] = 1.0; 4148 } 4149 4150 /* retransform given variables to active variables */ 4151 if( nactivevars > 0 ) 4152 { 4153 assert( activevars != NULL ); 4154 assert( activevals != NULL ); 4155 SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activeconstant, transformed) ); 4156 } 4157 4158 /* If there may be continuous variables or coefficients in the constraint, scan for them */ 4159 if( mayhavefloats ) 4160 { 4161 /* fractional sides trigger a constraint to be of float type */ 4162 if( !SCIPisInfinity(scip, -lhs) ) 4163 hasfloats = hasfloats || !SCIPisIntegral(scip, lhs-activeconstant); 4164 if( !SCIPisInfinity(scip, rhs) ) 4165 hasfloats = hasfloats || !SCIPisIntegral(scip, rhs-activeconstant); 4166 4167 /* any continuous variable or fractional variable coefficient triggers a constraint to be of float type */ 4168 for( v = 0; v < nactivevars && !hasfloats; v++ ) 4169 { 4170 SCIP_VAR* var; 4171 4172 assert(activevars != 0); 4173 var = activevars[v]; 4174 4175 hasfloats = hasfloats || (SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && SCIPvarGetType(var) != SCIP_VARTYPE_INTEGER); 4176 hasfloats = hasfloats || !SCIPisIntegral(scip, activevals[v]); 4177 } 4178 4179 /* If the constraint has to be written as float type, all discrete variables need to have a float counterpart */ 4180 if( hasfloats ) 4181 { 4182 for( v = 0; v < nactivevars; v++ ) 4183 { 4184 SCIP_VAR* var; 4185 int idx; 4186 4187 assert(activevars != 0); 4188 var = activevars[v]; 4189 idx = SCIPvarGetProbindex(var); 4190 assert( idx >= 0); 4191 4192 /* If there was no float representation of the variable before, add an auxiliary variable and a conversion constraint */ 4193 if( idx < fznoutput->ndiscretevars && !fznoutput->varhasfloat[idx] ) 4194 { 4195 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY || SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER); 4196 4197 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "var float: %s_float;\n", SCIPvarGetName(var)); 4198 SCIP_CALL( appendBuffer(scip, &(fznoutput->varbuffer), &(fznoutput->varbufferlen), &(fznoutput->varbufferpos),buffer) ); 4199 4200 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "constraint int2float(%s, %s_float);\n", SCIPvarGetName(var), SCIPvarGetName(var)); 4201 SCIP_CALL( appendBuffer(scip, &(fznoutput->castbuffer), &(fznoutput->castbufferlen), &(fznoutput->castbufferpos),buffer) ); 4202 4203 fznoutput->varhasfloat[idx] = TRUE; 4204 } 4205 } 4206 } 4207 } 4208 4209 if( SCIPisEQ(scip, lhs, rhs) ) 4210 { 4211 assert( !SCIPisInfinity(scip, rhs) ); 4212 4213 /* equality constraint */ 4214 SCIP_CALL( printRow(scip, fznoutput, "eq", activevars, activevals, nactivevars, rhs - activeconstant, hasfloats) ); 4215 } 4216 else 4217 { 4218 if( !SCIPisInfinity(scip, -lhs) ) 4219 { 4220 /* print inequality ">=" */ 4221 SCIP_CALL( printRow(scip, fznoutput, "ge", activevars, activevals, nactivevars, lhs - activeconstant, hasfloats) ); 4222 } 4223 4224 if( !SCIPisInfinity(scip, rhs) ) 4225 { 4226 /* print inequality "<=" */ 4227 SCIP_CALL( printRow(scip, fznoutput, "le", activevars, activevals, nactivevars, rhs - activeconstant, hasfloats) ); 4228 } 4229 } 4230 4231 /* free buffer arrays */ 4232 if( activevars != NULL ) 4233 SCIPfreeBufferArray(scip, &activevars); 4234 SCIPfreeBufferArray(scip, &activevals); 4235 4236 return SCIP_OKAY; 4237 } 4238 4239 /* writes problem to a flatzinc conform file, including introduction of several auxiliary variables and constraints */ 4240 static 4241 SCIP_RETCODE writeFzn( 4242 SCIP* scip, /**< SCIP data structure */ 4243 FILE* file, /**< output file, or NULL if standard output should be used */ 4244 const char* name, /**< problem name */ 4245 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */ 4246 SCIP_OBJSENSE objsense, /**< objective sense */ 4247 SCIP_Real objscale, /**< scalar applied to objective function; external objective value is 4248 * extobj = objsense * objscale * (intobj + objoffset) */ 4249 SCIP_Real objoffset, /**< objective offset from bound shifting and fixing */ 4250 SCIP_VAR** vars, /**< array with active variables ordered binary, integer, implicit, continuous */ 4251 int nvars, /**< number of active variables in the problem */ 4252 int nbinvars, /**< number of binary variables */ 4253 int nintvars, /**< number of general integer variables */ 4254 int nimplvars, /**< number of implicit integer variables */ 4255 int ncontvars, /**< number of continuous variables */ 4256 SCIP_CONS** conss, /**< array with constraints of the problem */ 4257 int nconss, /**< number of constraints in the problem */ 4258 SCIP_RESULT* result /**< pointer to store the result of the file writing call */ 4259 ) 4260 { 4261 FZNOUTPUT fznoutput; /* data structure for writing in fzn format */ 4262 4263 SCIP_CONSHDLR* conshdlr; 4264 SCIP_CONS* cons; 4265 const char* conshdlrname; 4266 SCIP_VAR** consvars; /* variables of a specific constraint */ 4267 SCIP_VAR* var; 4268 SCIP_BOUNDTYPE* boundtypes; /* indicates whether to which side the variables are bounded */ 4269 SCIP_Real* consvals; /* coefficients of a specific constraint */ 4270 4271 int* boundedvars; /* variables which are bounded to exactly one side */ 4272 int* floatobjvars; /* discrete variables which have a fractional objective coefficient */ 4273 int* intobjvars; /* discrete variables which have an integral objective coefficient */ 4274 4275 SCIP_Real lb; /* lower bound of some variable */ 4276 SCIP_Real ub; /* upper bound of some variable */ 4277 4278 int nboundedvars; /* number of variables which are bounded to exactly one side */ 4279 int nconsvars; /* number of variables appearing in a specific constraint */ 4280 int nfloatobjvars; /* number of discrete variables which have a fractional objective coefficient */ 4281 int nintobjvars; /* number of discrete variables which have an integral objective coefficient */ 4282 int c; /* counter for the constraints */ 4283 int v; /* counter for the variables */ 4284 const int ndiscretevars = nbinvars+nintvars; /* number of discrete variables */ 4285 4286 char varname[SCIP_MAXSTRLEN]; /* buffer for storing variable names */ 4287 char buffer[FZN_BUFFERLEN]; /* buffer for storing auxiliary variables and constraints */ 4288 char buffy[FZN_BUFFERLEN]; 4289 4290 assert( scip != NULL ); 4291 4292 /* print problem statistics as comment to file */ 4293 SCIPinfoMessage(scip, file, "%% SCIP STATISTICS\n"); 4294 SCIPinfoMessage(scip, file, "%% Problem name : %s\n", name); 4295 SCIPinfoMessage(scip, file, "%% Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n", 4296 nvars, nbinvars, nintvars, nimplvars, ncontvars); 4297 SCIPinfoMessage(scip, file, "%% Constraints : %d\n", nconss); 4298 4299 SCIP_CALL( SCIPallocBufferArray(scip, &boundedvars, nvars) ); 4300 SCIP_CALL( SCIPallocBufferArray(scip, &boundtypes, nvars) ); 4301 nboundedvars = 0; 4302 4303 if( nvars > 0 ) 4304 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Problem variables %%%%%%%%%%%%\n"); 4305 4306 /* write all (active) problem variables */ 4307 for( v = 0; v < nvars; v++ ) 4308 { 4309 var = vars[v]; 4310 assert( var != NULL ); 4311 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var) ); 4312 4313 if( transformed ) 4314 { 4315 /* in case the transformed is written only local bounds are posted which are valid in the current node */ 4316 lb = SCIPvarGetLbLocal(var); 4317 ub = SCIPvarGetUbLocal(var); 4318 } 4319 else 4320 { 4321 lb = SCIPvarGetLbOriginal(var); 4322 ub = SCIPvarGetUbOriginal(var); 4323 } 4324 4325 /* If a variable is bounded to both sides, the bounds are added to the declaration, 4326 * for variables bounded to exactly one side, an auxiliary constraint will be added later-on. 4327 */ 4328 if( !SCIPisInfinity(scip, -lb) && !SCIPisInfinity(scip, ub) ) 4329 { 4330 SCIP_Bool fixed; 4331 fixed = FALSE; 4332 4333 if( SCIPisEQ(scip, lb, ub) ) 4334 fixed = TRUE; 4335 4336 if( v < ndiscretevars ) 4337 { 4338 assert( SCIPisFeasIntegral(scip, lb) && SCIPisFeasIntegral(scip, ub) ); 4339 4340 if( fixed ) 4341 SCIPinfoMessage(scip, file, "var int: %s = %.f;\n", varname, lb); 4342 else 4343 SCIPinfoMessage(scip, file, "var %.f..%.f: %s;\n", lb, ub, varname); 4344 } 4345 else 4346 { 4347 /* Real valued bounds have to be made type conform */ 4348 if( fixed ) 4349 { 4350 flattenFloat(scip, lb, buffy); 4351 SCIPinfoMessage(scip, file, "var float: %s = %s;\n", varname, buffy); 4352 } 4353 else 4354 { 4355 char buffy2[FZN_BUFFERLEN]; 4356 4357 flattenFloat(scip, lb, buffy); 4358 flattenFloat(scip, ub, buffy2); 4359 SCIPinfoMessage(scip, file, "var %s..%s: %s;\n", buffy, buffy2, varname); 4360 } 4361 } 4362 } 4363 else 4364 { 4365 assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY); 4366 assert( v >= nbinvars ); 4367 4368 /* declare the variable without any bound */ 4369 if( v < ndiscretevars ) 4370 SCIPinfoMessage(scip, file, "var int: %s;\n", varname); 4371 else 4372 SCIPinfoMessage(scip, file, "var float: %s;\n", varname); 4373 4374 /* if there is a bound, store the variable and its boundtype for adding a corresponding constraint later-on */ 4375 if( ! SCIPisInfinity(scip, ub) ) 4376 { 4377 boundedvars[nboundedvars] = v; 4378 boundtypes[nboundedvars] = SCIP_BOUNDTYPE_UPPER; 4379 nboundedvars++; 4380 } 4381 if( ! SCIPisInfinity(scip, -lb) ) 4382 { 4383 boundedvars[nboundedvars] = v; 4384 boundtypes[nboundedvars] = SCIP_BOUNDTYPE_LOWER; 4385 nboundedvars++; 4386 } 4387 } 4388 } 4389 4390 /* set up the datastructures for the auxiliary int2float variables, the casting constraints and the problem constraints */ 4391 fznoutput.ndiscretevars = ndiscretevars; 4392 fznoutput.varbufferpos = 0; 4393 fznoutput.consbufferpos = 0; 4394 fznoutput.castbufferpos = 0; 4395 4396 SCIP_CALL( SCIPallocBufferArray(scip, &fznoutput.varhasfloat, ndiscretevars) ); 4397 SCIP_CALL( SCIPallocBufferArray(scip, &fznoutput.varbuffer, FZN_BUFFERLEN) ); 4398 SCIP_CALL( SCIPallocBufferArray(scip, &fznoutput.castbuffer, FZN_BUFFERLEN) ); 4399 SCIP_CALL( SCIPallocBufferArray(scip, &fznoutput.consbuffer, FZN_BUFFERLEN) ); 4400 fznoutput.consbufferlen = FZN_BUFFERLEN; 4401 fznoutput.varbufferlen = FZN_BUFFERLEN; 4402 fznoutput.castbufferlen = FZN_BUFFERLEN; 4403 4404 for( v = 0; v < ndiscretevars; v++ ) 4405 fznoutput.varhasfloat[v] = FALSE; 4406 fznoutput.varbuffer[0] = '\0'; 4407 fznoutput.consbuffer[0] = '\0'; 4408 fznoutput.castbuffer[0] = '\0'; 4409 4410 /* output all problem constraints */ 4411 for( c = 0; c < nconss; c++ ) 4412 { 4413 cons = conss[c]; 4414 assert( cons != NULL); 4415 4416 /* in case the transformed is written only constraint are posted which are enabled in the current node */ 4417 assert(!transformed || SCIPconsIsEnabled(cons)); 4418 4419 conshdlr = SCIPconsGetHdlr(cons); 4420 assert( conshdlr != NULL ); 4421 4422 conshdlrname = SCIPconshdlrGetName(conshdlr); 4423 assert( transformed == SCIPconsIsTransformed(cons) ); 4424 4425 /* By now, only linear, setppc, logicor, knapsack, and varbound constraints can be written. 4426 * Since they are all linearizable, a linear representation of them is written. 4427 */ 4428 if( strcmp(conshdlrname, "linear") == 0 ) 4429 { 4430 SCIP_CALL( printLinearCons(scip, &fznoutput, 4431 SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons), SCIPgetNVarsLinear(scip, cons), 4432 SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons), transformed, TRUE) ); 4433 } 4434 else if( strcmp(conshdlrname, "setppc") == 0 ) 4435 { 4436 consvars = SCIPgetVarsSetppc(scip, cons); 4437 nconsvars = SCIPgetNVarsSetppc(scip, cons); 4438 4439 /* Setppc constraints only differ in their lhs/rhs (+- INF or 1) */ 4440 switch( SCIPgetTypeSetppc(scip, cons) ) 4441 { 4442 case SCIP_SETPPCTYPE_PARTITIONING : 4443 SCIP_CALL( printLinearCons(scip, &fznoutput, 4444 consvars, NULL, nconsvars, 1.0, 1.0, transformed, FALSE) ); 4445 break; 4446 case SCIP_SETPPCTYPE_PACKING : 4447 SCIP_CALL( printLinearCons(scip, &fznoutput, 4448 consvars, NULL, nconsvars, -SCIPinfinity(scip), 1.0, transformed, FALSE) ); 4449 break; 4450 case SCIP_SETPPCTYPE_COVERING : 4451 SCIP_CALL( printLinearCons(scip, &fznoutput, 4452 consvars, NULL, nconsvars, 1.0, SCIPinfinity(scip), transformed, FALSE) ); 4453 break; 4454 } 4455 } 4456 else if( strcmp(conshdlrname, "logicor") == 0 ) 4457 { 4458 SCIP_CALL( printLinearCons(scip, &fznoutput, 4459 SCIPgetVarsLogicor(scip, cons), NULL, SCIPgetNVarsLogicor(scip, cons), 4460 1.0, SCIPinfinity(scip), transformed, FALSE) ); 4461 } 4462 else if( strcmp(conshdlrname, "knapsack") == 0 ) 4463 { 4464 SCIP_Longint* weights; 4465 4466 consvars = SCIPgetVarsKnapsack(scip, cons); 4467 nconsvars = SCIPgetNVarsKnapsack(scip, cons); 4468 4469 /* copy Longint array to SCIP_Real array */ 4470 weights = SCIPgetWeightsKnapsack(scip, cons); 4471 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) ); 4472 for( v = 0; v < nconsvars; ++v ) 4473 consvals[v] = (SCIP_Real)weights[v]; 4474 4475 SCIP_CALL( printLinearCons(scip, &fznoutput, consvars, consvals, nconsvars, -SCIPinfinity(scip), 4476 (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), transformed, FALSE) ); 4477 4478 SCIPfreeBufferArray(scip, &consvals); 4479 } 4480 else if( strcmp(conshdlrname, "varbound") == 0 ) 4481 { 4482 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) ); 4483 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) ); 4484 4485 consvars[0] = SCIPgetVarVarbound(scip, cons); 4486 consvars[1] = SCIPgetVbdvarVarbound(scip, cons); 4487 4488 consvals[0] = 1.0; 4489 consvals[1] = SCIPgetVbdcoefVarbound(scip, cons); 4490 4491 /* Varbound constraints always consist of exactly two variables */ 4492 SCIP_CALL( printLinearCons(scip, &fznoutput, 4493 consvars, consvals, 2, 4494 SCIPgetLhsVarbound(scip, cons), SCIPgetRhsVarbound(scip, cons), transformed, TRUE) ); 4495 4496 SCIPfreeBufferArray(scip, &consvars); 4497 SCIPfreeBufferArray(scip, &consvals); 4498 } 4499 else if( strcmp(conshdlrname, "cumulative") == 0 ) 4500 { 4501 int* intvals; 4502 4503 consvars = SCIPgetVarsCumulative(scip, cons); 4504 nconsvars = SCIPgetNVarsCumulative(scip, cons); 4505 4506 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), "cumulative([") ); 4507 4508 for( v = 0; v < nconsvars; ++v ) 4509 { 4510 if( v < nconsvars - 1) 4511 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s, ", SCIPvarGetName(consvars[v]) ); 4512 else 4513 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s", SCIPvarGetName(consvars[v]) ); 4514 4515 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), varname) ); 4516 } 4517 4518 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), "], [") ); 4519 4520 intvals = SCIPgetDurationsCumulative(scip, cons); 4521 4522 for( v = 0; v < nconsvars; ++v ) 4523 { 4524 if( v < nconsvars - 1) 4525 (void) SCIPsnprintf(buffy, SCIP_MAXSTRLEN, "%d, ", intvals[v] ); 4526 else 4527 (void) SCIPsnprintf(buffy, SCIP_MAXSTRLEN, "%d", intvals[v] ); 4528 4529 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), buffy) ); 4530 } 4531 4532 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), "], [") ); 4533 4534 intvals = SCIPgetDemandsCumulative(scip, cons); 4535 4536 for( v = 0; v < nconsvars; ++v ) 4537 { 4538 if( v < nconsvars - 1) 4539 (void) SCIPsnprintf(buffy, SCIP_MAXSTRLEN, "%d, ", intvals[v] ); 4540 else 4541 (void) SCIPsnprintf(buffy, SCIP_MAXSTRLEN, "%d", intvals[v] ); 4542 4543 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), buffy) ); 4544 } 4545 (void) SCIPsnprintf(buffy, SCIP_MAXSTRLEN, "], %d);\n", SCIPgetCapacityCumulative(scip, cons) ); 4546 4547 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), buffy) ); 4548 } 4549 else 4550 { 4551 SCIPwarningMessage(scip, "constraint handler <%s> cannot print flatzinc format\n", conshdlrname ); 4552 } 4553 } 4554 4555 SCIP_CALL( SCIPallocBufferArray(scip,&intobjvars,ndiscretevars) ); 4556 SCIP_CALL( SCIPallocBufferArray(scip,&floatobjvars,nvars) ); 4557 nintobjvars = 0; 4558 nfloatobjvars = 0; 4559 4560 /* scan objective function: Which variables have to be put to the float part, which to the int part? */ 4561 for( v = 0; v < nvars; v++ ) 4562 { 4563 SCIP_Real obj; 4564 4565 var = vars[v]; 4566 obj = SCIPvarGetObj(var); 4567 4568 if( !SCIPisZero(scip,obj) ) 4569 { 4570 /* only discrete variables with integral objective coefficient will be put to the int part of the objective */ 4571 if( v < ndiscretevars && SCIPisIntegral(scip, objscale*obj) ) 4572 { 4573 intobjvars[nintobjvars] = v; 4574 SCIPdebugMsg(scip, "variable <%s> at pos <%d,%d> has an integral obj: %f=%f*%f\n", 4575 SCIPvarGetName(var), nintobjvars, v, obj, objscale, SCIPvarGetObj(var)); 4576 nintobjvars++; 4577 } 4578 else 4579 { 4580 /* if not happened yet, introduce an auxiliary variable for discrete variables with fractional coefficients */ 4581 if( v < ndiscretevars && !fznoutput.varhasfloat[v] ) 4582 { 4583 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY || SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER); 4584 4585 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "var float: %s_float;\n", SCIPvarGetName(var)); 4586 SCIP_CALL( appendBuffer(scip, &(fznoutput.varbuffer), &(fznoutput.varbufferlen), &(fznoutput.varbufferpos),buffer) ); 4587 4588 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "constraint int2float(%s, %s_float);\n", SCIPvarGetName(var), SCIPvarGetName(var)); 4589 SCIP_CALL( appendBuffer(scip, &(fznoutput.castbuffer), &(fznoutput.castbufferlen), &(fznoutput.castbufferpos),buffer) ); 4590 4591 fznoutput.varhasfloat[v] = TRUE; 4592 } 4593 4594 floatobjvars[nfloatobjvars] = v; 4595 nfloatobjvars++; 4596 } 4597 } 4598 } 4599 4600 /* output all created auxiliary variables (float equivalents of discrete variables) */ 4601 if( fznoutput.varbufferpos > 0 ) 4602 { 4603 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Auxiliary variables %%%%%%%%%%%%\n"); 4604 writeBuffer(scip, file, fznoutput.varbuffer, fznoutput.varbufferpos ); 4605 } 4606 4607 /* output all int2float casting/conversion constraints */ 4608 if( fznoutput.castbufferpos > 0 ) 4609 { 4610 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Variable conversions %%%%%%%%%%%%\n"); 4611 writeBuffer(scip, file, fznoutput.castbuffer, fznoutput.castbufferpos ); 4612 } 4613 4614 if( nboundedvars > 0 ) 4615 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Variable bounds %%%%%%%%%%%%\n"); 4616 4617 /* output all bounds of variables with exactly one bound*/ 4618 for( v = 0; v < nboundedvars; v++ ) 4619 { 4620 var = vars[boundedvars[v]]; 4621 4622 if( SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER ) 4623 { 4624 if( boundtypes[v] == SCIP_BOUNDTYPE_LOWER ) 4625 SCIPinfoMessage(scip, file,"constraint int_ge(%s, %.f);\n",SCIPvarGetName(var), 4626 transformed ? SCIPvarGetLbLocal(var) : SCIPvarGetLbOriginal(var)); 4627 else 4628 { 4629 assert( boundtypes[v] == SCIP_BOUNDTYPE_UPPER ); 4630 SCIPinfoMessage(scip, file,"constraint int_le(%s, %.f);\n",SCIPvarGetName(var), 4631 transformed ? SCIPvarGetUbLocal(var) : SCIPvarGetUbOriginal(var)); 4632 } 4633 } 4634 else 4635 { 4636 assert(SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS); 4637 4638 if( boundtypes[v] == SCIP_BOUNDTYPE_LOWER ) 4639 { 4640 flattenFloat(scip, transformed ? SCIPvarGetLbLocal(var) : SCIPvarGetLbOriginal(var), buffy); 4641 SCIPinfoMessage(scip, file,"constraint float_ge(%s, %s);\n", SCIPvarGetName(var), buffy); 4642 } 4643 else 4644 { 4645 assert( boundtypes[v] == SCIP_BOUNDTYPE_UPPER ); 4646 flattenFloat(scip, transformed ? SCIPvarGetUbLocal(var) : SCIPvarGetUbOriginal(var), buffy); 4647 SCIPinfoMessage(scip, file,"constraint float_le(%s, %s);\n",SCIPvarGetName(var), buffy); 4648 } 4649 } 4650 } 4651 4652 /* output all problem constraints */ 4653 if( fznoutput.consbufferpos > 0 ) 4654 { 4655 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Problem constraints %%%%%%%%%%%%\n"); 4656 writeBuffer(scip, file, fznoutput.consbuffer, fznoutput.consbufferpos ); 4657 } 4658 4659 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Objective function %%%%%%%%%%%%\n"); 4660 4661 /* If there is at least one variable in the objective function write down the optimization problem, else declare it to be a satisfiability problem */ 4662 if( nintobjvars > 0 || nfloatobjvars > 0 || !SCIPisZero(scip, objoffset) ) 4663 { 4664 SCIPinfoMessage(scip, file, "solve %s int_float_lin([", objsense == SCIP_OBJSENSE_MINIMIZE ? "minimize" : "maximize" ); 4665 4666 /* first array: coefficients (in float representation) of discrete variables with integral objective coefficient */ 4667 for( v = 0; v < nintobjvars; v++ ) 4668 { 4669 SCIP_Real obj; 4670 var = vars[intobjvars[v]]; 4671 obj = objscale * SCIPvarGetObj(var); 4672 SCIPdebugMsg(scip, "variable <%s> at pos <%d,%d> has an integral obj: %f=%f*%f\n", SCIPvarGetName(var), v, intobjvars[v], obj, objscale, SCIPvarGetObj(var)); 4673 4674 assert( SCIPisIntegral(scip, obj) ); 4675 flattenFloat(scip, obj, buffy); 4676 SCIPinfoMessage(scip, file, "%s%s", buffy, v < nintobjvars-1 ? ", " : "" ); 4677 } 4678 4679 /* second array: all other objective coefficients */ 4680 SCIPinfoMessage(scip, file, "], ["); 4681 for( v = 0; v < nfloatobjvars; v++ ) 4682 { 4683 SCIP_Real obj; 4684 obj = objscale * SCIPvarGetObj(vars[floatobjvars[v]]); 4685 flattenFloat(scip, obj, buffy); 4686 assert( !SCIPisIntegral(scip, obj) || SCIPvarGetType(vars[floatobjvars[v]]) == SCIP_VARTYPE_CONTINUOUS 4687 || SCIPvarGetType(vars[floatobjvars[v]]) == SCIP_VARTYPE_IMPLINT); 4688 SCIPinfoMessage(scip, file, "%s%s", buffy, v < nfloatobjvars-1 ? ", " : "" ); 4689 } 4690 4691 /* potentially add an objective offset */ 4692 if( !SCIPisZero(scip, objoffset) ) 4693 { 4694 flattenFloat(scip, objscale * objoffset, buffy); 4695 SCIPinfoMessage(scip, file, "%s%s", nfloatobjvars == 0 ? "" : ", ", buffy ); 4696 } 4697 4698 /* third array: all discrete variables with integral objective coefficient */ 4699 SCIPinfoMessage(scip, file, "], ["); 4700 for( v = 0; v < nintobjvars; v++ ) 4701 SCIPinfoMessage(scip, file, "%s%s", SCIPvarGetName(vars[intobjvars[v]]), v < nintobjvars-1 ? ", " : "" ); 4702 4703 /* fourth array: all other variables with nonzero objective coefficient */ 4704 SCIPinfoMessage(scip, file, "], ["); 4705 for( v = 0; v < nfloatobjvars; v++ ) 4706 SCIPinfoMessage(scip, file, "%s%s%s", SCIPvarGetName(vars[floatobjvars[v]]), floatobjvars[v] < ndiscretevars ? "_float" : "", v < nfloatobjvars-1 ? ", " : "" ); 4707 4708 /* potentially add a 1.0 for the objective offset */ 4709 if( !SCIPisZero(scip, objoffset) ) 4710 SCIPinfoMessage(scip, file, "%s%.1f", nfloatobjvars == 0 ? "" : ", ", 1.0 ); 4711 SCIPinfoMessage(scip, file, "]);\n"); 4712 } 4713 else 4714 SCIPinfoMessage(scip, file, "solve satisfy;\n"); 4715 4716 /* free all memory */ 4717 SCIPfreeBufferArray(scip, &fznoutput.castbuffer); 4718 SCIPfreeBufferArray(scip, &fznoutput.consbuffer); 4719 SCIPfreeBufferArray(scip, &fznoutput.varbuffer); 4720 4721 SCIPfreeBufferArray(scip, &boundtypes); 4722 SCIPfreeBufferArray(scip, &boundedvars); 4723 SCIPfreeBufferArray(scip, &floatobjvars); 4724 SCIPfreeBufferArray(scip, &intobjvars); 4725 SCIPfreeBufferArray(scip, &fznoutput.varhasfloat); 4726 4727 *result = SCIP_SUCCESS; 4728 return SCIP_OKAY; 4729 } 4730 4731 /* 4732 * Callback methods of reader 4733 */ 4734 4735 /** copy method for reader plugins (called when SCIP copies plugins) */ 4736 static 4737 SCIP_DECL_READERCOPY(readerCopyFzn) 4738 { /*lint --e{715}*/ 4739 assert(scip != NULL); 4740 assert(reader != NULL); 4741 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); 4742 4743 /* call inclusion method of reader */ 4744 SCIP_CALL( SCIPincludeReaderFzn(scip) ); 4745 4746 return SCIP_OKAY; 4747 } 4748 4749 4750 /** destructor of reader to free user data (called when SCIP is exiting) */ 4751 static 4752 SCIP_DECL_READERFREE(readerFreeFzn) 4753 { 4754 SCIP_READERDATA* readerdata; 4755 int v; 4756 4757 readerdata = SCIPreaderGetData(reader); 4758 assert(readerdata != NULL); 4759 4760 /* free all variable array elements */ 4761 for( v = 0; v < readerdata->nvararrays; ++v ) 4762 { 4763 freeVararray(scip, &readerdata->vararrays[v]); 4764 } 4765 4766 SCIPfreeBlockMemoryArrayNull(scip, &readerdata->vararrays, readerdata->vararrayssize); 4767 4768 /* free reader data */ 4769 SCIPfreeBlockMemory(scip, &readerdata); 4770 4771 return SCIP_OKAY; 4772 } 4773 4774 4775 /** problem reading method of reader */ 4776 static 4777 SCIP_DECL_READERREAD(readerReadFzn) 4778 { /*lint --e{715}*/ 4779 FZNINPUT fzninput; 4780 int i; 4781 4782 /* initialize FZN input data */ 4783 fzninput.file = NULL; 4784 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &fzninput.linebuf, FZN_INIT_LINELEN) ); 4785 fzninput.linebuf[0] = '\0'; 4786 fzninput.linebufsize = FZN_INIT_LINELEN; 4787 SCIP_CALL( SCIPallocBufferArray(scip, &fzninput.token, FZN_BUFFERLEN) ); 4788 fzninput.token[0] = '\0'; 4789 4790 for( i = 0; i < FZN_MAX_PUSHEDTOKENS; ++i ) 4791 { 4792 SCIP_CALL( SCIPallocBufferArray(scip, &(fzninput.pushedtokens[i]), FZN_BUFFERLEN) ); /*lint !e866*/ 4793 } 4794 4795 fzninput.npushedtokens = 0; 4796 fzninput.linenumber = 1; 4797 fzninput.bufpos = 0; 4798 fzninput.linepos = 0; 4799 fzninput.objsense = SCIP_OBJSENSE_MINIMIZE; 4800 fzninput.comment = FALSE; 4801 fzninput.haserror = FALSE; 4802 fzninput.valid = TRUE; 4803 fzninput.vararrays = NULL; 4804 fzninput.nvararrays = 0; 4805 fzninput.vararrayssize = 0; 4806 fzninput.constarrays = NULL; 4807 fzninput.nconstarrays = 0; 4808 fzninput.constarrayssize = 0; 4809 4810 SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &(fzninput.initialconss)) ); 4811 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &(fzninput.dynamicconss)) ); 4812 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &(fzninput.dynamiccols)) ); 4813 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &(fzninput.dynamicrows)) ); 4814 4815 SCIP_CALL( SCIPhashtableCreate(&fzninput.varHashtable, SCIPblkmem(scip), SCIP_HASHSIZE_NAMES, 4816 hashGetKeyVar, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) ); 4817 4818 SCIP_CALL( SCIPhashtableCreate(&fzninput.constantHashtable, SCIPblkmem(scip), SCIP_HASHSIZE_NAMES, 4819 hashGetKeyConstant, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) ); 4820 SCIP_CALL( SCIPallocBufferArray(scip, &fzninput.constants, 10) ); 4821 4822 fzninput.nconstants = 0; 4823 fzninput.sconstants = 10; 4824 4825 /* read the file */ 4826 SCIP_CALL( readFZNFile(scip, SCIPreaderGetData(reader), &fzninput, filename) ); 4827 4828 /* free dynamically allocated memory */ 4829 for( i = fzninput.nconstants - 1; i >= 0; --i ) 4830 { 4831 SCIPfreeBufferArray(scip, &fzninput.constants[i]->name); 4832 SCIPfreeBuffer(scip, &fzninput.constants[i]); 4833 } 4834 SCIPfreeBufferArray(scip, &fzninput.constants); 4835 4836 for( i = FZN_MAX_PUSHEDTOKENS - 1; i >= 0; --i ) /*lint !e778*/ 4837 { 4838 SCIPfreeBufferArrayNull(scip, &fzninput.pushedtokens[i]); 4839 } 4840 SCIPfreeBufferArrayNull(scip, &fzninput.token); 4841 4842 /* free memory */ 4843 SCIPhashtableFree(&fzninput.varHashtable); 4844 SCIPhashtableFree(&fzninput.constantHashtable); 4845 4846 /* free variable arrays */ 4847 for( i = 0; i < fzninput.nvararrays; ++i ) 4848 { 4849 freeVararray(scip, &fzninput.vararrays[i]); 4850 } 4851 SCIPfreeBlockMemoryArrayNull(scip, &(fzninput.vararrays), fzninput.vararrayssize); 4852 4853 /* free constant arrays */ 4854 for( i = 0; i < fzninput.nconstarrays; ++i ) 4855 { 4856 freeConstarray(scip, &(fzninput.constarrays[i])); 4857 } 4858 SCIPfreeBlockMemoryArrayNull(scip, &fzninput.constarrays, fzninput.constarrayssize); 4859 4860 SCIPfreeBlockMemoryArray(scip, &fzninput.linebuf, fzninput.linebufsize); 4861 4862 /* evaluate the result */ 4863 if( fzninput.haserror || ! fzninput.valid ) 4864 return SCIP_READERROR; 4865 4866 *result = SCIP_SUCCESS; 4867 4868 return SCIP_OKAY; 4869 } 4870 4871 4872 /** problem writing method of reader */ 4873 static 4874 SCIP_DECL_READERWRITE(readerWriteFzn) 4875 { /*lint --e{715}*/ 4876 if( genericnames ) 4877 { 4878 SCIP_CALL( writeFzn(scip, file, name, transformed, objsense, objscale, objoffset, vars, 4879 nvars, nbinvars, nintvars, nimplvars, ncontvars, conss, nconss, result) ); 4880 } 4881 else 4882 { 4883 int i; 4884 SCIP_Bool legal; 4885 4886 legal = TRUE; 4887 4888 /* Scan whether all variable names are flatzinc conform */ 4889 for( i = 0; i < nvars; i++ ) 4890 { 4891 const char* varname; 4892 size_t length; 4893 4894 varname = SCIPvarGetName(vars[i]); 4895 length = strlen(varname); 4896 legal = isIdentifier(varname); 4897 if( !legal ) 4898 { 4899 SCIPwarningMessage(scip, "The name of variable <%d>: \"%s\" is not conform to the fzn standard.\n", i, varname); 4900 break; 4901 } 4902 4903 if( length >= 7 ) 4904 legal = (strncmp(&varname[length-6],"_float",6) != 0); 4905 if( !legal ) 4906 { 4907 SCIPwarningMessage(scip, "The name of variable <%d>: \"%s\" ends with \"_float\" which is not supported.\n", i, varname); 4908 break; 4909 } 4910 } 4911 4912 /* If there is at least one name, which is not conform, use generic names */ 4913 if( legal ) 4914 { 4915 SCIP_CALL( writeFzn(scip, file, name, transformed, objsense, objscale, objoffset, vars, 4916 nvars, nbinvars, nintvars, nimplvars, ncontvars, conss, nconss, result) ); 4917 } 4918 else if( transformed ) 4919 { 4920 SCIPwarningMessage(scip, "Write transformed problem with generic variable names.\n"); 4921 SCIP_CALL( SCIPprintTransProblem(scip, file, "fzn", TRUE) ); 4922 } 4923 else 4924 { 4925 SCIPwarningMessage(scip, "Write original problem with generic variable names.\n"); 4926 SCIP_CALL( SCIPprintOrigProblem(scip, file, "fzn", TRUE) ); 4927 } 4928 } 4929 4930 *result = SCIP_SUCCESS; 4931 4932 return SCIP_OKAY; 4933 } 4934 4935 /* 4936 * reader specific interface methods 4937 */ 4938 4939 /** includes the fzn file reader in SCIP */ 4940 SCIP_RETCODE SCIPincludeReaderFzn( 4941 SCIP* scip /**< SCIP data structure */ 4942 ) 4943 { 4944 SCIP_READERDATA* readerdata; 4945 SCIP_READER* reader; 4946 4947 /* create fzn reader data */ 4948 SCIP_CALL( readerdataCreate(scip, &readerdata) ); 4949 4950 /* include reader */ 4951 SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, readerdata) ); 4952 4953 /* set non fundamental callbacks via setter functions */ 4954 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyFzn) ); 4955 SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeFzn) ); 4956 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadFzn) ); 4957 SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteFzn) ); 4958 4959 return SCIP_OKAY; 4960 } 4961 4962 /** print given solution in Flatzinc format w.r.t. the output annotation */ 4963 SCIP_RETCODE SCIPprintSolReaderFzn( 4964 SCIP* scip, /**< SCIP data structure */ 4965 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */ 4966 FILE* file /**< output file (or NULL for standard output) */ 4967 ) 4968 { 4969 SCIP_READER* reader; 4970 SCIP_READERDATA* readerdata; 4971 SCIP_VAR** vars; 4972 VARARRAY** vararrays; 4973 DIMENSIONS* info; 4974 VARARRAY* vararray; 4975 FZNNUMBERTYPE type; 4976 SCIP_Real solvalue; 4977 int nvararrays; 4978 int nvars; 4979 int i; 4980 int v; 4981 4982 reader = SCIPfindReader(scip, READER_NAME); 4983 assert(reader != NULL); 4984 4985 readerdata = SCIPreaderGetData(reader); 4986 assert(readerdata != NULL); 4987 4988 vararrays = readerdata->vararrays; 4989 nvararrays = readerdata->nvararrays; 4990 4991 /* sort variable arrays */ 4992 SCIPsortPtr((void**)vararrays, vararraysComp, nvararrays); 4993 4994 for( i = 0; i < nvararrays; ++i ) 4995 { 4996 vararray = vararrays[i]; 4997 info = vararray->info; 4998 vars = vararray->vars; 4999 nvars = vararray->nvars; 5000 type = vararray->type; 5001 5002 if( info->ndims == 0 ) 5003 { 5004 solvalue = SCIPgetSolVal(scip, sol, vars[0]); 5005 5006 SCIPinfoMessage(scip, file, "%s = ", vararray->name); 5007 5008 printValue(scip, file, solvalue, type); 5009 5010 SCIPinfoMessage(scip, file, ";\n"); 5011 } 5012 else 5013 { 5014 SCIPinfoMessage(scip, file, "%s = array%dd(", vararray->name, info->ndims); 5015 5016 for( v = 0; v < info->ndims; ++v ) 5017 { 5018 SCIPinfoMessage(scip, file, "%d..%d, ", info->lbs[v], info->ubs[v]); 5019 } 5020 5021 SCIPinfoMessage(scip, file, "["); 5022 5023 for( v = 0; v < nvars; ++v ) 5024 { 5025 if( v > 0) 5026 SCIPinfoMessage(scip, file, ", "); 5027 5028 solvalue = SCIPgetSolVal(scip, sol, vars[v]); 5029 printValue(scip, file, solvalue, type); 5030 } 5031 5032 SCIPinfoMessage(scip, file, "]);\n"); 5033 } 5034 } 5035 5036 SCIPinfoMessage(scip, file, "----------\n"); 5037 5038 return SCIP_OKAY; 5039 } 5040