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_zpl.c 26 * @ingroup DEFPLUGINS_READER 27 * @brief ZIMPL model file reader 28 * @author Tobias Achterberg 29 * @author Timo Berthold 30 */ 31 32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 33 34 #include "scip/reader_zpl.h" 35 36 #ifdef SCIP_WITH_ZIMPL 37 38 #include <unistd.h> 39 #include <stdbool.h> 40 #include <string.h> 41 42 #include "scip/cons_indicator.h" 43 #include "scip/cons_linear.h" 44 #include "scip/cons_sos1.h" 45 #include "scip/cons_sos2.h" 46 #include "scip/pub_misc.h" 47 #include "scip/pub_nlp.h" 48 #include "scip/pub_reader.h" 49 #include "scip/pub_var.h" 50 #include "scip/scip_cons.h" 51 #include "scip/scip_general.h" 52 #include "scip/scip_mem.h" 53 #include "scip/scip_message.h" 54 #include "scip/scip_numerics.h" 55 #include "scip/scip_param.h" 56 #include "scip/scip_prob.h" 57 #include "scip/scip_reader.h" 58 #include "scip/scip_sol.h" 59 #include "scip/scip_var.h" 60 #include "scip/cons_nonlinear.h" 61 #include "scip/struct_misc.h" 62 #include "scip/expr_pow.h" 63 #include "scip/expr_log.h" 64 #include "scip/expr_exp.h" 65 #include "scip/expr_abs.h" 66 #include "scip/expr_sum.h" 67 #include "scip/expr_trig.h" 68 #include "scip/expr_product.h" 69 #include "scip/pub_expr.h" 70 #include "scip/type_reader.h" 71 72 #ifdef __cplusplus 73 extern "C" { 74 #endif 75 76 /* @Note: Due to dependencies we need the following order. */ 77 /* include the ZIMPL headers necessary to define the LP and MINLP construction interface */ 78 #include "zimpl/attribute.h" 79 #include "zimpl/ratlptypes.h" 80 #include "zimpl/lint.h" 81 #include "zimpl/mme.h" 82 83 #include "zimpl/numb.h" 84 #include "zimpl/bound.h" 85 #include "zimpl/mono.h" 86 #include "zimpl/term.h" 87 88 #include "zimpl/xlpglue.h" 89 #include "zimpl/zimpllib.h" 90 91 #ifdef __cplusplus 92 } 93 #endif 94 95 #define READER_NAME "zplreader" 96 #define READER_DESC "file reader for ZIMPL model files" 97 #define READER_EXTENSION "zpl" 98 99 /* 100 * LP construction interface of ZIMPL 101 */ 102 103 /* we only support ZIMPL with a version higher than 3.4.1 */ 104 #if (ZIMPL_VERSION >= 341) 105 106 /* ZIMPL does not support user data in callbacks - we have to use static variables */ 107 struct 108 SCIP_ReaderData 109 { 110 SCIP* scip; /**< scip data structure */ 111 SCIP_SOL* sol; /**< primal solution candidate */ 112 SCIP_Bool valid; /**< is the primal solution candidate valid */ 113 SCIP_Bool branchpriowarning; /**< store if the waring regarding fractional value for the branching 114 * priority was already posted */ 115 SCIP_Bool initialconss; /**< should model constraints be marked as initial? */ 116 SCIP_Bool dynamicconss; /**< should model constraints be subject to aging? */ 117 SCIP_Bool dynamiccols; /**< should columns be added and removed dynamically to the LP? */ 118 SCIP_Bool dynamicrows; /**< should rows be added and removed dynamically to the LP? */ 119 SCIP_Bool readerror; /**< was a reading error be discovered */ 120 SCIP_RETCODE retcode; /**< store a none SCIP_OKAY return code if an error occurred */ 121 }; 122 123 /** create problem */ 124 static 125 SCIP_RETCODE createProb( 126 SCIP* scip, /**< SCIP data structure */ 127 SCIP_READERDATA* readerdata, /**< reader data */ 128 const char* name /**< name of the problem */ 129 ) 130 { 131 SCIP_Bool usestartsol; 132 133 /* create problem */ 134 SCIP_CALL( SCIPcreateProb(scip, name, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); 135 136 /* check if are interested in the primal solution candidate */ 137 SCIP_CALL( SCIPgetBoolParam(scip, "reading/zplreader/usestartsol", &usestartsol) ); 138 139 if( usestartsol ) 140 { 141 /* create primal solution */ 142 SCIP_CALL( SCIPcreateSol(scip, &readerdata->sol, NULL) ); 143 readerdata->valid = TRUE; 144 } 145 146 return SCIP_OKAY; 147 } 148 149 /** Allocate storage for the mathematical program instance generated by ZIMPL. xlp_alloc() is the first xlpglue routine 150 * that will be called by ZIMPL. The user_data pointer may hold an arbitray value. 151 */ 152 Lps* xlp_alloc( 153 const char* name, /**< name of the problem */ 154 bool need_startval, /**< does ZIMPL provides a primal solution candidate */ 155 void* user_data /**< user data which was previously passed to ZIMPL */ 156 ) 157 { /*lint --e{715}*/ 158 SCIP* scip; 159 SCIP_READERDATA* readerdata; 160 161 readerdata = (SCIP_READERDATA*)user_data; 162 assert(readerdata != NULL); 163 assert(readerdata->retcode == SCIP_OKAY); 164 assert(!readerdata->readerror); 165 166 scip = readerdata->scip; 167 assert(scip != NULL); 168 169 readerdata->retcode = createProb(scip, readerdata, name); 170 171 /* return the reader data pointer to receive it all other ZIMPL call backs */ 172 return (Lps*) readerdata; 173 } 174 175 /** free storage for mathematical program. xlp_free() is the last xlpglue routine that will be called by Zimpl */ 176 void xlp_free( 177 Lps* data /**< pointer to reader data */ 178 ) 179 { /*lint --e{715}*/ 180 /* nothing to be done here */ 181 } 182 183 /** does there already exists a constraint with the given name? */ 184 bool xlp_conname_exists( 185 const Lps* data, /**< pointer to reader data */ 186 const char* name /**< constraint name to check */ 187 ) 188 { 189 SCIP_READERDATA* readerdata; 190 191 readerdata = (SCIP_READERDATA*)data; 192 assert(readerdata != NULL); 193 194 /* check if constraint with the given name already exists */ 195 return (SCIPfindCons(readerdata->scip, name) != NULL); 196 } 197 198 /** create a SCIP expression from a ZIMPL term 199 * 200 * Returns *expr == NULL if could not create expression due to unsupported ZIMPL functions. 201 */ 202 static 203 SCIP_RETCODE createExpr( 204 SCIP* scip, /**< SCIP data structure */ 205 SCIP_READERDATA* readerdata, /**< reader data */ 206 SCIP_EXPR** expr, /**< buffer to store expression */ 207 const Term* term /**< term to convert to expression */ 208 ) 209 { 210 assert(scip != NULL); 211 assert(readerdata != NULL); 212 assert(expr != NULL); 213 assert(term != NULL); 214 215 *expr = NULL; 216 217 if( term_get_degree(term) == 2 ) 218 { 219 int nlinvars; 220 int nquadterms; 221 SCIP_VAR** linvars; 222 SCIP_VAR** quadvar1; 223 SCIP_VAR** quadvar2; 224 SCIP_Real* lincoefs; 225 SCIP_Real* quadcoefs; 226 Mono* monom; 227 int i; 228 229 nlinvars = 0; 230 nquadterms = 0; 231 232 SCIP_CALL( SCIPallocBufferArray(scip, &linvars, term_get_elements(term)) ); 233 SCIP_CALL( SCIPallocBufferArray(scip, &quadvar1, term_get_elements(term)) ); 234 SCIP_CALL( SCIPallocBufferArray(scip, &quadvar2, term_get_elements(term)) ); 235 SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, term_get_elements(term)) ); 236 SCIP_CALL( SCIPallocBufferArray(scip, &quadcoefs, term_get_elements(term)) ); 237 238 for( i = 0; i < term_get_elements(term); ++i ) 239 { 240 monom = term_get_element(term, i); 241 assert(!numb_equal(mono_get_coeff(monom), numb_zero())); 242 assert(mono_get_degree(monom) <= 2); 243 assert(mono_get_degree(monom) > 0); 244 if (mono_get_degree(monom) == 1) 245 { 246 linvars [nlinvars] = (SCIP_VAR*)mono_get_var(monom, 0); 247 lincoefs[nlinvars] = numb_todbl(mono_get_coeff(monom)); 248 ++nlinvars; 249 } 250 else 251 { 252 assert(mono_get_degree(monom) == 2); 253 quadvar1 [nquadterms] = (SCIP_VAR*)mono_get_var(monom, 0); 254 quadvar2 [nquadterms] = (SCIP_VAR*)mono_get_var(monom, 1); 255 quadcoefs[nquadterms] = numb_todbl(mono_get_coeff(monom)); 256 ++nquadterms; 257 } 258 } 259 260 SCIP_CALL( SCIPcreateExprQuadratic(scip, expr, nlinvars, linvars, lincoefs, nquadterms, quadvar1, quadvar2, quadcoefs, NULL, NULL) ); 261 262 SCIPfreeBufferArray(scip, &linvars); 263 SCIPfreeBufferArray(scip, &quadvar1); 264 SCIPfreeBufferArray(scip, &quadvar2); 265 SCIPfreeBufferArray(scip, &lincoefs); 266 SCIPfreeBufferArray(scip, &quadcoefs); 267 } 268 else 269 { 270 SCIP_VAR** polyvars; 271 SCIP_Real* polyexps; 272 SCIP_HASHMAP* varexpmap; 273 SCIP_EXPR** monomials; 274 int nmonomials; 275 int monomialssize; 276 SCIP_Real* coefs; 277 Mono* monomial; 278 SCIP_EXPR* monomialexpr; 279 SCIP_Bool created; 280 int varpos; 281 int i; 282 int j; 283 284 polyvars = NULL; 285 polyexps = NULL; 286 287 monomials = NULL; 288 nmonomials = 0; 289 monomialssize = 0; 290 coefs = NULL; 291 created = TRUE; 292 293 SCIP_CALL( SCIPhashmapCreate(&varexpmap, SCIPblkmem(scip), SCIPcalcMemGrowSize(scip, 10)) ); 294 295 for( i = 0; i < term_get_elements(term); ++i ) 296 { 297 monomial = term_get_element(term, i); 298 assert(monomial != NULL); 299 assert(!numb_equal(mono_get_coeff(monomial), numb_zero())); 300 assert(mono_get_degree(monomial) > 0); 301 302 /* allocate space in the monomials array */ 303 if( monomialssize == 0 ) 304 { 305 monomialssize = SCIPcalcMemGrowSize(scip, 1); 306 SCIP_CALL( SCIPallocBufferArray(scip, &monomials, monomialssize) ); 307 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, monomialssize) ); 308 } 309 else if( monomialssize < nmonomials + 1 ) 310 { 311 monomialssize = SCIPcalcMemGrowSize(scip, nmonomials+1); 312 SCIP_CALL( SCIPreallocBufferArray(scip, &monomials, monomialssize) ); 313 SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, monomialssize) ); 314 } 315 assert(monomials != NULL); 316 assert(coefs != NULL); 317 318 /* create SCIP monomial expression */ 319 for( j = 0; j < mono_get_degree(monomial); ++j ) 320 { 321 SCIP_Real exponent; 322 323 exponent = SCIPhashmapGetImageReal(varexpmap, (void*)mono_get_var(monomial, j)); 324 exponent = exponent == SCIP_INVALID ? 1.0 : exponent + 1.0; 325 326 SCIP_CALL( SCIPhashmapSetImageReal(varexpmap, (void*)mono_get_var(monomial, j), exponent) ); 327 } 328 329 SCIP_CALL( SCIPallocBufferArray(scip, &polyvars, SCIPhashmapGetNElements(varexpmap)) ); 330 SCIP_CALL( SCIPallocBufferArray(scip, &polyexps, SCIPhashmapGetNElements(varexpmap)) ); 331 332 varpos = 0; 333 334 for( j = 0; j < SCIPhashmapGetNEntries(varexpmap); ++j ) 335 { 336 SCIP_HASHMAPENTRY* entry; 337 338 entry = SCIPhashmapGetEntry(varexpmap, j); 339 if( entry == NULL ) 340 continue; 341 342 polyvars[varpos] = (SCIP_VAR*) SCIPhashmapEntryGetOrigin(entry); 343 polyexps[varpos] = SCIPhashmapEntryGetImageReal(entry); 344 ++varpos; 345 } 346 assert(varpos == SCIPhashmapGetNElements(varexpmap)); 347 SCIPhashmapRemoveAll(varexpmap); 348 349 SCIP_CALL( SCIPcreateExprMonomial(scip, &monomialexpr, varpos, polyvars, polyexps, NULL, NULL) ); 350 351 SCIPfreeBufferArrayNull(scip, &polyexps); 352 SCIPfreeBufferArrayNull(scip, &polyvars); 353 354 /* add monomial to array, possibly with an extra function around it */ 355 if( mono_get_function(monomial) == MFUN_NONE ) 356 { 357 monomials[nmonomials] = monomialexpr; 358 coefs[nmonomials] = numb_todbl(mono_get_coeff(monomial)); 359 } 360 else 361 { 362 SCIP_EXPR* cosexpr; 363 SCIP_EXPR* prodchildren[2]; 364 365 coefs[nmonomials] = 1.0; 366 367 /* nonlinear monomial with an extra function around it */ 368 switch( mono_get_function(monomial) ) 369 { 370 case MFUN_SQRT: 371 SCIP_CALL( SCIPcreateExprPow(scip, &monomials[nmonomials], monomialexpr, 0.5, NULL, NULL) ); 372 break; 373 case MFUN_LOG: 374 /* log10(x) = ln(x) / ln(10.0) */ 375 coefs[nmonomials] = 1.0 / log(10.0); 376 SCIP_CALL( SCIPcreateExprLog(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) ); 377 break; 378 case MFUN_EXP: 379 SCIP_CALL( SCIPcreateExprExp(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) ); 380 break; 381 case MFUN_LN: 382 SCIP_CALL( SCIPcreateExprLog(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) ); 383 break; 384 case MFUN_SIN: 385 SCIP_CALL( SCIPcreateExprSin(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) ); 386 break; 387 case MFUN_COS: 388 SCIP_CALL( SCIPcreateExprCos(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) ); 389 break; 390 case MFUN_TAN: 391 SCIP_CALL( SCIPcreateExprSin(scip, &prodchildren[0], monomialexpr, NULL, NULL) ); 392 SCIP_CALL( SCIPcreateExprCos(scip, &cosexpr, monomialexpr, NULL, NULL) ); 393 SCIP_CALL( SCIPcreateExprPow(scip, &prodchildren[1], cosexpr, -1.0, NULL, NULL) ); 394 SCIP_CALL( SCIPcreateExprProduct(scip, &monomials[nmonomials], 2, prodchildren, 1.0, NULL, NULL) ); 395 396 SCIP_CALL( SCIPreleaseExpr(scip, &prodchildren[1]) ); 397 SCIP_CALL( SCIPreleaseExpr(scip, &cosexpr) ); 398 SCIP_CALL( SCIPreleaseExpr(scip, &prodchildren[0]) ); 399 400 break; 401 case MFUN_ABS: 402 SCIP_CALL( SCIPcreateExprAbs(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) ); 403 break; 404 case MFUN_POW: 405 SCIP_CALL( SCIPcreateExprPow(scip, &monomials[nmonomials], monomialexpr, 406 numb_todbl(mono_get_coeff(monomial)), NULL, NULL) ); 407 break; 408 case MFUN_SGNPOW: 409 SCIP_CALL( SCIPcreateExprSignpower(scip, &monomials[nmonomials], monomialexpr, 410 numb_todbl(mono_get_coeff(monomial)), NULL, NULL) ); 411 break; 412 case MFUN_NONE: 413 case MFUN_TRUE: 414 case MFUN_FALSE: 415 SCIPerrorMessage("ZIMPL function %d invalid here.\n", mono_get_function(monomial)); 416 created = FALSE; 417 break; 418 default: 419 SCIPerrorMessage("ZIMPL function %d not supported\n", mono_get_function(monomial)); 420 created = FALSE; 421 break; 422 } /*lint !e788*/ 423 424 SCIP_CALL( SCIPreleaseExpr(scip, &monomialexpr) ); 425 } 426 427 ++nmonomials; 428 429 if( !created ) 430 break; 431 } 432 433 if( created ) 434 { 435 SCIP_CALL( SCIPcreateExprSum(scip, expr, nmonomials, monomials, coefs, 0.0, NULL, NULL) ); 436 } 437 438 /* free memory */ 439 for( j = nmonomials - 1; j >= 0; --j ) 440 { 441 if( monomials[j] != NULL ) 442 { 443 SCIP_CALL( SCIPreleaseExpr(scip, &monomials[j]) ); 444 } 445 } 446 447 SCIPfreeBufferArrayNull(scip, &coefs); 448 SCIPfreeBufferArrayNull(scip, &monomials); 449 SCIPhashmapFree(&varexpmap); 450 } 451 452 return SCIP_OKAY; 453 } 454 455 /** method creates a constraint and is called directly from ZIMPL 456 * 457 * @note this method is used by ZIMPL beginning from version 3.00 458 */ 459 static 460 SCIP_RETCODE addConsTerm( 461 SCIP* scip, /**< SCIP data structure */ 462 SCIP_READERDATA* readerdata, /**< reader data */ 463 const char* name, /**< constraint name */ 464 ConType type, /**< constraint type (LHS, RHS, EQUAL, RANGE, etc) */ 465 const Numb* lhs, /**< left hand side */ 466 const Numb* rhs, /**< right hand side */ 467 unsigned int flags, /**< special constraint flags, see ratlptypes.h */ 468 const Term* term, /**< term to use */ 469 SCIP_Bool* created /**< pointer to store if a constraint was created */ 470 ) 471 { 472 SCIP_CONS* cons; 473 SCIP_Real sciplhs; 474 SCIP_Real sciprhs; 475 SCIP_Bool initial; 476 SCIP_Bool separate; 477 SCIP_Bool enforce; 478 SCIP_Bool check; 479 SCIP_Bool propagate; 480 SCIP_Bool local; 481 SCIP_Bool modifiable; 482 SCIP_Bool usercut; 483 SCIP_Bool lazycut; 484 int i; 485 486 switch( type ) 487 { 488 case CON_FREE: 489 sciplhs = -SCIPinfinity(scip); 490 sciprhs = SCIPinfinity(scip); 491 break; 492 case CON_LHS: 493 sciplhs = (SCIP_Real)numb_todbl(lhs); 494 sciprhs = SCIPinfinity(scip); 495 break; 496 case CON_RHS: 497 sciplhs = -SCIPinfinity(scip); 498 sciprhs = (SCIP_Real)numb_todbl(rhs); 499 break; 500 case CON_RANGE: 501 sciplhs = (SCIP_Real)numb_todbl(lhs); 502 sciprhs = (SCIP_Real)numb_todbl(rhs); 503 break; 504 case CON_EQUAL: 505 sciplhs = (SCIP_Real)numb_todbl(lhs); 506 sciprhs = (SCIP_Real)numb_todbl(rhs); 507 assert(sciplhs == sciprhs); /*lint !e777*/ 508 break; 509 default: 510 SCIPwarningMessage(scip, "invalid constraint type <%d> in ZIMPL callback xlp_addcon()\n", type); 511 sciplhs = (SCIP_Real)numb_todbl(lhs); 512 sciprhs = (SCIP_Real)numb_todbl(rhs); 513 readerdata->readerror = TRUE; 514 break; 515 } 516 517 cons = NULL; 518 519 /* default values */ 520 initial = readerdata->initialconss; 521 separate = TRUE; 522 propagate = TRUE; 523 enforce = TRUE; 524 check = TRUE; 525 local = FALSE; 526 modifiable = FALSE; 527 528 usercut = (flags & LP_FLAG_CON_SEPAR) != 0; 529 lazycut = (flags & LP_FLAG_CON_CHECK) != 0; 530 531 /* evaluate constraint flags */ 532 if( usercut && lazycut ) 533 { 534 initial = FALSE; 535 separate = TRUE; 536 check = TRUE; 537 } 538 else if( usercut ) 539 { 540 initial = FALSE; 541 separate = TRUE; 542 check = FALSE; 543 } 544 else if( lazycut ) 545 { 546 initial = FALSE; 547 separate = FALSE; 548 check = TRUE; 549 } 550 551 if( term_is_linear(term) ) 552 { 553 /* if the constraint gives an indicator constraint */ 554 if ( flags & LP_FLAG_CON_INDIC ) 555 { 556 bool lhsIndCons = FALSE; /* generate lhs form for indicator constraints */ 557 bool rhsIndCons = FALSE; /* generate rhs form for indicator constraints */ 558 559 /* currently indicator constraints can only handle "<=" constraints */ 560 switch( type ) 561 { 562 case CON_LHS: 563 lhsIndCons = TRUE; 564 break; 565 case CON_RHS: 566 rhsIndCons = TRUE; 567 break; 568 case CON_RANGE: 569 case CON_EQUAL: 570 lhsIndCons = TRUE; 571 rhsIndCons = TRUE; 572 break; 573 case CON_FREE: 574 /*lint -fallthrough*/ 575 default: 576 SCIPerrorMessage("invalid constraint type <%d> in ZIMPL callback xlp_addcon()\n", type); 577 readerdata->readerror = TRUE; 578 break; 579 } 580 581 /* insert lhs form of indicator */ 582 if ( lhsIndCons ) 583 { 584 SCIP_CALL( SCIPcreateConsIndicator(scip, &cons, name, NULL, 0, NULL, NULL, -sciplhs, 585 initial, separate, enforce, check, propagate, local, readerdata->dynamicconss, readerdata->dynamicrows, FALSE) ); 586 SCIP_CALL( SCIPaddCons(scip, cons) ); 587 588 for( i = 0; i < term_get_elements(term); i++ ) 589 { 590 SCIP_VAR* scipvar; 591 SCIP_Real scipval; 592 const Mono* mono = term_get_element(term, i); 593 MFun mfun; 594 595 scipvar = (SCIP_VAR*)mono_get_var(mono, 0); 596 597 /* check whether variable is the binary variable */ 598 mfun = mono_get_function(mono); 599 if (mfun == MFUN_TRUE || mfun == MFUN_FALSE) 600 { 601 scipvar = (SCIP_VAR*)mono_get_var(mono, 0); 602 SCIP_CALL( SCIPsetBinaryVarIndicator(scip, cons, scipvar) ); 603 } 604 else 605 { 606 assert(!numb_equal(mono_get_coeff(mono), numb_zero())); 607 assert(mono_is_linear(mono)); 608 609 scipval = -numb_todbl(mono_get_coeff(mono)); 610 SCIP_CALL( SCIPaddVarIndicator(scip, cons, scipvar, scipval) ); 611 } 612 } 613 614 (*created) = TRUE; 615 } 616 617 /* insert rhs form of indicator */ 618 if ( rhsIndCons ) 619 { 620 SCIP_CALL( SCIPcreateConsIndicator(scip, &cons, name, NULL, 0, NULL, NULL, sciprhs, 621 initial, separate, enforce, check, propagate, local, readerdata->dynamicconss, readerdata->dynamicrows, FALSE) ); 622 SCIP_CALL( SCIPaddCons(scip, cons) ); 623 624 for( i = 0; i < term_get_elements(term); i++ ) 625 { 626 SCIP_VAR* scipvar; 627 SCIP_Real scipval; 628 const Mono* mono = term_get_element(term, i); 629 MFun mfun; 630 631 scipvar = (SCIP_VAR*)mono_get_var(mono, 0); 632 633 /* check whether variable is the binary variable */ 634 mfun = mono_get_function(mono); 635 if (mfun == MFUN_TRUE || mfun == MFUN_FALSE) 636 { 637 scipvar = (SCIP_VAR*)mono_get_var(mono, 0); 638 SCIP_CALL( SCIPsetBinaryVarIndicator(scip, cons, scipvar) ); 639 } 640 else 641 { 642 assert(!numb_equal(mono_get_coeff(mono), numb_zero())); 643 assert(mono_is_linear(mono)); 644 645 scipval = numb_todbl(mono_get_coeff(mono)); 646 SCIP_CALL( SCIPaddVarIndicator(scip, cons, scipvar, scipval) ); 647 } 648 } 649 650 (*created) = TRUE; 651 } 652 } 653 else 654 { 655 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 0, NULL, NULL, sciplhs, sciprhs, 656 initial, separate, enforce, check, propagate, local, modifiable, readerdata->dynamicconss, readerdata->dynamicrows, FALSE) ); 657 SCIP_CALL( SCIPaddCons(scip, cons) ); 658 659 for( i = 0; i < term_get_elements(term); i++ ) 660 { 661 SCIP_VAR* scipvar; 662 SCIP_Real scipval; 663 664 assert(!numb_equal(mono_get_coeff(term_get_element(term, i)), numb_zero())); 665 assert(mono_is_linear(term_get_element(term, i))); 666 667 scipvar = (SCIP_VAR*)mono_get_var(term_get_element(term, i), 0); 668 scipval = numb_todbl(mono_get_coeff(term_get_element(term, i))); 669 670 SCIP_CALL( SCIPaddCoefLinear(scip, cons, scipvar, scipval) ); 671 } 672 673 (*created) = TRUE; 674 } 675 } 676 else 677 { 678 SCIP_EXPR* expr; 679 680 /* convert term into expression */ 681 SCIP_CALL( createExpr(scip, readerdata, &expr, term) ); 682 683 if( expr == NULL ) 684 { 685 /* ZIMPL term could not be represented as SCIP expression */ 686 (*created) = FALSE; 687 } 688 else 689 { 690 /* create constraint with expression */ 691 SCIP_CALL( SCIPcreateConsNonlinear(scip, &cons, name, expr, sciplhs, sciprhs, 692 initial, separate, enforce, check, propagate, local, modifiable, readerdata->dynamicconss, readerdata->dynamicrows) ); 693 SCIP_CALL( SCIPaddCons(scip, cons) ); 694 695 SCIP_CALL( SCIPreleaseExpr(scip, &expr) ); 696 697 (*created) = TRUE; 698 } 699 } 700 701 if( cons != NULL ) 702 { 703 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 704 } 705 706 return SCIP_OKAY; 707 } 708 709 /** method adds objective term and is called directly from ZIMPL 710 * 711 * @note this method is used by ZIMPL beginning from version 3.4.1 712 */ 713 static 714 SCIP_RETCODE addObjTerm( 715 SCIP* scip, /**< SCIP data structure */ 716 SCIP_READERDATA* readerdata, /**< reader data */ 717 const Term* term /**< term to use */ 718 ) 719 { 720 SCIP_Real objoffset; 721 722 if( term_is_linear(term) ) 723 { 724 int i; 725 for( i = 0; i < term_get_elements(term); i++ ) 726 { 727 SCIP_VAR* scipvar; 728 SCIP_Real scipval; 729 730 assert(!numb_equal(mono_get_coeff(term_get_element(term, i)), numb_zero())); 731 assert(mono_is_linear(term_get_element(term, i))); 732 733 scipvar = (SCIP_VAR*)mono_get_var(term_get_element(term, i), 0); 734 scipval = numb_todbl(mono_get_coeff(term_get_element(term, i))); 735 736 SCIP_CALL( SCIPaddVarObj(scip, scipvar, scipval) ); 737 } 738 } 739 else 740 { 741 /* create variable objvar, add 1*objvar to objective, and add constraint term - objvar = 0 */ 742 SCIP_EXPR* expr; 743 SCIP_CONS* cons; 744 SCIP_VAR* objvar; 745 746 SCIP_CALL( createExpr(scip, readerdata, &expr, term) ); 747 748 if( expr == NULL ) 749 { 750 SCIPerrorMessage("Could not convert ZIMPL objective term into SCIP expression due to unsupported ZIMPL function.\n"); 751 return SCIP_READERROR; 752 } 753 754 SCIP_CALL( SCIPcreateConsNonlinear(scip, &cons, "obj", expr, 755 SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE ? -SCIPinfinity(scip) : 0.0, 756 SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE ? SCIPinfinity(scip) : 0.0, 757 readerdata->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, readerdata->dynamicconss, FALSE) ); 758 759 SCIP_CALL( SCIPcreateVarBasic(scip, &objvar, "objvar", -SCIPinfinity(scip), SCIPinfinity(scip), 1.0, SCIP_VARTYPE_CONTINUOUS) ); 760 SCIP_CALL( SCIPaddLinearVarNonlinear(scip, cons, objvar, -1.0) ); 761 762 SCIP_CALL( SCIPaddVar(scip, objvar) ); 763 SCIP_CALL( SCIPaddCons(scip, cons) ); 764 765 SCIP_CALL( SCIPreleaseExpr(scip, &expr) ); 766 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 767 SCIP_CALL( SCIPreleaseVar(scip, &objvar) ); 768 } 769 770 objoffset = numb_todbl(term_get_constant(term)); 771 SCIP_CALL( SCIPaddOrigObjoffset(scip, objoffset) ); 772 773 return SCIP_OKAY; 774 } 775 776 /** method creates a constraint and is called directly from ZIMPL 777 * 778 * @note this method is used by ZIMPL beginning from version 3.00 779 */ 780 bool xlp_addcon_term( 781 Lps* data, /**< pointer to reader data */ 782 const char* name, /**< constraint name */ 783 ConType type, /**< constraint type (LHS, RHS, EQUAL, RANGE, etc) */ 784 const Numb* lhs, /**< left hand side */ 785 const Numb* rhs, /**< right hand side */ 786 unsigned int flags, /**< special constraint flags, see ratlptypes.h */ 787 const Term* term /**< term to use */ 788 ) 789 { 790 SCIP* scip; 791 SCIP_READERDATA* readerdata; 792 SCIP_Bool created = FALSE; 793 794 readerdata = (SCIP_READERDATA*)data; 795 assert(readerdata != NULL); 796 797 scip = readerdata->scip; 798 assert(scip != NULL); 799 800 if( readerdata->retcode != SCIP_OKAY || readerdata->readerror ) 801 return TRUE; 802 803 readerdata->retcode = addConsTerm(scip, readerdata, name, type, lhs, rhs, flags, term, &created); 804 805 return !created; 806 } 807 808 /** adde variable */ 809 static 810 SCIP_RETCODE addVar( 811 SCIP* scip, /**< SCIP data structure */ 812 SCIP_READERDATA* readerdata, /**< reader data */ 813 const char* name, /**< variable name */ 814 VarClass usevarclass, /**< variable type */ 815 const Bound* lower, /**< lower bound */ 816 const Bound* upper, /**< upper bound */ 817 const Numb* priority, /**< branching priority */ 818 const Numb* startval, /**< start value for the variable within in the start solution */ 819 Var** zplvar /**< pointer to store the created variable */ 820 ) 821 { 822 SCIP_VAR* var; 823 SCIP_Real lb; 824 SCIP_Real ub; 825 SCIP_VARTYPE vartype; 826 SCIP_Bool initial; 827 SCIP_Bool removable; 828 int branchpriority; 829 830 switch( bound_get_type(lower) ) 831 { 832 case BOUND_VALUE: 833 lb = (SCIP_Real)numb_todbl(bound_get_value(lower)); 834 break; 835 case BOUND_INFTY: 836 lb = SCIPinfinity(scip); 837 break; 838 case BOUND_MINUS_INFTY: 839 lb = -SCIPinfinity(scip); 840 break; 841 case BOUND_ERROR: 842 default: 843 SCIPerrorMessage("invalid lower bound type <%d> in ZIMPL reader\n", bound_get_type(lower)); 844 lb = 0.0; 845 break; 846 } 847 848 switch( bound_get_type(upper) ) 849 { 850 case BOUND_VALUE: 851 ub = (SCIP_Real)numb_todbl(bound_get_value(upper)); 852 break; 853 case BOUND_INFTY: 854 ub = SCIPinfinity(scip); 855 break; 856 case BOUND_MINUS_INFTY: 857 ub = -SCIPinfinity(scip); 858 break; 859 case BOUND_ERROR: 860 default: 861 SCIPerrorMessage("invalid upper bound type <%d> in ZIMPL reader\n", bound_get_type(upper)); 862 ub = 0.0; 863 break; 864 } 865 866 switch( usevarclass ) 867 { 868 case VAR_CON: 869 vartype = SCIP_VARTYPE_CONTINUOUS; 870 break; 871 case VAR_INT: 872 vartype = SCIP_VARTYPE_INTEGER; 873 break; 874 case VAR_IMP: 875 vartype = SCIP_VARTYPE_IMPLINT; 876 break; 877 default: 878 SCIPwarningMessage(scip, "invalid variable class <%d> in ZIMPL callback xlp_addvar()\n", usevarclass); 879 vartype = SCIP_VARTYPE_CONTINUOUS; 880 readerdata->readerror = TRUE; 881 break; 882 } 883 initial = !(readerdata->dynamiccols); 884 removable = readerdata->dynamiccols; 885 886 /* create variable */ 887 SCIP_CALL( SCIPcreateVar(scip, &var, name, lb, ub, 0.0, vartype, initial, removable, NULL, NULL, NULL, NULL, NULL) ); 888 889 /* add variable to the problem; we are releasing the variable later */ 890 SCIP_CALL( SCIPaddVar(scip, var) ); 891 892 if( !numb_equal(priority, numb_unknown()) ) 893 { 894 if( numb_is_int(priority) ) 895 branchpriority = numb_toint(priority); 896 else 897 { 898 if( !readerdata->branchpriowarning ) 899 { 900 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, 901 "ZIMPL reader: fractional branching priorities in input - rounding down to integer values\n"); 902 readerdata->branchpriowarning = TRUE; 903 } 904 branchpriority = (int)numb_todbl(priority); 905 } 906 907 /* change the branching priority of the variable */ 908 SCIP_CALL( SCIPchgVarBranchPriority(scip, var, branchpriority) ); 909 } 910 911 /* check if we are willing to except a primal solution candidate */ 912 if( readerdata->valid ) 913 { 914 /* if the number is unknown we have no valid primal solution candidate */ 915 if( numb_equal(startval, numb_unknown()) ) 916 { 917 SCIPdebugMsg(scip, "primal solution candidate contains an unknown value for variable <%s>(%g)\n", 918 SCIPvarGetName(var), (SCIP_Real)numb_todbl(startval)); 919 readerdata->valid = FALSE; 920 } 921 else 922 { 923 assert(readerdata->sol != NULL); 924 SCIPdebugMsg(scip, "change solution solution <%p>: <%s> = <%g>\n", 925 (void*)readerdata->sol, SCIPvarGetName(var), (SCIP_Real)numb_todbl(startval)); 926 927 /* set value within the primal solution candidate */ 928 SCIP_CALL( SCIPsetSolVal(scip, readerdata->sol, var, (SCIP_Real)numb_todbl(startval)) ); 929 } 930 } 931 932 /* copy the variable pointer before we release the variable */ 933 (*zplvar) = (Var*)var; 934 935 /* release variable */ 936 SCIP_CALL( SCIPreleaseVar(scip, &var) ); 937 938 return SCIP_OKAY; 939 } 940 941 /** method adds a variable; is called directly by ZIMPL */ 942 Var* xlp_addvar( 943 Lps* data, /**< pointer to reader data */ 944 const char* name, /**< variable name */ 945 VarClass usevarclass, /**< variable type */ 946 const Bound* lower, /**< lower bound */ 947 const Bound* upper, /**< upper bound */ 948 const Numb* priority, /**< branching priority */ 949 const Numb* startval /**< start value for the variable within in the start solution */ 950 ) 951 { /*lint --e{715}*/ 952 SCIP* scip; 953 SCIP_READERDATA* readerdata; 954 Var* zplvar; 955 956 readerdata = (SCIP_READERDATA*)data; 957 assert(readerdata != NULL); 958 959 scip = readerdata->scip; 960 assert(scip != NULL); 961 962 zplvar = NULL; 963 964 if( readerdata->retcode != SCIP_OKAY || readerdata->readerror ) 965 return NULL; 966 967 readerdata->retcode = addVar(scip, readerdata, name, usevarclass, lower, upper, priority, startval, &zplvar); 968 969 return zplvar; 970 } 971 972 /** add a SOS constraint. Add a given a Zimpl term as an SOS constraint to the mathematical program */ 973 static 974 SCIP_RETCODE addSOS( 975 SCIP* scip, /**< SCIP data structure */ 976 SCIP_READERDATA* readerdata, /**< reader data */ 977 const char* name, /**< constraint name */ 978 SosType type, /**< SOS type */ 979 const Term* term /**< terms indicating sos */ 980 ) 981 { 982 SCIP_CONS* cons; 983 SCIP_Bool separate; 984 SCIP_Bool enforce; 985 SCIP_Bool check; 986 SCIP_Bool propagate; 987 SCIP_Bool local; 988 int i; 989 990 switch( type ) 991 { 992 case SOS_TYPE1: 993 separate = TRUE; 994 enforce = TRUE; 995 check = enforce; 996 propagate = TRUE; 997 local = FALSE; 998 999 SCIP_CALL( SCIPcreateConsSOS1(scip, &cons, name, 0, NULL, NULL, 1000 readerdata->initialconss, separate, enforce, check, propagate, local, readerdata->dynamicconss, readerdata->dynamicrows, FALSE) ); 1001 SCIP_CALL( SCIPaddCons(scip, cons) ); 1002 1003 for( i = 0; i < term_get_elements(term); i++ ) 1004 { 1005 SCIP_VAR* var; 1006 SCIP_Real weight; 1007 1008 assert( mono_is_linear(term_get_element(term, i)) ); 1009 1010 var = (SCIP_VAR*) mono_get_var(term_get_element(term, i), 0); 1011 weight = numb_todbl(mono_get_coeff(term_get_element(term, i))); 1012 1013 SCIP_CALL( SCIPaddVarSOS1(scip, cons, var, weight) ); 1014 } 1015 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 1016 break; 1017 case SOS_TYPE2: 1018 separate = TRUE; 1019 enforce = TRUE; 1020 check = enforce; 1021 propagate = TRUE; 1022 local = FALSE; 1023 1024 SCIP_CALL( SCIPcreateConsSOS2(scip, &cons, name, 0, NULL, NULL, 1025 readerdata->initialconss, separate, enforce, check, propagate, local, readerdata->dynamicconss, readerdata->dynamicrows, FALSE) ); 1026 SCIP_CALL( SCIPaddCons(scip, cons) ); 1027 for( i = 0; i < term_get_elements(term); i++ ) 1028 { 1029 SCIP_VAR* var; 1030 SCIP_Real weight; 1031 1032 assert( mono_is_linear(term_get_element(term, i)) ); 1033 1034 var = (SCIP_VAR*) mono_get_var(term_get_element(term, i), 0); 1035 weight = numb_todbl(mono_get_coeff(term_get_element(term, i))); 1036 1037 SCIP_CALL( SCIPaddVarSOS2(scip, cons, var, weight) ); 1038 } 1039 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 1040 break; 1041 case SOS_ERR: 1042 /*lint -fallthrough*/ 1043 default: 1044 SCIPerrorMessage("invalid SOS type <%d> in ZIMPL callback xlp_addsos_term()\n", type); 1045 readerdata->readerror = TRUE; 1046 break; 1047 } 1048 1049 return SCIP_OKAY; 1050 } 1051 1052 /** add a SOS constraint. Add a given a Zimpl term as an SOS constraint to the mathematical program */ 1053 int xlp_addsos_term( 1054 Lps* data, /**< pointer to reader data */ 1055 const char* name, /**< constraint name */ 1056 SosType type, /**< SOS type */ 1057 const Numb* priority, /**< priority */ 1058 const Term* term /**< terms indicating sos */ 1059 ) 1060 { 1061 /*lint --e{715}*/ 1062 SCIP* scip; 1063 SCIP_READERDATA* readerdata; 1064 1065 readerdata = (SCIP_READERDATA*)data; 1066 assert(readerdata != NULL); 1067 1068 scip = readerdata->scip; 1069 assert(scip != NULL); 1070 1071 if( readerdata->retcode != SCIP_OKAY || readerdata->readerror ) 1072 return TRUE; 1073 1074 readerdata->retcode = addSOS(scip, readerdata, name, type, term); 1075 1076 return 0; 1077 } 1078 1079 /** returns the variable name */ 1080 const char* xlp_getvarname( 1081 const Lps* data, /**< pointer to reader data */ 1082 const Var* var /**< variable */ 1083 ) 1084 { 1085 #ifndef NDEBUG 1086 SCIP* scip; 1087 SCIP_READERDATA* readerdata; 1088 1089 readerdata = (SCIP_READERDATA*)data; 1090 assert(readerdata != NULL); 1091 1092 scip = readerdata->scip; 1093 assert(scip != NULL); 1094 #endif 1095 1096 return SCIPvarGetName((SCIP_VAR*)var); 1097 } 1098 1099 /** return variable type */ 1100 VarClass xlp_getclass( 1101 const Lps* data, /**< pointer to reader data */ 1102 const Var* var /**< variable */ 1103 ) 1104 { 1105 SCIP_READERDATA* readerdata; 1106 SCIP_VAR* scipvar; 1107 1108 readerdata = (SCIP_READERDATA*)data; 1109 assert(readerdata != NULL); 1110 1111 scipvar = (SCIP_VAR*)var; 1112 switch( SCIPvarGetType(scipvar) ) 1113 { 1114 case SCIP_VARTYPE_BINARY: 1115 case SCIP_VARTYPE_INTEGER: 1116 return VAR_INT; 1117 case SCIP_VARTYPE_IMPLINT: 1118 return VAR_IMP; 1119 case SCIP_VARTYPE_CONTINUOUS: 1120 return VAR_CON; 1121 default: 1122 SCIPerrorMessage("invalid SCIP variable type <%d> in ZIMPL callback xlp_getclass()\n", SCIPvarGetType(scipvar)); 1123 readerdata->readerror = TRUE; 1124 break; 1125 } 1126 1127 return VAR_CON; 1128 } 1129 1130 /** returns lower bound */ 1131 Bound* xlp_getlower( 1132 const Lps* data, /**< pointer to reader data */ 1133 const Var* var /**< variable */ 1134 ) 1135 { 1136 SCIP* scip; 1137 SCIP_READERDATA* readerdata; 1138 SCIP_VAR* scipvar; 1139 SCIP_Real lb; 1140 char s[SCIP_MAXSTRLEN]; 1141 BoundType boundtype; 1142 Numb* numb; 1143 Bound* bound; 1144 1145 readerdata = (SCIP_READERDATA*)data; 1146 assert(readerdata != NULL); 1147 1148 scip = readerdata->scip; 1149 assert(scip != NULL); 1150 1151 scipvar = (SCIP_VAR*)var; 1152 assert(scipvar != NULL); 1153 1154 /* collect lower bound */ 1155 lb = SCIPvarGetLbGlobal(scipvar); 1156 numb = NULL; 1157 1158 /* check if lower bound is infinity */ 1159 if( SCIPisInfinity(scip, -lb) ) 1160 boundtype = BOUND_MINUS_INFTY; 1161 else if( SCIPisInfinity(scip, lb) ) 1162 boundtype = BOUND_INFTY; 1163 else 1164 { 1165 boundtype = BOUND_VALUE; 1166 1167 /* create double form string */ 1168 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "%.20f", lb); 1169 numb = numb_new_ascii(s); 1170 } 1171 1172 /* create bound */ 1173 bound = bound_new(boundtype, numb); 1174 1175 if( numb != NULL ) 1176 numb_free(numb); 1177 1178 return bound; 1179 } 1180 1181 /** returns upper bound */ 1182 Bound* xlp_getupper( 1183 const Lps* data, /**< pointer to reader data */ 1184 const Var* var /**< variable */ 1185 ) 1186 { 1187 SCIP* scip; 1188 SCIP_READERDATA* readerdata; 1189 SCIP_VAR* scipvar; 1190 SCIP_Real ub; 1191 char s[SCIP_MAXSTRLEN]; 1192 BoundType boundtype; 1193 Numb* numb; 1194 Bound* bound; 1195 1196 readerdata = (SCIP_READERDATA*)data; 1197 assert(readerdata != NULL); 1198 1199 scip = readerdata->scip; 1200 assert(scip != NULL); 1201 1202 scipvar = (SCIP_VAR*)var; 1203 assert(scipvar != NULL); 1204 1205 /* collect upper bound */ 1206 ub = SCIPvarGetUbGlobal(scipvar); 1207 numb = NULL; 1208 1209 /* check if upper bound is infinity */ 1210 if( SCIPisInfinity(scip, -ub) ) 1211 boundtype = BOUND_MINUS_INFTY; 1212 else if( SCIPisInfinity(scip, ub) ) 1213 boundtype = BOUND_INFTY; 1214 else 1215 { 1216 boundtype = BOUND_VALUE; 1217 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "%.20f", ub); 1218 numb = numb_new_ascii(s); 1219 } 1220 1221 /* create ZIMPL bound */ 1222 bound = bound_new(boundtype, numb); 1223 1224 if (numb != NULL) 1225 numb_free(numb); 1226 1227 return bound; 1228 } 1229 1230 /** Set the name and direction of the objective function, i.e. minimization or maximization 1231 * Coefficents of the objective function will be set to all zero. 1232 */ 1233 bool xlp_setobj( 1234 Lps* data, /**< pointer to reader data */ 1235 const char* name, /**< name of the objective function */ 1236 bool minimize /**< True if the problem should be minimized, False if it should be maximized */ 1237 ) 1238 { 1239 SCIP* scip; 1240 SCIP_READERDATA* readerdata; 1241 SCIP_OBJSENSE objsense; 1242 1243 readerdata = (SCIP_READERDATA*)data; 1244 assert(readerdata != NULL); 1245 1246 scip = readerdata->scip; 1247 assert(scip != NULL); 1248 1249 if( readerdata->retcode != SCIP_OKAY || readerdata->readerror ) 1250 return FALSE; 1251 1252 objsense = (minimize ? SCIP_OBJSENSE_MINIMIZE : SCIP_OBJSENSE_MAXIMIZE); 1253 readerdata->retcode = SCIPsetObjsense(scip, objsense); 1254 1255 return FALSE; 1256 } 1257 1258 /** adds objective function */ 1259 void xlp_addtoobj( 1260 Lps* data, /**< pointer to reader data */ 1261 const Term* term /**< objective term */ 1262 ) 1263 { 1264 SCIP* scip; 1265 SCIP_READERDATA* readerdata; 1266 1267 readerdata = (SCIP_READERDATA*)data; 1268 assert(readerdata != NULL); 1269 1270 scip = readerdata->scip; 1271 assert(scip != NULL); 1272 1273 if( readerdata->retcode != SCIP_OKAY || readerdata->readerror ) 1274 return; 1275 1276 readerdata->retcode = addObjTerm(scip, readerdata, term); 1277 } 1278 1279 /* 1280 * Callback methods of reader 1281 */ 1282 1283 /** copy method for reader plugins (called when SCIP copies plugins) */ 1284 static 1285 SCIP_DECL_READERCOPY(readerCopyZpl) 1286 { /*lint --e{715}*/ 1287 assert(scip != NULL); 1288 assert(reader != NULL); 1289 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); 1290 1291 /* call inclusion method of reader */ 1292 SCIP_CALL( SCIPincludeReaderZpl(scip) ); 1293 1294 return SCIP_OKAY; 1295 } 1296 1297 1298 /** problem reading method of reader */ 1299 static 1300 SCIP_DECL_READERREAD(readerReadZpl) 1301 { /*lint --e{715}*/ 1302 SCIP_READERDATA* readerdata; 1303 SCIP_RETCODE retcode; 1304 char oldpath[SCIP_MAXSTRLEN]; 1305 char buffer[SCIP_MAXSTRLEN]; 1306 char compextension[SCIP_MAXSTRLEN]; 1307 char namewithoutpath[SCIP_MAXSTRLEN]; 1308 char* path; 1309 char* name; 1310 char* extension; 1311 char* compression; 1312 char* paramstr; 1313 1314 SCIP_Bool changedir; 1315 int i; 1316 1317 SCIP_CALL( SCIPgetBoolParam(scip, "reading/zplreader/changedir", &changedir) ); 1318 1319 path = NULL; 1320 oldpath[0] = '\0'; 1321 if( changedir ) 1322 { 1323 /* change to the directory of the ZIMPL file, s.t. paths of data files read by the ZIMPL model are relative to 1324 * the location of the ZIMPL file 1325 */ 1326 (void)SCIPstrncpy(buffer, filename, SCIP_MAXSTRLEN); 1327 SCIPsplitFilename(buffer, &path, &name, &extension, &compression); 1328 if( compression != NULL ) 1329 (void) SCIPsnprintf(compextension, SCIP_MAXSTRLEN, ".%s", compression); 1330 else 1331 *compextension = '\0'; 1332 (void) SCIPsnprintf(namewithoutpath, SCIP_MAXSTRLEN, "%s.%s%s", name, extension, compextension); 1333 if( (char*)getcwd(oldpath, SCIP_MAXSTRLEN) == NULL ) 1334 { 1335 SCIPerrorMessage("error getting the current path\n"); 1336 return SCIP_READERROR; 1337 } 1338 if( path != NULL ) 1339 { 1340 if( chdir(path) != 0 ) 1341 { 1342 SCIPerrorMessage("error changing to directory <%s>\n", path); 1343 return SCIP_NOFILE; 1344 } 1345 } 1346 filename = namewithoutpath; 1347 } 1348 1349 /* get current path for output */ 1350 if( SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) 1351 { 1352 char currentpath[SCIP_MAXSTRLEN]; 1353 if( (char*)getcwd(currentpath, SCIP_MAXSTRLEN) == NULL ) 1354 { 1355 SCIPerrorMessage("error getting the current path\n"); 1356 return SCIP_READERROR; 1357 } 1358 /* an extra blank line should be printed separately since the buffer message handler only handle up to one line 1359 * correctly */ 1360 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "\n"); 1361 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "base directory for ZIMPL parsing: <%s>\n", currentpath); 1362 /* an extra blank line should be printed separately since the buffer message handler only handle up to one line 1363 * correctly */ 1364 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "\n"); 1365 } 1366 1367 /* allocate storage */ 1368 SCIP_CALL( SCIPallocBuffer(scip, &readerdata) ); 1369 1370 readerdata->scip = scip; 1371 readerdata->sol = NULL; 1372 readerdata->valid = FALSE; 1373 readerdata->branchpriowarning = FALSE; 1374 readerdata->readerror = FALSE; 1375 readerdata->retcode = SCIP_OKAY; 1376 SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &(readerdata->initialconss)) ); 1377 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &(readerdata->dynamicconss)) ); 1378 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &(readerdata->dynamiccols)) ); 1379 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &(readerdata->dynamicrows)) ); 1380 1381 /* get the parameter string */ 1382 SCIP_CALL( SCIPgetStringParam(scip, "reading/zplreader/parameters", ¶mstr) ); 1383 if( strcmp(paramstr, "-") == 0 ) 1384 { 1385 /* call ZIMPL parser without arguments */ 1386 if( !zpl_read(filename, TRUE, (void*)readerdata) ) 1387 readerdata->readerror = TRUE; 1388 else 1389 { 1390 /* evaluate retcode */ 1391 if ( readerdata->retcode != SCIP_OKAY ) 1392 { 1393 SCIPfreeBuffer(scip, &readerdata); 1394 return readerdata->retcode; 1395 } 1396 } 1397 } 1398 else 1399 { 1400 char dummy[2] = "x"; 1401 char** argv; 1402 int argc; 1403 int p; 1404 int len; 1405 1406 len = (int) strlen(paramstr); 1407 SCIP_CALL( SCIPallocBufferArray(scip, &argv, len+1) ); 1408 argv[0] = dummy; /* argument 0 is irrelevant */ 1409 argc = 1; 1410 p = 0; 1411 while( p < len ) 1412 { 1413 int arglen; 1414 1415 /* process next argument */ 1416 SCIP_CALL( SCIPallocBufferArray(scip, &argv[argc], len+1) ); /*lint !e866*/ 1417 arglen = 0; 1418 1419 /* skip spaces */ 1420 while( p < len && paramstr[p] == ' ' ) 1421 p++; 1422 1423 /* process characters */ 1424 while( p < len && paramstr[p] != ' ' ) 1425 { 1426 switch( paramstr[p] ) 1427 { 1428 case '"': 1429 p++; 1430 /* read characters as they are until the next " */ 1431 while( p < len && paramstr[p] != '"' ) 1432 { 1433 argv[argc][arglen] = paramstr[p]; 1434 arglen++; 1435 p++; 1436 } 1437 p++; /* skip final " */ 1438 break; 1439 case '\\': 1440 /* read next character as it is */ 1441 p++; 1442 argv[argc][arglen] = paramstr[p]; 1443 arglen++; 1444 p++; 1445 break; 1446 default: 1447 argv[argc][arglen] = paramstr[p]; 1448 arglen++; 1449 p++; 1450 break; 1451 } 1452 } 1453 argv[argc][arglen] = '\0'; 1454 1455 /* check for empty argument */ 1456 if( arglen == 0 ) 1457 { 1458 SCIPfreeBufferArray(scip, &argv[argc]); 1459 } 1460 else 1461 argc++; 1462 } 1463 1464 /* append file name as last argument */ 1465 SCIP_CALL( SCIPduplicateBufferArray(scip, &argv[argc], filename, (int) strlen(filename)+1) ); /*lint !e866*/ 1466 argc++; 1467 1468 /* display parsed arguments */ 1469 if( SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_FULL ) 1470 { 1471 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "ZIMPL arguments:\n"); 1472 for( i = 1; i < argc; ++i ) 1473 { 1474 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "%d: <%s>\n", i, argv[i]); 1475 } 1476 } 1477 1478 /* call ZIMPL parser with arguments */ 1479 if( !zpl_read_with_args(argv, argc, TRUE, (void*)readerdata) ) 1480 readerdata->readerror = TRUE; 1481 1482 /* free argument memory */ 1483 for( i = argc - 1; i >= 1; --i ) 1484 { 1485 SCIPfreeBufferArray(scip, &argv[i]); 1486 } 1487 SCIPfreeBufferArray(scip, &argv); 1488 1489 if ( readerdata->retcode != SCIP_OKAY ) 1490 { 1491 SCIPfreeBuffer(scip, &readerdata); 1492 return readerdata->retcode; 1493 } 1494 } 1495 1496 if( changedir ) 1497 { 1498 /* change directory back to old path */ 1499 if( path != NULL ) 1500 { 1501 if( chdir(oldpath) != 0 ) 1502 { 1503 SCIPwarningMessage(scip, "error changing back to directory <%s>\n", oldpath); 1504 } 1505 } 1506 } 1507 1508 if( readerdata->valid ) 1509 { 1510 SCIP_Bool stored; 1511 1512 assert(readerdata->sol != NULL); 1513 1514 stored = FALSE; 1515 1516 /* add primal solution to solution candidate storage, frees the solution afterwards */ 1517 SCIP_CALL( SCIPaddSolFree(scip, &readerdata->sol, &stored) ); 1518 1519 if( stored ) 1520 { 1521 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "ZIMPL starting solution candidate accepted\n"); 1522 } 1523 } 1524 1525 *result = SCIP_SUCCESS; 1526 1527 /* evaluate if a reading error occurred */ 1528 if( readerdata->readerror ) 1529 retcode = SCIP_READERROR; 1530 else 1531 retcode = SCIP_OKAY; 1532 1533 /* free primal solution candidate */ 1534 if( readerdata->sol != NULL ) 1535 { 1536 SCIP_CALL( SCIPfreeSol(scip, &readerdata->sol) ); 1537 } 1538 1539 /* free reader data */ 1540 SCIPfreeBuffer(scip, &readerdata); 1541 1542 return retcode; 1543 } 1544 1545 1546 #endif 1547 #endif 1548 1549 1550 /* 1551 * reader specific interface methods 1552 */ 1553 1554 /** includes the zpl file reader in SCIP */ /*lint --e{715}*/ 1555 SCIP_RETCODE SCIPincludeReaderZpl( 1556 SCIP* scip /**< SCIP data structure */ 1557 ) 1558 { /*lint --e{715}*/ 1559 #ifdef SCIP_WITH_ZIMPL 1560 #if (ZIMPL_VERSION >= 341) 1561 SCIP_READERDATA* readerdata; 1562 SCIP_READER* reader; 1563 char extcodename[SCIP_MAXSTRLEN]; 1564 1565 assert(scip != NULL); 1566 1567 /* create zpl reader data */ 1568 readerdata = NULL; 1569 reader = NULL; 1570 /* include zpl reader */ 1571 SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, readerdata) ); 1572 assert(reader != NULL); 1573 1574 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyZpl) ); 1575 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadZpl) ); 1576 1577 /* add zpl reader parameters */ 1578 SCIP_CALL( SCIPaddBoolParam(scip, 1579 "reading/zplreader/changedir", "should the current directory be changed to that of the ZIMPL file before parsing?", 1580 NULL, FALSE, TRUE, NULL, NULL) ); 1581 SCIP_CALL( SCIPaddBoolParam(scip, 1582 "reading/zplreader/usestartsol", "should ZIMPL starting solutions be forwarded to SCIP?", 1583 NULL, FALSE, TRUE, NULL, NULL) ); 1584 SCIP_CALL( SCIPaddStringParam(scip, 1585 "reading/zplreader/parameters", "additional parameter string passed to the ZIMPL parser (or - for no additional parameters)", 1586 NULL, FALSE, "-", NULL, NULL) ); 1587 1588 (void) SCIPsnprintf(extcodename, SCIP_MAXSTRLEN, "ZIMPL %d.%d.%d", ZIMPL_VERSION/100, (ZIMPL_VERSION%100)/10, ZIMPL_VERSION%10); /*lint !e778*/ 1589 SCIP_CALL( SCIPincludeExternalCodeInformation(scip, extcodename, "Zuse Institute Mathematical Programming Language developed by T. Koch (zimpl.zib.de)")); 1590 #else 1591 assert(scip != NULL); 1592 1593 SCIPwarningMessage(scip, "SCIP does only support ZIMPL 3.4.1 and higher. Please update your ZIMPL version %d.%d.%d\n", 1594 ZIMPL_VERSION/100, (ZIMPL_VERSION%100)/10, ZIMPL_VERSION%10); 1595 #endif 1596 #endif 1597 1598 return SCIP_OKAY; 1599 } 1600