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_gms.c 26 * @ingroup DEFPLUGINS_READER 27 * @brief GAMS file writer 28 * @author Ambros Gleixner 29 * @author Stefan Vigerske 30 * 31 * @todo Check for words reserved for GAMS. 32 */ 33 34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 35 36 #include "blockmemshell/memory.h" 37 #include "scip/cons_nonlinear.h" 38 #include "scip/cons_indicator.h" 39 #include "scip/cons_knapsack.h" 40 #include "scip/cons_linear.h" 41 #include "scip/cons_logicor.h" 42 #include "scip/cons_setppc.h" 43 #include "scip/cons_sos1.h" 44 #include "scip/cons_sos2.h" 45 #include "scip/cons_varbound.h" 46 #include "scip/pub_cons.h" 47 #include "scip/pub_message.h" 48 #include "scip/pub_misc.h" 49 #include "scip/pub_reader.h" 50 #include "scip/pub_var.h" 51 #include "scip/reader_gms.h" 52 #include "scip/scip_cons.h" 53 #include "scip/scip_general.h" 54 #include "scip/scip_mem.h" 55 #include "scip/scip_message.h" 56 #include "scip/scip_numerics.h" 57 #include "scip/scip_param.h" 58 #include "scip/scip_reader.h" 59 #include "scip/scip_var.h" 60 #include "scip/expr_abs.h" 61 #include <string.h> 62 63 64 #define READER_NAME "gmsreader" 65 #define READER_DESC "file writer for (MI)(N)LPs in GAMS file format" 66 #define READER_EXTENSION "gms" 67 68 69 #define GMS_MAX_LINELEN 256 70 #define GMS_MAX_PRINTLEN 256 /**< the maximum length of any line is 255 + '\\0' = 256*/ 71 #define GMS_MAX_NAMELEN 64 /**< the maximum length for any name is 63 + '\\0' = 64 */ 72 #define GMS_PRINTLEN 100 73 #define GMS_DEFAULT_BIGM 1e+6 74 #define GMS_DEFAULT_INDICATORREFORM 's' 75 #define GMS_DEFAULT_SIGNPOWER FALSE 76 77 /* 78 * Local methods (for writing) 79 */ 80 81 static const char badchars[] = "#*+/-@$[](){}"; 82 83 /** transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant */ 84 static 85 SCIP_RETCODE getActiveVariables( 86 SCIP* scip, /**< SCIP data structure */ 87 SCIP_VAR*** vars, /**< pointer to vars array to get active variables for */ 88 SCIP_Real** scalars, /**< pointer to scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */ 89 int* nvars, /**< pointer to number of variables and values in vars and vals array */ 90 int* varssize, /**< pointer to length of vars and scalars array */ 91 SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */ 92 SCIP_Bool transformed /**< transformed constraint? */ 93 ) 94 { 95 int requiredsize; 96 int v; 97 98 assert( scip != NULL ); 99 assert( vars != NULL ); 100 assert( *vars != NULL ); 101 assert( scalars != NULL ); 102 assert( *scalars != NULL ); 103 assert( nvars != NULL ); 104 assert( varssize != NULL ); 105 assert( *varssize >= *nvars ); 106 assert( constant != NULL ); 107 108 if( transformed ) 109 { 110 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *varssize, constant, &requiredsize, TRUE) ); 111 112 if( requiredsize > *varssize ) 113 { 114 *varssize = SCIPcalcMemGrowSize(scip, requiredsize); 115 SCIP_CALL( SCIPreallocBufferArray(scip, vars, *varssize) ); 116 SCIP_CALL( SCIPreallocBufferArray(scip, scalars, *varssize) ); 117 118 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *varssize, constant, &requiredsize, TRUE) ); 119 assert(requiredsize <= *varssize); 120 } 121 } 122 else 123 { 124 for( v = 0; v < *nvars; ++v ) 125 { 126 SCIP_CALL( SCIPvarGetOrigvarSum(&(*vars)[v], &(*scalars)[v], constant) ); 127 } 128 } 129 130 return SCIP_OKAY; 131 } 132 133 /** clears the given line buffer */ 134 static 135 void clearLine( 136 char* linebuffer, /**< line */ 137 int* linecnt /**< number of characters in line */ 138 ) 139 { 140 assert( linebuffer != NULL ); 141 assert( linecnt != NULL ); 142 143 (*linecnt) = 0; 144 linebuffer[0] = '\0'; 145 } 146 147 /** ends the given line with '\\0' and prints it to the given file stream, with a newline at the end */ 148 static 149 void endLine( 150 SCIP* scip, /**< SCIP data structure */ 151 FILE* file, /**< output file (or NULL for standard output) */ 152 char* linebuffer, /**< line */ 153 int* linecnt /**< number of characters in line */ 154 ) 155 { 156 assert( scip != NULL ); 157 assert( linebuffer != NULL ); 158 assert( linecnt != NULL ); 159 assert( 0 <= *linecnt && *linecnt < GMS_MAX_LINELEN ); 160 161 if( (*linecnt) > 0 ) 162 { 163 linebuffer[(*linecnt)] = '\0'; 164 SCIPinfoMessage(scip, file, "%s\n", linebuffer); 165 clearLine(linebuffer, linecnt); 166 } 167 } 168 169 /** ends the given line with '\\0' and prints it to the given file stream, without a newline at the end */ 170 static 171 void endLineNoNewline( 172 SCIP* scip, /**< SCIP data structure */ 173 FILE* file, /**< output file (or NULL for standard output) */ 174 char* linebuffer, /**< line */ 175 int* linecnt /**< number of characters in line */ 176 ) 177 { 178 assert( scip != NULL ); 179 assert( linebuffer != NULL ); 180 assert( linecnt != NULL ); 181 assert( 0 <= *linecnt && *linecnt < GMS_MAX_LINELEN ); 182 183 if( (*linecnt) > 0 ) 184 { 185 linebuffer[(*linecnt)] = '\0'; 186 SCIPinfoMessage(scip, file, "%s", linebuffer); 187 clearLine(linebuffer, linecnt); 188 } 189 } 190 191 /** appends extension to line and prints it to the give file stream if the 192 * line exceeded the length given in the define GMS_PRINTLEN */ 193 static 194 void appendLine( 195 SCIP* scip, /**< SCIP data structure */ 196 FILE* file, /**< output file (or NULL for standard output) */ 197 char* linebuffer, /**< line */ 198 int* linecnt, /**< number of characters in line */ 199 const char* extension /**< string to extend the line */ 200 ) 201 { 202 size_t len; 203 assert( scip != NULL ); 204 assert( linebuffer != NULL ); 205 assert( linecnt != NULL ); 206 assert( extension != NULL ); 207 assert( strlen(linebuffer) + strlen(extension) < GMS_MAX_PRINTLEN ); 208 209 /* NOTE: avoid 210 * sprintf(linebuffer, "%s%s", linebuffer, extension); 211 * because of overlapping memory areas in memcpy used in sprintf. 212 */ 213 len = strlen(linebuffer); 214 (void) strncat(linebuffer, extension, GMS_MAX_PRINTLEN - len); 215 216 (*linecnt) += (int) strlen(extension); 217 218 SCIPdebugMsg(scip, "linebuffer <%s>, length = %lu\n", linebuffer, (unsigned long)len); 219 220 if( (*linecnt) > GMS_PRINTLEN ) 221 endLine(scip, file, linebuffer, linecnt); 222 } 223 224 /** checks string for occurences of bad symbols and replace those by '_' */ 225 static 226 void conformName( 227 char* name /**< string to adjust */ 228 ) 229 { 230 const char* badchar; 231 232 assert( name != NULL ); 233 234 for( badchar = badchars; *badchar; ++badchar ) 235 { 236 char* c = strchr(name, *badchar); 237 238 while( c != NULL ) 239 { 240 assert( *c == *badchar ); 241 242 *c = '_'; 243 c = strchr(c, *badchar); 244 } 245 } 246 } 247 248 /* print first len-1 characters of name to string s and replace '#', '*', '+', '/', and '-' by '_' if necessary */ 249 static 250 SCIP_RETCODE printConformName( 251 SCIP* scip, /**< SCIP data structure */ 252 char* t, /**< target string */ 253 int len, /**< length of t */ 254 const char* name /**< source string or format string */ 255 ) 256 { 257 SCIP_Bool replaceforbiddenchars; 258 259 assert( t != NULL ); 260 assert( len > 0 ); 261 262 SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/replaceforbiddenchars", &replaceforbiddenchars) ); 263 264 (void) SCIPsnprintf(t, len, "%s", name); 265 266 if( replaceforbiddenchars ) 267 conformName(t); 268 269 return SCIP_OKAY; 270 } 271 272 273 /* retransform to active variables and print in GAMS format to file stream with surrounding bracket, pre- and suffix */ 274 static 275 SCIP_RETCODE printActiveVariables( 276 SCIP* scip, /**< SCIP data structure */ 277 FILE* file, /**< output file (or NULL for standard output) */ 278 char* linebuffer, /**< line */ 279 int* linecnt, /**< number of characters in line */ 280 const char* prefix, /**< prefix (maybe NULL) */ 281 const char* suffix, /**< suffix (maybe NULL) */ 282 int nvars, /**< number of variables */ 283 SCIP_VAR** vars, /**< array of variables */ 284 SCIP_Real* vals, /**< array of values (or NULL if all ones) */ 285 SCIP_Bool transformed /**< transformed constraint? */ 286 ) 287 { 288 int v; 289 int closingbracket; 290 291 SCIP_VAR* var; 292 char varname[GMS_MAX_NAMELEN]; 293 char buffer[GMS_MAX_PRINTLEN]; 294 char ext[GMS_MAX_PRINTLEN]; 295 296 SCIP_VAR** activevars = NULL; 297 SCIP_Real* activevals = NULL; 298 int nactivevars; 299 int activevarssize; 300 SCIP_Real activeconstant = 0.0; 301 302 assert( scip != NULL ); 303 assert( vars != NULL || nvars == 0 ); 304 305 if( *linecnt == 0 ) 306 /* we start a new line; therefore we tab this line */ 307 appendLine(scip, file, linebuffer, linecnt, " "); 308 309 if( nvars == 0 ) 310 { 311 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s(0)%s", prefix != NULL ? prefix : "", suffix != NULL ? suffix : ""); 312 313 appendLine(scip, file, linebuffer, linecnt, buffer); 314 } 315 else 316 { 317 nactivevars = nvars; 318 319 /* duplicate variable and value array */ 320 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars) ); 321 if( vals != NULL ) 322 { 323 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars) ); 324 } 325 else 326 { 327 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) ); 328 329 for( v = 0; v < nactivevars; ++v ) 330 activevals[v] = 1.0; 331 } 332 activevarssize = nactivevars; 333 334 /* retransform given variables to active variables */ 335 SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activevarssize, &activeconstant, transformed) ); 336 337 assert( nactivevars == 0 || activevals != NULL ); 338 339 if( nactivevars == 0 && SCIPisZero(scip, activeconstant) ) 340 { 341 if( *linecnt == 0 ) 342 /* we start a new line; therefore we tab this line */ 343 appendLine(scip, file, linebuffer, linecnt, " "); 344 345 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s(0)%s", prefix != NULL ? prefix : "", suffix != NULL ? suffix : ""); 346 347 appendLine(scip, file, linebuffer, linecnt, buffer); 348 } 349 else 350 { 351 /* buffer prefix */ 352 (void) SCIPsnprintf(ext, GMS_MAX_PRINTLEN, "%s(", prefix != NULL ? prefix : ""); 353 354 /* find position of closing bracket */ 355 closingbracket = nactivevars; 356 if( SCIPisZero(scip, activeconstant) ) 357 { 358 do 359 --closingbracket; 360 while( SCIPisZero(scip, activevals[closingbracket]) && closingbracket > 0 ); 361 } 362 363 /* print active variables */ 364 for( v = 0; v < nactivevars; ++v ) 365 { 366 var = activevars[v]; 367 assert( var != NULL ); 368 369 if( !SCIPisZero(scip, activevals[v]) ) 370 { 371 if( *linecnt == 0 ) 372 /* we start a new line; therefore we tab this line */ 373 appendLine(scip, file, linebuffer, linecnt, " "); 374 375 SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) ); 376 377 if( SCIPisEQ(scip, activevals[v], 1.0) ) 378 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%s%s%s%s", ext, strchr(ext, '(') == NULL ? "+" : "", 379 varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : ""); 380 else if( SCIPisEQ(scip, activevals[v], -1.0) ) 381 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s-%s%s%s", ext, 382 varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : ""); 383 else if( strchr(ext, '(') != NULL ) 384 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%.15g*%s%s%s", ext, 385 activevals[v], varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : ""); 386 else 387 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%+.15g*%s%s%s", ext, 388 activevals[v], varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : ""); 389 390 appendLine(scip, file, linebuffer, linecnt, buffer); 391 392 (void) SCIPsnprintf(ext, GMS_MAX_PRINTLEN, (*linecnt == 0) ? "" : " "); 393 } 394 } 395 396 /* print active constant */ 397 if( !SCIPisZero(scip, activeconstant) ) 398 { 399 if( *linecnt == 0 ) 400 /* we start a new line; therefore we tab this line */ 401 appendLine(scip, file, linebuffer, linecnt, " "); 402 403 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%+.15g)%s", ext, activeconstant, suffix ? suffix : ""); 404 405 appendLine(scip, file, linebuffer, linecnt, buffer); 406 } 407 /* nothing has been printed, yet */ 408 else if( strchr(ext, '(') != NULL ) 409 { 410 if( *linecnt == 0 ) 411 /* we start a new line; therefore we tab this line */ 412 appendLine(scip, file, linebuffer, linecnt, " "); 413 414 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s(0)%s", prefix ? prefix : "", suffix ? suffix : ""); 415 416 appendLine(scip, file, linebuffer, linecnt, buffer); 417 } 418 } 419 420 /* free buffer arrays */ 421 SCIPfreeBufferArray(scip, &activevars); 422 SCIPfreeBufferArray(scip, &activevals); 423 } 424 425 return SCIP_OKAY; 426 } 427 428 429 /* print linear row in GAMS format to file stream (without retransformation to active variables) */ 430 static 431 SCIP_RETCODE printLinearRow( 432 SCIP* scip, /**< SCIP data structure */ 433 FILE* file, /**< output file (or NULL for standard output) */ 434 const char* rowname, /**< row name */ 435 const char* rownameextension, /**< row name extension */ 436 const char* type, /**< row type ("=e=", "=l=", or "=g=") */ 437 int nvars, /**< number of variables */ 438 SCIP_VAR** vars, /**< array of variables */ 439 SCIP_Real* vals, /**< array of values */ 440 SCIP_Real rhs /**< right hand side */ 441 ) 442 { 443 int v; 444 char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' }; 445 int linecnt; 446 447 SCIP_VAR* var; 448 char varname[GMS_MAX_NAMELEN]; 449 char consname[GMS_MAX_NAMELEN + 3]; /* four extra characters for ' ..' */ 450 char buffer[GMS_MAX_PRINTLEN]; 451 452 assert( scip != NULL ); 453 assert( strcmp(type, "=e=") == 0 || strcmp(type, "=l=") == 0 || strcmp(type, "=g=") == 0); 454 assert( nvars == 0 || (vars != NULL && vals != NULL) ); 455 456 clearLine(linebuffer, &linecnt); 457 458 /* start each line with a space */ 459 appendLine(scip, file, linebuffer, &linecnt, " "); 460 461 /* print row name */ 462 if( strlen(rowname) > 0 || strlen(rownameextension) > 0 ) 463 { 464 (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s%s ..", rowname, rownameextension); 465 SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) ); 466 appendLine(scip, file, linebuffer, &linecnt, consname); 467 } 468 469 /* print coefficients */ 470 if( nvars == 0 ) 471 { 472 /* we start a new line; therefore we tab this line */ 473 if( linecnt == 0 ) 474 appendLine(scip, file, linebuffer, &linecnt, " "); 475 476 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " 0"); 477 478 appendLine(scip, file, linebuffer, &linecnt, buffer); 479 } 480 481 for( v = 0; v < nvars; ++v ) 482 { 483 assert(vars != NULL); /* for lint */ 484 assert(vals != NULL); 485 486 var = vars[v]; 487 assert( var != NULL ); 488 489 /* we start a new line; therefore we tab this line */ 490 if( linecnt == 0 ) 491 appendLine(scip, file, linebuffer, &linecnt, " "); 492 493 SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) ); 494 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %+.15g*%s", vals[v], varname); 495 496 appendLine(scip, file, linebuffer, &linecnt, buffer); 497 } 498 499 /* print right hand side */ 500 if( SCIPisZero(scip, rhs) ) 501 rhs = 0.0; 502 503 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s %.15g;", type, rhs); 504 505 /* we start a new line; therefore we tab this line */ 506 if( linecnt == 0 ) 507 appendLine(scip, file, linebuffer, &linecnt, " "); 508 appendLine(scip, file, linebuffer, &linecnt, buffer); 509 510 endLine(scip, file, linebuffer, &linecnt); 511 512 return SCIP_OKAY; 513 } 514 515 516 /** prints given linear constraint information in GAMS format to file stream */ 517 static 518 SCIP_RETCODE printLinearCons( 519 SCIP* scip, /**< SCIP data structure */ 520 FILE* file, /**< output file (or NULL for standard output) */ 521 const char* rowname, /**< name of the row */ 522 int nvars, /**< number of variables */ 523 SCIP_VAR** vars, /**< array of variables */ 524 SCIP_Real* vals, /**< array of coefficients values (or NULL if all coefficient values are 1) */ 525 SCIP_Real lhs, /**< left hand side */ 526 SCIP_Real rhs, /**< right hand side */ 527 SCIP_Bool transformed /**< transformed constraint? */ 528 ) 529 { 530 int v; 531 SCIP_VAR** activevars = NULL; 532 SCIP_Real* activevals = NULL; 533 int nactivevars; 534 SCIP_Real activeconstant = 0.0; 535 int activevarssize; 536 537 assert( scip != NULL ); 538 assert( rowname != NULL ); 539 540 /* The GAMS format does not forbid that the variable array is empty */ 541 assert( nvars == 0 || vars != NULL ); 542 543 assert( lhs <= rhs ); 544 545 if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) ) 546 return SCIP_OKAY; 547 548 nactivevars = nvars; 549 if( nvars > 0 ) 550 { 551 /* duplicate variable and value array */ 552 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars) ); 553 if( vals != NULL ) 554 { 555 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars) ); 556 } 557 else 558 { 559 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) ); 560 561 for( v = 0; v < nactivevars; ++v ) 562 activevals[v] = 1.0; 563 } 564 activevarssize = nactivevars; 565 566 /* retransform given variables to active variables */ 567 SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activevarssize, &activeconstant, transformed) ); 568 } 569 570 /* print row(s) in GAMS format */ 571 if( SCIPisEQ(scip, lhs, rhs) ) 572 { 573 assert( !SCIPisInfinity(scip, rhs) ); 574 575 /* print equality constraint */ 576 SCIP_CALL( printLinearRow(scip, file, rowname, "", "=e=", 577 nactivevars, activevars, activevals, rhs - activeconstant) ); 578 } 579 else 580 { 581 if( !SCIPisInfinity(scip, -lhs) ) 582 { 583 /* print inequality ">=" */ 584 SCIP_CALL( printLinearRow(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", "=g=", 585 nactivevars, activevars, activevals, lhs - activeconstant) ); 586 } 587 if( !SCIPisInfinity(scip, rhs) ) 588 { 589 /* print inequality "<=" */ 590 SCIP_CALL( printLinearRow(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "=l=", 591 nactivevars, activevars, activevals, rhs - activeconstant) ); 592 } 593 } 594 595 if( nvars > 0 ) 596 { 597 /* free buffer arrays */ 598 SCIPfreeBufferArray(scip, &activevars); 599 SCIPfreeBufferArray(scip, &activevals); 600 } 601 602 return SCIP_OKAY; 603 } 604 605 606 /* print indicator constraint in some GAMS format to file stream (performing retransformation to active variables) 607 * The constraints are of the following form: 608 * \f[ 609 * z = 1 -> s = 0 610 * \f] 611 * */ 612 static 613 SCIP_RETCODE printIndicatorCons( 614 SCIP* scip, /**< SCIP data structure */ 615 FILE* file, /**< output file (or NULL for standard output) */ 616 const char* rowname, /**< row name */ 617 SCIP_VAR* z, /**< indicating variable (binary) */ 618 SCIP_VAR* s, /**< slack variable */ 619 SCIP_Bool* sossetdeclr, /**< buffer to store whether we declared the SOS set for indicator reform */ 620 SCIP_Bool transformed /**< transformed constraint? */ 621 ) 622 { 623 char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' }; 624 int linecnt; 625 SCIP_Real coef; 626 char indicatorform; 627 628 char consname[GMS_MAX_NAMELEN + 30]; 629 char buffer[GMS_MAX_PRINTLEN]; 630 631 assert( scip != NULL ); 632 assert( strlen(rowname) > 0 ); 633 assert( z != NULL ); 634 assert( s != NULL ); 635 assert( SCIPvarIsBinary(z) ); 636 assert( sossetdeclr != NULL ); 637 638 clearLine(linebuffer, &linecnt); 639 640 /* start each line with a space */ 641 appendLine(scip, file, linebuffer, &linecnt, " "); 642 643 SCIP_CALL( SCIPgetCharParam(scip, "reading/gmsreader/indicatorreform", &indicatorform) ); 644 645 switch( indicatorform ) 646 { 647 case 'b': 648 { 649 /* print row name */ 650 (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s ..", rowname); 651 SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) ); 652 653 appendLine(scip, file, linebuffer, &linecnt, consname); 654 655 /* write as s <= upperbound(s)*(1-z) or s <= upperbound(s) * negation(z) */ 656 coef = 1.0; 657 SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, NULL, " =l= ", 1, &s, &coef, transformed) ); 658 659 coef = SCIPvarGetUbGlobal(s); 660 if( SCIPisInfinity(scip, coef) ) 661 { 662 SCIP_CALL( SCIPgetRealParam(scip, "reading/gmsreader/bigmdefault", &coef) ); 663 664 SCIPwarningMessage(scip, "do not have upper bound on slack variable <%s> in indicator constraint <%s>, will use M = %g.\n", 665 SCIPvarGetName(s), rowname, coef); 666 } 667 668 if( SCIPvarIsNegated(z) ) 669 { 670 SCIP_CALL( SCIPgetNegatedVar(scip, z, &z) ); 671 SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "", ";", 1, &z, &coef, transformed) ); 672 } 673 else 674 { 675 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%.15g + ", coef); 676 677 coef = -coef; 678 SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, buffer, ";", 1, &z, &coef, transformed) ); 679 } 680 681 break; 682 } 683 684 case 's': 685 { 686 /* write as 687 * sos1 Variable name_sos(sosset); 688 * name_soseq(sosset).. name_sos(sosset) =e= s$(sameas(sosset,'slack') + z$(sameas(sosset,'bin')); 689 */ 690 coef = 1.0; 691 SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, rowname) ); 692 693 /* declare set for SOS1 declarations from reformulation of indicator, if needed */ 694 if( !*sossetdeclr ) 695 { 696 SCIPinfoMessage(scip, file, " Set sosset / slack, bin /;\n"); 697 *sossetdeclr = TRUE; 698 } 699 700 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "sos1 Variable %s_sos(sosset);", consname); 701 appendLine(scip, file, linebuffer, &linecnt, buffer); 702 endLine(scip, file, linebuffer, &linecnt); 703 704 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s(sosset).. %s_sos(sosset) =e= ", consname, consname); 705 appendLine(scip, file, linebuffer, &linecnt, buffer); 706 SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, NULL, "$sameas(sosset,'slack')", 1, &s, &coef, transformed) ); 707 if( SCIPvarIsNegated(z) ) 708 { 709 SCIP_CALL( SCIPgetNegatedVar(scip, z, &z) ); 710 SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, " + (1-(", "))$sameas(sosset,'bin');", 1, &z, &coef, transformed) ); 711 } 712 else 713 { 714 SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, " + ", "$sameas(sosset,'bin');", 1, &z, &coef, transformed) ); 715 } 716 endLine(scip, file, linebuffer, &linecnt); 717 718 break; 719 } 720 721 default: 722 SCIPerrorMessage("wrong value '%c' for parameter reading/gmsreader/indicatorreform\n", indicatorform); 723 return SCIP_ERROR; 724 } 725 726 endLine(scip, file, linebuffer, &linecnt); 727 728 return SCIP_OKAY; 729 } 730 731 /* print SOS constraint in some GAMS format to file stream (performing retransformation to active variables) 732 * 733 * write as 734 * Set name_sosset /1*nvars/; 735 * SOS1/2 Variable name_sosvar(name_sosset); name_sosvar.lo(name_sosset) = -inf; 736 * Equation name_sosequ(e1_sosset); 737 * name_sosequ(name_sosset).. name_sosvar(e1_sosset) =e= 738 * vars[0]$sameas(name_sosset, '1') + vars[1]$sameas(name_sosset, '2') + ... + vars[nvars-1]$sameas(name_sosset, nvars); 739 */ 740 static 741 SCIP_RETCODE printSOSCons( 742 SCIP* scip, /**< SCIP data structure */ 743 FILE* file, /**< output file (or NULL for standard output) */ 744 const char* rowname, /**< row name */ 745 int nvars, /**< number of variables in SOS */ 746 SCIP_VAR** vars, /**< variables in SOS */ 747 int sostype, /**< type of SOS: 1 or 2 */ 748 SCIP_Bool transformed /**< transformed constraint? */ 749 ) 750 { 751 char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' }; 752 int linecnt; 753 SCIP_Real coef; 754 int v; 755 756 char consname[GMS_MAX_NAMELEN + 30]; 757 char buffer[GMS_MAX_PRINTLEN]; 758 759 assert( scip != NULL ); 760 assert( strlen(rowname) > 0 ); 761 assert( vars != NULL || nvars == 0 ); 762 assert( sostype == 1 || sostype == 2 ); 763 764 clearLine(linebuffer, &linecnt); 765 766 /* start each line with a space */ 767 appendLine(scip, file, linebuffer, &linecnt, " "); 768 769 SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, rowname) ); 770 771 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "Set %s_sosset /1*%d/;", consname, nvars); 772 appendLine(scip, file, linebuffer, &linecnt, buffer); 773 endLine(scip, file, linebuffer, &linecnt); 774 775 /* explicitly set lower bound of SOS variables to -inf, as GAMS default is 0.0 */ 776 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " SOS%d Variable %s_sosvar(%s_sosset); %s_sosvar.lo(%s_sosset) = -inf;", sostype, consname, consname, consname, consname); 777 appendLine(scip, file, linebuffer, &linecnt, buffer); 778 endLine(scip, file, linebuffer, &linecnt); 779 780 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s(%s_sosset).. %s_sosvar(%s_sosset) =e= ", consname, consname, consname, consname); 781 appendLine(scip, file, linebuffer, &linecnt, buffer); 782 endLine(scip, file, linebuffer, &linecnt); 783 784 coef = 1.0; 785 for( v = 0; v < nvars; ++v ) 786 { 787 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "$sameas(%s_sosset,'%d')", consname, v+1); 788 SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, v > 0 ? " + " : NULL, buffer, 1, &vars[v], &coef, transformed) ); /*lint !e613*/ 789 } 790 appendLine(scip, file, linebuffer, &linecnt, ";"); 791 endLine(scip, file, linebuffer, &linecnt); 792 793 return SCIP_OKAY; 794 } 795 796 /** prints expression in GAMS format to file stream */ 797 static 798 SCIP_RETCODE printExpr( 799 SCIP* scip, /**< SCIP data structure */ 800 FILE* file, /**< output file (or NULL for standard output) */ 801 char* linebuffer, /**< line buffer of length GMS_MAX_PRINTLEN */ 802 int* linecnt, /**< number of characters in line so far */ 803 SCIP_Bool* nsmooth, /**< buffer to store whether we printed a nonsmooth function */ 804 SCIP_Bool* nqcons, /**< buffer to update whether we are still quadratic */ 805 SCIP_Bool transformed, /**< expression belongs to transformed constraint? */ 806 SCIP_EXPR* expr /**< expression to print */ 807 ) 808 { 809 SCIP_EXPRITER* it; 810 SCIP_EXPRITER_STAGE stage; 811 int currentchild; 812 unsigned int parentprecedence; 813 long int fpos; 814 SCIP_VAR** activevars = NULL; 815 SCIP_Real* activecoefs = NULL; 816 int nactivevars; 817 int activevarssize; 818 SCIP_Real activeconstant = 0.0; 819 char varname[GMS_MAX_NAMELEN]; 820 unsigned int sumprecedence; 821 822 assert(scip != NULL); 823 assert(linebuffer != NULL); 824 assert(linecnt != NULL); 825 assert(nsmooth != NULL); 826 assert(nqcons != NULL); 827 assert(expr != NULL); 828 829 if( file == NULL ) 830 file = stdout; 831 832 appendLine(scip, file, linebuffer, linecnt, " "); 833 834 /* store file position at begin of current line */ 835 fpos = ftell(file) - *linecnt; 836 837 /* print out current buffer, as we print the expression directly to file */ 838 endLineNoNewline(scip, file, linebuffer, linecnt); 839 840 activevarssize = 5; 841 SCIP_CALL( SCIPallocBufferArray(scip, &activevars, activevarssize) ); 842 SCIP_CALL( SCIPallocBufferArray(scip, &activecoefs, activevarssize) ); 843 844 SCIP_CALL( SCIPcreateExpriter(scip, &it) ); 845 SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) ); 846 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ALLSTAGES); 847 848 sumprecedence = SCIPexprhdlrGetPrecedence(SCIPgetExprhdlrSum(scip)); 849 850 while( !SCIPexpriterIsEnd(it) ) 851 { 852 stage = SCIPexpriterGetStageDFS(it); 853 854 if( stage == SCIP_EXPRITER_VISITEDCHILD || stage == SCIP_EXPRITER_VISITINGCHILD ) 855 currentchild = SCIPexpriterGetChildIdxDFS(it); 856 else 857 currentchild = -1; 858 859 if( SCIPexpriterGetParentDFS(it) != NULL ) 860 parentprecedence = SCIPexprhdlrGetPrecedence(SCIPexprGetHdlr(SCIPexpriterGetParentDFS(it))); 861 else 862 parentprecedence = 0; 863 864 /* print a newline, if we have printed at least GMS_PRINTLEN chars since the last newline */ 865 if( ftell(file) > fpos + GMS_PRINTLEN ) 866 { 867 SCIPinfoMessage(scip, file, "\n "); 868 /* store file position at begin of current line again; the -5 is for the whitespace we printed already */ 869 fpos = ftell(file) - 5; 870 } 871 872 if( SCIPisExprVar(scip, expr) ) 873 { 874 /* special handler for variables: 875 * - map to active variables 876 * - pass variable name through printConformName 877 */ 878 if( stage == SCIP_EXPRITER_ENTEREXPR ) 879 { 880 activevars[0] = SCIPgetVarExprVar(expr); 881 activecoefs[0] = 1.0; 882 nactivevars = 1; 883 884 SCIP_CALL( getActiveVariables(scip, &activevars, &activecoefs, &nactivevars, &activevarssize, &activeconstant, transformed) ); 885 886 if( nactivevars == 1 && activecoefs[0] == 1.0 && activeconstant == 0.0 ) 887 { 888 SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(activevars[0])) ); 889 SCIPinfoMessage(scip, file, "%s", varname); 890 } 891 else 892 { 893 SCIP_Bool needsign = FALSE; 894 int i; 895 896 /* do as in print of expr_sum: an opening parenthesis may be required */ 897 if( sumprecedence <= parentprecedence ) 898 SCIPinfoMessage(scip, file, "("); 899 900 if( activeconstant != 0.0 ) 901 { 902 SCIPinfoMessage(scip, file, "%.15g", activeconstant); 903 needsign = TRUE; 904 } 905 for( i = 0; i < nactivevars; ++i ) 906 { 907 if( REALABS(activecoefs[i]) != 1.0 ) 908 { 909 SCIPinfoMessage(scip, file, needsign ? "%+.15g*" : "%.15g*", activecoefs[i]); 910 } 911 else if( activecoefs[i] == 1.0 && needsign ) 912 { 913 SCIPinfoMessage(scip, file, "+"); 914 } 915 else if( activecoefs[i] == -1.0 ) 916 { 917 SCIPinfoMessage(scip, file, "-"); 918 } 919 920 SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(activevars[0])) ); 921 SCIPinfoMessage(scip, file, "%s", varname); 922 923 needsign = TRUE; 924 925 /* check whether it is time for a linebreak */ 926 if( ftell(file) > fpos + GMS_PRINTLEN ) 927 { 928 SCIPinfoMessage(scip, file, "\n "); 929 fpos = ftell(file) - 5; 930 } 931 } 932 933 if( sumprecedence <= parentprecedence ) 934 SCIPinfoMessage(scip, file, ")"); 935 } 936 } 937 } 938 else if( SCIPisExprPower(scip, expr) ) 939 { 940 /* special handler for power */ 941 SCIP_Real exponent = SCIPgetExponentExprPow(expr); 942 943 if( exponent == 2.0 ) 944 { 945 /* write squares as "sqr(child)" */ 946 if( stage == SCIP_EXPRITER_ENTEREXPR ) 947 SCIPinfoMessage(scip, file, "sqr("); 948 else if( stage == SCIP_EXPRITER_LEAVEEXPR ) 949 SCIPinfoMessage(scip, file, ")"); 950 } 951 else if( EPSISINT(exponent, 0.0) ) /*lint !e835*/ 952 { 953 /* write integer powers as "power(child, exponent)" */ 954 if( stage == SCIP_EXPRITER_ENTEREXPR ) 955 SCIPinfoMessage(scip, file, "power("); 956 else if( stage == SCIP_EXPRITER_LEAVEEXPR ) 957 SCIPinfoMessage(scip, file, ",%g)", exponent); 958 /* if power but not square, then we are no longer quadratic */ 959 *nqcons = FALSE; 960 } 961 else if( exponent == 0.5 ) 962 { 963 /* write square roots as "sqrt(child)" */ 964 if( stage == SCIP_EXPRITER_ENTEREXPR ) 965 SCIPinfoMessage(scip, file, "sqrt("); 966 else if( stage == SCIP_EXPRITER_LEAVEEXPR ) 967 SCIPinfoMessage(scip, file, ")"); 968 *nqcons = FALSE; 969 } 970 else 971 { 972 /* write any other power as "(child)**exponent" */ 973 if( stage == SCIP_EXPRITER_ENTEREXPR ) 974 SCIPinfoMessage(scip, file, "("); 975 else if( stage == SCIP_EXPRITER_LEAVEEXPR ) 976 SCIPinfoMessage(scip, file, exponent >= 0.0 ? ")**%.15g" : ")**(%.15g)", exponent); 977 *nqcons = FALSE; 978 } 979 } 980 else 981 { 982 /* for any other expression, use the print callback of the exprhdlr */ 983 SCIP_CALL( SCIPcallExprPrint(scip, expr, stage, currentchild, parentprecedence, file) ); 984 985 if( !*nsmooth ) 986 { 987 /* check for expression types that require changing modeltype from NLP to DNLP: currently only abs */ 988 if( SCIPisExprAbs(scip, expr) ) 989 { 990 *nsmooth = TRUE; 991 *nqcons = FALSE; 992 } 993 } 994 995 /* if still quadratic, then check whether expression type is one that cannot occur in quadratics 996 * allowed are sum, product, value, var, and power; the latter two were handled above 997 */ 998 if( *nqcons && !SCIPisExprSum(scip, expr) && !SCIPisExprProduct(scip, expr) && !SCIPisExprValue(scip, expr) ) 999 *nqcons = FALSE; 1000 } 1001 1002 expr = SCIPexpriterGetNext(it); 1003 } 1004 1005 SCIPfreeExpriter(&it); 1006 1007 SCIPfreeBufferArray(scip, &activecoefs); 1008 SCIPfreeBufferArray(scip, &activevars); 1009 1010 return SCIP_OKAY; 1011 } 1012 1013 /** print nonlinear row in GAMS format to file stream */ 1014 static 1015 SCIP_RETCODE printNonlinearRow( 1016 SCIP* scip, /**< SCIP data structure */ 1017 FILE* file, /**< output file (or NULL for standard output) */ 1018 const char* rowname, /**< row name */ 1019 const char* rownameextension, /**< row name extension */ 1020 const char* type, /**< row type ("=e=", "=l=", or "=g=") */ 1021 SCIP_EXPR* expr, /**< expression */ 1022 SCIP_Real rhs, /**< right hand side */ 1023 SCIP_Bool transformed, /**< transformed constraint? */ 1024 SCIP_Bool* nsmooth, /**< buffer to store whether we printed a nonsmooth function */ 1025 SCIP_Bool* nqcons /**< buffer to update whether we are still quadratic */ 1026 ) 1027 { 1028 char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' }; 1029 int linecnt; 1030 char consname[GMS_MAX_NAMELEN + 3]; 1031 char buffer[GMS_MAX_PRINTLEN]; 1032 1033 assert( scip != NULL ); 1034 assert( strlen(rowname) > 0 || strlen(rownameextension) > 0 ); 1035 assert( strcmp(type, "=e=") == 0 || strcmp(type, "=l=") == 0 || strcmp(type, "=g=") == 0 ); 1036 1037 clearLine(linebuffer, &linecnt); 1038 1039 /* start each line with a space */ 1040 appendLine(scip, file, linebuffer, &linecnt, " "); 1041 1042 /* print row name */ 1043 (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s%s ..", rowname, rownameextension); 1044 SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) ); 1045 appendLine(scip, file, linebuffer, &linecnt, consname); 1046 1047 SCIP_CALL( printExpr(scip, file, linebuffer, &linecnt, nsmooth, nqcons, transformed, expr) ); 1048 1049 /* print right hand side */ 1050 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s %.15g;", type, rhs); 1051 appendLine(scip, file, linebuffer, &linecnt, buffer); 1052 1053 endLine(scip, file, linebuffer, &linecnt); 1054 1055 return SCIP_OKAY; 1056 } 1057 1058 /** print nonlinear row in GAMS format to file stream (performing retransformation to active linear variables) */ 1059 static 1060 SCIP_RETCODE printNonlinearCons( 1061 SCIP* scip, /**< SCIP data structure */ 1062 FILE* file, /**< output file (or NULL for standard output) */ 1063 const char* rowname, /**< row name */ 1064 SCIP_EXPR* expr, /**< expression */ 1065 SCIP_Real lhs, /**< left hand side */ 1066 SCIP_Real rhs, /**< right hand side */ 1067 SCIP_Bool transformed, /**< transformed constraint? */ 1068 SCIP_Bool* nsmooth, /**< buffer to store whether we printed a nonsmooth function */ 1069 SCIP_Bool* nqcons /**< buffer to update whether we are still quadratic */ 1070 ) 1071 { 1072 assert( scip != NULL ); 1073 assert( strlen(rowname) > 0 ); 1074 1075 /* print row(s) in GAMS format */ 1076 if( SCIPisEQ(scip, lhs, rhs) ) 1077 { 1078 assert( !SCIPisInfinity(scip, rhs) ); 1079 1080 /* print equality constraint */ 1081 SCIP_CALL( printNonlinearRow(scip, file, rowname, "", "=e=", expr, rhs, transformed, nsmooth, nqcons) ); 1082 } 1083 else 1084 { 1085 if( !SCIPisInfinity(scip, -lhs) ) 1086 { 1087 /* print inequality ">=" */ 1088 SCIP_CALL( printNonlinearRow(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", "=g=", expr, lhs, transformed, nsmooth, nqcons) ); 1089 } 1090 if( !SCIPisInfinity(scip, rhs) ) 1091 { 1092 /* print inequality "<=" */ 1093 SCIP_CALL( printNonlinearRow(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "=l=", expr, rhs, transformed, nsmooth, nqcons) ); 1094 } 1095 } 1096 1097 if( *nqcons ) 1098 { 1099 /* if we are still at most quadratic, check whether that is still the case when considering current constraint */ 1100 SCIP_CALL( SCIPcheckExprQuadratic(scip, expr, nqcons) ); 1101 if( *nqcons ) 1102 *nqcons = SCIPexprAreQuadraticExprsVariables(expr); 1103 } 1104 1105 return SCIP_OKAY; 1106 } 1107 1108 /** method check if the variable names are not longer than GMS_MAX_NAMELEN */ 1109 static 1110 SCIP_RETCODE checkVarnames( 1111 SCIP* scip, /**< SCIP data structure */ 1112 SCIP_VAR** vars, /**< array of variables */ 1113 int nvars /**< number of variables */ 1114 ) 1115 { 1116 int v; 1117 SCIP_VAR* var; 1118 SCIP_Bool replaceforbiddenchars; 1119 const char* badchar; 1120 1121 assert( scip != NULL ); 1122 assert( vars != NULL ); 1123 1124 SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/replaceforbiddenchars", &replaceforbiddenchars) ); 1125 1126 /* check if the variable names contain any of the bad symbols */ 1127 for( badchar = badchars; *badchar; ++badchar ) 1128 { 1129 for( v = 0; v < nvars; ++v ) 1130 { 1131 var = vars[v]; 1132 assert( var != NULL ); 1133 1134 if( strchr(SCIPvarGetName(var), *badchar) != NULL ) 1135 { 1136 if( replaceforbiddenchars ) 1137 { 1138 SCIPinfoMessage(scip, NULL, "there is a variable name with symbol '%c', not allowed in GAMS format; all '%c' replaced by '_' (consider using 'write genproblem'/'write gentransproblem').\n", *badchar, *badchar); 1139 } 1140 else 1141 { 1142 SCIPwarningMessage(scip, "there is a variable name with symbol '%c', not allowed in GAMS format; use 'write genproblem'/'write gentransproblem', or set 'reading/gmsreader/replaceforbiddenchars' to TRUE and risk duplicate variable names.\n", *badchar); 1143 } 1144 1145 break; 1146 } 1147 } 1148 } 1149 1150 /* check if the variable names are too long */ 1151 for( v = 0; v < nvars; ++v ) 1152 { 1153 var = vars[v]; 1154 assert( var != NULL ); 1155 1156 if( strlen(SCIPvarGetName(var)) > GMS_MAX_NAMELEN ) 1157 { 1158 SCIPwarningMessage(scip, "there is a variable name which has to be cut down to %d characters; GAMS model might be corrupted.\n", 1159 GMS_MAX_NAMELEN - 1); 1160 break; 1161 } 1162 } 1163 1164 return SCIP_OKAY; 1165 } 1166 1167 /** method check if the constraint names are not longer than GMS_MAX_NAMELEN */ 1168 static 1169 SCIP_RETCODE checkConsnames( 1170 SCIP* scip, /**< SCIP data structure */ 1171 SCIP_CONS** conss, /**< array of constraints */ 1172 int nconss, /**< number of constraints */ 1173 SCIP_Bool transformed /**< TRUE iff problem is the transformed problem */ 1174 ) 1175 { 1176 int c; 1177 SCIP_CONS* cons; 1178 SCIP_CONSHDLR* conshdlr; 1179 const char* conshdlrname; 1180 SCIP_Bool replaceforbiddenchars; 1181 const char* badchar; 1182 1183 assert( scip != NULL ); 1184 assert( conss != NULL ); 1185 1186 SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/replaceforbiddenchars", &replaceforbiddenchars) ); 1187 1188 /* check if the constraint names contain any of the bad symbols */ 1189 for( badchar = badchars; *badchar; ++badchar ) 1190 { 1191 for( c = 0; c < nconss; ++c ) 1192 { 1193 cons = conss[c]; 1194 assert( cons != NULL ); 1195 1196 if( strchr(SCIPconsGetName(cons), *badchar) != NULL ) 1197 { 1198 if( replaceforbiddenchars ) 1199 { 1200 SCIPinfoMessage(scip, NULL, "there is a constraint name with symbol '%c', not allowed in GAMS format; all '%c' replaced by '_' (consider using 'write genproblem'/'write gentransproblem').\n", *badchar, *badchar); 1201 } 1202 else 1203 { 1204 SCIPwarningMessage(scip, "there is a constraint name with symbol '%c', not allowed in GAMS format; use 'write genproblem'/'write gentransproblem', or set 'reading/gmsreader/replaceforbiddenchars' to TRUE and risk duplicate variable names.\n", *badchar); 1205 } 1206 1207 break; 1208 } 1209 } 1210 } 1211 1212 /* check if the constraint names are too long */ 1213 for( c = 0; c < nconss; ++c ) 1214 { 1215 cons = conss[c]; 1216 assert( cons != NULL ); 1217 1218 /* in case the transformed is written, only constraints are posted which are enabled in the current node */ 1219 assert(!transformed || SCIPconsIsEnabled(cons)); 1220 1221 conshdlr = SCIPconsGetHdlr(cons); 1222 assert( conshdlr != NULL ); 1223 1224 conshdlrname = SCIPconshdlrGetName(conshdlr); 1225 assert( transformed == SCIPconsIsTransformed(cons) ); 1226 1227 if( strcmp(conshdlrname, "linear") == 0 || strcmp(conshdlrname, "nonlinear") == 0 ) 1228 { 1229 SCIP_Real lhs = strcmp(conshdlrname, "linear") == 0 ? SCIPgetLhsLinear(scip, cons) : SCIPgetLhsNonlinear(cons); 1230 SCIP_Real rhs = strcmp(conshdlrname, "linear") == 0 ? SCIPgetLhsLinear(scip, cons) : SCIPgetRhsNonlinear(cons); 1231 1232 if( SCIPisEQ(scip, lhs, rhs) && strlen(SCIPconsGetName(conss[c])) > GMS_MAX_NAMELEN ) 1233 { 1234 SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n", 1235 GMS_MAX_NAMELEN - 1); 1236 break; 1237 } 1238 else if( !SCIPisEQ(scip, lhs, rhs) && strlen(SCIPconsGetName(conss[c])) > GMS_MAX_NAMELEN - 4 ) 1239 { 1240 SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n", 1241 GMS_MAX_NAMELEN - 5); 1242 break; 1243 } 1244 } 1245 else if( strlen(SCIPconsGetName(conss[c])) > GMS_MAX_NAMELEN ) 1246 { 1247 SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n", 1248 GMS_MAX_NAMELEN - 1); 1249 break; 1250 } 1251 } 1252 return SCIP_OKAY; 1253 } 1254 1255 1256 /* 1257 * Callback methods of reader 1258 */ 1259 1260 /** copy method for reader plugins (called when SCIP copies plugins) */ 1261 static 1262 SCIP_DECL_READERCOPY(readerCopyGms) 1263 { /*lint --e{715}*/ 1264 assert(scip != NULL); 1265 assert(reader != NULL); 1266 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); 1267 1268 /* call inclusion method of reader */ 1269 SCIP_CALL( SCIPincludeReaderGms(scip) ); 1270 1271 return SCIP_OKAY; 1272 } 1273 1274 1275 /** problem writing method of reader */ 1276 static 1277 SCIP_DECL_READERWRITE(readerWriteGms) 1278 { /*lint --e{715}*/ 1279 SCIP_CALL( SCIPwriteGms(scip, file, name, transformed, objsense, objscale, objoffset, vars, 1280 nvars, nbinvars, nintvars, nimplvars, ncontvars, conss, nconss, result) ); 1281 1282 return SCIP_OKAY; 1283 } 1284 1285 /* 1286 * reader specific interface methods 1287 */ 1288 1289 /** includes the gms file reader in SCIP */ 1290 SCIP_RETCODE SCIPincludeReaderGms( 1291 SCIP* scip /**< SCIP data structure */ 1292 ) 1293 { 1294 SCIP_READER* reader; 1295 1296 /* include reader */ 1297 SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, NULL) ); 1298 1299 /* set non fundamental callbacks via setter functions */ 1300 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyGms) ); 1301 SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteGms) ); 1302 1303 /* add gms reader parameters for writing routines*/ 1304 SCIP_CALL( SCIPaddBoolParam(scip, 1305 "reading/gmsreader/replaceforbiddenchars", "shall characters '#', '*', '+', '/', and '-' in variable and constraint names be replaced by '_'?", 1306 NULL, FALSE, FALSE, NULL, NULL) ); 1307 1308 SCIP_CALL( SCIPaddRealParam(scip, 1309 "reading/gmsreader/bigmdefault", "default M value for big-M reformulation of indicator constraints in case no bound on slack variable is given", 1310 NULL, FALSE, GMS_DEFAULT_BIGM, 0.0, SCIP_REAL_MAX, NULL, NULL) ); 1311 1312 SCIP_CALL( SCIPaddCharParam(scip, 1313 "reading/gmsreader/indicatorreform", "which reformulation to use for indicator constraints: 'b'ig-M, 's'os1", 1314 NULL, FALSE, GMS_DEFAULT_INDICATORREFORM, "bs", NULL, NULL) ); 1315 1316 SCIP_CALL( SCIPaddBoolParam(scip, 1317 "reading/gmsreader/signpower", "is it allowed to use the gams function signpower(x,a)?", 1318 NULL, FALSE, GMS_DEFAULT_SIGNPOWER, NULL, NULL) ); 1319 1320 return SCIP_OKAY; 1321 } 1322 1323 1324 /** writes problem to gms file */ 1325 SCIP_RETCODE SCIPwriteGms( 1326 SCIP* scip, /**< SCIP data structure */ 1327 FILE* file, /**< output file, or NULL if standard output should be used */ 1328 const char* name, /**< problem name */ 1329 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */ 1330 SCIP_OBJSENSE objsense, /**< objective sense */ 1331 SCIP_Real objscale, /**< scalar applied to objective function; external objective value is 1332 * extobj = objsense * objscale * (intobj + objoffset) */ 1333 SCIP_Real objoffset, /**< objective offset from bound shifting and fixing */ 1334 SCIP_VAR** vars, /**< array with active variables ordered binary, integer, implicit, continuous */ 1335 int nvars, /**< number of active variables in the problem */ 1336 int nbinvars, /**< number of binary variables */ 1337 int nintvars, /**< number of general integer variables */ 1338 int nimplvars, /**< number of implicit integer variables */ 1339 int ncontvars, /**< number of continuous variables */ 1340 SCIP_CONS** conss, /**< array with constraints of the problem */ 1341 int nconss, /**< number of constraints in the problem */ 1342 SCIP_RESULT* result /**< pointer to store the result of the file writing call */ 1343 ) 1344 { 1345 int c; 1346 int v; 1347 int linecnt; 1348 char linebuffer[GMS_MAX_PRINTLEN+1]; 1349 1350 char varname[GMS_MAX_NAMELEN]; 1351 char buffer[GMS_MAX_PRINTLEN]; 1352 1353 SCIP_Real* objcoeffs; 1354 1355 SCIP_CONSHDLR* conshdlr; 1356 const char* conshdlrname; 1357 SCIP_CONS* cons; 1358 1359 char consname[GMS_MAX_NAMELEN]; 1360 1361 SCIP_VAR** consvars; 1362 SCIP_Real* consvals; 1363 int nconsvars; 1364 1365 SCIP_VAR* var; 1366 SCIP_VAR* objvar; 1367 SCIP_Real lb; 1368 SCIP_Real ub; 1369 SCIP_Bool nondefbounds; 1370 SCIP_Bool nlcons = FALSE; /* whether there are nonlinear constraints */ 1371 SCIP_Bool nqcons = TRUE; /* whether nonlinear constraints are at most quadratic */ 1372 SCIP_Bool nsmooth = FALSE; /* whether there are nonsmooth nonlinear constraints */ 1373 SCIP_Bool discrete; 1374 SCIP_Bool rangedrow; 1375 SCIP_Bool indicatorsosdef; 1376 SCIP_Bool signpowerallowed; 1377 SCIP_Bool needcomma; 1378 1379 assert( scip != NULL ); 1380 assert( vars != NULL || nvars == 0 ); 1381 1382 /* check if the variable names are not too long */ 1383 SCIP_CALL( checkVarnames(scip, vars, nvars) ); 1384 /* check if the constraint names are too long */ 1385 SCIP_CALL( checkConsnames(scip, conss, nconss, transformed) ); 1386 1387 SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/signpower", &signpowerallowed) ); 1388 1389 /* check if the objective is a single continuous variable, so we would not have to introduce an auxiliary variable 1390 * for GAMS 1391 */ 1392 objvar = NULL; 1393 if( objscale == 1.0 && objoffset == 0.0 ) 1394 { 1395 for( v = 0; v < nvars; ++v ) 1396 { 1397 if( SCIPvarGetObj(vars[v]) == 0.0 ) /*lint !e613*/ 1398 continue; 1399 1400 if( objvar == NULL ) 1401 { 1402 /* first variable with nonzero obj coefficient 1403 * if not active or having coefficient != 1.0, or being binary/integer, then give up 1404 */ 1405 if( !SCIPvarIsActive(vars[v]) || SCIPvarGetObj(vars[v]) != 1.0 || 1406 SCIPvarGetType(vars[v]) < SCIP_VARTYPE_IMPLINT ) /*lint !e613*/ 1407 break; 1408 1409 objvar = vars[v]; /*lint !e613*/ 1410 } 1411 else 1412 { 1413 /* second variable with nonzero obj coefficient -> give up */ 1414 objvar = NULL; 1415 break; 1416 } 1417 } 1418 } 1419 1420 /* print statistics as comment to file */ 1421 SCIPinfoMessage(scip, file, "$OFFLISTING\n"); 1422 SCIPinfoMessage(scip, file, "* SCIP STATISTICS\n"); 1423 SCIPinfoMessage(scip, file, "* Problem name : %s\n", name); 1424 SCIPinfoMessage(scip, file, "* Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n", 1425 nvars, nbinvars, nintvars, nimplvars, ncontvars); 1426 SCIPinfoMessage(scip, file, "* Constraints : %d\n\n", nconss); 1427 1428 /* print flags */ 1429 SCIPinfoMessage(scip, file, "$MAXCOL %d\n", GMS_MAX_LINELEN - 1); 1430 SCIPinfoMessage(scip, file, "$OFFDIGIT\n\n"); 1431 1432 /* print variable section */ 1433 SCIPinfoMessage(scip, file, "Variables\n"); 1434 clearLine(linebuffer, &linecnt); 1435 1436 if( objvar == NULL ) 1437 { 1438 /* auxiliary objective variable */ 1439 SCIPinfoMessage(scip, file, " objvar%c", nvars > 0 ? ',' : ';'); 1440 } 1441 1442 /* "model" variables */ 1443 for( v = 0; v < nvars; ++v ) 1444 { 1445 var = vars[v]; /*lint !e613*/ 1446 assert( var != NULL ); 1447 1448 SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) ); 1449 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%c", varname, (v < nvars - 1) ? ',' : ';'); 1450 appendLine(scip, file, linebuffer, &linecnt, buffer); 1451 1452 if( (linecnt > 0 && (v == nbinvars - 1 || v == nbinvars + nintvars - 1 || 1453 v == nbinvars + nintvars + nimplvars - 1)) || v == nvars - 1 ) 1454 { 1455 endLine(scip, file, linebuffer, &linecnt); 1456 clearLine(linebuffer, &linecnt); 1457 } 1458 } 1459 1460 SCIPinfoMessage(scip, file, "\n"); 1461 1462 /* declare binary variables if present */ 1463 if( nbinvars > 0 ) 1464 { 1465 SCIPinfoMessage(scip, file, "Binary variables\n"); 1466 clearLine(linebuffer, &linecnt); 1467 1468 for( v = 0; v < nbinvars; ++v ) 1469 { 1470 var = vars[v]; /*lint !e613*/ 1471 1472 SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) ); 1473 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%s", varname, (v < nbinvars - 1) ? "," : ";"); 1474 1475 appendLine(scip, file, linebuffer, &linecnt, buffer); 1476 } 1477 1478 endLine(scip, file, linebuffer, &linecnt); 1479 SCIPinfoMessage(scip, file, "\n"); 1480 } 1481 1482 /* declare integer variables if present */ 1483 if( nintvars > 0 ) 1484 { 1485 SCIPinfoMessage(scip, file, "Integer variables\n"); 1486 clearLine(linebuffer, &linecnt); 1487 1488 for( v = 0; v < nintvars; ++v ) 1489 { 1490 var = vars[nbinvars + v]; /*lint !e613*/ 1491 1492 SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) ); 1493 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%s", varname, (v < nintvars - 1) ? "," : ";"); 1494 1495 appendLine(scip, file, linebuffer, &linecnt, buffer); 1496 } 1497 endLine(scip, file, linebuffer, &linecnt); 1498 SCIPinfoMessage(scip, file, "\n"); 1499 } 1500 1501 /* print variable bounds */ 1502 SCIPinfoMessage(scip, file, "* Variable bounds\n"); 1503 nondefbounds = FALSE; 1504 1505 for( v = 0; v < nvars; ++v ) 1506 { 1507 var = vars[v]; /*lint !e613*/ 1508 assert( var != NULL ); 1509 1510 SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) ); 1511 1512 if( transformed ) 1513 { 1514 /* in case the transformed is written only local bounds are posted which are valid in the current node */ 1515 lb = SCIPvarGetLbLocal(var); 1516 ub = SCIPvarGetUbLocal(var); 1517 } 1518 else 1519 { 1520 lb = SCIPvarGetLbOriginal(var); 1521 ub = SCIPvarGetUbOriginal(var); 1522 } 1523 assert( lb <= ub ); 1524 1525 /* fixed */ 1526 if( SCIPisEQ(scip, lb, ub) ) 1527 { 1528 if( v < nintvars ) 1529 SCIPinfoMessage(scip, file, " %s.fx = %g;\n", varname, SCIPfloor(scip, lb + 0.5)); 1530 else 1531 SCIPinfoMessage(scip, file, " %s.fx = %.15g;\n", varname, lb); 1532 nondefbounds = TRUE; 1533 1534 /* no need to write lower and upper bounds additionally */ 1535 continue; 1536 } 1537 1538 /* lower bound */ 1539 if( v < nbinvars + nintvars ) 1540 { 1541 /* default lower bound of binaries and integers is 0 */ 1542 if( !SCIPisZero(scip, lb) ) 1543 { 1544 if( !SCIPisInfinity(scip, -lb) ) 1545 SCIPinfoMessage(scip, file, " %s.lo = %g;\n", varname, SCIPceil(scip, lb)); 1546 else 1547 SCIPinfoMessage(scip, file, " %s.lo = -inf;\n", varname); 1548 nondefbounds = TRUE; 1549 } 1550 } 1551 else if( v >= nbinvars + nintvars && !SCIPisInfinity(scip, -lb) ) 1552 { 1553 /* continuous variables are free by default */ 1554 SCIPinfoMessage(scip, file, " %s.lo = %.15g;\n", varname, lb); 1555 nondefbounds = TRUE; 1556 } 1557 1558 /* upper bound */ 1559 if( v < nbinvars ) 1560 { 1561 /* binary variables have default upper bound 1.0 */ 1562 if( !SCIPisFeasEQ(scip, ub, 1.0) ) 1563 { 1564 SCIPinfoMessage(scip, file, " %s.up = %g;\n", varname, SCIPfeasFloor(scip, ub)); 1565 nondefbounds = TRUE; 1566 } 1567 } 1568 else if( v < nbinvars + nintvars ) 1569 { 1570 /* integer variables have default upper bound +inf */ 1571 if( !SCIPisInfinity(scip, ub) ) 1572 { 1573 SCIPinfoMessage(scip, file, " %s.up = %g;\n", varname, SCIPfeasFloor(scip, ub)); 1574 nondefbounds = TRUE; 1575 } 1576 } 1577 else 1578 { 1579 /* continuous variables have default upper bound +inf */ 1580 if( !SCIPisInfinity(scip, ub) ) 1581 { 1582 SCIPinfoMessage(scip, file, " %s.up = %.15g;\n", varname, ub); 1583 nondefbounds = TRUE; 1584 } 1585 } 1586 } 1587 1588 if( !nondefbounds ) 1589 SCIPinfoMessage(scip, file, "* (All other bounds at default value: binary [0,1], integer [0,+inf], continuous [-inf,+inf].)\n"); 1590 SCIPinfoMessage(scip, file, "\n"); 1591 1592 /* print equations section */ 1593 if( nconss > 0 || objvar == NULL ) 1594 { 1595 SCIPinfoMessage(scip, file, "Equations\n"); 1596 clearLine(linebuffer, &linecnt); 1597 } 1598 needcomma = FALSE; 1599 1600 if( objvar == NULL ) 1601 { 1602 SCIPinfoMessage(scip, file, " objequ"); 1603 needcomma = TRUE; 1604 } 1605 1606 /* declare equations */ 1607 for( c = 0; c < nconss; ++c ) 1608 { 1609 cons = conss[c]; 1610 assert( cons != NULL ); 1611 1612 conshdlr = SCIPconsGetHdlr(cons); 1613 assert( conshdlr != NULL ); 1614 1615 SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, SCIPconsGetName(cons)) ); 1616 conshdlrname = SCIPconshdlrGetName(conshdlr); 1617 assert( transformed == SCIPconsIsTransformed(cons) ); 1618 1619 rangedrow = strcmp(conshdlrname, "linear") == 0 1620 && !SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, cons)) && !SCIPisInfinity(scip, SCIPgetRhsLinear(scip, cons)) 1621 && !SCIPisEQ(scip, SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons)); 1622 rangedrow = rangedrow || (strcmp(conshdlrname, "nonlinear") == 0 1623 && !SCIPisInfinity(scip, -SCIPgetLhsNonlinear(cons)) && !SCIPisInfinity(scip, SCIPgetRhsNonlinear(cons)) 1624 && !SCIPisEQ(scip, SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons))); 1625 rangedrow = rangedrow || (strcmp(conshdlrname, "varbound") == 0 1626 && !SCIPisInfinity(scip, -SCIPgetLhsVarbound(scip, cons)) && !SCIPisInfinity(scip, SCIPgetRhsVarbound(scip, cons)) 1627 && !SCIPisEQ(scip, SCIPgetLhsVarbound(scip, cons), SCIPgetRhsVarbound(scip, cons))); 1628 1629 /* we declare only those constraints which we can print in GAMS format */ 1630 if( strcmp(conshdlrname, "knapsack") != 0 && strcmp(conshdlrname, "logicor") != 0 && strcmp(conshdlrname, "setppc") != 0 1631 && strcmp(conshdlrname, "linear") != 0 && strcmp(conshdlrname, "SOS1") != 0 && strcmp(conshdlrname, "SOS2") != 0 1632 && strcmp(conshdlrname, "nonlinear") != 0 1633 && strcmp(conshdlrname, "varbound") != 0 1634 && strcmp(conshdlrname, "indicator") != 0 ) 1635 { 1636 SCIPwarningMessage(scip, "Constraint type <%s> not supported. Skip writing constraint <%s>.\n", conshdlrname, SCIPconsGetName(cons)); 1637 continue; 1638 } 1639 1640 if( needcomma ) 1641 appendLine(scip, file, linebuffer, &linecnt, ","); 1642 1643 SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, SCIPconsGetName(cons)) ); 1644 if( rangedrow ) 1645 { 1646 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%s%s%s", consname, "_lhs, ", consname, "_rhs"); 1647 appendLine(scip, file, linebuffer, &linecnt, buffer); 1648 } 1649 else 1650 { 1651 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s", consname); 1652 appendLine(scip, file, linebuffer, &linecnt, buffer); 1653 } 1654 needcomma = TRUE; 1655 } 1656 1657 if( nconss > 0 || objvar == NULL ) 1658 { 1659 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, ";"); 1660 appendLine(scip, file, linebuffer, &linecnt, buffer); 1661 1662 endLine(scip, file, linebuffer, &linecnt); 1663 SCIPinfoMessage(scip, file, "\n"); 1664 } 1665 1666 if( objvar == NULL ) 1667 { 1668 /* print objective function equation */ 1669 clearLine(linebuffer, &linecnt); 1670 if( objoffset != 0.0 ) 1671 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " objequ .. objvar =e= %.15g + ", objscale * objoffset); 1672 else 1673 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " objequ .. objvar =e= "); 1674 appendLine(scip, file, linebuffer, &linecnt, buffer); 1675 1676 SCIP_CALL( SCIPallocBufferArray(scip, &objcoeffs, nvars) ); 1677 1678 for( v = 0; v < nvars; ++v ) 1679 { 1680 var = vars[v]; /*lint !e613*/ 1681 assert( var != NULL ); 1682 1683 /* in case the original problem has to be posted the variables have to be either "original" or "negated" */ 1684 assert( transformed || SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED ); 1685 1686 objcoeffs[v] = SCIPisZero(scip, SCIPvarGetObj(var)) ? 0.0 : objscale * SCIPvarGetObj(var); 1687 } 1688 1689 SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "", ";", nvars, vars, objcoeffs, transformed) ); 1690 1691 SCIPfreeBufferArray(scip, &objcoeffs); 1692 endLine(scip, file, linebuffer, &linecnt); 1693 SCIPinfoMessage(scip, file, "\n"); 1694 } 1695 1696 /* print constraints */ 1697 discrete = nbinvars > 0 || nintvars > 0; 1698 indicatorsosdef = FALSE; 1699 for( c = 0; c < nconss; ++c ) 1700 { 1701 cons = conss[c]; 1702 assert( cons != NULL ); 1703 1704 /* in case the transformed is written, only constraints are posted which are enabled in the current node */ 1705 assert(!transformed || SCIPconsIsEnabled(cons)); 1706 1707 conshdlr = SCIPconsGetHdlr(cons); 1708 assert( conshdlr != NULL ); 1709 1710 SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, SCIPconsGetName(cons)) ); 1711 conshdlrname = SCIPconshdlrGetName(conshdlr); 1712 assert( transformed == SCIPconsIsTransformed(cons) ); 1713 1714 if( strcmp(conshdlrname, "knapsack") == 0 ) 1715 { 1716 SCIP_Longint* weights; 1717 1718 consvars = SCIPgetVarsKnapsack(scip, cons); 1719 nconsvars = SCIPgetNVarsKnapsack(scip, cons); 1720 1721 /* copy Longint array to SCIP_Real array */ 1722 weights = SCIPgetWeightsKnapsack(scip, cons); 1723 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) ); 1724 for( v = 0; v < nconsvars; ++v ) 1725 consvals[v] = (SCIP_Real)weights[v]; 1726 1727 SCIP_CALL( printLinearCons(scip, file, consname, nconsvars, consvars, consvals, 1728 -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), transformed) ); 1729 1730 SCIPfreeBufferArray(scip, &consvals); 1731 } 1732 else if( strcmp(conshdlrname, "linear") == 0 ) 1733 { 1734 SCIP_CALL( printLinearCons(scip, file, consname, 1735 SCIPgetNVarsLinear(scip, cons), SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons), 1736 SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons), transformed) ); 1737 } 1738 else if( strcmp(conshdlrname, "logicor") == 0 ) 1739 { 1740 SCIP_CALL( printLinearCons(scip, file, consname, 1741 SCIPgetNVarsLogicor(scip, cons), SCIPgetVarsLogicor(scip, cons), NULL, 1742 1.0, SCIPinfinity(scip), transformed) ); 1743 } 1744 else if( strcmp(conshdlrname, "nonlinear") == 0 ) 1745 { 1746 SCIP_CALL( printNonlinearCons(scip, file, consname, 1747 SCIPgetExprNonlinear(cons), SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), transformed, &nsmooth, &nqcons) ); 1748 nlcons = TRUE; 1749 } 1750 else if( strcmp(conshdlrname, "setppc") == 0 ) 1751 { 1752 consvars = SCIPgetVarsSetppc(scip, cons); 1753 nconsvars = SCIPgetNVarsSetppc(scip, cons); 1754 1755 switch( SCIPgetTypeSetppc(scip, cons) ) 1756 { 1757 case SCIP_SETPPCTYPE_PARTITIONING : 1758 SCIP_CALL( printLinearCons(scip, file, consname, 1759 nconsvars, consvars, NULL, 1.0, 1.0, transformed) ); 1760 break; 1761 case SCIP_SETPPCTYPE_PACKING : 1762 SCIP_CALL( printLinearCons(scip, file, consname, 1763 nconsvars, consvars, NULL, -SCIPinfinity(scip), 1.0, transformed) ); 1764 break; 1765 case SCIP_SETPPCTYPE_COVERING : 1766 SCIP_CALL( printLinearCons(scip, file, consname, 1767 nconsvars, consvars, NULL, 1.0, SCIPinfinity(scip), transformed) ); 1768 break; 1769 } 1770 } 1771 else if( strcmp(conshdlrname, "varbound") == 0 ) 1772 { 1773 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) ); 1774 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) ); 1775 1776 consvars[0] = SCIPgetVarVarbound(scip, cons); 1777 consvars[1] = SCIPgetVbdvarVarbound(scip, cons); 1778 1779 consvals[0] = 1.0; 1780 consvals[1] = SCIPgetVbdcoefVarbound(scip, cons); 1781 1782 SCIP_CALL( printLinearCons(scip, file, consname, 1783 2, consvars, consvals, 1784 SCIPgetLhsVarbound(scip, cons), SCIPgetRhsVarbound(scip, cons), transformed) ); 1785 1786 SCIPfreeBufferArray(scip, &consvars); 1787 SCIPfreeBufferArray(scip, &consvals); 1788 } 1789 else if( strcmp(conshdlrname, "indicator") == 0 ) 1790 { 1791 SCIP_CALL( printIndicatorCons(scip, file, consname, 1792 SCIPgetBinaryVarIndicator(cons), SCIPgetSlackVarIndicator(cons), &indicatorsosdef, 1793 transformed) ); 1794 } 1795 else if( strcmp(conshdlrname, "SOS1") == 0 ) 1796 { 1797 SCIP_CALL( printSOSCons(scip, file, consname, 1798 SCIPgetNVarsSOS1(scip, cons), SCIPgetVarsSOS1(scip, cons), 1, 1799 transformed) ); 1800 discrete = TRUE; 1801 } 1802 else if( strcmp(conshdlrname, "SOS2") == 0 ) 1803 { 1804 SCIP_CALL( printSOSCons(scip, file, consname, 1805 SCIPgetNVarsSOS2(scip, cons), SCIPgetVarsSOS2(scip, cons), 2, 1806 transformed) ); 1807 discrete = TRUE; 1808 } 1809 else 1810 { 1811 SCIPwarningMessage(scip, "constraint handler <%s> cannot print requested format\n", conshdlrname ); 1812 SCIPinfoMessage(scip, file, "* "); 1813 SCIP_CALL( SCIPprintCons(scip, cons, file) ); 1814 SCIPinfoMessage(scip, file, ";\n"); 1815 } 1816 1817 SCIPinfoMessage(scip, file, "\n"); 1818 } 1819 /* if at most quadratic, then cannot have nonsmooth functions */ 1820 assert(nlcons || !nsmooth); 1821 1822 /* print model creation */ 1823 SCIPinfoMessage(scip, file, "Model m / all /;\n\n"); 1824 1825 /* set some options to reduce listing file size */ 1826 SCIPinfoMessage(scip, file, "option limrow = 0;\n"); 1827 SCIPinfoMessage(scip, file, "option limcol = 0;\n"); 1828 /* if GAMS >= 24.2, then set option to ensure default upper bound on integer vars is inf (since 32.1 this is also the default) */ 1829 SCIPinfoMessage(scip, file, "$if gamsversion 242 option intvarup = 0;\n\n"); 1830 1831 /* print solve command */ 1832 (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%s", 1833 discrete ? "MI" : "", nlcons ? (nqcons ? "QCP" : ((nsmooth && !discrete) ? "DNLP" : "NLP")) : (discrete > 0 ? "P" : "LP")); 1834 1835 if( objvar != NULL ) 1836 { 1837 SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(objvar)) ); 1838 } 1839 1840 SCIPinfoMessage(scip, file, "$if not set %s $set %s %s\n", buffer, buffer, buffer); 1841 SCIPinfoMessage(scip, file, "Solve m using %%%s%% %simizing %s;\n", 1842 buffer, objsense == SCIP_OBJSENSE_MINIMIZE ? "min" : "max", objvar != NULL ? varname : "objvar"); 1843 1844 *result = SCIP_SUCCESS; 1845 1846 return SCIP_OKAY; 1847 } 1848