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 nlp.c 26 * @ingroup OTHER_CFILES 27 * @brief NLP management methods 28 * @author Thorsten Gellermann 29 * @author Stefan Vigerske 30 * 31 * In NLP management, we have to distinguish between the current NLP and the NLPI problem 32 * stored in the NLP solver. All NLP methods affect the current NLP only. 33 * Before solving the current NLP with the NLP solver, the NLP solvers data 34 * has to be updated to the current NLP with a call to SCIPnlpFlush(). 35 * 36 * @todo handle linear rows from LP 37 */ 38 39 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 40 41 42 #include "scip/nlpi.h" 43 #include "scip/pub_expr.h" 44 #include "scip/expr.h" 45 #include "scip/expr_varidx.h" 46 #include "scip/clock.h" 47 #include "scip/event.h" 48 #include "scip/nlp.h" 49 #include "scip/primal.h" 50 #include "scip/pub_event.h" 51 #include "scip/pub_lp.h" 52 #include "scip/pub_message.h" 53 #include "scip/pub_misc.h" 54 #include "scip/pub_misc_sort.h" 55 #include "scip/pub_nlp.h" 56 #include "scip/pub_var.h" 57 #include "scip/set.h" 58 #include "scip/sol.h" 59 #include "scip/struct_nlp.h" 60 /* to get nlp, set, ... in event handling and mapvar2varidx */ 61 #include "scip/struct_scip.h" 62 /* to get value of parameter "nlp/solver" and nlpis array and to get access to set->lp for releasing a variable */ 63 #include "scip/struct_set.h" 64 #include "scip/struct_stat.h" 65 #include "scip/var.h" 66 #include <string.h> 67 68 /* defines */ 69 70 #define EVENTHDLR_NAME "nlpEventHdlr" /**< name of NLP event handler that catches variable events */ 71 #define EVENTHDLR_DESC "handles all events necessary for maintaining NLP data" /**< description of NLP event handler */ 72 #define ADDNAMESTONLPI 0 /**< whether to give variable and row names to NLPI */ 73 74 /*lint -e440*/ 75 /*lint -e441*/ 76 /*lint -e777*/ 77 78 #ifdef __cplusplus 79 extern "C" { 80 #endif 81 82 /* avoid inclusion of scip.h */ /*lint -e{2701}*/ 83 BMS_BLKMEM* SCIPblkmem( 84 SCIP* scip /**< SCIP data structure */ 85 ); 86 87 #ifdef __cplusplus 88 } 89 #endif 90 91 /* 92 * forward declarations 93 */ 94 95 /** NLP event handler execution method */ 96 static 97 SCIP_DECL_EVENTEXEC( eventExecNlp ); 98 99 /** announces, that a row of the NLP was modified 100 * 101 * adjusts status of current solution; 102 * calling method has to ensure that change is passed on to the NLPI! 103 */ 104 static 105 SCIP_RETCODE nlpRowChanged( 106 SCIP_NLP* nlp, /**< current NLP data */ 107 SCIP_SET* set, /**< global SCIP settings */ 108 SCIP_STAT* stat, /**< problem statistics data */ 109 SCIP_NLROW* nlrow /**< nonlinear row which was changed */ 110 ); 111 112 /* 113 * private NLP nonlinear row methods 114 */ 115 116 /** announces, that the given linear coefficient in the constraint matrix changed */ 117 static 118 SCIP_RETCODE nlrowLinearCoefChanged( 119 SCIP_NLROW* nlrow, /**< nonlinear row */ 120 SCIP_SET* set, /**< global SCIP settings */ 121 SCIP_STAT* stat, /**< problem statistics data */ 122 SCIP_VAR* var, /**< variable which coefficient changed */ 123 SCIP_Real coef, /**< new coefficient of variable, 0.0 if deleted */ 124 SCIP_NLP* nlp /**< current NLP data */ 125 ) 126 { 127 assert(nlrow != NULL); 128 assert(var != NULL); 129 130 nlrow->activity = SCIP_INVALID; 131 nlrow->validactivitynlp = -1; 132 nlrow->pseudoactivity = SCIP_INVALID; 133 nlrow->validpsactivitydomchg = -1; 134 nlrow->minactivity = SCIP_INVALID; 135 nlrow->maxactivity = SCIP_INVALID; 136 nlrow->validactivitybdsdomchg = -1; 137 138 if( nlrow->nlpindex >= 0 ) 139 { 140 assert(nlp != NULL); 141 142 /* notify NLP that row has changed */ 143 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) ); 144 145 /* update NLPI problem, if row is in NLPI already */ 146 if( nlrow->nlpiindex >= 0 ) 147 { 148 int idx; 149 150 /* get index of variable in NLPI */ 151 assert(SCIPhashmapExists(nlp->varhash, var)); 152 idx = SCIPhashmapGetImageInt(nlp->varhash, var); 153 assert(idx >= 0 && idx < nlp->nvars); 154 155 idx = nlp->varmap_nlp2nlpi[idx]; 156 assert(idx >= 0 && idx < nlp->nvars_solver); 157 158 /* change coefficient in NLPI problem */ 159 SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, nlrow->nlpiindex, 1, &idx, &coef) ); 160 } 161 } 162 163 return SCIP_OKAY; 164 } 165 166 /** create varidx expression for var expression 167 * 168 * called when expr is duplicated for addition to NLPI 169 */ 170 static 171 SCIP_DECL_EXPR_MAPEXPR(mapvar2varidx) 172 { 173 SCIP_NLP* nlp; 174 int nlpidx; 175 176 assert(sourcescip != NULL); 177 assert(sourcescip == targetscip); 178 assert(sourceexpr != NULL); 179 assert(targetexpr != NULL); 180 assert(*targetexpr == NULL); 181 assert(mapexprdata != NULL); 182 183 nlp = (SCIP_NLP*)mapexprdata; 184 185 /* do not provide map if not variable */ 186 if( !SCIPexprIsVar(sourcescip->set, sourceexpr) ) 187 return SCIP_OKAY; 188 189 assert(SCIPvarIsActive(SCIPgetVarExprVar(sourceexpr))); /* because we simplified exprs */ 190 191 assert(SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(sourceexpr))); 192 nlpidx = SCIPhashmapGetImageInt(nlp->varhash, SCIPgetVarExprVar(sourceexpr)); 193 assert(nlpidx < nlp->nvars); 194 195 assert(nlp->varmap_nlp2nlpi[nlpidx] >= 0); 196 assert(nlp->varmap_nlp2nlpi[nlpidx] < nlp->nvars_solver); 197 SCIP_CALL( SCIPcreateExprVaridx(targetscip, targetexpr, nlp->varmap_nlp2nlpi[nlpidx], ownercreate, ownercreatedata) ); 198 199 return SCIP_OKAY; 200 } 201 202 /** announces, that an expression changed */ 203 static 204 SCIP_RETCODE nlrowExprChanged( 205 SCIP_NLROW* nlrow, /**< nonlinear row */ 206 BMS_BLKMEM* blkmem, /**< block memory */ 207 SCIP_SET* set, /**< global SCIP settings */ 208 SCIP_STAT* stat, /**< problem statistics data */ 209 SCIP_NLP* nlp /**< current NLP data */ 210 ) 211 { 212 assert(nlrow != NULL); 213 214 nlrow->activity = SCIP_INVALID; 215 nlrow->validactivitynlp = -1; 216 nlrow->pseudoactivity = SCIP_INVALID; 217 nlrow->validpsactivitydomchg = -1; 218 nlrow->minactivity = SCIP_INVALID; 219 nlrow->maxactivity = SCIP_INVALID; 220 nlrow->validactivitybdsdomchg = -1; 221 222 if( nlrow->nlpindex >= 0 ) 223 { 224 assert(nlp != NULL); 225 226 /* notify NLP that row has changed */ 227 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) ); 228 229 if( nlrow->nlpiindex >= 0 ) 230 { 231 /* change expression tree in NLPI problem */ 232 SCIP_EXPR* nlpiexpr; 233 234 SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, nlrow->expr, &nlpiexpr, mapvar2varidx, (void*)nlp, NULL, NULL) ); 235 SCIP_CALL( SCIPnlpiChgExpr(set, nlp->solver, nlp->problem, nlrow->nlpiindex, nlpiexpr) ); 236 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlpiexpr) ); 237 } 238 } 239 240 return SCIP_OKAY; 241 } 242 243 /** notifies nonlinear row, that its sides were changed */ 244 static 245 SCIP_RETCODE nlrowSideChanged( 246 SCIP_NLROW* nlrow, /**< nonlinear row */ 247 SCIP_SET* set, /**< global SCIP settings */ 248 SCIP_STAT* stat, /**< problem statistics data */ 249 SCIP_NLP* nlp /**< current NLP data */ 250 ) 251 { 252 assert(nlrow != NULL); 253 254 if( nlrow->nlpindex >= 0 ) 255 { 256 assert(nlp != NULL); 257 258 /* notify NLP that row has changed */ 259 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) ); 260 261 if( nlrow->nlpiindex >= 0 ) 262 { 263 SCIP_Real lhs; 264 SCIP_Real rhs; 265 266 /* change sides in NLPI problem */ 267 lhs = nlrow->lhs; 268 rhs = nlrow->rhs; 269 if( !SCIPsetIsInfinity(set, -lhs) ) 270 lhs -= nlrow->constant; 271 if( !SCIPsetIsInfinity(set, rhs) ) 272 rhs -= nlrow->constant; 273 274 SCIP_CALL( SCIPnlpiChgConsSides(set, nlp->solver, nlp->problem, 1, &nlrow->nlpiindex, &lhs, &rhs) ); 275 } 276 } 277 278 return SCIP_OKAY; 279 } 280 281 /** notifies nonlinear row, that its constant was changed */ 282 static 283 SCIP_RETCODE nlrowConstantChanged( 284 SCIP_NLROW* nlrow, /**< nonlinear row */ 285 SCIP_SET* set, /**< global SCIP settings */ 286 SCIP_STAT* stat, /**< problem statistics data */ 287 SCIP_NLP* nlp /**< current NLP data */ 288 ) 289 { 290 assert(nlrow != NULL); 291 292 nlrow->activity = SCIP_INVALID; 293 nlrow->validactivitynlp = -1; 294 nlrow->pseudoactivity = SCIP_INVALID; 295 nlrow->validpsactivitydomchg = -1; 296 nlrow->minactivity = SCIP_INVALID; 297 nlrow->maxactivity = SCIP_INVALID; 298 nlrow->validactivitybdsdomchg = -1; 299 300 if( nlrow->nlpindex >= 0 ) 301 { 302 assert(nlp != NULL); 303 304 /* notify NLP that row has changed */ 305 SCIP_CALL( nlpRowChanged(nlp, set, stat, nlrow) ); 306 307 if( nlrow->nlpiindex >= 0 ) 308 { 309 SCIP_Real lhs; 310 SCIP_Real rhs; 311 312 lhs = nlrow->lhs; 313 rhs = nlrow->rhs; 314 if( !SCIPsetIsInfinity(set, -lhs) ) 315 lhs -= nlrow->constant; 316 if( !SCIPsetIsInfinity(set, rhs) ) 317 rhs -= nlrow->constant; 318 319 /* change sides in NLPI problem */ 320 SCIP_CALL( SCIPnlpiChgConsSides(set, nlp->solver, nlp->problem, 1, &nlrow->nlpiindex, &lhs, &rhs) ); 321 } 322 } 323 324 return SCIP_OKAY; 325 } 326 327 /** increments or decrements count of NLROW in NLP statistics 328 * 329 * Updates count on linear/convex/nonconvex NLP rows w.r.t. given NLROW. 330 */ 331 static 332 void nlrowAddToStat( 333 SCIP_NLP* nlp, /**< NLP */ 334 SCIP_SET* set, /**< global SCIP settings */ 335 SCIP_NLROW* nlrow, /**< nonlinear row */ 336 int incr /**< by how much to increment statistic: +1 or -1 */ 337 ) 338 { 339 assert(nlp != NULL); 340 assert(nlrow != NULL); 341 assert(set != NULL); 342 assert(incr == 1 || incr == -1); 343 344 if( nlrow->expr == NULL ) 345 { 346 nlp->nnlrowlinear += incr; 347 assert(nlp->nnlrowlinear >= 0); 348 return; 349 } 350 351 if( !SCIPsetIsInfinity(set, -nlrow->lhs) && !SCIPsetIsInfinity(set, nlrow->rhs) ) 352 { 353 nlp->nnlrownonlineareq += incr; 354 assert(nlp->nnlrownonlineareq >= 0); 355 return; 356 } 357 358 if( (SCIPsetIsInfinity(set, -nlrow->lhs) && (nlrow->curvature & SCIP_EXPRCURV_CONVEX)) || /* g(x) <= rhs with g(x) convex */ 359 (SCIPsetIsInfinity(set, nlrow->rhs) && (nlrow->curvature & SCIP_EXPRCURV_CONCAVE)) ) /* g(x) >= lhs with g(x) concave */ 360 { 361 nlp->nnlrowconvexineq += incr; 362 assert(nlp->nnlrowconvexineq >= 0); 363 return; 364 } 365 366 nlp->nnlrownonconvexineq += incr; 367 assert(nlp->nnlrownonconvexineq >= 0); 368 } 369 370 /** sorts linear part of row entries such that lower variable indices precede higher ones */ 371 static 372 void nlrowSortLinear( 373 SCIP_NLROW* nlrow /**< nonlinear row to be sorted */ 374 ) 375 { 376 assert(nlrow != NULL); 377 378 /* check, if row is already sorted in the LP part, or if the sorting should be delayed */ 379 if( nlrow->linvarssorted ) 380 return; 381 382 /* sort linear coefficients */ 383 SCIPsortPtrReal((void**)nlrow->linvars, nlrow->lincoefs, SCIPvarComp, nlrow->nlinvars); 384 385 nlrow->linvarssorted = TRUE; 386 } 387 388 /** searches linear variable in nonlinear row, returns position in linvars vector or -1 if not found */ 389 static 390 int nlrowSearchLinearCoef( 391 SCIP_NLROW* nlrow, /**< nonlinear row to be searched in */ 392 SCIP_VAR* var /**< variable to be searched for */ 393 ) 394 { 395 int pos; 396 397 assert(nlrow != NULL); 398 assert(var != NULL); 399 400 if( nlrow->nlinvars == 0 ) 401 return -1; 402 403 nlrowSortLinear(nlrow); 404 if( !SCIPsortedvecFindPtr((void**)nlrow->linvars, SCIPvarComp, (void*)var, nlrow->nlinvars, &pos) ) 405 return -1; 406 407 return pos; 408 } 409 410 /** moves a coefficient in a nonlinear row to a different place, and updates all corresponding data structures */ 411 static 412 void nlrowMoveLinearCoef( 413 SCIP_NLROW* nlrow, /**< NLP row */ 414 int oldpos, /**< old position of coefficient */ 415 int newpos /**< new position of coefficient */ 416 ) 417 { 418 assert(nlrow != NULL); 419 assert(0 <= oldpos && oldpos < nlrow->nlinvars); 420 assert(0 <= newpos && newpos < nlrow->nlinvars); 421 assert(nlrow->linvars[oldpos] != NULL); 422 423 if( oldpos == newpos ) 424 return; 425 426 nlrow->linvars[newpos] = nlrow->linvars[oldpos]; 427 nlrow->lincoefs[newpos] = nlrow->lincoefs[oldpos]; 428 429 /* update sorted flags */ 430 nlrow->linvarssorted = FALSE; 431 } 432 433 /** adds a previously non existing linear coefficient to a nonlinear row */ 434 static 435 SCIP_RETCODE nlrowAddLinearCoef( 436 SCIP_NLROW* nlrow, /**< nonlinear row */ 437 BMS_BLKMEM* blkmem, /**< block memory */ 438 SCIP_SET* set, /**< global SCIP settings */ 439 SCIP_STAT* stat, /**< problem statistics data */ 440 SCIP_NLP* nlp, /**< current NLP data */ 441 SCIP_VAR* var, /**< variable */ 442 SCIP_Real coef /**< value of coefficient */ 443 ) 444 { 445 int pos; 446 447 assert(nlrow != NULL); 448 assert(blkmem != NULL); 449 assert(var != NULL); 450 assert(coef != 0.0); 451 452 /* assert that only active variables are added once the row is in the NLP */ 453 assert(nlrow->nlpindex == -1 || SCIPvarIsActive(var) ); 454 455 SCIP_CALL( SCIPnlrowEnsureLinearSize(nlrow, blkmem, set, nlrow->nlinvars+1) ); 456 assert(nlrow->linvars != NULL); 457 assert(nlrow->lincoefs != NULL); 458 459 pos = nlrow->nlinvars; 460 nlrow->nlinvars++; 461 462 /* insert the variable */ 463 nlrow->linvars [pos] = var; 464 nlrow->lincoefs[pos] = coef; 465 466 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, coef, nlp) ); 467 468 /* update sorted flag */ 469 if( pos > 0 && SCIPvarCompare(nlrow->linvars[pos-1], nlrow->linvars[pos]) > 0 ) 470 nlrow->linvarssorted = FALSE; 471 472 SCIPsetDebugMsg(set, "added linear coefficient %g * <%s> at position %d to nonlinear row <%s>\n", 473 coef, SCIPvarGetName(var), pos, nlrow->name); 474 475 return SCIP_OKAY; 476 } 477 478 #ifdef SCIP_DISABLED_CODE 479 /** adds a linear coefficient to a nonlinear row 480 * if the variable exists in the linear part of the row already, the coefficients are added 481 * otherwise the variable is added to the row */ 482 static 483 SCIP_RETCODE nlrowAddToLinearCoef( 484 SCIP_NLROW* nlrow, /**< nonlinear row */ 485 BMS_BLKMEM* blkmem, /**< block memory */ 486 SCIP_SET* set, /**< global SCIP settings */ 487 SCIP_STAT* stat, /**< problem statistics data */ 488 SCIP_NLP* nlp, /**< current NLP data */ 489 SCIP_VAR* var, /**< variable */ 490 SCIP_Real coef, /**< value of coefficient */ 491 SCIP_Bool removefixed /**< whether to disaggregate var before adding */ 492 ) 493 { 494 int pos; 495 496 assert(nlrow != NULL); 497 assert(blkmem != NULL); 498 assert(var != NULL); 499 500 if( removefixed && !SCIPvarIsActive(var) ) 501 { 502 SCIP_Real constant; 503 504 constant = 0.0; 505 SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &coef, &constant) ); 506 if( constant != 0.0 ) 507 { 508 nlrow->constant += constant; 509 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) ); 510 } 511 512 if( SCIPsetIsZero(set, coef) ) 513 return SCIP_OKAY; 514 515 if( !SCIPvarIsActive(var) ) 516 { 517 int j; 518 519 /* if var is still not active, then it is multi-aggregated */ 520 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); 521 522 if( SCIPvarGetMultaggrConstant(var) != 0.0 ) 523 { 524 nlrow->constant += coef * SCIPvarGetMultaggrConstant(var); 525 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) ); 526 } 527 528 for( j = 0; j < SCIPvarGetMultaggrNVars(var); ++j ) 529 { 530 SCIP_CALL( nlrowAddToLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[j], SCIPvarGetMultaggrScalars(var)[j] * coef, TRUE) ); 531 } 532 533 return SCIP_OKAY; 534 } 535 } 536 else if( SCIPsetIsZero(set, coef) ) 537 return SCIP_OKAY; 538 539 assert(!removefixed || SCIPvarIsActive(var)); 540 541 pos = nlrowSearchLinearCoef(nlrow, var); 542 543 if( pos == -1 ) 544 { 545 /* add as new coefficient */ 546 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, coef) ); 547 } 548 else 549 { 550 assert(pos >= 0); 551 assert(pos < nlrow->nlinvars); 552 assert(nlrow->linvars[pos] == var); 553 554 /* add to previously existing coefficient */ 555 nlrow->lincoefs[pos] += coef; 556 } 557 558 return SCIP_OKAY; 559 } 560 #endif 561 562 /** deletes coefficient at given position from row */ 563 static 564 SCIP_RETCODE nlrowDelLinearCoefPos( 565 SCIP_NLROW* nlrow, /**< nonlinear row to be changed */ 566 SCIP_SET* set, /**< global SCIP settings */ 567 SCIP_STAT* stat, /**< problem statistics data */ 568 SCIP_NLP* nlp, /**< current NLP data */ 569 int pos /**< position in row vector to delete */ 570 ) 571 { 572 SCIP_VAR* var; 573 574 assert(nlrow != NULL); 575 assert(set != NULL); 576 assert(0 <= pos && pos < nlrow->nlinvars); 577 assert(nlrow->linvars[pos] != NULL); 578 579 var = nlrow->linvars[pos]; 580 581 /* move last coefficient to position of empty slot (should set sorted flag to FALSE, if not last variable was deleted) */ 582 nlrowMoveLinearCoef(nlrow, nlrow->nlinvars-1, pos); 583 nlrow->nlinvars--; 584 assert(pos == nlrow->nlinvars || nlrow->linvarssorted == FALSE); 585 586 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, 0.0, nlp) ); 587 588 return SCIP_OKAY; 589 } 590 591 /** changes a coefficient at given position of a nonlinear row */ 592 static 593 SCIP_RETCODE nlrowChgLinearCoefPos( 594 SCIP_NLROW* nlrow, /**< NLP row */ 595 SCIP_SET* set, /**< global SCIP settings */ 596 SCIP_STAT* stat, /**< problem statistics data */ 597 SCIP_NLP* nlp, /**< current NLP data */ 598 int pos, /**< position in row vector to change */ 599 SCIP_Real coef /**< new value of coefficient */ 600 ) 601 { 602 assert(nlrow != NULL); 603 assert(0 <= pos && pos < nlrow->nlinvars); 604 assert(nlrow->linvars != NULL); 605 assert(nlrow->linvars[pos] != NULL); 606 607 if( SCIPsetIsZero(set, coef) ) 608 { 609 /* delete existing coefficient */ 610 SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) ); 611 } 612 else if( !SCIPsetIsEQ(set, nlrow->lincoefs[pos], coef) ) 613 { 614 /* change existing coefficient */ 615 nlrow->lincoefs[pos] = coef; 616 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, nlrow->linvars[pos], coef, nlp) ); 617 } 618 619 return SCIP_OKAY; 620 } 621 622 /** calculates minimal and maximal activity of row w.r.t. the variable's bounds */ 623 static 624 SCIP_RETCODE nlrowCalcActivityBounds( 625 SCIP_NLROW* nlrow, /**< nonlinear row */ 626 BMS_BLKMEM* blkmem, /**< block memory */ 627 SCIP_SET* set, /**< global SCIP settings */ 628 SCIP_STAT* stat /**< problem statistics data */ 629 ) 630 { 631 SCIP_Real inf; 632 SCIP_INTERVAL activity; 633 SCIP_INTERVAL bounds; 634 int i; 635 636 assert(nlrow != NULL); 637 assert(set != NULL); 638 assert(stat != NULL); 639 640 inf = SCIPsetInfinity(set); 641 642 /* calculate activity bounds */ 643 SCIPintervalSet(&activity, nlrow->constant); 644 for( i = 0; i < nlrow->nlinvars && !SCIPintervalIsEntire(inf, activity); ++i ) 645 { 646 SCIPintervalSetBounds(&bounds, SCIPvarGetLbLocal(nlrow->linvars[i]), SCIPvarGetUbLocal(nlrow->linvars[i])); 647 SCIPintervalMulScalar(inf, &bounds, bounds, nlrow->lincoefs[i]); 648 SCIPintervalAdd(inf, &activity, activity, bounds); 649 } 650 651 if( nlrow->expr != NULL && !SCIPintervalIsEntire(inf, activity) ) 652 { 653 SCIP_CALL( SCIPexprEvalActivity(set, stat, blkmem, nlrow->expr) ); 654 SCIPintervalAdd(inf, &activity, activity, SCIPexprGetActivity(nlrow->expr)); 655 } 656 657 nlrow->minactivity = SCIPintervalGetInf(activity); 658 nlrow->maxactivity = SCIPintervalGetSup(activity); 659 660 nlrow->validactivitybdsdomchg = stat->domchgcount; 661 662 return SCIP_OKAY; 663 } 664 665 /** makes sure that there is no fixed variable at position pos of the linear part of a nonlinear row 666 * 667 * a fixed variable is replaced with the corresponding constant or disaggregated term 668 */ 669 static 670 SCIP_RETCODE nlrowRemoveFixedLinearCoefPos( 671 SCIP_NLROW* nlrow, /**< nonlinear row */ 672 BMS_BLKMEM* blkmem, /**< block memory */ 673 SCIP_SET* set, /**< global SCIP settings */ 674 SCIP_STAT* stat, /**< problem statistics data */ 675 SCIP_NLP* nlp, /**< current NLP data */ 676 int pos /**< position of variable in linear variables array */ 677 ) 678 { 679 SCIP_Real oldconstant; 680 SCIP_VAR* var; 681 682 assert(nlrow != NULL); 683 assert(blkmem != NULL); 684 assert(pos >= 0); 685 assert(pos < nlrow->nlinvars); 686 687 var = nlrow->linvars[pos]; 688 689 if( SCIPvarIsActive(var) ) 690 return SCIP_OKAY; 691 692 oldconstant = nlrow->constant; 693 694 /* replace fixed, aggregated, or negated variable */ 695 SCIP_CALL( SCIPvarGetProbvarSum( &nlrow->linvars[pos], set, &nlrow->lincoefs[pos], &nlrow->constant) ); 696 697 /* if var had been fixed, entry should be removed from row */ 698 if( nlrow->lincoefs[pos] == 0.0 ) 699 { 700 nlrowMoveLinearCoef(nlrow, nlrow->nlinvars-1, pos); 701 nlrow->nlinvars--; 702 703 if( pos < nlrow->nlinvars ) 704 { 705 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) ); 706 } 707 708 return SCIP_OKAY; 709 } 710 nlrow->linvarssorted = FALSE; 711 712 /* notify nlrow that coefficient of var is now 0.0 in row */ 713 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, var, 0.0, nlp) ); 714 715 /* notify nlrow that constant of row has changed */ 716 if( oldconstant != nlrow->constant ) 717 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) ); 718 719 if( SCIPvarIsActive(nlrow->linvars[pos]) ) 720 { 721 /* if var was aggregated or negated, notify nlrow about new coefficient */ 722 SCIP_CALL( nlrowLinearCoefChanged(nlrow, set, stat, nlrow->linvars[pos], nlrow->lincoefs[pos], nlp) ); 723 } 724 else 725 { 726 SCIP_Real coef; 727 int i; 728 729 /* if not removed or active, the new variable should be multi-aggregated */ 730 assert(SCIPvarGetStatus(nlrow->linvars[pos]) == SCIP_VARSTATUS_MULTAGGR); 731 732 var = nlrow->linvars[pos]; 733 coef = nlrow->lincoefs[pos]; 734 735 /* remove the variable from the row */ 736 SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) ); 737 738 /* add multi-aggregated term to row */ 739 if( SCIPvarGetMultaggrConstant(var) != 0.0 ) 740 { 741 nlrow->constant += coef * SCIPvarGetMultaggrConstant(var); 742 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) ); 743 } 744 SCIP_CALL( SCIPnlrowEnsureLinearSize(nlrow, blkmem, set, nlrow->nlinvars + SCIPvarGetMultaggrNVars(var)) ); 745 for( i = 0; i < SCIPvarGetMultaggrNVars(var); ++i ) 746 { 747 if( SCIPsetIsZero(set, coef * SCIPvarGetMultaggrScalars(var)[i]) ) 748 continue; 749 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[i], coef * SCIPvarGetMultaggrScalars(var)[i]) ); 750 assert(SCIPvarGetMultaggrVars(var)[i] == nlrow->linvars[nlrow->nlinvars-1]); 751 if( !SCIPvarIsActive(SCIPvarGetMultaggrVars(var)[i]) ) 752 { 753 /* if newly added variable is fixed, replace it now */ 754 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, nlrow->nlinvars-1) ); 755 } 756 } 757 758 /* due to nlrowDelLinearCoefPos, an inactive variable may have moved to position pos 759 * if that is the case, call ourself recursively 760 */ 761 if( pos < nlrow->nlinvars && !SCIPvarIsActive(nlrow->linvars[pos]) ) 762 { 763 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) ); 764 } 765 } 766 767 return SCIP_OKAY; 768 } 769 770 /** removes fixed variables from the linear part of a nonlinear row */ 771 static 772 SCIP_RETCODE nlrowRemoveFixedLinearCoefs( 773 SCIP_NLROW* nlrow, /**< nonlinear row */ 774 BMS_BLKMEM* blkmem, /**< block memory */ 775 SCIP_SET* set, /**< global SCIP settings */ 776 SCIP_STAT* stat, /**< problem statistics data */ 777 SCIP_NLP* nlp /**< current NLP data */ 778 ) 779 { 780 int i; 781 int oldlen; 782 783 assert(nlrow != NULL); 784 assert(nlrow->linvars != NULL || nlrow->nlinvars == 0); 785 786 oldlen = nlrow->nlinvars; 787 for( i = 0; i < MIN(oldlen, nlrow->nlinvars); ++i ) 788 { 789 assert(nlrow->linvars[i] != NULL); 790 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, i) ); 791 } 792 793 return SCIP_OKAY; 794 } 795 796 /** removes fixed variables from expression of a nonlinear row */ 797 static 798 SCIP_RETCODE nlrowSimplifyExpr( 799 SCIP_NLROW* nlrow, /**< nonlinear row */ 800 BMS_BLKMEM* blkmem, /**< block memory */ 801 SCIP_SET* set, /**< global SCIP settings */ 802 SCIP_STAT* stat, /**< problem statistics data */ 803 SCIP_NLP* nlp /**< current NLP data */ 804 ) 805 { 806 SCIP_EXPR* simplified; 807 SCIP_Bool changed; 808 SCIP_Bool infeasible; 809 810 if( nlrow->expr == NULL ) 811 return SCIP_OKAY; 812 813 SCIP_CALL( SCIPexprSimplify(set, stat, blkmem, nlrow->expr, &simplified, &changed, &infeasible, NULL, NULL) ); 814 assert(!infeasible); 815 816 if( !changed ) 817 { 818 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &simplified) ); 819 return SCIP_OKAY; 820 } 821 822 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) ); 823 nlrow->expr = simplified; 824 825 if( SCIPexprIsValue(set, nlrow->expr) ) 826 { 827 /* if expression tree is constant, remove it */ 828 SCIP_CALL( SCIPnlrowChgConstant(nlrow, set, stat, nlp, nlrow->constant + SCIPgetValueExprValue(nlrow->expr)) ); 829 830 /* removing the expression changes statistics on rows in stat, if row is already in NLP 831 * first remove current nlrow from stat, then add again after releasing expression 832 */ 833 if( nlrow->nlpindex >= 0 ) 834 nlrowAddToStat(nlp, set, nlrow, -1); 835 836 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) ); 837 nlrow->curvature = SCIP_EXPRCURV_LINEAR; 838 839 if( nlrow->nlpindex >= 0 ) 840 nlrowAddToStat(nlp, set, nlrow, 1); 841 } 842 843 SCIP_CALL( nlrowExprChanged(nlrow, blkmem, set, stat, nlp) ); 844 845 return SCIP_OKAY; 846 } 847 848 /** removes fixed variable from nonlinear row */ 849 static 850 SCIP_RETCODE nlrowRemoveFixedVar( 851 SCIP_NLROW* nlrow, /**< nonlinear row */ 852 BMS_BLKMEM* blkmem, /**< block memory */ 853 SCIP_SET* set, /**< global SCIP settings */ 854 SCIP_STAT* stat, /**< problem statistics data */ 855 SCIP_NLP* nlp, /**< current NLP data */ 856 SCIP_VAR* var /**< variable that had been fixed */ 857 ) 858 { 859 int pos; 860 861 assert(nlrow != NULL); 862 assert(var != NULL); 863 assert(!SCIPvarIsActive(var)); 864 865 /* search for variable in linear part and remove if existing */ 866 pos = nlrowSearchLinearCoef(nlrow, var); 867 if( pos >= 0 ) 868 { 869 SCIP_CALL( nlrowRemoveFixedLinearCoefPos(nlrow, blkmem, set, stat, nlp, pos) ); 870 } 871 872 /* search for variable in nonlinear part and remove all fixed variables in expression if existing 873 * TODO only call simplify if var appears in expr, but currently we don't store the vars in a separate array 874 */ 875 if( nlrow->expr != NULL ) 876 { 877 SCIP_CALL( nlrowSimplifyExpr(nlrow, blkmem, set, stat, nlp) ); 878 } 879 880 return SCIP_OKAY; 881 } 882 883 /* 884 * public NLP nonlinear row methods 885 */ 886 /**@addtogroup PublicNLRowMethods 887 * 888 * @{ 889 */ 890 891 /** create a new nonlinear row 892 * 893 * the new row is already captured 894 */ 895 SCIP_RETCODE SCIPnlrowCreate( 896 SCIP_NLROW** nlrow, /**< buffer to store pointer to nonlinear row */ 897 BMS_BLKMEM* blkmem, /**< block memory */ 898 SCIP_SET* set, /**< global SCIP settings */ 899 SCIP_STAT* stat, /**< problem statistics data */ 900 const char* name, /**< name of nonlinear row */ 901 SCIP_Real constant, /**< constant */ 902 int nlinvars, /**< number of linear variables */ 903 SCIP_VAR** linvars, /**< linear variables, or NULL if nlinvars == 0 */ 904 SCIP_Real* lincoefs, /**< linear coefficients, or NULL if nlinvars == 0 */ 905 SCIP_EXPR* expr, /**< expression, or NULL */ 906 SCIP_Real lhs, /**< left hand side */ 907 SCIP_Real rhs, /**< right hand side */ 908 SCIP_EXPRCURV curvature /**< curvature of the nonlinear row */ 909 ) 910 { 911 #ifndef NDEBUG 912 int i; 913 #endif 914 915 assert(nlrow != NULL); 916 assert(blkmem != NULL); 917 assert(set != NULL); 918 assert(name != NULL); 919 assert(!SCIPsetIsInfinity(set, ABS(constant))); 920 assert(nlinvars == 0 || linvars != NULL); 921 assert(nlinvars == 0 || lincoefs != NULL); 922 assert(SCIPsetIsRelLE(set, lhs, rhs)); 923 924 SCIP_ALLOC( BMSallocBlockMemory(blkmem, nlrow) ); 925 926 /* constant part */ 927 assert(!SCIPsetIsInfinity(set, REALABS(constant))); 928 (*nlrow)->constant = constant; 929 930 #ifndef NDEBUG 931 for( i = 0; i < nlinvars; ++i ) 932 { 933 assert(linvars[i] != NULL); 934 assert(!SCIPsetIsInfinity(set, REALABS(lincoefs[i]))); 935 } 936 #endif 937 938 /* linear part */ 939 (*nlrow)->nlinvars = nlinvars; 940 (*nlrow)->linvarssize = nlinvars; 941 if( nlinvars > 0 ) 942 { 943 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->linvars, linvars, nlinvars) ); 944 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->lincoefs, lincoefs, nlinvars) ); 945 (*nlrow)->linvarssorted = FALSE; 946 } 947 else 948 { 949 (*nlrow)->linvars = NULL; 950 (*nlrow)->lincoefs = NULL; 951 (*nlrow)->linvarssorted = TRUE; 952 } 953 954 /* nonlinear part */ 955 if( expr != NULL ) 956 { 957 /* TODO preserve common subexpressions, or at least use only one varexpr per var */ 958 SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, expr, &(*nlrow)->expr, NULL, NULL, NULL, NULL) ); 959 } 960 else 961 { 962 (*nlrow)->expr = NULL; 963 } 964 965 /* left and right hand sides, asserted above that lhs is relatively less equal than rhs */ 966 (*nlrow)->lhs = MIN(lhs, rhs); 967 (*nlrow)->rhs = MAX(lhs, rhs); 968 969 /* miscellaneous */ 970 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlrow)->name, name, strlen(name)+1) ); 971 (*nlrow)->activity = SCIP_INVALID; 972 (*nlrow)->validactivitynlp = FALSE; 973 (*nlrow)->pseudoactivity = SCIP_INVALID; 974 (*nlrow)->validpsactivitydomchg = FALSE; 975 (*nlrow)->minactivity = SCIP_INVALID; 976 (*nlrow)->maxactivity = SCIP_INVALID; 977 (*nlrow)->validactivitybdsdomchg = FALSE; 978 (*nlrow)->nlpindex = -1; 979 (*nlrow)->nlpiindex = -1; 980 (*nlrow)->nuses = 0; 981 (*nlrow)->dualsol = 0.0; 982 (*nlrow)->curvature = curvature; 983 984 /* capture the nonlinear row */ 985 SCIPnlrowCapture(*nlrow); 986 987 return SCIP_OKAY; 988 } 989 990 /** create a nonlinear row that is a copy of a given row 991 * 992 * the new row is already captured 993 */ 994 SCIP_RETCODE SCIPnlrowCreateCopy( 995 SCIP_NLROW** nlrow, /**< buffer to store pointer to nonlinear row */ 996 BMS_BLKMEM* blkmem, /**< block memory */ 997 SCIP_SET* set, /**< global SCIP settings */ 998 SCIP_STAT* stat, /**< problem statistics data */ 999 SCIP_NLROW* sourcenlrow /**< nonlinear row to copy */ 1000 ) 1001 { 1002 assert(nlrow != NULL); 1003 assert(blkmem != NULL); 1004 assert(set != NULL); 1005 assert(sourcenlrow != NULL); 1006 1007 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, sourcenlrow->name, 1008 sourcenlrow->constant, 1009 sourcenlrow->nlinvars, sourcenlrow->linvars, sourcenlrow->lincoefs, 1010 sourcenlrow->expr, 1011 sourcenlrow->lhs, sourcenlrow->rhs, sourcenlrow->curvature) ); 1012 1013 (*nlrow)->linvarssorted = sourcenlrow->linvarssorted; 1014 (*nlrow)->activity = sourcenlrow->activity; 1015 (*nlrow)->validactivitynlp = sourcenlrow->validactivitynlp; 1016 (*nlrow)->pseudoactivity = sourcenlrow->pseudoactivity; 1017 (*nlrow)->validpsactivitydomchg = sourcenlrow->validpsactivitydomchg; 1018 (*nlrow)->minactivity = sourcenlrow->minactivity; 1019 (*nlrow)->maxactivity = sourcenlrow->maxactivity; 1020 (*nlrow)->validactivitybdsdomchg = sourcenlrow->validactivitybdsdomchg; 1021 1022 return SCIP_OKAY; 1023 } 1024 1025 /** create a new nonlinear row from a linear row 1026 * 1027 * the new row is already captured 1028 */ 1029 SCIP_RETCODE SCIPnlrowCreateFromRow( 1030 SCIP_NLROW** nlrow, /**< buffer to store pointer to nonlinear row */ 1031 BMS_BLKMEM* blkmem, /**< block memory */ 1032 SCIP_SET* set, /**< global SCIP settings */ 1033 SCIP_STAT* stat, /**< problem statistics data */ 1034 SCIP_ROW* row /**< the linear row to copy */ 1035 ) 1036 { 1037 int rownz; 1038 1039 assert(nlrow != NULL); 1040 assert(blkmem != NULL); 1041 assert(set != NULL); 1042 assert(row != NULL); 1043 1044 rownz = SCIProwGetNNonz(row); 1045 1046 if( rownz > 1 ) 1047 { 1048 SCIP_VAR** rowvars; 1049 int i; 1050 1051 SCIP_CALL( SCIPsetAllocBufferArray(set, &rowvars, rownz) ); 1052 1053 for( i = 0; i < rownz; ++i ) 1054 { 1055 rowvars[i] = SCIPcolGetVar(SCIProwGetCols(row)[i]); 1056 assert(rowvars[i] != NULL); 1057 } 1058 1059 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, SCIProwGetName(row), 1060 SCIProwGetConstant(row), 1061 rownz, rowvars, SCIProwGetVals(row), NULL, 1062 SCIProwGetLhs(row), SCIProwGetRhs(row), 1063 SCIP_EXPRCURV_LINEAR) ); 1064 1065 SCIPsetFreeBufferArray(set, &rowvars); 1066 } 1067 else if( rownz == 1 ) 1068 { 1069 SCIP_VAR* rowvar; 1070 1071 rowvar = SCIPcolGetVar(SCIProwGetCols(row)[0]); 1072 1073 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, SCIProwGetName(row), 1074 SCIProwGetConstant(row), 1075 1, &rowvar, SCIProwGetVals(row), NULL, 1076 SCIProwGetLhs(row), SCIProwGetRhs(row), 1077 SCIP_EXPRCURV_LINEAR) ); 1078 } 1079 else 1080 { 1081 SCIP_CALL( SCIPnlrowCreate(nlrow, blkmem, set, stat, SCIProwGetName(row), 1082 SCIProwGetConstant(row), 1083 0, NULL, NULL, NULL, 1084 SCIProwGetLhs(row), SCIProwGetRhs(row), 1085 SCIP_EXPRCURV_LINEAR) ); 1086 } 1087 1088 return SCIP_OKAY; 1089 } 1090 1091 /** output nonlinear row to file stream */ 1092 SCIP_RETCODE SCIPnlrowPrint( 1093 SCIP_NLROW* nlrow, /**< NLP row */ 1094 BMS_BLKMEM* blkmem, /**< block memory */ 1095 SCIP_SET* set, /**< global SCIP settings */ 1096 SCIP_STAT* stat, /**< problem statistics data */ 1097 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 1098 FILE* file /**< output file (or NULL for standard output) */ 1099 ) 1100 { 1101 int i; 1102 1103 assert(nlrow != NULL); 1104 1105 /* print row name */ 1106 if( nlrow->name != NULL && nlrow->name[0] != '\0' ) 1107 { 1108 SCIPmessageFPrintInfo(messagehdlr, file, "%s: ", nlrow->name); 1109 } 1110 1111 /* print left hand side */ 1112 SCIPmessageFPrintInfo(messagehdlr, file, "%.15g <= ", nlrow->lhs); 1113 1114 /* print constant */ 1115 SCIPmessageFPrintInfo(messagehdlr, file, "%.15g ", nlrow->constant); 1116 1117 /* print linear coefficients */ 1118 for( i = 0; i < nlrow->nlinvars; ++i ) 1119 { 1120 assert(nlrow->linvars[i] != NULL); 1121 assert(SCIPvarGetName(nlrow->linvars[i]) != NULL); 1122 SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", nlrow->lincoefs[i], SCIPvarGetName(nlrow->linvars[i])); 1123 } 1124 1125 /* print nonlinear part */ 1126 if( nlrow->expr != NULL ) 1127 { 1128 SCIPmessageFPrintInfo(messagehdlr, file, " + "); 1129 SCIP_CALL( SCIPexprPrint(set, stat, blkmem, messagehdlr, file, nlrow->expr) ); 1130 } 1131 1132 /* print right hand side */ 1133 SCIPmessageFPrintInfo(messagehdlr, file, " <= %.15g", nlrow->rhs); 1134 1135 /* print convexity */ 1136 SCIPmessageFPrintInfo(messagehdlr, file, " [%s]\n", SCIPexprcurvGetName(nlrow->curvature)); 1137 1138 return SCIP_OKAY; 1139 } 1140 1141 /** increases usage counter of nonlinear row */ 1142 void SCIPnlrowCapture( 1143 SCIP_NLROW* nlrow /**< nonlinear row to capture */ 1144 ) 1145 { 1146 assert(nlrow != NULL); 1147 assert(nlrow->nuses >= 0); 1148 1149 SCIPdebugMessage("capture nonlinear row <%s> with nuses=%d\n", nlrow->name, nlrow->nuses); 1150 nlrow->nuses++; 1151 } 1152 1153 /** decreases usage counter of nonlinear row */ 1154 SCIP_RETCODE SCIPnlrowRelease( 1155 SCIP_NLROW** nlrow, /**< nonlinear row to free */ 1156 BMS_BLKMEM* blkmem, /**< block memory */ 1157 SCIP_SET* set, /**< global SCIP settings */ 1158 SCIP_STAT* stat /**< problem statistics data */ 1159 ) 1160 { 1161 assert(blkmem != NULL); 1162 assert(nlrow != NULL); 1163 assert(*nlrow != NULL); 1164 assert((*nlrow)->nuses >= 1); 1165 1166 SCIPsetDebugMsg(set, "release nonlinear row <%s> with nuses=%d\n", (*nlrow)->name, (*nlrow)->nuses); 1167 (*nlrow)->nuses--; 1168 if( (*nlrow)->nuses > 0 ) 1169 { 1170 *nlrow = NULL; 1171 return SCIP_OKAY; 1172 } 1173 1174 /* free row */ 1175 1176 assert((*nlrow)->nuses == 0); 1177 assert((*nlrow)->nlpindex == -1); 1178 assert((*nlrow)->nlpiindex == -1); 1179 1180 /* linear part */ 1181 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlrow)->linvars, (*nlrow)->linvarssize); 1182 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlrow)->lincoefs, (*nlrow)->linvarssize); 1183 1184 /* nonlinear part */ 1185 if( (*nlrow)->expr != NULL ) 1186 { 1187 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &(*nlrow)->expr) ); 1188 } 1189 1190 /* miscellaneous */ 1191 BMSfreeBlockMemoryArray(blkmem, &(*nlrow)->name, strlen((*nlrow)->name)+1); 1192 1193 BMSfreeBlockMemory(blkmem, nlrow); 1194 1195 return SCIP_OKAY; 1196 } 1197 1198 /** ensures, that linear coefficient array of nonlinear row can store at least num entries */ 1199 SCIP_RETCODE SCIPnlrowEnsureLinearSize( 1200 SCIP_NLROW* nlrow, /**< NLP row */ 1201 BMS_BLKMEM* blkmem, /**< block memory */ 1202 SCIP_SET* set, /**< global SCIP settings */ 1203 int num /**< minimum number of entries to store */ 1204 ) 1205 { 1206 assert(nlrow != NULL); 1207 assert(nlrow->nlinvars <= nlrow->linvarssize); 1208 1209 if( num > nlrow->linvarssize ) 1210 { 1211 int newsize; 1212 1213 newsize = SCIPsetCalcMemGrowSize(set, num); 1214 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlrow->linvars, nlrow->linvarssize, newsize) ); 1215 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlrow->lincoefs, nlrow->linvarssize, newsize) ); 1216 nlrow->linvarssize = newsize; 1217 } 1218 assert(num <= nlrow->linvarssize); 1219 1220 return SCIP_OKAY; 1221 } 1222 1223 /** adds a previously non existing linear coefficient to a nonlinear row */ 1224 SCIP_RETCODE SCIPnlrowAddLinearCoef( 1225 SCIP_NLROW* nlrow, /**< NLP nonlinear row */ 1226 BMS_BLKMEM* blkmem, /**< block memory */ 1227 SCIP_SET* set, /**< global SCIP settings */ 1228 SCIP_STAT* stat, /**< problem statistics data */ 1229 SCIP_NLP* nlp, /**< current NLP data */ 1230 SCIP_VAR* var, /**< variable */ 1231 SCIP_Real val /**< value of coefficient */ 1232 ) 1233 { 1234 /* if row is in NLP already, make sure that only active variables are added */ 1235 if( nlrow->nlpindex >= 0 ) 1236 { 1237 SCIP_Real constant; 1238 1239 /* get corresponding active or multi-aggregated variable */ 1240 constant = 0.0; 1241 SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &val, &constant) ); 1242 1243 /* add constant */ 1244 SCIP_CALL( SCIPnlrowChgConstant(nlrow, set, stat, nlp, nlrow->constant + constant) ); 1245 1246 if( val == 0.0 ) 1247 /* var has been fixed */ 1248 return SCIP_OKAY; 1249 1250 if( !SCIPvarIsActive(var) ) 1251 { 1252 /* var should be multi-aggregated, so call this function recursively */ 1253 int i; 1254 1255 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); 1256 for( i = 0; i < SCIPvarGetMultaggrNVars(var); ++i ) 1257 { 1258 SCIP_CALL( SCIPnlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, SCIPvarGetMultaggrVars(var)[i], SCIPvarGetMultaggrScalars(var)[i] * val) ); 1259 } 1260 return SCIP_OKAY; 1261 } 1262 1263 /* var is active, so can go on like normal */ 1264 } 1265 1266 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, val) ); 1267 1268 return SCIP_OKAY; 1269 } 1270 1271 /** deletes linear coefficient from nonlinear row */ 1272 SCIP_RETCODE SCIPnlrowDelLinearCoef( 1273 SCIP_NLROW* nlrow, /**< nonlinear row to be changed */ 1274 SCIP_SET* set, /**< global SCIP settings */ 1275 SCIP_STAT* stat, /**< problem statistics data */ 1276 SCIP_NLP* nlp, /**< current NLP data */ 1277 SCIP_VAR* var /**< coefficient to be deleted */ 1278 ) 1279 { 1280 int pos; 1281 1282 assert(nlrow != NULL); 1283 assert(var != NULL); 1284 1285 /* if the row is in the NLP already, we can only have active variables, so var should also be active; in non-debug mode, one gets an error below */ 1286 assert(nlrow->nlpindex == -1 || SCIPvarIsActive(var) ); 1287 1288 /* search the position of the variable in the row's variable vector */ 1289 pos = nlrowSearchLinearCoef(nlrow, var); 1290 if( pos == -1 ) 1291 { 1292 SCIPerrorMessage("coefficient for variable <%s> doesn't exist in nonlinear row <%s>\n", SCIPvarGetName(var), nlrow->name); 1293 return SCIP_INVALIDDATA; 1294 } 1295 assert(0 <= pos && pos < nlrow->nlinvars); 1296 assert(nlrow->linvars[pos] == var); 1297 1298 /* delete the variable from the row's variable vector */ 1299 SCIP_CALL( nlrowDelLinearCoefPos(nlrow, set, stat, nlp, pos) ); 1300 1301 return SCIP_OKAY; 1302 } 1303 1304 /** changes or adds a linear coefficient to a nonlinear row */ 1305 SCIP_RETCODE SCIPnlrowChgLinearCoef( 1306 SCIP_NLROW* nlrow, /**< nonlinear row */ 1307 BMS_BLKMEM* blkmem, /**< block memory */ 1308 SCIP_SET* set, /**< global SCIP settings */ 1309 SCIP_STAT* stat, /**< problem statistics data */ 1310 SCIP_NLP* nlp, /**< current NLP data */ 1311 SCIP_VAR* var, /**< variable */ 1312 SCIP_Real coef /**< new value of coefficient */ 1313 ) 1314 { 1315 int pos; 1316 1317 assert(nlrow != NULL); 1318 assert(nlp != NULL); 1319 assert(var != NULL); 1320 1321 /* search the position of the variable in the row's linvars vector */ 1322 pos = nlrowSearchLinearCoef(nlrow, var); 1323 1324 /* check, if column already exists in the row's linear variables vector */ 1325 if( pos == -1 ) 1326 { 1327 if( !SCIPsetIsZero(set, coef) ) 1328 { 1329 /* add previously not existing coefficient */ 1330 SCIP_CALL( nlrowAddLinearCoef(nlrow, blkmem, set, stat, nlp, var, coef) ); 1331 } 1332 } 1333 else 1334 { 1335 /* change the coefficient in the row */ 1336 SCIP_CALL( nlrowChgLinearCoefPos(nlrow, set, stat, nlp, pos, coef) ); 1337 } 1338 1339 return SCIP_OKAY; 1340 } 1341 1342 /** replaces or deletes an expression in a nonlinear row */ 1343 SCIP_RETCODE SCIPnlrowChgExpr( 1344 SCIP_NLROW* nlrow, /**< nonlinear row */ 1345 BMS_BLKMEM* blkmem, /**< block memory */ 1346 SCIP_SET* set, /**< global SCIP settings */ 1347 SCIP_STAT* stat, /**< problem statistics data */ 1348 SCIP_NLP* nlp, /**< current NLP data */ 1349 SCIP_EXPR* expr /**< new expression */ 1350 ) 1351 { 1352 assert(nlrow != NULL); 1353 assert(blkmem != NULL); 1354 1355 /* if row in NLP, then remove it from statistics on NLP rows */ 1356 if( nlrow->nlpindex >= 0 ) 1357 nlrowAddToStat(nlp, set, nlrow, -1); 1358 1359 /* free previous expression tree */ 1360 if( nlrow->expr != NULL ) 1361 { 1362 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) ); 1363 assert(nlrow->expr == NULL); 1364 } 1365 1366 /* adds new expression tree */ 1367 if( expr != NULL ) 1368 { 1369 /* TODO preserve common subexpressions, or at least use only one varexpr per var */ 1370 SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, expr, &nlrow->expr, NULL, NULL, NULL, NULL) ); 1371 1372 /* if row is already in NLP, ensure that expr has only active variables */ 1373 if( nlrow->nlpindex >= 0 ) 1374 { 1375 SCIP_EXPR* simplified; 1376 SCIP_Bool changed; 1377 SCIP_Bool infeasible; 1378 1379 SCIP_CALL( SCIPexprSimplify(set, stat, blkmem, nlrow->expr, &simplified, &changed, &infeasible, NULL, NULL) ); 1380 assert(!infeasible); 1381 1382 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &nlrow->expr) ); 1383 nlrow->expr = simplified; 1384 } 1385 } 1386 1387 /* notify row about the change */ 1388 SCIP_CALL( nlrowExprChanged(nlrow, blkmem, set, stat, nlp) ); 1389 1390 /* if row in NLP, then add it again to statistics on NLP rows */ 1391 if( nlrow->nlpindex >= 0 ) 1392 nlrowAddToStat(nlp, set, nlrow, 1); 1393 1394 return SCIP_OKAY; 1395 } 1396 1397 /** changes constant of nonlinear row */ 1398 SCIP_RETCODE SCIPnlrowChgConstant( 1399 SCIP_NLROW* nlrow, /**< nonlinear row */ 1400 SCIP_SET* set, /**< global SCIP settings */ 1401 SCIP_STAT* stat, /**< problem statistics data */ 1402 SCIP_NLP* nlp, /**< current NLP data */ 1403 SCIP_Real constant /**< new constant */ 1404 ) 1405 { 1406 assert(nlrow != NULL); 1407 1408 if( !SCIPsetIsEQ(set, nlrow->constant, constant) ) 1409 { 1410 nlrow->constant = constant; 1411 SCIP_CALL( nlrowConstantChanged(nlrow, set, stat, nlp) ); 1412 } 1413 1414 return SCIP_OKAY; 1415 } 1416 1417 /** changes left hand side of nonlinear row */ 1418 SCIP_RETCODE SCIPnlrowChgLhs( 1419 SCIP_NLROW* nlrow, /**< nonlinear row */ 1420 SCIP_SET* set, /**< global SCIP settings */ 1421 SCIP_STAT* stat, /**< problem statistics data */ 1422 SCIP_NLP* nlp, /**< current NLP data */ 1423 SCIP_Real lhs /**< new left hand side */ 1424 ) 1425 { 1426 assert(nlrow != NULL); 1427 1428 if( !SCIPsetIsEQ(set, nlrow->lhs, lhs) ) 1429 { 1430 if( nlrow->nlpindex >= 0 ) 1431 nlrowAddToStat(nlp, set, nlrow, -1); 1432 1433 nlrow->lhs = lhs; 1434 SCIP_CALL( nlrowSideChanged(nlrow, set, stat, nlp) ); 1435 1436 if( nlrow->nlpindex >= 0 ) 1437 nlrowAddToStat(nlp, set, nlrow, 1); 1438 } 1439 1440 return SCIP_OKAY; 1441 } 1442 1443 /** changes right hand side of nonlinear row */ 1444 SCIP_RETCODE SCIPnlrowChgRhs( 1445 SCIP_NLROW* nlrow, /**< nonlinear row */ 1446 SCIP_SET* set, /**< global SCIP settings */ 1447 SCIP_STAT* stat, /**< problem statistics data */ 1448 SCIP_NLP* nlp, /**< current NLP data */ 1449 SCIP_Real rhs /**< new right hand side */ 1450 ) 1451 { 1452 assert(nlrow != NULL); 1453 1454 if( !SCIPsetIsEQ(set, nlrow->rhs, rhs) ) 1455 { 1456 if( nlrow->nlpindex >= 0 ) 1457 nlrowAddToStat(nlp, set, nlrow, -1); 1458 1459 nlrow->rhs = rhs; 1460 SCIP_CALL( nlrowSideChanged(nlrow, set, stat, nlp) ); 1461 1462 if( nlrow->nlpindex >= 0 ) 1463 nlrowAddToStat(nlp, set, nlrow, 1); 1464 } 1465 1466 return SCIP_OKAY; 1467 } 1468 1469 /** sets the curvature of a nonlinear row */ 1470 void SCIPnlrowSetCurvature( 1471 SCIP_NLP* nlp, /**< NLP */ 1472 SCIP_SET* set, /**< global SCIP settings */ 1473 SCIP_NLROW* nlrow, /**< NLP row */ 1474 SCIP_EXPRCURV curvature /**< curvature of NLP row */ 1475 ) 1476 { 1477 assert(nlrow != NULL); 1478 1479 if( nlrow->nlpindex >= 0 ) 1480 nlrowAddToStat(nlp, set, nlrow, -1); 1481 1482 nlrow->curvature = curvature; 1483 1484 if( nlrow->nlpindex >= 0 ) 1485 nlrowAddToStat(nlp, set, nlrow, 1); 1486 } 1487 1488 /** removes (or substitutes) all fixed, negated, aggregated, multi-aggregated variables from the linear and nonlinear part of a nonlinear row and simplifies its expression */ 1489 SCIP_RETCODE SCIPnlrowSimplify( 1490 SCIP_NLROW* nlrow, /**< nonlinear row */ 1491 BMS_BLKMEM* blkmem, /**< block memory */ 1492 SCIP_SET* set, /**< global SCIP settings */ 1493 SCIP_STAT* stat, /**< problem statistics data */ 1494 SCIP_NLP* nlp /**< current NLP data */ 1495 ) 1496 { 1497 SCIP_CALL( nlrowRemoveFixedLinearCoefs(nlrow, blkmem, set, stat, nlp) ); 1498 SCIP_CALL( nlrowSimplifyExpr(nlrow, blkmem, set, stat, nlp) ); 1499 1500 return SCIP_OKAY; 1501 } 1502 1503 /** recalculates the current activity of a nonlinear row in the current NLP solution */ 1504 SCIP_RETCODE SCIPnlrowRecalcNLPActivity( 1505 SCIP_NLROW* nlrow, /**< nonlinear row */ 1506 BMS_BLKMEM* blkmem, /**< block memory */ 1507 SCIP_SET* set, /**< global SCIP settings */ 1508 SCIP_STAT* stat, /**< problem statistics data */ 1509 SCIP_PRIMAL* primal, /**< primal data */ 1510 SCIP_TREE* tree, /**< branch and bound tree */ 1511 SCIP_NLP* nlp /**< current NLP data */ 1512 ) 1513 { 1514 int i; 1515 1516 assert(nlrow != NULL); 1517 assert(stat != NULL); 1518 assert(nlp != NULL); 1519 1520 if( nlp->solstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE ) 1521 { 1522 SCIPerrorMessage("do not have NLP solution for computing NLP activity\n"); 1523 return SCIP_ERROR; 1524 } 1525 1526 nlrow->activity = nlrow->constant; 1527 for( i = 0; i < nlrow->nlinvars; ++i ) 1528 { 1529 assert(nlrow->linvars[i] != NULL); 1530 assert(SCIPvarGetNLPSol(nlrow->linvars[i]) < SCIP_INVALID); 1531 1532 nlrow->activity += nlrow->lincoefs[i] * SCIPvarGetNLPSol(nlrow->linvars[i]); 1533 } 1534 1535 if( nlrow->expr != NULL ) 1536 { 1537 SCIP_SOL* sol; 1538 1539 SCIP_CALL( SCIPsolCreateNLPSol(&sol, blkmem, set, stat, primal, tree, nlp, NULL) ); 1540 1541 SCIP_CALL( SCIPexprEval(set, stat, blkmem, nlrow->expr, sol, 0L) ); 1542 if( SCIPexprGetEvalValue(nlrow->expr) == SCIP_INVALID ) 1543 nlrow->activity = SCIP_INVALID; 1544 else 1545 nlrow->activity += SCIPexprGetEvalValue(nlrow->expr); 1546 1547 SCIP_CALL( SCIPsolFree(&sol, blkmem, primal) ); 1548 } 1549 1550 nlrow->validactivitynlp = stat->nnlps; 1551 1552 return SCIP_OKAY; 1553 } 1554 1555 /** gives the activity of a nonlinear row in the current NLP solution */ 1556 SCIP_RETCODE SCIPnlrowGetNLPActivity( 1557 SCIP_NLROW* nlrow, /**< nonlinear row */ 1558 BMS_BLKMEM* blkmem, /**< block memory */ 1559 SCIP_SET* set, /**< global SCIP settings */ 1560 SCIP_STAT* stat, /**< problem statistics data */ 1561 SCIP_PRIMAL* primal, /**< primal data */ 1562 SCIP_TREE* tree, /**< branch and bound tree */ 1563 SCIP_NLP* nlp, /**< current NLP data */ 1564 SCIP_Real* activity /**< buffer to store activity value */ 1565 ) 1566 { 1567 assert(nlrow != NULL); 1568 assert(stat != NULL); 1569 assert(activity != NULL); 1570 1571 assert(nlrow->validactivitynlp <= stat->nnlps); 1572 1573 if( nlrow->validactivitynlp != stat->nnlps ) 1574 { 1575 SCIP_CALL( SCIPnlrowRecalcNLPActivity(nlrow, blkmem, set, stat, primal, tree, nlp) ); 1576 } 1577 assert(nlrow->validactivitynlp == stat->nnlps); 1578 assert(nlrow->activity < SCIP_INVALID); 1579 1580 *activity = nlrow->activity; 1581 1582 return SCIP_OKAY; 1583 } 1584 1585 /** gives the feasibility of a nonlinear row in the current NLP solution: negative value means infeasibility */ 1586 SCIP_RETCODE SCIPnlrowGetNLPFeasibility( 1587 SCIP_NLROW* nlrow, /**< nonlinear row */ 1588 BMS_BLKMEM* blkmem, /**< block memory */ 1589 SCIP_SET* set, /**< global SCIP settings */ 1590 SCIP_STAT* stat, /**< problem statistics data */ 1591 SCIP_PRIMAL* primal, /**< primal data */ 1592 SCIP_TREE* tree, /**< branch and bound tree */ 1593 SCIP_NLP* nlp, /**< current NLP data */ 1594 SCIP_Real* feasibility /**< buffer to store feasibility value */ 1595 ) 1596 { 1597 SCIP_Real activity; 1598 1599 assert(nlrow != NULL); 1600 assert(feasibility != NULL); 1601 1602 SCIP_CALL( SCIPnlrowGetNLPActivity(nlrow, blkmem, set, stat, primal, tree, nlp, &activity) ); 1603 *feasibility = MIN(nlrow->rhs - activity, activity - nlrow->lhs); 1604 1605 return SCIP_OKAY; 1606 } 1607 1608 /** calculates the current pseudo activity of a nonlinear row */ 1609 SCIP_RETCODE SCIPnlrowRecalcPseudoActivity( 1610 SCIP_NLROW* nlrow, /**< nonlinear row */ 1611 BMS_BLKMEM* blkmem, /**< block memory */ 1612 SCIP_SET* set, /**< global SCIP settings */ 1613 SCIP_STAT* stat, /**< problem statistics data */ 1614 SCIP_PROB* prob, /**< SCIP problem */ 1615 SCIP_PRIMAL* primal, /**< primal data */ 1616 SCIP_TREE* tree, /**< branch and bound tree */ 1617 SCIP_LP* lp /**< SCIP LP */ 1618 ) 1619 { 1620 SCIP_Real val1; 1621 int i; 1622 1623 assert(nlrow != NULL); 1624 assert(stat != NULL); 1625 1626 nlrow->pseudoactivity = nlrow->constant; 1627 for( i = 0; i < nlrow->nlinvars; ++i ) 1628 { 1629 assert(nlrow->linvars[i] != NULL); 1630 1631 val1 = SCIPvarGetBestBoundLocal(nlrow->linvars[i]); 1632 nlrow->pseudoactivity += nlrow->lincoefs[i] * val1; 1633 } 1634 1635 if( nlrow->expr != NULL ) 1636 { 1637 SCIP_SOL* sol; 1638 1639 SCIP_CALL( SCIPsolCreatePseudoSol(&sol, blkmem, set, stat, prob, primal, tree, lp, NULL) ); 1640 1641 SCIP_CALL( SCIPexprEval(set, stat, blkmem, nlrow->expr, sol, 0L) ); 1642 if( SCIPexprGetEvalValue(nlrow->expr) == SCIP_INVALID ) 1643 nlrow->pseudoactivity = SCIP_INVALID; 1644 else 1645 nlrow->pseudoactivity += SCIPexprGetEvalValue(nlrow->expr); 1646 1647 SCIP_CALL( SCIPsolFree(&sol, blkmem, primal) ); 1648 } 1649 1650 nlrow->validpsactivitydomchg = stat->domchgcount; 1651 1652 return SCIP_OKAY; 1653 } 1654 1655 /** returns the pseudo activity of a nonlinear row in the current pseudo solution */ 1656 SCIP_RETCODE SCIPnlrowGetPseudoActivity( 1657 SCIP_NLROW* nlrow, /**< nonlinear row */ 1658 BMS_BLKMEM* blkmem, /**< block memory */ 1659 SCIP_SET* set, /**< global SCIP settings */ 1660 SCIP_STAT* stat, /**< problem statistics data */ 1661 SCIP_PROB* prob, /**< SCIP problem */ 1662 SCIP_PRIMAL* primal, /**< primal data */ 1663 SCIP_TREE* tree, /**< branch and bound tree */ 1664 SCIP_LP* lp, /**< SCIP LP */ 1665 SCIP_Real* pseudoactivity /**< buffer to store pseudo activity value */ 1666 ) 1667 { 1668 assert(nlrow != NULL); 1669 assert(stat != NULL); 1670 assert(pseudoactivity != NULL); 1671 assert(nlrow->validpsactivitydomchg <= stat->domchgcount); 1672 1673 /* check, if pseudo activity has to be calculated */ 1674 if( nlrow->validpsactivitydomchg != stat->domchgcount ) 1675 { 1676 SCIP_CALL( SCIPnlrowRecalcPseudoActivity(nlrow, blkmem, set, stat, prob, primal, tree, lp) ); 1677 } 1678 assert(nlrow->validpsactivitydomchg == stat->domchgcount); 1679 assert(nlrow->pseudoactivity < SCIP_INVALID); 1680 1681 *pseudoactivity = nlrow->pseudoactivity; 1682 1683 return SCIP_OKAY; 1684 } 1685 1686 /** returns the pseudo feasibility of a nonlinear row in the current pseudo solution: negative value means infeasibility */ 1687 SCIP_RETCODE SCIPnlrowGetPseudoFeasibility( 1688 SCIP_NLROW* nlrow, /**< nonlinear row */ 1689 BMS_BLKMEM* blkmem, /**< block memory */ 1690 SCIP_SET* set, /**< global SCIP settings */ 1691 SCIP_STAT* stat, /**< problem statistics data */ 1692 SCIP_PROB* prob, /**< SCIP problem */ 1693 SCIP_PRIMAL* primal, /**< primal data */ 1694 SCIP_TREE* tree, /**< branch and bound tree */ 1695 SCIP_LP* lp, /**< SCIP LP */ 1696 SCIP_Real* pseudofeasibility /**< buffer to store pseudo feasibility value */ 1697 ) 1698 { 1699 SCIP_Real pseudoactivity; 1700 1701 assert(nlrow != NULL); 1702 assert(stat != NULL); 1703 assert(pseudofeasibility != NULL); 1704 1705 SCIP_CALL( SCIPnlrowGetPseudoActivity(nlrow, blkmem, set, stat, prob, primal, tree, lp, &pseudoactivity) ); 1706 *pseudofeasibility = MIN(nlrow->rhs - pseudoactivity, pseudoactivity - nlrow->lhs); 1707 1708 return SCIP_OKAY; 1709 } 1710 1711 /** returns the activity of a nonlinear row for a given solution */ 1712 SCIP_RETCODE SCIPnlrowGetSolActivity( 1713 SCIP_NLROW* nlrow, /**< nonlinear row */ 1714 BMS_BLKMEM* blkmem, /**< block memory */ 1715 SCIP_SET* set, /**< global SCIP settings */ 1716 SCIP_STAT* stat, /**< problem statistics data */ 1717 SCIP_SOL* sol, /**< primal CIP solution */ 1718 SCIP_Real* activity /**< buffer to store activity value */ 1719 ) 1720 { 1721 SCIP_Real inf; 1722 SCIP_Real val1; 1723 int i; 1724 1725 assert(nlrow != NULL); 1726 assert(set != NULL); 1727 assert(stat != NULL); 1728 assert(activity != NULL); 1729 1730 *activity = nlrow->constant; 1731 for( i = 0; i < nlrow->nlinvars; ++i ) 1732 { 1733 assert(nlrow->linvars[i] != NULL); 1734 1735 val1 = SCIPsolGetVal(sol, set, stat, nlrow->linvars[i]); 1736 if( val1 == SCIP_UNKNOWN ) 1737 { 1738 *activity = SCIP_INVALID; 1739 return SCIP_OKAY; 1740 } 1741 *activity += nlrow->lincoefs[i] * val1; 1742 } 1743 1744 if( nlrow->expr != NULL ) 1745 { 1746 SCIP_CALL( SCIPexprEval(set, stat, blkmem, nlrow->expr, sol, 0L) ); 1747 if( SCIPexprGetEvalValue(nlrow->expr) == SCIP_INVALID ) 1748 *activity = SCIP_INVALID; 1749 else 1750 *activity += SCIPexprGetEvalValue(nlrow->expr); 1751 } 1752 1753 inf = SCIPsetInfinity(set); 1754 *activity = MAX(*activity, -inf); 1755 *activity = MIN(*activity, +inf); 1756 1757 return SCIP_OKAY; 1758 } 1759 1760 /** returns the feasibility of a nonlinear row for the given solution */ 1761 SCIP_RETCODE SCIPnlrowGetSolFeasibility( 1762 SCIP_NLROW* nlrow, /**< nonlinear row */ 1763 BMS_BLKMEM* blkmem, /**< block memory */ 1764 SCIP_SET* set, /**< global SCIP settings */ 1765 SCIP_STAT* stat, /**< problem statistics data */ 1766 SCIP_SOL* sol, /**< primal CIP solution */ 1767 SCIP_Real* feasibility /**< buffer to store feasibility value */ 1768 ) 1769 { 1770 SCIP_Real activity; 1771 1772 assert(nlrow != NULL); 1773 assert(feasibility != NULL); 1774 1775 SCIP_CALL( SCIPnlrowGetSolActivity(nlrow, blkmem, set, stat, sol, &activity) ); 1776 1777 *feasibility = MIN(nlrow->rhs - activity, activity - nlrow->lhs); 1778 1779 return SCIP_OKAY; 1780 } 1781 1782 /** returns the minimal activity of a nonlinear row w.r.t. the variables' bounds */ 1783 SCIP_RETCODE SCIPnlrowGetActivityBounds( 1784 SCIP_NLROW* nlrow, /**< nonlinear row */ 1785 BMS_BLKMEM* blkmem, /**< block memory */ 1786 SCIP_SET* set, /**< global SCIP settings */ 1787 SCIP_STAT* stat, /**< problem statistics data */ 1788 SCIP_Real* minactivity, /**< buffer to store minimal activity, or NULL */ 1789 SCIP_Real* maxactivity /**< buffer to store maximal activity, or NULL */ 1790 ) 1791 { 1792 assert(nlrow != NULL); 1793 assert(set != NULL); 1794 assert(stat != NULL); 1795 assert(nlrow->validactivitybdsdomchg <= stat->domchgcount); 1796 1797 /* check, if activity bounds has to be calculated */ 1798 if( nlrow->validactivitybdsdomchg != stat->domchgcount ) 1799 { 1800 SCIP_CALL( nlrowCalcActivityBounds(nlrow, blkmem, set, stat) ); 1801 } 1802 assert(nlrow->validactivitybdsdomchg == stat->domchgcount); 1803 assert(nlrow->minactivity < SCIP_INVALID); 1804 assert(nlrow->maxactivity < SCIP_INVALID); 1805 1806 if( minactivity != NULL ) 1807 *minactivity = nlrow->minactivity; 1808 if( maxactivity != NULL ) 1809 *maxactivity = nlrow->maxactivity; 1810 1811 return SCIP_OKAY; 1812 } 1813 1814 /** returns whether the nonlinear row is redundant w.r.t. the variables' bounds */ 1815 SCIP_RETCODE SCIPnlrowIsRedundant( 1816 SCIP_NLROW* nlrow, /**< nonlinear row */ 1817 BMS_BLKMEM* blkmem, /**< block memory */ 1818 SCIP_SET* set, /**< global SCIP settings */ 1819 SCIP_STAT* stat, /**< problem statistics data */ 1820 SCIP_Bool* isredundant /**< buffer to store whether row is redundant */ 1821 ) 1822 { 1823 SCIP_Real minactivity; 1824 SCIP_Real maxactivity; 1825 1826 assert(nlrow != NULL); 1827 assert(set != NULL); 1828 assert(isredundant != NULL); 1829 1830 SCIP_CALL( SCIPnlrowGetActivityBounds(nlrow, blkmem, set, stat, &minactivity, &maxactivity) ); 1831 1832 *isredundant = TRUE; 1833 if( (!SCIPsetIsInfinity(set, -nlrow->lhs) && SCIPsetIsFeasLT(set, minactivity, nlrow->lhs)) || 1834 ( !SCIPsetIsInfinity(set, nlrow->rhs) && SCIPsetIsFeasGT(set, maxactivity, nlrow->rhs)) ) 1835 *isredundant = FALSE; 1836 1837 return SCIP_OKAY; 1838 } 1839 1840 #ifdef NDEBUG 1841 /* Undo the defines from pub_nlhdlr.h, which exist if NDEBUG is defined. */ 1842 #undef SCIPnlrowGetConstant 1843 #undef SCIPnlrowGetNLinearVars 1844 #undef SCIPnlrowGetLinearVars 1845 #undef SCIPnlrowGetLinearCoefs 1846 #undef SCIPnlrowGetExpr 1847 #undef SCIPnlrowGetLhs 1848 #undef SCIPnlrowGetRhs 1849 #undef SCIPnlrowGetCurvature 1850 #undef SCIPnlrowGetName 1851 #undef SCIPnlrowGetNLPPos 1852 #undef SCIPnlrowIsInNLP 1853 #undef SCIPnlrowGetDualsol 1854 #endif 1855 1856 /** gets constant */ 1857 SCIP_Real SCIPnlrowGetConstant( 1858 SCIP_NLROW* nlrow /**< NLP row */ 1859 ) 1860 { 1861 assert(nlrow != NULL); 1862 1863 return nlrow->constant; 1864 } 1865 1866 /** gets number of variables of linear part */ 1867 int SCIPnlrowGetNLinearVars( 1868 SCIP_NLROW* nlrow /**< NLP row */ 1869 ) 1870 { 1871 assert(nlrow != NULL); 1872 1873 return nlrow->nlinvars; 1874 } 1875 1876 /** gets array with variables of linear part */ 1877 SCIP_VAR** SCIPnlrowGetLinearVars( 1878 SCIP_NLROW* nlrow /**< NLP row */ 1879 ) 1880 { 1881 assert(nlrow != NULL); 1882 1883 return nlrow->linvars; 1884 } 1885 1886 /** gets array with coefficients in linear part */ 1887 SCIP_Real* SCIPnlrowGetLinearCoefs( 1888 SCIP_NLROW* nlrow /**< NLP row */ 1889 ) 1890 { 1891 assert(nlrow != NULL); 1892 1893 return nlrow->lincoefs; 1894 } 1895 1896 /** gets expression */ 1897 SCIP_EXPR* SCIPnlrowGetExpr( 1898 SCIP_NLROW* nlrow /**< NLP row */ 1899 ) 1900 { 1901 assert(nlrow != NULL); 1902 1903 return nlrow->expr; 1904 } 1905 1906 /** returns the left hand side of a nonlinear row */ 1907 SCIP_Real SCIPnlrowGetLhs( 1908 SCIP_NLROW* nlrow /**< NLP row */ 1909 ) 1910 { 1911 assert(nlrow != NULL); 1912 1913 return nlrow->lhs; 1914 } 1915 1916 /** returns the right hand side of a nonlinear row */ 1917 SCIP_Real SCIPnlrowGetRhs( 1918 SCIP_NLROW* nlrow /**< NLP row */ 1919 ) 1920 { 1921 assert(nlrow != NULL); 1922 1923 return nlrow->rhs; 1924 } 1925 1926 /** returns the curvature of a nonlinear row */ 1927 SCIP_EXPRCURV SCIPnlrowGetCurvature( 1928 SCIP_NLROW* nlrow /**< NLP row */ 1929 ) 1930 { 1931 assert(nlrow != NULL); 1932 return nlrow->curvature; 1933 } 1934 1935 /** returns the name of a nonlinear row */ 1936 const char* SCIPnlrowGetName( 1937 SCIP_NLROW* nlrow /**< NLP row */ 1938 ) 1939 { 1940 assert(nlrow != NULL); 1941 1942 return nlrow->name; 1943 } 1944 1945 /** gets position of a nonlinear row in current NLP, or -1 if not in NLP */ 1946 int SCIPnlrowGetNLPPos( 1947 SCIP_NLROW* nlrow /**< NLP row */ 1948 ) 1949 { 1950 assert(nlrow != NULL); 1951 1952 return nlrow->nlpindex; 1953 } 1954 1955 /** returns TRUE iff row is member of current NLP */ 1956 SCIP_Bool SCIPnlrowIsInNLP( 1957 SCIP_NLROW* nlrow /**< NLP row */ 1958 ) 1959 { 1960 assert(nlrow != NULL); 1961 1962 return nlrow->nlpindex != -1; 1963 } 1964 1965 /** gets the dual NLP solution of a nlrow 1966 * 1967 * for a ranged constraint, the dual value is positive if the right hand side is active and negative if the left hand side is active 1968 */ 1969 SCIP_Real SCIPnlrowGetDualsol( 1970 SCIP_NLROW* nlrow /**< NLP row */ 1971 ) 1972 { 1973 assert(nlrow != NULL); 1974 1975 return nlrow->nlpiindex >= 0 ? nlrow->dualsol : 0.0; 1976 } 1977 1978 /** @} */ 1979 1980 /* 1981 * local NLP methods 1982 */ 1983 1984 /** announces, that a row of the NLP was modified 1985 * adjusts status of current solution 1986 * calling method has to ensure that change is passed to the NLPI! 1987 */ /*lint -e{715}*/ 1988 static 1989 SCIP_RETCODE nlpRowChanged( 1990 SCIP_NLP* nlp, /**< current NLP data */ 1991 SCIP_SET* set, /**< global SCIP settings */ 1992 SCIP_STAT* stat, /**< problem statistics data */ 1993 SCIP_NLROW* nlrow /**< nonlinear row which was changed */ 1994 ) 1995 { /*lint --e{715}*/ 1996 assert(nlp != NULL); 1997 assert(nlrow != NULL); 1998 assert(!nlp->indiving); 1999 assert(nlrow->nlpindex >= 0); 2000 2001 /* nlrow is a row in the NLP, so changes effect feasibility */ 2002 /* if we have a feasible NLP solution and it satisfies the modified row, then it is still feasible 2003 * if the NLP was globally or locally infeasible or unbounded, then this may not be the case anymore 2004 */ 2005 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE ) 2006 { 2007 /* TODO bring this back? then everything that may call nlpRowChanged will need to pass on blkmem, primal, tree as well 2008 SCIP_Real feasibility; 2009 SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, blkmem, set, stat, primal, tree, nlp, &feasibility) ); 2010 if( !SCIPsetIsFeasNegative(set, feasibility) ) 2011 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE; 2012 else */ 2013 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE; 2014 } 2015 else 2016 { 2017 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN; 2018 } 2019 2020 return SCIP_OKAY; 2021 } 2022 2023 /** adds a set of nonlinear rows to the NLP and captures them */ 2024 static 2025 SCIP_RETCODE nlpAddNlRows( 2026 SCIP_NLP* nlp, /**< NLP data */ 2027 BMS_BLKMEM* blkmem, /**< block memory */ 2028 SCIP_SET* set, /**< global SCIP settings */ 2029 SCIP_STAT* stat, /**< problem statistics data */ 2030 int nnlrows, /**< number of nonlinear rows to add */ 2031 SCIP_NLROW** nlrows /**< nonlinear rows to add */ 2032 ) 2033 { 2034 #ifndef NDEBUG 2035 int i; 2036 #endif 2037 int j; 2038 SCIP_NLROW* nlrow; 2039 2040 assert(nlp != NULL); 2041 assert(blkmem != NULL); 2042 assert(set != NULL); 2043 assert(nlrows != NULL || nnlrows == 0); 2044 assert(!nlp->indiving); 2045 2046 SCIP_CALL( SCIPnlpEnsureNlRowsSize(nlp, blkmem, set, nlp->nnlrows + nnlrows) ); 2047 2048 for( j = 0; j < nnlrows; ++j ) 2049 { 2050 nlrow = nlrows[j]; /*lint !e613*/ 2051 2052 /* assert that row is not in NLP (or even NLPI) yet */ 2053 assert(nlrow->nlpindex == -1); 2054 assert(nlrow->nlpiindex == -1); 2055 2056 /* make sure there are only active variables in row */ 2057 SCIP_CALL( SCIPnlrowSimplify(nlrow, blkmem, set, stat, nlp) ); 2058 2059 #ifndef NDEBUG 2060 /* assert that variables of row are in NLP */ 2061 for( i = 0; i < nlrow->nlinvars; ++i ) 2062 assert(SCIPhashmapExists(nlp->varhash, nlrow->linvars[i])); 2063 2064 if( nlrow->expr != NULL ) 2065 { 2066 SCIP_EXPRITER* it; 2067 SCIP_EXPR* expr; 2068 2069 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) ); 2070 SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, TRUE) ); 2071 for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) ) 2072 assert(!SCIPexprIsVar(set, expr) || SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(expr))); 2073 SCIPexpriterFree(&it); 2074 } 2075 #endif 2076 2077 /* add row to NLP and capture it */ 2078 nlp->nlrows[nlp->nnlrows + j] = nlrow; 2079 nlrow->nlpindex = nlp->nnlrows + j; 2080 2081 nlrowAddToStat(nlp, set, nlrow, 1); 2082 2083 SCIPnlrowCapture(nlrow); 2084 2085 /* if we have a feasible NLP solution and it satisfies the new solution, then it is still feasible 2086 * if the NLP was globally or locally infeasible, then it stays that way 2087 * if the NLP was unbounded, then this may not be the case anymore 2088 */ 2089 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE ) 2090 { 2091 /* TODO bring this back? then everything that may call nlpAddNlRows will need to pass on primal, tree as well 2092 SCIP_Real feasibility; 2093 SCIP_CALL( SCIPnlrowGetNLPFeasibility(nlrow, blkmem, set, stat, primal, tree, nlp, &feasibility) ); 2094 if( !SCIPsetIsFeasNegative(set, feasibility) ) 2095 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE; 2096 else 2097 */ 2098 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE; 2099 } 2100 else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED ) 2101 { 2102 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN; 2103 } 2104 } 2105 2106 nlp->nnlrows += nnlrows; 2107 nlp->nunflushednlrowadd += nnlrows; 2108 2109 return SCIP_OKAY; 2110 } 2111 2112 /** moves a nonlinear row to a different place, and updates all corresponding data structures */ 2113 static 2114 void nlpMoveNlrow( 2115 SCIP_NLP* nlp, /**< NLP data structure */ 2116 int oldpos, /**< old position of nonlinear row */ 2117 int newpos /**< new position of nonlinear row */ 2118 ) 2119 { 2120 assert(nlp != NULL); 2121 assert(0 <= oldpos && oldpos < nlp->nnlrows); 2122 assert(0 <= newpos && newpos < nlp->nnlrows); 2123 assert(nlp->nlrows[oldpos] != NULL); 2124 2125 if( oldpos == newpos ) 2126 return; 2127 2128 nlp->nlrows[newpos] = nlp->nlrows[oldpos]; 2129 nlp->nlrows[newpos]->nlpindex = newpos; 2130 2131 /* update nlpi to nlp row index mapping */ 2132 if( nlp->nlrows[newpos]->nlpiindex >= 0 ) 2133 { 2134 assert(nlp->nlrowmap_nlpi2nlp != NULL); 2135 assert(nlp->nlrows[newpos]->nlpiindex < nlp->sizenlrows_solver); 2136 nlp->nlrowmap_nlpi2nlp[nlp->nlrows[newpos]->nlpiindex] = newpos; 2137 } 2138 } 2139 2140 /** deletes nonlinear row with given position from NLP */ 2141 static 2142 SCIP_RETCODE nlpDelNlRowPos( 2143 SCIP_NLP* nlp, /**< NLP data structure */ 2144 BMS_BLKMEM* blkmem, /**< block memory */ 2145 SCIP_SET* set, /**< global SCIP settings */ 2146 SCIP_STAT* stat, /**< problem statistics data */ 2147 int pos /**< position of nonlinear row that is to be removed */ 2148 ) 2149 { 2150 SCIP_NLROW* nlrow; 2151 2152 assert(nlp != NULL); 2153 assert(blkmem != NULL); 2154 assert(set != NULL); 2155 assert(pos >= 0); 2156 assert(pos < nlp->nnlrows); 2157 assert(!nlp->indiving); 2158 assert(nlp->nlrows != NULL); 2159 2160 nlrow = nlp->nlrows[pos]; 2161 assert(nlrow != NULL); 2162 assert(nlrow->nlpindex == pos); 2163 2164 /* if row is in NLPI, then mark that it has to be removed in the next flush 2165 * if row was not in NLPI yet, then we have one unflushed nlrow addition less */ 2166 if( nlrow->nlpiindex >= 0 ) 2167 { 2168 assert(nlrow->nlpiindex < nlp->nnlrows_solver); 2169 nlp->nlrowmap_nlpi2nlp[nlrow->nlpiindex] = -1; 2170 nlrow->nlpiindex = -1; 2171 ++nlp->nunflushednlrowdel; 2172 } 2173 else 2174 { 2175 assert(nlrow->nlpiindex == -1); 2176 --nlp->nunflushednlrowadd; 2177 } 2178 2179 /* move NLP row from the end to pos and mark nlrow to be not in NLP anymore */ 2180 nlpMoveNlrow(nlp, nlp->nnlrows-1, pos); 2181 nlrow->nlpindex = -1; 2182 2183 /* do no longer count nlrow in NLP row statistics */ 2184 nlrowAddToStat(nlp, set, nlrow, -1); 2185 2186 /* forget about restriction */ 2187 SCIP_CALL( SCIPnlrowRelease(&nlrow, blkmem, set, stat) ); 2188 --nlp->nnlrows; 2189 2190 if( nlp->solstat < SCIP_NLPSOLSTAT_LOCOPT ) 2191 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE; 2192 else if( nlp->solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE ) 2193 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE; 2194 2195 return SCIP_OKAY; /*lint !e438*/ 2196 } 2197 2198 /** updates bounds on a variable in the NLPI problem */ 2199 static 2200 SCIP_RETCODE nlpUpdateVarBounds( 2201 SCIP_NLP* nlp, /**< NLP data */ 2202 SCIP_SET* set, /**< global SCIP settings */ 2203 SCIP_VAR* var, /**< variable which bounds have changed */ 2204 SCIP_Bool tightened /**< whether the bound change was a bound tightening */ 2205 ) 2206 { 2207 int pos; 2208 SCIP_Real lb; 2209 SCIP_Real ub; 2210 2211 assert(nlp != NULL); 2212 assert(var != NULL); 2213 assert(SCIPhashmapExists(nlp->varhash, var)); 2214 2215 /* original variable bounds are ignored during diving 2216 * (all variable bounds are reset to their current value in exitDiving) */ 2217 if( nlp->indiving ) 2218 return SCIP_OKAY; 2219 2220 /* get position of variable in NLP */ 2221 pos = SCIPhashmapGetImageInt(nlp->varhash, var); 2222 2223 /* if variable not in NLPI yet, nothing to do */ 2224 if( nlp->varmap_nlp2nlpi[pos] == -1 ) 2225 return SCIP_OKAY; 2226 2227 /* update bounds in NLPI problem */ 2228 assert(nlp->solver != NULL); 2229 assert(nlp->problem != NULL); 2230 2231 pos = nlp->varmap_nlp2nlpi[pos]; 2232 lb = SCIPvarGetLbLocal(var); 2233 ub = SCIPvarGetUbLocal(var); 2234 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, 1, &pos, &lb, &ub) ); 2235 2236 /* if we have a feasible NLP solution and it satisfies the new bounds, then it is still feasible 2237 * if the NLP was globally or locally infeasible and we tightened a bound, then it stays that way 2238 * if the NLP was unbounded and we tightened a bound, then this may not be the case anymore 2239 */ 2240 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE ) 2241 { 2242 if( !tightened || 2243 ((SCIPsetIsInfinity(set, -lb) || SCIPsetIsFeasLE(set, lb, SCIPvarGetNLPSol(var))) && 2244 (SCIPsetIsInfinity(set, ub) || SCIPsetIsFeasGE(set, ub, SCIPvarGetNLPSol(var)))) ) 2245 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE; 2246 else 2247 nlp->solstat = SCIP_NLPSOLSTAT_LOCINFEASIBLE; 2248 } 2249 else if( !tightened || nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED ) 2250 { 2251 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN; 2252 } 2253 2254 return SCIP_OKAY; 2255 } 2256 2257 /** updates coefficient of a variable in the objective */ 2258 static 2259 SCIP_RETCODE nlpUpdateObjCoef( 2260 SCIP_SET* set, /**< global SCIP settings */ 2261 SCIP_NLP* nlp, /**< NLP data */ 2262 SCIP_VAR* var /**< variable which bounds have changed */ 2263 ) 2264 { 2265 int pos; 2266 int objidx; 2267 SCIP_Real coef; 2268 2269 assert(nlp != NULL); 2270 assert(var != NULL); 2271 assert(SCIPhashmapExists(nlp->varhash, var)); 2272 2273 /* if the objective in the NLPI is not up to date, then we do not need to do something here */ 2274 if( !nlp->objflushed ) 2275 return SCIP_OKAY; 2276 2277 /* original objective is ignored during diving 2278 * we just need to remember that at end of diving we have to flush the objective */ 2279 if( nlp->indiving ) 2280 { 2281 nlp->objflushed = FALSE; 2282 return SCIP_OKAY; 2283 } 2284 2285 /* get position of variable in NLP and objective coefficient */ 2286 pos = SCIPhashmapGetImageInt(nlp->varhash, var); 2287 assert(nlp->varmap_nlp2nlpi[pos] == -1 || nlp->solver != NULL); 2288 2289 /* actually we only need to remember flushing the objective if we also have an NLPI */ 2290 if( nlp->solver == NULL ) 2291 return SCIP_OKAY; 2292 2293 coef = SCIPvarGetObj(var); 2294 2295 /* if variable not in NLPI yet, then we only need to remember to update the objective after variable additions were flushed */ 2296 if( nlp->varmap_nlp2nlpi[pos] == -1 && coef != 0.0 ) 2297 { 2298 nlp->objflushed = FALSE; 2299 2300 return SCIP_OKAY; 2301 } 2302 2303 /* if we are here, then the objective in the NLPI is up to date, 2304 * we keep it this way by changing the coefficient of var in the NLPI problem objective */ 2305 assert(nlp->solver != NULL); 2306 assert(nlp->problem != NULL); 2307 2308 pos = nlp->varmap_nlp2nlpi[pos]; 2309 objidx = -1; 2310 SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, objidx, 1, &pos, &coef) ); 2311 2312 /* if we had a solution and it was locally (or globally) optimal, then now we can only be sure that it is still feasible */ 2313 if( nlp->solstat < SCIP_NLPSOLSTAT_FEASIBLE ) 2314 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE; 2315 2316 return SCIP_OKAY; 2317 } 2318 2319 /** adds new variables to the NLP */ 2320 static 2321 SCIP_RETCODE nlpAddVars( 2322 SCIP_NLP* nlp, /**< NLP data structure */ 2323 BMS_BLKMEM* blkmem, /**< block memory */ 2324 SCIP_SET* set, /**< global SCIP settings */ 2325 int nvars, /**< number of variables to add */ 2326 SCIP_VAR** vars /**< variable to add to NLP */ 2327 ) 2328 { 2329 int i; 2330 SCIP_VAR* var; 2331 2332 assert(nlp != NULL); 2333 assert(blkmem != NULL); 2334 assert(set != NULL); 2335 assert(vars != NULL || nvars == 0); 2336 assert(!nlp->indiving || nvars == 0); 2337 2338 if( nvars == 0 ) 2339 return SCIP_OKAY; 2340 2341 SCIP_CALL( SCIPnlpEnsureVarsSize(nlp, blkmem, set, nlp->nvars + nvars) ); 2342 assert(nlp->sizevars >= nlp->nvars + nvars); 2343 2344 for( i = 0; i < nvars; ++i ) 2345 { 2346 var = vars[i]; /*lint !e613*/ 2347 2348 assert(SCIPvarIsTransformed(var)); 2349 assert(SCIPvarIsActive(var)); 2350 assert(!SCIPhashmapExists(nlp->varhash, var)); 2351 2352 SCIPvarCapture(var); 2353 2354 nlp->vars[nlp->nvars+i] = var; 2355 nlp->varmap_nlp2nlpi[nlp->nvars+i] = -1; 2356 SCIP_CALL( SCIPhashmapInsertInt(nlp->varhash, var, nlp->nvars+i) ); 2357 2358 nlp->varlbdualvals[nlp->nvars+i] = 0.0; 2359 nlp->varubdualvals[nlp->nvars+i] = 0.0; 2360 2361 /* update objective, if necessary (new variables have coefficient 0.0 anyway) */ 2362 if( SCIPvarGetObj(var) != 0.0 ) 2363 { 2364 SCIP_CALL( nlpUpdateObjCoef(set, nlp, var) ); 2365 } 2366 2367 /* let's keep the previous initial guess and set it for the new variable to the best bound 2368 * (since there can be no row that uses this variable yet, this seems a good guess) */ 2369 if( nlp->haveinitguess ) 2370 { 2371 assert(nlp->initialguess != NULL); 2372 2373 nlp->initialguess[nlp->nvars+i] = SCIPvarGetBestBoundLocal(var); 2374 } 2375 2376 /* if we have a feasible NLP solution, then it remains feasible 2377 * but we have to update the objective function 2378 */ 2379 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE ) 2380 { 2381 SCIP_CALL( SCIPvarSetNLPSol(var, set, SCIPvarGetBestBoundLocal(var)) ); 2382 nlp->primalsolobjval += SCIPvarGetObj(var) * SCIPvarGetBestBoundLocal(var); 2383 nlp->solstat = SCIP_NLPSOLSTAT_FEASIBLE; 2384 } 2385 2386 /* catch events on variable */ 2387 SCIP_CALL( SCIPvarCatchEvent(var, blkmem, set, \ 2388 SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \ 2389 nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, NULL) ); /* @todo should store event filter position in nlp? */ 2390 } 2391 2392 nlp->nvars += nvars; 2393 nlp->nunflushedvaradd += nvars; 2394 2395 return SCIP_OKAY; 2396 } 2397 2398 /** moves a variable to a different place, and updates all corresponding data structures */ 2399 static 2400 SCIP_RETCODE nlpMoveVar( 2401 SCIP_NLP* nlp, /**< NLP data structure */ 2402 int oldpos, /**< old position of variable */ 2403 int newpos /**< new position of variable */ 2404 ) 2405 { 2406 int nlpipos; 2407 2408 assert(nlp != NULL); 2409 assert(0 <= oldpos && oldpos < nlp->nvars); 2410 assert(0 <= newpos && newpos < nlp->nvars); 2411 assert(nlp->vars[oldpos] != NULL); 2412 2413 if( oldpos == newpos ) 2414 return SCIP_OKAY; 2415 2416 SCIP_CALL( SCIPhashmapSetImageInt(nlp->varhash, nlp->vars[oldpos], newpos) ); 2417 nlp->vars[newpos] = nlp->vars[oldpos]; 2418 nlp->varmap_nlp2nlpi[newpos] = nlp->varmap_nlp2nlpi[oldpos]; 2419 nlp->varlbdualvals[newpos] = nlp->varlbdualvals[oldpos]; 2420 nlp->varubdualvals[newpos] = nlp->varubdualvals[oldpos]; 2421 if( nlp->initialguess != NULL ) 2422 nlp->initialguess[newpos] = nlp->initialguess[oldpos]; 2423 2424 nlpipos = nlp->varmap_nlp2nlpi[newpos]; 2425 if( nlpipos > 0 ) 2426 nlp->varmap_nlpi2nlp[nlpipos] = newpos; 2427 2428 return SCIP_OKAY; 2429 } 2430 2431 /** deletes variable with given position from NLP */ 2432 static 2433 SCIP_RETCODE nlpDelVarPos( 2434 SCIP_NLP* nlp, /**< NLP data structure */ 2435 BMS_BLKMEM* blkmem, /**< block memory */ 2436 SCIP_SET* set, /**< global SCIP settings */ 2437 SCIP_STAT* stat, /**< problem statistics data */ 2438 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 2439 SCIP_LP* lp, /**< SCIP LP, needed if a column-variable is freed */ 2440 int pos /**< position of nonlinear row that is to be removed */ 2441 ) 2442 { 2443 SCIP_VAR* var; 2444 #ifndef NDEBUG 2445 int i; 2446 #endif 2447 int nlpipos; 2448 2449 assert(nlp != NULL); 2450 assert(blkmem != NULL); 2451 assert(set != NULL); 2452 assert(pos >= 0); 2453 assert(pos < nlp->nvars); 2454 assert(!nlp->indiving); 2455 2456 var = nlp->vars[pos]; 2457 assert(var != NULL); 2458 2459 #ifndef NDEBUG 2460 /* assert that variable is not used by any nonlinear row */ 2461 for( i = 0; i < nlp->nnlrows; ++i ) 2462 { 2463 int j; 2464 SCIP_NLROW* nlrow; 2465 2466 nlrow = nlp->nlrows[i]; 2467 assert(nlrow != NULL); 2468 2469 /* use nlrowSearchLinearCoef only if already sorted, since otherwise we may change the solving process slightly */ 2470 if( nlrow->linvarssorted ) 2471 assert( nlrowSearchLinearCoef(nlrow, var) == -1 ); 2472 else 2473 for( j = 0; j < nlrow->nlinvars; ++j ) 2474 assert( nlrow->linvars[j] != var ); 2475 2476 if( nlrow->expr != NULL ) 2477 { 2478 SCIP_EXPRITER* it; 2479 SCIP_EXPR* expr; 2480 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) ); 2481 SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, TRUE) ); 2482 for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) ) 2483 assert(!SCIPexprIsVar(set, expr) || SCIPgetVarExprVar(expr) != var); 2484 SCIPexpriterFree(&it); 2485 } 2486 } 2487 #endif 2488 2489 /* if we had a feasible solution, then adjust objective function value 2490 * if NLP was unbounded before, then maybe it is not anymore */ 2491 if( nlp->solstat <= SCIP_NLPSOLSTAT_FEASIBLE ) 2492 nlp->primalsolobjval -= SCIPvarGetObj(var) * SCIPvarGetNLPSol(var); 2493 else if( nlp->solstat == SCIP_NLPSOLSTAT_UNBOUNDED ) 2494 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN; 2495 2496 /* if variable is in NLPI problem, mark that we have to remember to delete it there 2497 * if it was not in the NLPI yet, then we have one unflushed var addition less now */ 2498 nlpipos = nlp->varmap_nlp2nlpi[pos]; 2499 if( nlpipos >= 0 ) 2500 { 2501 assert(nlpipos < nlp->nvars_solver); 2502 2503 nlp->varmap_nlpi2nlp[nlpipos] = -1; 2504 ++nlp->nunflushedvardel; 2505 } 2506 else 2507 --nlp->nunflushedvaradd; 2508 2509 /* drop events on variable */ 2510 SCIP_CALL( SCIPvarDropEvent(var, blkmem, set, \ 2511 SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED, \ 2512 nlp->eventhdlr, (SCIP_EVENTDATA*)nlp, -1) ); 2513 2514 /* move variable from end to pos */ 2515 SCIP_CALL( nlpMoveVar(nlp, nlp->nvars-1, pos) ); 2516 2517 /* forget about variable */ 2518 SCIP_CALL( SCIPhashmapRemove(nlp->varhash, var) ); 2519 SCIP_CALL( SCIPvarRelease(&var, blkmem, set, eventqueue, lp) ); 2520 --nlp->nvars; 2521 2522 return SCIP_OKAY; 2523 } 2524 2525 /** notifies NLP that a variable was fixed, so it is removed from objective, all rows, and the NLP variables */ 2526 static 2527 SCIP_RETCODE nlpRemoveFixedVar( 2528 SCIP_NLP* nlp, /**< NLP data */ 2529 BMS_BLKMEM* blkmem, /**< block memory */ 2530 SCIP_SET* set, /**< global SCIP settings */ 2531 SCIP_STAT* stat, /**< problem statistics data */ 2532 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 2533 SCIP_LP* lp, /**< SCIP LP, needed to release variable */ 2534 SCIP_VAR* var /**< variable that has been fixed */ 2535 ) 2536 { 2537 int i; 2538 2539 assert(nlp != NULL); 2540 assert(var != NULL); 2541 assert(!SCIPvarIsActive(var)); 2542 assert(!nlp->indiving); 2543 assert(SCIPhashmapExists(nlp->varhash, var)); 2544 2545 /* remove var from all rows */ 2546 for( i = 0; i < nlp->nnlrows; ++i ) 2547 { 2548 SCIP_CALL( nlrowRemoveFixedVar(nlp->nlrows[i], blkmem, set, stat, nlp, var) ); 2549 } 2550 2551 /* remove variable from NLP */ 2552 SCIP_CALL( SCIPnlpDelVar(nlp, blkmem, set, stat, eventqueue, lp, var) ); 2553 2554 return SCIP_OKAY; 2555 } 2556 2557 /** creates arrays with NLPI variable indices of linear variables in a nonlinear row */ 2558 static 2559 SCIP_RETCODE nlpSetupNlpiIndices( 2560 SCIP_NLP* nlp, /**< NLP data */ 2561 SCIP_SET* set, /**< global SCIP settings */ 2562 SCIP_NLROW* nlrow, /**< nonlinear row */ 2563 int** linidxs /**< buffer to store pointer to NLPI indices of linear variables */ 2564 ) 2565 { 2566 int i; 2567 SCIP_VAR* var; 2568 2569 assert(nlp != NULL); 2570 assert(set != NULL); 2571 assert(nlrow != NULL); 2572 assert(linidxs != NULL); 2573 2574 /* get indices of variables in linear part of row */ 2575 if( nlrow->nlinvars > 0 ) 2576 { 2577 assert(nlrow->linvars != NULL); 2578 assert(nlrow->lincoefs != NULL); 2579 2580 SCIP_CALL( SCIPsetAllocBufferArray(set, linidxs, nlrow->nlinvars) ); 2581 2582 for( i = 0; i < nlrow->nlinvars; ++i ) 2583 { 2584 var = nlrow->linvars[i]; 2585 assert(var != NULL); 2586 assert(SCIPvarIsActive(var)); /* at this point, there should be only active variables in the row */ 2587 2588 assert(SCIPhashmapExists(nlp->varhash, var)); 2589 (*linidxs)[i] = nlp->varmap_nlp2nlpi[SCIPhashmapGetImageInt(nlp->varhash, var)]; 2590 assert((*linidxs)[i] >= 0); 2591 } 2592 } 2593 else 2594 *linidxs = NULL; 2595 2596 return SCIP_OKAY; 2597 } 2598 2599 /** ensures, that NLPI variables array of NLP can store at least num entries */ 2600 static 2601 SCIP_RETCODE nlpEnsureVarsSolverSize( 2602 SCIP_NLP* nlp, /**< NLP data */ 2603 BMS_BLKMEM* blkmem, /**< block memory */ 2604 SCIP_SET* set, /**< global SCIP settings */ 2605 int num /**< minimum number of entries to store */ 2606 ) 2607 { 2608 assert(nlp != NULL); 2609 assert(blkmem != NULL); 2610 assert(set != NULL); 2611 assert(nlp->nvars_solver <= nlp->sizevars_solver); 2612 2613 if( num > nlp->sizevars_solver ) 2614 { 2615 int newsize; 2616 2617 newsize = SCIPsetCalcMemGrowSize(set, num); 2618 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlpi2nlp, nlp->sizevars_solver, newsize) ); 2619 2620 nlp->sizevars_solver = newsize; 2621 } 2622 assert(num <= nlp->sizevars_solver); 2623 2624 return SCIP_OKAY; 2625 } 2626 2627 /** ensures, that NLPI nonlinear rows array of NLP can store at least num entries */ 2628 static 2629 SCIP_RETCODE nlpEnsureNlRowsSolverSize( 2630 SCIP_NLP* nlp, /**< NLP data */ 2631 BMS_BLKMEM* blkmem, /**< block memory */ 2632 SCIP_SET* set, /**< global SCIP settings */ 2633 int num /**< minimum number of entries to store */ 2634 ) 2635 { 2636 assert(nlp != NULL); 2637 assert(blkmem != NULL); 2638 assert(set != NULL); 2639 assert(nlp->nnlrows_solver <= nlp->sizenlrows_solver); 2640 2641 if( num > nlp->sizenlrows_solver ) 2642 { 2643 int newsize; 2644 2645 newsize = SCIPsetCalcMemGrowSize(set, num); 2646 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrowmap_nlpi2nlp, nlp->sizenlrows_solver, newsize) ); 2647 2648 nlp->sizenlrows_solver = newsize; 2649 } 2650 assert(num <= nlp->sizenlrows_solver); 2651 2652 return SCIP_OKAY; 2653 } 2654 2655 /** deletes rows from the NLPI problem that have been marked as to remove */ 2656 static 2657 SCIP_RETCODE nlpFlushNlRowDeletions( 2658 SCIP_NLP* nlp, /**< NLP data */ 2659 BMS_BLKMEM* blkmem, /**< block memory */ 2660 SCIP_SET* set /**< global SCIP settings */ 2661 ) 2662 { 2663 int j; 2664 int c; /* counts the number of rows to delete */ 2665 int* rowset; /* marks which rows to delete and stores new indices */ 2666 SCIP_NLROW* nlrow; 2667 2668 assert(nlp != NULL); 2669 assert(blkmem != NULL); 2670 assert(set != NULL); 2671 assert(nlp->nunflushednlrowdel >= 0); 2672 assert(!nlp->indiving); 2673 2674 if( nlp->nunflushednlrowdel == 0 ) 2675 { 2676 #ifndef NDEBUG 2677 /* check that there are really no pending removals of nonlinear rows */ 2678 for( j = 0; j < nlp->nnlrows_solver; ++j ) 2679 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0); 2680 #endif 2681 return SCIP_OKAY; 2682 } 2683 2684 assert(nlp->solver != NULL); 2685 assert(nlp->problem != NULL); 2686 2687 /* create marker which rows have to be deleted */ 2688 SCIP_CALL( SCIPsetAllocBufferArray(set, &rowset, nlp->nnlrows_solver) ); 2689 c = 0; 2690 for( j = 0; j < nlp->nnlrows_solver; ++j ) 2691 { 2692 if( nlp->nlrowmap_nlpi2nlp[j] == -1 ) 2693 { 2694 rowset[j] = 1; 2695 ++c; 2696 } 2697 else 2698 rowset[j] = 0; 2699 } 2700 assert(c == nlp->nunflushednlrowdel); 2701 2702 /* remove rows from NLPI problem */ 2703 SCIP_CALL( SCIPnlpiDelConsSet(set, nlp->solver, nlp->problem, rowset, nlp->nnlrows_solver) ); 2704 2705 /* update NLPI row indices */ 2706 for( j = 0; j < nlp->nnlrows_solver; ++j ) 2707 { 2708 assert(rowset[j] <= j); /* we assume that the NLP solver did not move a row behind its previous position!! */ 2709 if( rowset[j] < 0 ) 2710 { 2711 /* assert that row was marked as deleted */ 2712 assert(nlp->nlrowmap_nlpi2nlp[j] == -1); 2713 } 2714 else if( rowset[j] < j ) 2715 { 2716 /* nlrow at position j moved (forward) to position rowset[j] */ 2717 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0); 2718 assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows); 2719 2720 nlrow = nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]]; 2721 assert(nlrow->nlpiindex == j); 2722 2723 /* there should be no row at the new position already */ 2724 assert(nlp->nlrowmap_nlpi2nlp[rowset[j]] == -1); 2725 2726 nlrow->nlpiindex = rowset[j]; 2727 nlp->nlrowmap_nlpi2nlp[rowset[j]] = nlrow->nlpindex; 2728 } 2729 else 2730 { 2731 /* row j stays at position j */ 2732 assert(nlp->nlrowmap_nlpi2nlp[j] >= 0); 2733 assert(nlp->nlrowmap_nlpi2nlp[j] < nlp->nnlrows); 2734 assert(nlp->nlrows[nlp->nlrowmap_nlpi2nlp[j]]->nlpiindex == j); 2735 } 2736 } 2737 nlp->nnlrows_solver -= c; 2738 nlp->nunflushednlrowdel = 0; 2739 2740 /* cleanup */ 2741 SCIPsetFreeBufferArray(set, &rowset); 2742 2743 return SCIP_OKAY; 2744 } 2745 2746 /** deletes variables from the NLPI problem that have been marked as to remove 2747 * 2748 * assumes that there are no pending row deletions (nlpFlushNlRowDeletions() should be called first) 2749 */ 2750 static 2751 SCIP_RETCODE nlpFlushVarDeletions( 2752 SCIP_NLP* nlp, /**< NLP data */ 2753 BMS_BLKMEM* blkmem, /**< block memory */ 2754 SCIP_SET* set /**< global SCIP settings */ 2755 ) 2756 { 2757 int i; 2758 int c; /* counter on number of variables to remove in solver */ 2759 int* colset; /* marks which variables to delete and stores new indices */ 2760 2761 assert(nlp != NULL); 2762 assert(blkmem != NULL); 2763 assert(set != NULL); 2764 assert(nlp->nunflushedvardel >= 0); 2765 assert(nlp->nunflushednlrowdel == 0); 2766 assert(!nlp->indiving); 2767 2768 if( nlp->nunflushedvardel == 0 ) 2769 { 2770 #ifndef NDEBUG 2771 /* check that there are really no pending removals of variables */ 2772 for( i = 0; i < nlp->nvars_solver; ++i ) 2773 assert(nlp->varmap_nlpi2nlp[i] >= 0); 2774 #endif 2775 return SCIP_OKAY; 2776 } 2777 2778 assert(nlp->solver != NULL); 2779 assert(nlp->problem != NULL); 2780 2781 /* create marker which variables have to be deleted */ 2782 SCIP_CALL( SCIPsetAllocBufferArray(set, &colset, nlp->nvars_solver) ); 2783 c = 0; 2784 for( i = 0; i < nlp->nvars_solver; ++i ) 2785 { 2786 if( nlp->varmap_nlpi2nlp[i] == -1 ) 2787 { 2788 colset[i] = 1; 2789 ++c; 2790 } 2791 else 2792 colset[i] = 0; 2793 } 2794 assert(c == nlp->nunflushedvardel); 2795 2796 /* delete variables from NLPI problem */ 2797 SCIP_CALL( SCIPnlpiDelVarSet(set, nlp->solver, nlp->problem, colset, nlp->nvars_solver) ); 2798 2799 /* update NLPI variable indices */ 2800 for( i = 0; i < nlp->nvars_solver; ++i ) 2801 { 2802 assert(colset[i] <= i); /* we assume that the NLP solver did not move a variable behind its previous position!! */ 2803 if( colset[i] < 0 ) 2804 { 2805 /* assert that variable was marked as deleted */ 2806 assert(nlp->varmap_nlpi2nlp[i] == -1); 2807 } 2808 else if( colset[i] < i) 2809 { 2810 /* variable at position i moved (forward) to position colset[i] */ 2811 int varpos; 2812 2813 varpos = nlp->varmap_nlpi2nlp[i]; /* position of variable i in NLP */ 2814 assert(varpos >= 0); 2815 assert(varpos < nlp->nvars); 2816 assert(nlp->varmap_nlp2nlpi[varpos] == i); 2817 2818 /* there should be no variable at the new position already */ 2819 assert(nlp->varmap_nlpi2nlp[colset[i]] == -1); 2820 2821 nlp->varmap_nlp2nlpi[varpos] = colset[i]; 2822 nlp->varmap_nlpi2nlp[colset[i]] = varpos; 2823 } 2824 else 2825 { 2826 /* variable i stays at position i */ 2827 assert(nlp->varmap_nlpi2nlp[i] >= 0); 2828 assert(nlp->varmap_nlpi2nlp[i] < nlp->nvars); 2829 assert(nlp->varmap_nlp2nlpi[nlp->varmap_nlpi2nlp[i]] == i); 2830 } 2831 } 2832 2833 nlp->nvars_solver -= c; 2834 nlp->nunflushedvardel = 0; 2835 2836 /* cleanup */ 2837 SCIPsetFreeBufferArray(set, &colset); 2838 2839 return SCIP_OKAY; 2840 } 2841 2842 /** adds nonlinear rows to NLPI problem that have been added to NLP before 2843 * 2844 * assumes that there are no pending variable additions or deletions (nlpFlushVarDeletions() and nlpFlushVarAdditions() should be called first) 2845 */ 2846 static 2847 SCIP_RETCODE nlpFlushNlRowAdditions( 2848 SCIP_NLP* nlp, /**< NLP data */ 2849 BMS_BLKMEM* blkmem, /**< block memory */ 2850 SCIP_SET* set, /**< global SCIP settings */ 2851 SCIP_STAT* stat /**< problem statistics */ 2852 ) 2853 { 2854 int c, i; 2855 SCIP_NLROW* nlrow; 2856 SCIP_Real* lhss; 2857 SCIP_Real* rhss; 2858 int* nlinvars; 2859 int** linidxs; 2860 SCIP_Real** lincoefs; 2861 SCIP_EXPR** exprs; 2862 const char** names; 2863 2864 assert(nlp != NULL); 2865 assert(blkmem != NULL); 2866 assert(set != NULL); 2867 assert(nlp->nunflushednlrowadd >= 0); 2868 assert(nlp->nunflushedvaradd == 0); 2869 assert(nlp->nunflushedvardel == 0); 2870 assert(!nlp->indiving); 2871 2872 if( nlp->nunflushednlrowadd == 0 ) 2873 { 2874 #ifndef NDEBUG 2875 /* check that there are really no pending additions of variables */ 2876 for( i = 0; i < nlp->nnlrows; ++i ) 2877 assert(nlp->nlrows[i]->nlpiindex >= 0); 2878 #endif 2879 return SCIP_OKAY; 2880 } 2881 2882 assert(nlp->solver != NULL); 2883 assert(nlp->problem != NULL); 2884 2885 SCIP_CALL( nlpEnsureNlRowsSolverSize(nlp, blkmem, set, nlp->nnlrows_solver + nlp->nunflushednlrowadd) ); 2886 2887 SCIP_CALL( SCIPsetAllocBufferArray(set, &lhss, nlp->nunflushednlrowadd) ); 2888 SCIP_CALL( SCIPsetAllocBufferArray(set, &rhss, nlp->nunflushednlrowadd) ); 2889 SCIP_CALL( SCIPsetAllocBufferArray(set, &nlinvars, nlp->nunflushednlrowadd) ); 2890 SCIP_CALL( SCIPsetAllocBufferArray(set, &linidxs, nlp->nunflushednlrowadd) ); 2891 SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs, nlp->nunflushednlrowadd) ); 2892 SCIP_CALL( SCIPsetAllocBufferArray(set, &exprs, nlp->nunflushednlrowadd) ); 2893 #if ADDNAMESTONLPI 2894 SCIP_CALL( SCIPsetAllocBufferArray(set, &names, nlp->nunflushednlrowadd) ); 2895 #else 2896 names = NULL; 2897 #endif 2898 2899 c = 0; 2900 for( i = 0; i < nlp->nnlrows; ++i ) 2901 { 2902 nlrow = nlp->nlrows[i]; 2903 assert(nlrow != NULL); 2904 2905 /* skip nonlinear rows already in NLPI problem */ 2906 if( nlrow->nlpiindex >= 0 ) 2907 continue; 2908 assert(c < nlp->nunflushednlrowadd); 2909 2910 /* get indices in NLPI */ 2911 SCIP_CALL( nlpSetupNlpiIndices(nlp, set, nlrow, &linidxs[c]) ); 2912 assert(linidxs[c] != NULL || nlrow->nlinvars == 0); 2913 2914 nlp->nlrowmap_nlpi2nlp[nlp->nnlrows_solver+c] = i; 2915 nlrow->nlpiindex = nlp->nnlrows_solver+c; 2916 2917 lhss[c] = nlrow->lhs; 2918 rhss[c] = nlrow->rhs; 2919 if( nlrow->constant != 0.0 ) 2920 { 2921 if( !SCIPsetIsInfinity(set, -nlrow->lhs) ) 2922 lhss[c] -= nlrow->constant; 2923 if( !SCIPsetIsInfinity(set, nlrow->rhs) ) 2924 rhss[c] -= nlrow->constant; 2925 } 2926 if( rhss[c] < lhss[c] ) 2927 { 2928 assert(SCIPsetIsEQ(set, lhss[c], rhss[c])); 2929 rhss[c] = lhss[c]; 2930 } 2931 2932 nlinvars[c] = nlrow->nlinvars; 2933 lincoefs[c] = nlrow->lincoefs; 2934 2935 if( nlrow->expr != NULL ) 2936 { 2937 /* create copy of expr that uses varidx expressions corresponding to variables indices in NLPI */ 2938 SCIP_CALL( SCIPexprCopy(set, stat, blkmem, set, stat, blkmem, nlrow->expr, &exprs[c], mapvar2varidx, (void*)nlp, NULL, NULL) ); 2939 } 2940 else 2941 exprs[c] = NULL; 2942 2943 #if ADDNAMESTONLPI 2944 names[c] = nlrow->name; 2945 #endif 2946 2947 ++c; 2948 2949 #ifdef NDEBUG 2950 /* have c vars to add already, there can be no more */ 2951 if( c == nlp->nunflushednlrowadd ) 2952 break; 2953 #endif 2954 } 2955 assert(c == nlp->nunflushednlrowadd); 2956 2957 nlp->nnlrows_solver += c; 2958 2959 SCIP_CALL( SCIPnlpiAddConstraints(set, nlp->solver, nlp->problem, c, lhss, rhss, 2960 nlinvars, linidxs, lincoefs, 2961 exprs, 2962 names) ); 2963 2964 for( c = nlp->nunflushednlrowadd - 1; c >= 0 ; --c ) 2965 { 2966 if( linidxs[c] != NULL ) 2967 SCIPsetFreeBufferArray(set, &linidxs[c]); 2968 if( exprs[c] != NULL ) 2969 { 2970 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &exprs[c]) ); 2971 } 2972 } 2973 2974 #if ADDNAMESTONLPI 2975 SCIPsetFreeBufferArray(set, &names); 2976 #endif 2977 SCIPsetFreeBufferArray(set, &exprs); 2978 SCIPsetFreeBufferArray(set, &lincoefs); 2979 SCIPsetFreeBufferArray(set, &linidxs); 2980 SCIPsetFreeBufferArray(set, &nlinvars); 2981 SCIPsetFreeBufferArray(set, &rhss); 2982 SCIPsetFreeBufferArray(set, &lhss); 2983 2984 nlp->nunflushednlrowadd = 0; 2985 2986 return SCIP_OKAY; 2987 } 2988 2989 2990 /** adds variables to NLPI problem that have been added to NLP before 2991 * 2992 * may set nlp->objflushed to FALSE if a variable with nonzero objective coefficient is added to the NLPI problem 2993 */ 2994 static 2995 SCIP_RETCODE nlpFlushVarAdditions( 2996 SCIP_NLP* nlp, /**< NLP data */ 2997 BMS_BLKMEM* blkmem, /**< block memory */ 2998 SCIP_SET* set /**< global SCIP settings */ 2999 ) 3000 { 3001 int i, c; 3002 SCIP_Real* lbs; 3003 SCIP_Real* ubs; 3004 const char** names; 3005 3006 assert(nlp != NULL); 3007 assert(blkmem != NULL); 3008 assert(set != NULL); 3009 assert(nlp->nunflushedvaradd >= 0); 3010 assert(!nlp->indiving); 3011 3012 if( nlp->nunflushedvaradd == 0 ) 3013 { 3014 #ifndef NDEBUG 3015 /* check that there are really no pending additions of variables */ 3016 for( i = 0; i < nlp->nvars; ++i ) 3017 assert(nlp->varmap_nlp2nlpi[i] >= 0); 3018 #endif 3019 return SCIP_OKAY; 3020 } 3021 3022 assert(nlp->solver != NULL); 3023 assert(nlp->problem != NULL); 3024 3025 SCIP_CALL( nlpEnsureVarsSolverSize(nlp, blkmem, set, nlp->nvars_solver + nlp->nunflushedvaradd) ); 3026 3027 SCIP_CALL( SCIPsetAllocBufferArray(set, &lbs, nlp->nunflushedvaradd) ); 3028 SCIP_CALL( SCIPsetAllocBufferArray(set, &ubs, nlp->nunflushedvaradd) ); 3029 #if ADDNAMESTONLPI 3030 SCIP_CALL( SCIPsetAllocBufferArray(set, &names, nlp->nunflushedvaradd) ); 3031 #else 3032 names = NULL; 3033 #endif 3034 3035 c = 0; 3036 for( i = 0; i < nlp->nvars; ++i ) 3037 { 3038 /* skip variables already in NLPI problem */ 3039 if( nlp->varmap_nlp2nlpi[i] >= 0 ) 3040 continue; 3041 assert(c < nlp->nunflushedvaradd); 3042 3043 nlp->varmap_nlpi2nlp[nlp->nvars_solver+c] = i; 3044 nlp->varmap_nlp2nlpi[i] = nlp->nvars_solver+c; 3045 lbs[c] = SCIPvarGetLbLocal(nlp->vars[i]); 3046 ubs[c] = SCIPvarGetUbLocal(nlp->vars[i]); 3047 #if ADDNAMESTONLPI 3048 names[c] = SCIPvarGetName(nlp->vars[i]); 3049 #endif 3050 ++c; 3051 3052 /* if the new variable has a nonzero objective coefficient, then the objective need to be updated */ 3053 if( !SCIPsetIsZero(set, SCIPvarGetObj(nlp->vars[i])) ) 3054 nlp->objflushed = FALSE; 3055 3056 #ifdef NDEBUG 3057 /* have c vars to add already, there can be no more */ 3058 if( c == nlp->nunflushedvaradd ) 3059 break; 3060 #endif 3061 } 3062 assert(c == nlp->nunflushedvaradd); 3063 3064 nlp->nvars_solver += c; 3065 3066 SCIP_CALL( SCIPnlpiAddVars(set, nlp->solver, nlp->problem, c, lbs, ubs, names) ); 3067 3068 #if ADDNAMESTONLPI 3069 SCIPsetFreeBufferArray(set, &names); 3070 #endif 3071 SCIPsetFreeBufferArray(set, &ubs); 3072 SCIPsetFreeBufferArray(set, &lbs); 3073 3074 nlp->nunflushedvaradd = 0; 3075 3076 return SCIP_OKAY; 3077 } 3078 3079 /** updates the objective in the NLPI problem, if necessary 3080 * 3081 * assumes that there are no unflushed variable additions or deletions (nlpFlushVarDeletions() and nlpFlushVarAdditions() should be called first) 3082 */ 3083 static 3084 SCIP_RETCODE nlpFlushObjective( 3085 SCIP_NLP* nlp, /**< NLP data */ 3086 BMS_BLKMEM* blkmem, /**< block memory */ 3087 SCIP_SET* set /**< global SCIP settings */ 3088 ) 3089 { 3090 int* linindices; 3091 SCIP_Real* lincoefs; 3092 SCIP_Real coef; 3093 int i; 3094 int nz; 3095 3096 assert(nlp != NULL); 3097 assert(blkmem != NULL); 3098 assert(set != NULL); 3099 assert(nlp->nunflushedvaradd == 0); 3100 assert(nlp->nunflushedvardel == 0); 3101 assert(!nlp->indiving); 3102 3103 if( nlp->objflushed ) 3104 return SCIP_OKAY; 3105 3106 assert(nlp->solver != NULL); 3107 assert(nlp->problem != NULL); 3108 3109 /* assemble coefficients */ 3110 SCIP_CALL( SCIPsetAllocBufferArray(set, &linindices, nlp->nvars_solver) ); 3111 SCIP_CALL( SCIPsetAllocBufferArray(set, &lincoefs, nlp->nvars_solver) ); 3112 3113 nz = 0; 3114 for( i = 0; i < nlp->nvars_solver; ++i ) 3115 { 3116 assert(nlp->varmap_nlpi2nlp[i] >= 0); /* there should be no variable deletions pending */ 3117 3118 coef = SCIPvarGetObj(nlp->vars[nlp->varmap_nlpi2nlp[i]]); 3119 if( SCIPsetIsZero(set, coef) ) 3120 continue; 3121 3122 linindices[nz] = i; 3123 lincoefs[nz] = coef; 3124 ++nz; 3125 } 3126 3127 SCIP_CALL( SCIPnlpiSetObjective(set, nlp->solver, nlp->problem, 3128 nz, linindices, lincoefs, 3129 NULL, 3130 0.0) ); 3131 3132 SCIPsetFreeBufferArray(set, &lincoefs); 3133 SCIPsetFreeBufferArray(set, &linindices); 3134 3135 nlp->objflushed = TRUE; 3136 3137 return SCIP_OKAY; 3138 } 3139 3140 /** solves the NLP (or diving NLP), assuming it has been flushed already */ 3141 static 3142 SCIP_RETCODE nlpSolve( 3143 SCIP_NLP* nlp, /**< NLP data */ 3144 BMS_BLKMEM* blkmem, /**< block memory buffers */ 3145 SCIP_SET* set, /**< global SCIP settings */ 3146 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 3147 SCIP_STAT* stat, /**< problem statistics */ 3148 SCIP_PRIMAL* primal, /**< primal data */ 3149 SCIP_TREE* tree, /**< branch and bound tree */ 3150 SCIP_NLPPARAM* nlpparam /**< NLP solve parameters */ 3151 ) 3152 { 3153 int i; 3154 3155 assert(nlp != NULL); 3156 assert(blkmem != NULL); 3157 assert(set != NULL); 3158 assert(stat != NULL); 3159 3160 if( nlp->solver == NULL ) 3161 { 3162 SCIPmessagePrintWarning(messagehdlr, "Attempted to solve NLP, but no solver available.\n"); 3163 3164 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN; 3165 nlp->termstat = SCIP_NLPTERMSTAT_OTHER; 3166 3167 return SCIP_OKAY; 3168 } 3169 3170 assert(nlp->solver != NULL); 3171 assert(nlp->problem != NULL); 3172 3173 /* set initial guess, if available and warmstart hasn't been enabled 3174 * when using the NLP, passing a dual solution with the initguess is not available at the moment (TODO), 3175 * so a warmstart has to start from the last solution stored in the NLPI 3176 */ 3177 if( nlp->haveinitguess && !nlpparam->warmstart ) 3178 { 3179 /* @todo should we not set it if we had set it already? (initguessflushed...) */ 3180 SCIP_Real* initialguess_solver; 3181 int nlpidx; 3182 3183 assert(nlp->initialguess != NULL); 3184 3185 SCIP_CALL( SCIPsetAllocBufferArray(set, &initialguess_solver, nlp->nvars_solver) ); 3186 3187 for( i = 0; i < nlp->nvars_solver; ++i ) 3188 { 3189 nlpidx = nlp->varmap_nlpi2nlp[i]; 3190 assert(nlpidx >= 0); 3191 assert(nlpidx < nlp->nvars); 3192 3193 initialguess_solver[i] = nlp->initialguess[nlpidx]; 3194 } 3195 SCIP_CALL( SCIPnlpiSetInitialGuess(set, nlp->solver, nlp->problem, initialguess_solver, NULL, NULL, NULL) ); 3196 3197 SCIPsetFreeBufferArray(set, &initialguess_solver); 3198 } 3199 3200 /* let NLP solver do his work */ 3201 SCIPclockStart(stat->nlpsoltime, set); 3202 3203 SCIP_CALL( SCIPnlpiSolve(set, stat, nlp->solver, nlp->problem, nlpparam) ); 3204 3205 SCIPclockStop(stat->nlpsoltime, set); 3206 ++stat->nnlps; 3207 3208 nlp->termstat = SCIPnlpiGetTermstat(set, nlp->solver, nlp->problem); 3209 nlp->solstat = SCIPnlpiGetSolstat(set, nlp->solver, nlp->problem); 3210 switch( nlp->solstat ) 3211 { 3212 case SCIP_NLPSOLSTAT_GLOBOPT: 3213 case SCIP_NLPSOLSTAT_LOCOPT: 3214 case SCIP_NLPSOLSTAT_FEASIBLE: 3215 case SCIP_NLPSOLSTAT_LOCINFEASIBLE: 3216 { 3217 SCIP_Real* primalvals; 3218 SCIP_Real* nlrowdualvals; 3219 SCIP_Real* varlbdualvals; 3220 SCIP_Real* varubdualvals; 3221 3222 primalvals = NULL; 3223 nlrowdualvals = NULL; 3224 varlbdualvals = NULL; 3225 varubdualvals = NULL; 3226 3227 /* get NLP solution */ 3228 SCIP_CALL( SCIPnlpiGetSolution(set, nlp->solver, nlp->problem, &primalvals, &nlrowdualvals, &varlbdualvals, &varubdualvals, NULL) ); 3229 assert(primalvals != NULL || nlp->nvars == 0); 3230 assert((varlbdualvals != NULL) == (varubdualvals != NULL)); /* if there are duals for one bound, then there should also be duals for the other bound */ 3231 3232 /* store solution primal values in variable and evaluate objective function */ 3233 if( nlp->indiving && nlp->divingobj != NULL ) 3234 { 3235 for( i = 0; i < nlp->nvars; ++i ) 3236 { 3237 SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, primalvals[nlp->varmap_nlp2nlpi[i]]) ); /*lint !e613 */ 3238 } 3239 3240 /* evaluate modified diving objective */ 3241 SCIP_CALL( SCIPnlrowGetNLPActivity(nlp->divingobj, blkmem, set, stat, primal, tree, nlp, &nlp->primalsolobjval) ); 3242 } 3243 else 3244 { 3245 /* evaluate SCIP objective function */ 3246 nlp->primalsolobjval = 0.0; 3247 for( i = 0; i < nlp->nvars; ++i ) 3248 { 3249 SCIP_Real solval = primalvals[nlp->varmap_nlp2nlpi[i]]; /*lint !e613 */ 3250 3251 /* do a quick assert that variable bounds are satisfied, if feasibility is claimed */ 3252 assert(SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(nlp->vars[i])) || 3253 SCIPsetIsFeasGE(set, solval, SCIPvarGetLbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE); 3254 assert(SCIPsetIsInfinity(set, SCIPvarGetUbLocal(nlp->vars[i])) || 3255 SCIPsetIsFeasLE(set, solval, SCIPvarGetUbLocal(nlp->vars[i])) || nlp->solstat > SCIP_NLPSOLSTAT_FEASIBLE); 3256 3257 SCIP_CALL( SCIPvarSetNLPSol(nlp->vars[i], set, solval) ); /*lint !e613 */ 3258 nlp->primalsolobjval += SCIPvarGetObj(nlp->vars[i]) * solval; /*lint !e613 */ 3259 } 3260 } 3261 3262 /* store solution dual values in nlrows and variables */ 3263 for( i = 0; i < nlp->nnlrows; ++i ) 3264 { 3265 assert(nlp->nlrows[i]->nlpiindex >= 0); /* NLP was flushed before solve, so all nlrows should be in there */ 3266 3267 nlp->nlrows[i]->dualsol = nlrowdualvals != NULL ? nlrowdualvals[nlp->nlrows[i]->nlpiindex] : 0.0; 3268 3269 /* SCIPsetDebugMsg(set, "dual of nlrow <%s> = %g\n", nlp->nlrows[i]->name, nlp->nlrows[i]->dualsol); */ 3270 } 3271 assert(nlp->varlbdualvals != NULL || nlp->nvars == 0); 3272 assert(nlp->varubdualvals != NULL || nlp->nvars == 0); 3273 if( varlbdualvals != NULL ) 3274 { 3275 for( i = 0; i < nlp->nvars; ++i ) 3276 { 3277 assert(nlp->varmap_nlp2nlpi[i] >= 0); /* NLP was flushed before solve, so all vars should be in there */ 3278 3279 nlp->varlbdualvals[i] = varlbdualvals[nlp->varmap_nlp2nlpi[i]]; 3280 nlp->varubdualvals[i] = varubdualvals[nlp->varmap_nlp2nlpi[i]]; 3281 3282 /* SCIPsetDebugMsg(set, "duals of var <%s> = %g %g\n", SCIPvarGetName(nlp->vars[i]), nlp->varlbdualvals[i], nlp->varubdualvals[i]); */ 3283 } 3284 } 3285 else if( nlp->nvars > 0 ) 3286 { 3287 BMSclearMemoryArray(nlp->varlbdualvals, nlp->nvars); 3288 BMSclearMemoryArray(nlp->varubdualvals, nlp->nvars); 3289 } 3290 3291 break; 3292 } 3293 default: 3294 nlp->primalsolobjval = SCIP_INVALID; 3295 break; 3296 } /*lint !e788*/ 3297 3298 return SCIP_OKAY; 3299 } 3300 3301 /** assembles list of fractional variables in last NLP solution */ 3302 static 3303 SCIP_RETCODE nlpCalcFracVars( 3304 SCIP_NLP* nlp, /**< NLP data */ 3305 BMS_BLKMEM* blkmem, /**< block memory buffers */ 3306 SCIP_SET* set, /**< global SCIP settings */ 3307 SCIP_STAT* stat /**< problem statistics */ 3308 ) 3309 { 3310 assert(nlp != NULL); 3311 assert(blkmem != NULL); 3312 assert(set != NULL); 3313 assert(stat != NULL); 3314 assert(nlp->validfracvars <= stat->nnlps); 3315 assert(SCIPnlpHasSolution(nlp)); 3316 3317 SCIPsetDebugMsg(set, "calculating NLP fractional variables: validfracvars=%" SCIP_LONGINT_FORMAT ", nnlps=%" SCIP_LONGINT_FORMAT "\n", nlp->validfracvars, stat->nnlps); 3318 3319 if( nlp->solstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE ) 3320 { 3321 nlp->nfracvars = 0; 3322 nlp->npriofracvars = 0; 3323 nlp->validfracvars = stat->nnlps; 3324 3325 SCIPsetDebugMsg(set, "NLP globally infeasible, unbounded, or worse -> no solution values -> no fractional variables\n"); 3326 return SCIP_OKAY; 3327 } 3328 3329 /* check, if the current NLP fractional variables array is invalid */ 3330 if( nlp->validfracvars < stat->nnlps ) 3331 { 3332 SCIP_VAR* var; 3333 SCIP_Real primsol; 3334 SCIP_Real frac; 3335 int branchpriority; 3336 int insertpos; 3337 int maxpriority; 3338 int i; 3339 3340 SCIPsetDebugMsg(set, " -> recalculating NLP fractional variables\n"); 3341 3342 if( nlp->fracvarssize == 0 ) 3343 { 3344 assert(nlp->fracvars == NULL); 3345 assert(nlp->fracvarssol == NULL); 3346 assert(nlp->fracvarsfrac == NULL); 3347 nlp->fracvarssize = 5; 3348 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvars, nlp->fracvarssize) ); 3349 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarssol, nlp->fracvarssize) ); 3350 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize) ); 3351 } 3352 3353 maxpriority = INT_MIN; 3354 nlp->nfracvars = 0; 3355 nlp->npriofracvars = 0; 3356 for( i = 0; i < nlp->nvars; ++i ) 3357 { 3358 var = nlp->vars[i]; 3359 assert(var != NULL); 3360 3361 primsol = SCIPvarGetNLPSol(var); 3362 assert(primsol < SCIP_INVALID); 3363 3364 /* consider only binary and integer variables */ 3365 if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && SCIPvarGetType(var) != SCIP_VARTYPE_INTEGER ) 3366 continue; 3367 3368 /* ignore fixed variables (due to numerics, it is possible, that the NLP solution of a fixed integer variable 3369 * (with large fixed value) is fractional in terms of absolute feasibility measure) 3370 */ 3371 if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 ) 3372 continue; 3373 3374 /* check, if the LP solution value is fractional */ 3375 frac = SCIPsetFeasFrac(set, primsol); 3376 3377 /* The fractionality should not be smaller than -feastol, however, if the primsol is large enough 3378 * and close to an integer, fixed precision floating point arithmetic might give us values slightly 3379 * smaller than -feastol. Originally, the "frac >= -feastol"-check was within SCIPsetIsFeasFracIntegral(), 3380 * however, we relaxed it to "frac >= -2*feastol" and have the stricter check here for small-enough primsols. 3381 */ 3382 assert(SCIPsetIsGE(set, frac, -SCIPsetFeastol(set)) || (primsol > 1e14 * SCIPsetFeastol(set))); 3383 3384 if( SCIPsetIsFeasFracIntegral(set, frac) ) 3385 continue; 3386 3387 /* ensure enough space in fracvars arrays */ 3388 if( nlp->fracvarssize <= nlp->nfracvars ) 3389 { 3390 int newsize; 3391 3392 newsize = SCIPsetCalcMemGrowSize(set, nlp->nfracvars + 1); 3393 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvars, nlp->fracvarssize, newsize) ); 3394 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarssol, nlp->fracvarssize, newsize) ); 3395 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->fracvarsfrac, nlp->fracvarssize, newsize) ); 3396 nlp->fracvarssize = newsize; 3397 } 3398 assert(nlp->nfracvars < nlp->fracvarssize); 3399 assert(nlp->fracvars != NULL); 3400 assert(nlp->fracvarssol != NULL); 3401 assert(nlp->fracvarsfrac != NULL); 3402 3403 /* insert candidate in candidate list */ 3404 branchpriority = SCIPvarGetBranchPriority(var); 3405 insertpos = nlp->nfracvars; 3406 nlp->nfracvars++; 3407 if( branchpriority > maxpriority ) 3408 { 3409 /* candidate has higher priority than the current maximum: 3410 * move it to the front and declare it to be the single best candidate 3411 */ 3412 if( insertpos != 0 ) 3413 { 3414 nlp->fracvars[insertpos] = nlp->fracvars[0]; 3415 nlp->fracvarssol[insertpos] = nlp->fracvarssol[0]; 3416 nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[0]; 3417 insertpos = 0; 3418 } 3419 nlp->npriofracvars = 1; 3420 maxpriority = branchpriority; 3421 } 3422 else if( branchpriority == maxpriority ) 3423 { 3424 /* candidate has equal priority as the current maximum: 3425 * move away the first non-maximal priority candidate, move the current candidate to the correct 3426 * slot (binaries first) and increase the number of maximal priority candidates 3427 */ 3428 if( insertpos != nlp->npriofracvars ) 3429 { 3430 nlp->fracvars[insertpos] = nlp->fracvars[nlp->npriofracvars]; 3431 nlp->fracvarssol[insertpos] = nlp->fracvarssol[nlp->npriofracvars]; 3432 nlp->fracvarsfrac[insertpos] = nlp->fracvarsfrac[nlp->npriofracvars]; 3433 insertpos = nlp->npriofracvars; 3434 } 3435 ++nlp->npriofracvars; 3436 } 3437 nlp->fracvars[insertpos] = var; 3438 nlp->fracvarssol[insertpos] = primsol; 3439 nlp->fracvarsfrac[insertpos] = frac; 3440 3441 SCIPsetDebugMsg(set, " -> candidate %d: var=<%s>, sol=%g, frac=%g, prio=%d (max: %d) -> pos %d\n", 3442 nlp->nfracvars, SCIPvarGetName(var), primsol, frac, branchpriority, maxpriority, insertpos); 3443 } 3444 3445 nlp->validfracvars = stat->nnlps; 3446 } 3447 assert(0 <= nlp->npriofracvars); 3448 assert(nlp->npriofracvars <= nlp->nfracvars); 3449 3450 SCIPsetDebugMsg(set, " -> %d fractional variables (%d of maximal priority)\n", nlp->nfracvars, nlp->npriofracvars); 3451 3452 return SCIP_OKAY; 3453 } 3454 3455 /** event handling for variable events */ 3456 static 3457 SCIP_DECL_EVENTEXEC(eventExecNlp) 3458 { 3459 SCIP_EVENTTYPE etype; 3460 SCIP_VAR* var; 3461 3462 assert(scip != NULL); 3463 assert(eventhdlr != NULL); 3464 assert(event != NULL); 3465 assert(eventdata != NULL); 3466 3467 assert((SCIP_NLP*)eventdata == scip->nlp); 3468 3469 etype = SCIPeventGetType(event); 3470 var = SCIPeventGetVar(event); 3471 3472 if( SCIP_EVENTTYPE_VARADDED & etype ) 3473 { 3474 SCIPdebugMessage("-> handling varadd event, variable <%s>\n", SCIPvarGetName(var) ); 3475 SCIP_CALL( SCIPnlpAddVar(scip->nlp, SCIPblkmem(scip), scip->set, var) ); 3476 } 3477 else if( SCIP_EVENTTYPE_VARDELETED & etype ) 3478 { 3479 SCIPdebugMessage("-> handling vardel event, variable <%s>\n", SCIPvarGetName(var) ); 3480 SCIP_CALL( SCIPnlpDelVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) ); 3481 } 3482 else if( SCIP_EVENTTYPE_VARFIXED & etype ) 3483 { 3484 /* variable was fixed, aggregated, or multi-aggregated */ 3485 /* TODO is this ever happening? that is, can we have changes in a variable status during solve? */ 3486 SCIPdebugMessage("-> handling variable fixation event, variable <%s>\n", SCIPvarGetName(var) ); 3487 SCIP_CALL( nlpRemoveFixedVar(scip->nlp, SCIPblkmem(scip), scip->set, scip->stat, scip->eventqueue, scip->lp, var) ); 3488 } 3489 else if( SCIP_EVENTTYPE_BOUNDCHANGED & etype ) 3490 { 3491 SCIPdebugMessage("-> handling bound changed event %" SCIP_EVENTTYPE_FORMAT ", variable <%s>\n", etype, SCIPvarGetName(var) ); 3492 SCIP_CALL( nlpUpdateVarBounds(scip->nlp, scip->set, var, (SCIP_Bool)(SCIP_EVENTTYPE_BOUNDTIGHTENED & etype)) ); 3493 } 3494 else if( SCIP_EVENTTYPE_OBJCHANGED & etype ) 3495 { 3496 SCIPdebugMessage("-> handling objchg event, variable <%s>\n", SCIPvarGetName(var) ); 3497 SCIP_CALL( nlpUpdateObjCoef(scip->set, scip->nlp, var) ); 3498 } 3499 else 3500 { 3501 SCIPerrorMessage("unexpected event %" SCIP_EVENTTYPE_FORMAT " on variable <%s>\n", etype, SCIPvarGetName(var) ); 3502 return SCIP_ERROR; 3503 } 3504 3505 return SCIP_OKAY; 3506 } 3507 3508 3509 /* 3510 * public NLP methods 3511 */ 3512 3513 /** includes event handler that is used by NLP */ 3514 SCIP_RETCODE SCIPnlpInclude( 3515 SCIP_SET* set, /**< global SCIP settings */ 3516 BMS_BLKMEM* blkmem /**< block memory */ 3517 ) 3518 { 3519 SCIP_EVENTHDLR* eventhdlr; 3520 3521 assert(set != NULL); 3522 assert(blkmem != NULL); 3523 assert(set->stage == SCIP_STAGE_INIT); 3524 3525 /* check whether event handler is already present */ 3526 if( SCIPsetFindEventhdlr(set, EVENTHDLR_NAME) != NULL ) 3527 { 3528 SCIPerrorMessage("event handler <" EVENTHDLR_NAME "> already included.\n"); 3529 return SCIP_INVALIDDATA; 3530 } 3531 3532 SCIP_CALL( SCIPeventhdlrCreate(&eventhdlr, set, EVENTHDLR_NAME, EVENTHDLR_DESC, 3533 NULL, NULL, NULL, NULL, NULL, NULL, NULL, eventExecNlp, NULL) ); 3534 SCIP_CALL( SCIPsetIncludeEventhdlr(set, eventhdlr) ); 3535 3536 return SCIP_OKAY; 3537 } /*lint !e715*/ 3538 3539 /** construct a new empty NLP */ 3540 SCIP_RETCODE SCIPnlpCreate( 3541 SCIP_NLP** nlp, /**< NLP handler, call by reference */ 3542 BMS_BLKMEM* blkmem, /**< block memory */ 3543 SCIP_SET* set, /**< global SCIP settings */ 3544 SCIP_STAT* stat, /**< problem statistics */ 3545 const char* name, /**< problem name */ 3546 int nvars_estimate /**< an estimate on the number of variables that may be added to the NLP later */ 3547 ) 3548 { 3549 assert(nlp != NULL); 3550 assert(blkmem != NULL); 3551 assert(set != NULL); 3552 assert(stat != NULL); 3553 assert(name != NULL); 3554 3555 SCIP_ALLOC( BMSallocMemory(nlp) ); 3556 3557 /* select NLP solver (if any available) and setup problem */ 3558 if( set->nnlpis > 0 ) 3559 { 3560 assert(set->nlp_solver != NULL); 3561 if( set->nlp_solver[0] == '\0' ) 3562 { /* take solver with highest priority */ 3563 assert(set->nlpis != NULL); 3564 3565 /* sort the NLPIs if necessary */ 3566 if( !set->nlpissorted ) 3567 SCIPsetSortNlpis(set); 3568 3569 (*nlp)->solver = set->nlpis[0]; 3570 } 3571 else 3572 { /* find user specified NLP solver */ 3573 (*nlp)->solver = SCIPsetFindNlpi(set, set->nlp_solver); 3574 if( (*nlp)->solver == NULL ) 3575 { 3576 SCIPerrorMessage("Selected NLP solver <%s> not available.\n", set->nlp_solver); 3577 return SCIP_PLUGINNOTFOUND; 3578 } 3579 } 3580 assert((*nlp)->solver != NULL); 3581 SCIP_CALL( SCIPnlpiCreateProblem(set, (*nlp)->solver, &(*nlp)->problem, name) ); 3582 } 3583 else 3584 { 3585 /* maybe someone wanna use the NLP just to collect nonlinearities, but is not necessarily interesting on solving 3586 * so we allow this and just continue */ 3587 (*nlp)->solver = NULL; 3588 (*nlp)->problem = NULL; 3589 } 3590 3591 /* status */ 3592 (*nlp)->nunflushedvaradd = 0; 3593 (*nlp)->nunflushedvardel = 0; 3594 (*nlp)->nunflushednlrowadd = 0; 3595 (*nlp)->nunflushednlrowdel = 0; 3596 (*nlp)->indiving = FALSE; 3597 3598 /* variables in problem and NLPI problem */ 3599 (*nlp)->nvars = 0; 3600 (*nlp)->sizevars = 0; 3601 (*nlp)->vars = NULL; 3602 SCIP_CALL( SCIPhashmapCreate(&(*nlp)->varhash, blkmem, nvars_estimate) ); 3603 3604 (*nlp)->nvars_solver = 0; 3605 (*nlp)->sizevars_solver = 0; 3606 (*nlp)->varmap_nlp2nlpi = NULL; 3607 (*nlp)->varmap_nlpi2nlp = NULL; 3608 3609 /* nonlinear rows in problem and NLPI problem */ 3610 (*nlp)->nnlrows = 0; 3611 (*nlp)->sizenlrows = 0; 3612 (*nlp)->nlrows = NULL; 3613 (*nlp)->nnlrowlinear = 0; 3614 (*nlp)->nnlrowconvexineq = 0; 3615 (*nlp)->nnlrownonconvexineq = 0; 3616 (*nlp)->nnlrownonlineareq = 0; 3617 3618 (*nlp)->nnlrows_solver = 0; 3619 (*nlp)->sizenlrows_solver = 0; 3620 (*nlp)->nlrowmap_nlpi2nlp = NULL; 3621 3622 /* objective function */ 3623 (*nlp)->objflushed = TRUE; 3624 (*nlp)->divingobj = NULL; 3625 3626 /* initial guess */ 3627 (*nlp)->haveinitguess = FALSE; 3628 (*nlp)->initialguess = NULL; 3629 3630 /* solution of NLP */ 3631 (*nlp)->primalsolobjval = SCIP_INVALID; 3632 (*nlp)->solstat = SCIP_NLPSOLSTAT_UNKNOWN; 3633 (*nlp)->termstat = SCIP_NLPTERMSTAT_OTHER; 3634 (*nlp)->varlbdualvals = NULL; 3635 (*nlp)->varubdualvals = NULL; 3636 3637 /* event handling: catch variable addition and deletion events */ 3638 (*nlp)->eventhdlr = SCIPsetFindEventhdlr(set, EVENTHDLR_NAME); 3639 if( (*nlp)->eventhdlr == NULL ) 3640 { 3641 SCIPerrorMessage("NLP eventhandler <" EVENTHDLR_NAME "> not found.\n"); 3642 return SCIP_PLUGINNOTFOUND; 3643 } 3644 SCIP_CALL( SCIPeventfilterAdd(set->scip->eventfilter, blkmem, set, 3645 SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED, 3646 (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), &(*nlp)->globalfilterpos) ); 3647 3648 /* fractional variables in last NLP solution */ 3649 (*nlp)->fracvars = NULL; 3650 (*nlp)->fracvarssol = NULL; 3651 (*nlp)->fracvarsfrac = NULL; 3652 (*nlp)->nfracvars = 0; 3653 (*nlp)->npriofracvars = 0; 3654 (*nlp)->fracvarssize = 0; 3655 (*nlp)->validfracvars = -1; 3656 3657 /* miscellaneous */ 3658 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*nlp)->name, name, strlen(name)+1) ); 3659 3660 return SCIP_OKAY; 3661 } 3662 3663 /** frees NLP data object */ 3664 SCIP_RETCODE SCIPnlpFree( 3665 SCIP_NLP** nlp, /**< pointer to NLP data object */ 3666 BMS_BLKMEM* blkmem, /**< block memory */ 3667 SCIP_SET* set, /**< global SCIP settings */ 3668 SCIP_STAT* stat, /**< problem statistics */ 3669 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 3670 SCIP_LP* lp /**< SCIP LP, needed for releasing variables */ 3671 ) 3672 { 3673 assert(nlp != NULL); 3674 assert(*nlp != NULL); 3675 assert(blkmem != NULL); 3676 assert(set != NULL); 3677 3678 /* drop fractional variables */ 3679 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvars, (*nlp)->fracvarssize); 3680 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarssol, (*nlp)->fracvarssize); 3681 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->fracvarsfrac, (*nlp)->fracvarssize); 3682 3683 /* drop global events (variable addition and deletion) */ 3684 SCIP_CALL( SCIPeventfilterDel(set->scip->eventfilter, blkmem, set, 3685 SCIP_EVENTTYPE_VARADDED | SCIP_EVENTTYPE_VARDELETED, 3686 (*nlp)->eventhdlr, (SCIP_EVENTDATA*)(*nlp), (*nlp)->globalfilterpos) ); 3687 3688 SCIP_CALL( SCIPnlpReset(*nlp, blkmem, set, stat, eventqueue, lp) ); 3689 assert((*nlp)->nnlrows == 0); 3690 assert((*nlp)->nnlrows_solver == 0); 3691 assert((*nlp)->nvars == 0); 3692 assert((*nlp)->nvars_solver == 0); 3693 assert((*nlp)->initialguess == NULL); 3694 3695 BMSfreeBlockMemoryArray(blkmem, &(*nlp)->name, strlen((*nlp)->name)+1); 3696 3697 /* free nonlinear rows arrays */ 3698 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrowmap_nlpi2nlp, (*nlp)->sizenlrows_solver); 3699 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->nlrows, (*nlp)->sizenlrows); 3700 3701 /* free variables arrays */ 3702 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlp2nlpi, (*nlp)->sizevars); 3703 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varmap_nlpi2nlp, (*nlp)->sizevars_solver); 3704 SCIPhashmapFree(&(*nlp)->varhash); 3705 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->vars, (*nlp)->sizevars); 3706 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varlbdualvals, (*nlp)->sizevars); 3707 BMSfreeBlockMemoryArrayNull(blkmem, &(*nlp)->varubdualvals, (*nlp)->sizevars); 3708 3709 /* free NLPI problem */ 3710 if( (*nlp)->problem != NULL ) 3711 { 3712 SCIP_CALL( SCIPnlpiFreeProblem(set, (*nlp)->solver, &(*nlp)->problem) ); 3713 } 3714 3715 /* free NLP data structure */ 3716 BMSfreeMemory(nlp); 3717 3718 return SCIP_OKAY; 3719 } 3720 3721 /** resets the NLP to the empty NLP by removing all variables and rows from NLP, 3722 * releasing all rows, and flushing the changes to the NLP solver 3723 */ 3724 SCIP_RETCODE SCIPnlpReset( 3725 SCIP_NLP* nlp, /**< NLP data */ 3726 BMS_BLKMEM* blkmem, /**< block memory */ 3727 SCIP_SET* set, /**< global SCIP settings */ 3728 SCIP_STAT* stat, /**< problem statistics data */ 3729 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 3730 SCIP_LP* lp /**< SCIP LP, needed for releasing variables */ 3731 ) 3732 { 3733 int i; 3734 3735 assert(nlp != NULL); 3736 assert(blkmem != NULL); 3737 assert(set != NULL); 3738 3739 if( nlp->indiving ) 3740 { 3741 SCIP_CALL( SCIPnlpEndDive(nlp, blkmem, set, stat) ); 3742 } 3743 3744 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN; 3745 nlp->termstat = SCIP_NLPTERMSTAT_OTHER; 3746 3747 BMSfreeBlockMemoryArrayNull(blkmem, &nlp->initialguess, nlp->sizevars); 3748 nlp->haveinitguess = FALSE; 3749 3750 for(i = nlp->nnlrows - 1; i >= 0; --i) 3751 { 3752 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, i) ); 3753 } 3754 3755 for(i = nlp->nvars - 1; i >= 0; --i) 3756 { 3757 SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, stat, eventqueue, lp, i) ); 3758 } 3759 3760 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) ); 3761 3762 return SCIP_OKAY; 3763 } 3764 3765 /** currently a dummy function that always returns TRUE */ 3766 SCIP_Bool SCIPnlpHasCurrentNodeNLP( 3767 SCIP_NLP* nlp /**< NLP data */ 3768 ) 3769 { 3770 assert(nlp != NULL); 3771 return TRUE; 3772 } /*lint !e715*/ 3773 3774 /** ensures, that variables array of NLP can store at least num entries */ 3775 SCIP_RETCODE SCIPnlpEnsureVarsSize( 3776 SCIP_NLP* nlp, /**< NLP data */ 3777 BMS_BLKMEM* blkmem, /**< block memory */ 3778 SCIP_SET* set, /**< global SCIP settings */ 3779 int num /**< minimum number of entries to store */ 3780 ) 3781 { 3782 assert(nlp != NULL); 3783 assert(blkmem != NULL); 3784 assert(set != NULL); 3785 assert(nlp->nvars <= nlp->sizevars); 3786 3787 if( num > nlp->sizevars ) 3788 { 3789 int newsize; 3790 3791 newsize = SCIPsetCalcMemGrowSize(set, num); 3792 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->vars, nlp->sizevars, newsize) ); 3793 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varmap_nlp2nlpi, nlp->sizevars, newsize) ); 3794 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varlbdualvals, nlp->sizevars, newsize) ); 3795 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->varubdualvals, nlp->sizevars, newsize) ); 3796 if( nlp->initialguess != NULL ) 3797 { 3798 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars, newsize) ); 3799 } 3800 3801 nlp->sizevars = newsize; 3802 } 3803 assert(num <= nlp->sizevars); 3804 3805 return SCIP_OKAY; 3806 } 3807 3808 /** adds a variable to the NLP and captures the variable */ 3809 SCIP_RETCODE SCIPnlpAddVar( 3810 SCIP_NLP* nlp, /**< NLP data */ 3811 BMS_BLKMEM* blkmem, /**< block memory */ 3812 SCIP_SET* set, /**< global SCIP settings */ 3813 SCIP_VAR* var /**< variable */ 3814 ) 3815 { 3816 assert(nlp != NULL); 3817 assert(blkmem != NULL); 3818 assert(set != NULL); 3819 assert(var != NULL); 3820 assert(SCIPvarIsTransformed(var)); 3821 assert(!SCIPhashmapExists(nlp->varhash, var)); 3822 3823 if( nlp->indiving ) 3824 { 3825 SCIPerrorMessage("cannot add variable during NLP diving\n"); 3826 return SCIP_ERROR; 3827 } 3828 3829 SCIP_CALL( nlpAddVars(nlp, blkmem, set, 1, &var) ); 3830 3831 return SCIP_OKAY; 3832 } 3833 3834 /** adds a set of variables to the NLP and captures the variables */ 3835 SCIP_RETCODE SCIPnlpAddVars( 3836 SCIP_NLP* nlp, /**< NLP data */ 3837 BMS_BLKMEM* blkmem, /**< block memory */ 3838 SCIP_SET* set, /**< global SCIP settings */ 3839 int nvars, /**< number of variables to add */ 3840 SCIP_VAR** vars /**< variables to add */ 3841 ) 3842 { 3843 assert(nlp != NULL); 3844 assert(blkmem != NULL); 3845 assert(set != NULL); 3846 assert(vars != NULL || nvars == 0); 3847 3848 if( nlp->indiving && nvars > 0) 3849 { 3850 SCIPerrorMessage("cannot add variables during NLP diving\n"); 3851 return SCIP_ERROR; 3852 } 3853 3854 SCIP_CALL( nlpAddVars(nlp, blkmem, set, nvars, vars) ); 3855 3856 return SCIP_OKAY; 3857 } 3858 3859 /** deletes a variable from the NLP and releases the variable */ 3860 SCIP_RETCODE SCIPnlpDelVar( 3861 SCIP_NLP* nlp, /**< NLP data */ 3862 BMS_BLKMEM* blkmem, /**< block memory */ 3863 SCIP_SET* set, /**< global SCIP settings */ 3864 SCIP_STAT* stat, /**< problem statistics data */ 3865 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 3866 SCIP_LP* lp, /**< SCIP LP, needed to release variable */ 3867 SCIP_VAR* var /**< variable */ 3868 ) 3869 { 3870 int varpos; 3871 3872 assert(nlp != NULL); 3873 assert(blkmem != NULL); 3874 assert(set != NULL); 3875 assert(var != NULL); 3876 3877 if( !SCIPhashmapExists(nlp->varhash, var) ) 3878 { 3879 SCIPerrorMessage("variable <%s> not found in NLP, cannot delete\n", SCIPvarGetName(var)); 3880 return SCIP_ERROR; 3881 } 3882 3883 if( nlp->indiving ) 3884 { 3885 SCIPerrorMessage("cannot delete variable during NLP diving\n"); 3886 return SCIP_ERROR; 3887 } 3888 3889 varpos = SCIPhashmapGetImageInt(nlp->varhash, var); 3890 3891 SCIP_CALL( nlpDelVarPos(nlp, blkmem, set, stat, eventqueue, lp, varpos) ); 3892 3893 return SCIP_OKAY; 3894 } 3895 3896 /** ensures, that nonlinear rows array of NLP can store at least num entries */ 3897 SCIP_RETCODE SCIPnlpEnsureNlRowsSize( 3898 SCIP_NLP* nlp, /**< NLP data */ 3899 BMS_BLKMEM* blkmem, /**< block memory */ 3900 SCIP_SET* set, /**< global SCIP settings */ 3901 int num /**< minimum number of entries to store */ 3902 ) 3903 { 3904 assert(nlp != NULL); 3905 assert(blkmem != NULL); 3906 assert(set != NULL); 3907 assert(nlp->nnlrows <= nlp->sizenlrows); 3908 3909 if( num > nlp->sizenlrows ) 3910 { 3911 int newsize; 3912 3913 newsize = SCIPsetCalcMemGrowSize(set, num); 3914 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &nlp->nlrows, nlp->sizenlrows, newsize) ); 3915 3916 nlp->sizenlrows = newsize; 3917 } 3918 assert(num <= nlp->sizenlrows); 3919 3920 return SCIP_OKAY; 3921 } 3922 3923 /** adds a nonlinear row to the NLP and captures it 3924 * 3925 * all variables of the row need to be present in the NLP 3926 */ 3927 SCIP_RETCODE SCIPnlpAddNlRow( 3928 SCIP_NLP* nlp, /**< NLP data */ 3929 BMS_BLKMEM* blkmem, /**< block memory */ 3930 SCIP_SET* set, /**< global SCIP settings */ 3931 SCIP_STAT* stat, /**< problem statistics data */ 3932 SCIP_NLROW* nlrow /**< nonlinear row */ 3933 ) 3934 { 3935 assert(nlp != NULL); 3936 assert(nlrow != NULL); 3937 3938 if( nlp->indiving ) 3939 { 3940 SCIPerrorMessage("cannot add row during NLP diving\n"); 3941 return SCIP_ERROR; 3942 } 3943 3944 SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, 1, &nlrow) ); 3945 3946 return SCIP_OKAY; 3947 } 3948 3949 /** adds nonlinear rows to the NLP and captures them 3950 * 3951 * all variables of the row need to be present in the NLP 3952 */ 3953 SCIP_RETCODE SCIPnlpAddNlRows( 3954 SCIP_NLP* nlp, /**< NLP data */ 3955 BMS_BLKMEM* blkmem, /**< block memory */ 3956 SCIP_SET* set, /**< global SCIP settings */ 3957 SCIP_STAT* stat, /**< problem statistics data */ 3958 int nnlrows, /**< number of rows to add */ 3959 SCIP_NLROW** nlrows /**< rows to add */ 3960 ) 3961 { 3962 assert(nlp != NULL); 3963 assert(nlrows != NULL || nnlrows == 0); 3964 3965 if( nnlrows == 0 ) 3966 return SCIP_OKAY; 3967 3968 if( nlp->indiving ) 3969 { 3970 SCIPerrorMessage("cannot add rows during NLP diving\n"); 3971 return SCIP_ERROR; 3972 } 3973 3974 SCIP_CALL( nlpAddNlRows(nlp, blkmem, set, stat, nnlrows, nlrows) ); 3975 3976 return SCIP_OKAY; 3977 } 3978 3979 /** deletes a nonlinear row from the NLP 3980 * 3981 * does nothing if nonlinear row is not in NLP 3982 */ 3983 SCIP_RETCODE SCIPnlpDelNlRow( 3984 SCIP_NLP* nlp, /**< NLP data */ 3985 BMS_BLKMEM* blkmem, /**< block memory */ 3986 SCIP_SET* set, /**< global SCIP settings */ 3987 SCIP_STAT* stat, /**< problem statistics data */ 3988 SCIP_NLROW* nlrow /**< nonlinear row */ 3989 ) 3990 { 3991 assert(nlp != NULL); 3992 assert(blkmem != NULL); 3993 assert(set != NULL); 3994 assert(nlrow != NULL); 3995 3996 /* if row not in NLP, nothing to do */ 3997 if( nlrow->nlpindex == -1 ) 3998 return SCIP_OKAY; 3999 4000 assert(nlrow->nlpindex >= 0); 4001 assert(nlrow->nlpindex < nlp->nnlrows); 4002 4003 if( nlp->indiving ) 4004 { 4005 SCIPerrorMessage("cannot delete row during NLP diving\n"); 4006 return SCIP_ERROR; 4007 } 4008 4009 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, nlrow->nlpindex) ); 4010 4011 return SCIP_OKAY; 4012 } 4013 4014 /** applies all cached changes to the NLP solver */ 4015 SCIP_RETCODE SCIPnlpFlush( 4016 SCIP_NLP* nlp, /**< current NLP data */ 4017 BMS_BLKMEM* blkmem, /**< block memory */ 4018 SCIP_SET* set, /**< global SCIP settings */ 4019 SCIP_STAT* stat /**< problem statistics */ 4020 ) 4021 { 4022 assert(nlp != NULL); 4023 assert(blkmem != NULL); 4024 assert(set != NULL); 4025 4026 if( nlp->indiving ) 4027 { 4028 SCIPerrorMessage("cannot flush NLP during NLP diving\n"); 4029 return SCIP_ERROR; 4030 } 4031 4032 /* flush removals of nonlinear rows and variables */ 4033 SCIP_CALL( nlpFlushNlRowDeletions(nlp, blkmem, set) ); 4034 SCIP_CALL( nlpFlushVarDeletions(nlp, blkmem, set) ); 4035 assert(nlp->nunflushednlrowdel == 0); 4036 assert(nlp->nunflushedvardel == 0); 4037 4038 /* flush addition of variables, objective, and addition of rows */ 4039 SCIP_CALL( nlpFlushVarAdditions(nlp, blkmem, set) ); 4040 SCIP_CALL( nlpFlushObjective(nlp, blkmem, set) ); 4041 SCIP_CALL( nlpFlushNlRowAdditions(nlp, blkmem, set, stat) ); 4042 assert(nlp->nunflushedvaradd == 0); 4043 assert(nlp->objflushed == TRUE); 4044 assert(nlp->nunflushednlrowadd == 0); 4045 4046 assert(nlp->nvars == nlp->nvars_solver); 4047 assert(nlp->nnlrows == nlp->nnlrows_solver); 4048 4049 return SCIP_OKAY; 4050 } 4051 4052 /** solves the NLP or diving NLP */ 4053 SCIP_RETCODE SCIPnlpSolve( 4054 SCIP_NLP* nlp, /**< NLP data */ 4055 BMS_BLKMEM* blkmem, /**< block memory buffers */ 4056 SCIP_SET* set, /**< global SCIP settings */ 4057 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 4058 SCIP_STAT* stat, /**< problem statistics */ 4059 SCIP_PRIMAL* primal, /**< primal data */ 4060 SCIP_TREE* tree, /**< branch and bound tree */ 4061 SCIP_NLPPARAM* nlpparam /**< NLP solve parameters */ 4062 ) 4063 { 4064 assert(nlp != NULL); 4065 assert(blkmem != NULL); 4066 assert(set != NULL); 4067 assert(stat != NULL); 4068 4069 if( !nlp->indiving ) 4070 { 4071 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) ); 4072 } 4073 4074 SCIP_CALL( nlpSolve(nlp, blkmem, set, messagehdlr, stat, primal, tree, nlpparam) ); 4075 4076 return SCIP_OKAY; 4077 } 4078 4079 /** gets objective value of current NLP */ 4080 SCIP_Real SCIPnlpGetObjval( 4081 SCIP_NLP* nlp /**< current NLP data */ 4082 ) 4083 { 4084 assert(nlp != NULL); 4085 4086 return nlp->primalsolobjval; 4087 } 4088 4089 /** gives current pseudo objective value */ 4090 SCIP_RETCODE SCIPnlpGetPseudoObjval( 4091 SCIP_NLP* nlp, /**< current NLP data */ 4092 BMS_BLKMEM* blkmem, /**< block memory */ 4093 SCIP_SET* set, /**< global SCIP settings */ 4094 SCIP_STAT* stat, /**< problem statistics data */ 4095 SCIP_PROB* prob, /**< SCIP problem */ 4096 SCIP_PRIMAL* primal, /**< primal data */ 4097 SCIP_TREE* tree, /**< branch and bound tree */ 4098 SCIP_LP* lp, /**< SCIP LP */ 4099 SCIP_Real* pseudoobjval /**< buffer to store pseudo objective value */ 4100 ) 4101 { 4102 assert(nlp != NULL); 4103 assert(pseudoobjval != NULL); 4104 4105 if( nlp->divingobj != NULL ) 4106 { 4107 assert(nlp->indiving); 4108 SCIP_CALL( SCIPnlrowGetPseudoActivity(nlp->divingobj, blkmem, set, stat, prob, primal, tree, lp, pseudoobjval) ); 4109 } 4110 else 4111 { 4112 int i; 4113 4114 *pseudoobjval = 0.0; 4115 for( i = 0; i < nlp->nvars; ++i ) 4116 *pseudoobjval += SCIPvarGetObj(nlp->vars[i]) * SCIPvarGetBestBoundLocal(nlp->vars[i]); 4117 } 4118 4119 return SCIP_OKAY; 4120 } 4121 4122 /** gets fractional variables of last NLP solution along with solution values and fractionalities 4123 */ 4124 SCIP_RETCODE SCIPnlpGetFracVars( 4125 SCIP_NLP* nlp, /**< NLP data structure */ 4126 BMS_BLKMEM* blkmem, /**< block memory */ 4127 SCIP_SET* set, /**< global SCIP settings */ 4128 SCIP_STAT* stat, /**< problem statistics */ 4129 SCIP_VAR*** fracvars, /**< pointer to store the array of NLP fractional variables, or NULL */ 4130 SCIP_Real** fracvarssol, /**< pointer to store the array of NLP fractional variables solution values, or NULL */ 4131 SCIP_Real** fracvarsfrac, /**< pointer to store the array of NLP fractional variables fractionalities, or NULL */ 4132 int* nfracvars, /**< pointer to store the number of NLP fractional variables , or NULL */ 4133 int* npriofracvars /**< pointer to store the number of NLP fractional variables with maximal branching priority, or NULL */ 4134 ) 4135 { 4136 assert(nlp != NULL); 4137 4138 SCIP_CALL( nlpCalcFracVars(nlp, blkmem, set, stat) ); 4139 assert(nlp->fracvars != NULL); 4140 assert(nlp->fracvarssol != NULL); 4141 assert(nlp->fracvarsfrac != NULL); 4142 4143 if( fracvars != NULL ) 4144 *fracvars = nlp->fracvars; 4145 if( fracvarssol != NULL ) 4146 *fracvarssol = nlp->fracvarssol; 4147 if( fracvarsfrac != NULL ) 4148 *fracvarsfrac = nlp->fracvarsfrac; 4149 if( nfracvars != NULL ) 4150 *nfracvars = nlp->nfracvars; 4151 if( npriofracvars != NULL ) 4152 *npriofracvars = nlp->npriofracvars; 4153 4154 return SCIP_OKAY; 4155 } 4156 4157 /** removes all redundant nonlinear rows */ 4158 SCIP_RETCODE SCIPnlpRemoveRedundantNlRows( 4159 SCIP_NLP* nlp, /**< current NLP data */ 4160 BMS_BLKMEM* blkmem, /**< block memory buffers */ 4161 SCIP_SET* set, /**< global SCIP settings */ 4162 SCIP_STAT* stat /**< problem statistics */ 4163 ) 4164 { 4165 SCIP_NLPSOLSTAT solstatus; 4166 SCIP_Bool isredundant; 4167 int i; 4168 4169 assert(nlp != NULL); 4170 assert(blkmem != NULL); 4171 assert(set != NULL); 4172 assert(stat != NULL); 4173 4174 if( nlp->nnlrows == 0 ) 4175 return SCIP_OKAY; 4176 4177 if( nlp->indiving ) 4178 { 4179 SCIPerrorMessage("cannot remove redundant rows during NLP diving\n"); 4180 return SCIP_ERROR; 4181 } 4182 4183 /* removing redundant rows should not change the solution status, so we reset it at the end */ 4184 solstatus = nlp->solstat; 4185 4186 for( i = 0; i < nlp->nnlrows; ++i ) 4187 { 4188 SCIP_CALL( SCIPnlrowIsRedundant(nlp->nlrows[i], blkmem, set, stat, &isredundant) ); 4189 if( isredundant ) 4190 { 4191 SCIP_CALL( nlpDelNlRowPos(nlp, blkmem, set, stat, i) ); 4192 } 4193 } 4194 4195 nlp->solstat = solstatus; 4196 4197 return SCIP_OKAY; 4198 } 4199 4200 /** set initial guess (approximate primal solution) for next solve 4201 * 4202 * array initguess must be NULL or have length at least SCIPnlpGetNVars() 4203 */ 4204 SCIP_RETCODE SCIPnlpSetInitialGuess( 4205 SCIP_SET* set, /**< global SCIP settings */ 4206 SCIP_NLP* nlp, /**< current NLP data */ 4207 BMS_BLKMEM* blkmem, /**< block memory buffers */ 4208 SCIP_Real* initguess /**< new initial guess, or NULL to clear previous one */ 4209 ) 4210 { 4211 assert(nlp != NULL); 4212 assert(blkmem != NULL); 4213 assert(nlp->solver != NULL); 4214 assert(nlp->problem != NULL); 4215 4216 /* if user wants to let NLP solver choose start point, then invalidate current initial guess both in NLP and in NLPI */ 4217 if( initguess == NULL ) 4218 { 4219 nlp->haveinitguess = FALSE; 4220 SCIP_CALL( SCIPnlpiSetInitialGuess(set, nlp->solver, nlp->problem, NULL, NULL, NULL, NULL) ); 4221 return SCIP_OKAY; 4222 } 4223 4224 if( nlp->initialguess != NULL ) 4225 { 4226 BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars); 4227 } 4228 else 4229 { 4230 assert( nlp->sizevars >= nlp->nvars ); 4231 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &nlp->initialguess, nlp->sizevars) ); 4232 BMScopyMemoryArray(nlp->initialguess, initguess, nlp->nvars); 4233 } 4234 nlp->haveinitguess = TRUE; 4235 4236 return SCIP_OKAY; 4237 } 4238 4239 /** writes NLP to a file */ 4240 SCIP_RETCODE SCIPnlpWrite( 4241 SCIP_NLP* nlp, /**< current NLP data */ 4242 BMS_BLKMEM* blkmem, /**< block memory buffers */ 4243 SCIP_SET* set, /**< global SCIP settings */ 4244 SCIP_STAT* stat, /**< problem statistics */ 4245 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 4246 const char* fname /**< file name */ 4247 ) 4248 { 4249 SCIP_RETCODE retcode = SCIP_OKAY; 4250 FILE* file; 4251 int i; 4252 4253 assert(nlp != NULL); 4254 4255 if( fname != NULL ) 4256 { 4257 file = fopen(fname, "w"); 4258 if( file == NULL ) 4259 { 4260 SCIPerrorMessage("could not open file <%s> for writing\n", fname); 4261 return SCIP_FILECREATEERROR; 4262 } 4263 } 4264 else 4265 file = stdout; 4266 4267 SCIPmessageFPrintInfo(messagehdlr, file, "STATISTICS\n"); 4268 SCIPmessageFPrintInfo(messagehdlr, file, " NLP name: %s\n", nlp->name); 4269 SCIPmessageFPrintInfo(messagehdlr, file, " Variables: %d\n", nlp->nvars); 4270 SCIPmessageFPrintInfo(messagehdlr, file, " Rows: %d\n", nlp->nnlrows); 4271 4272 SCIPmessageFPrintInfo(messagehdlr, file, "VARIABLES\n"); 4273 for( i = 0; i < nlp->nvars; ++i ) 4274 { 4275 SCIP_CALL( SCIPvarPrint(nlp->vars[i], set, messagehdlr, file) ); 4276 } 4277 4278 SCIPmessageFPrintInfo(messagehdlr, file, "NONLINEAR ROWS\n"); 4279 for( i = 0; i < nlp->nnlrows; ++i ) 4280 { 4281 SCIPmessageFPrintInfo(messagehdlr, file, " "); 4282 SCIP_CALL_TERMINATE( retcode, SCIPnlrowPrint(nlp->nlrows[i], blkmem, set, stat, messagehdlr, file), TERMINATE ); 4283 } 4284 4285 TERMINATE: 4286 if( fname != NULL ) 4287 { 4288 fclose(file); 4289 } 4290 4291 return retcode; 4292 } 4293 4294 /** gets array with variables of the NLP */ 4295 SCIP_VAR** SCIPnlpGetVars( 4296 SCIP_NLP* nlp /**< current NLP data */ 4297 ) 4298 { 4299 assert(nlp != NULL); 4300 4301 return nlp->vars; 4302 } 4303 4304 /** gets current number of variables in NLP */ 4305 int SCIPnlpGetNVars( 4306 SCIP_NLP* nlp /**< current NLP data */ 4307 ) 4308 { 4309 assert(nlp != NULL); 4310 4311 return nlp->nvars; 4312 } 4313 4314 /** computes for each variables the number of NLP rows in which the variable appears in a nonlinear var */ 4315 SCIP_RETCODE SCIPnlpGetVarsNonlinearity( 4316 SCIP_NLP* nlp, /**< current NLP data */ 4317 BMS_BLKMEM* blkmem, /**< block memory buffers */ 4318 SCIP_SET* set, /**< global SCIP settings */ 4319 SCIP_STAT* stat, /**< problem statistics */ 4320 int* nlcount /**< an array of length at least SCIPnlpGetNVars() to store nonlinearity counts of variables */ 4321 ) 4322 { 4323 SCIP_NLROW* nlrow; 4324 SCIP_EXPRITER* it; 4325 SCIP_EXPR* expr; 4326 int varidx; 4327 int c; 4328 4329 assert(nlp != NULL); 4330 assert(nlcount != NULL || nlp->nvars == 0); 4331 4332 BMSclearMemoryArray(nlcount, nlp->nvars); 4333 4334 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) ); 4335 4336 for( c = 0; c < nlp->nnlrows; ++c ) 4337 { 4338 nlrow = nlp->nlrows[c]; 4339 assert(nlrow != NULL); 4340 4341 if( nlrow->expr == NULL ) 4342 continue; 4343 4344 SCIP_CALL( SCIPexpriterInit(it, nlrow->expr, SCIP_EXPRITER_DFS, FALSE) ); 4345 for( expr = nlrow->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) ) 4346 { 4347 if( !SCIPexprIsVar(set, expr) ) 4348 continue; 4349 4350 assert(SCIPhashmapExists(nlp->varhash, SCIPgetVarExprVar(expr))); 4351 4352 varidx = SCIPhashmapGetImageInt(nlp->varhash, SCIPgetVarExprVar(expr)); 4353 assert(varidx < nlp->nvars); 4354 assert(nlcount != NULL); 4355 ++nlcount[varidx]; 4356 } 4357 } 4358 4359 SCIPexpriterFree(&it); 4360 4361 return SCIP_OKAY; 4362 } 4363 4364 4365 /** indicates whether there exists a row that contains a continuous variable in a nonlinear term 4366 * 4367 * @note The method may have to touch every row and nonlinear term to compute its result. 4368 */ 4369 SCIP_RETCODE SCIPnlpHasContinuousNonlinearity( 4370 SCIP_NLP* nlp, /**< current NLP data */ 4371 BMS_BLKMEM* blkmem, /**< block memory buffers */ 4372 SCIP_SET* set, /**< global SCIP settings */ 4373 SCIP_STAT* stat, /**< problem statistics */ 4374 SCIP_Bool* result /**< buffer to store whether continuous variable present in an expression of any row */ 4375 ) 4376 { 4377 SCIP_NLROW* nlrow; 4378 SCIP_EXPRITER* it; 4379 SCIP_EXPR* expr; 4380 int c; 4381 4382 assert(nlp != NULL); 4383 4384 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) ); 4385 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) ); 4386 4387 *result = FALSE; 4388 for( c = 0; c < nlp->nnlrows && !*result; ++c ) 4389 { 4390 nlrow = nlp->nlrows[c]; 4391 assert(nlrow != NULL); 4392 4393 if( nlrow->expr == NULL ) 4394 continue; 4395 4396 for( expr = SCIPexpriterRestartDFS(it, nlrow->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) ) 4397 { 4398 if( SCIPexprIsVar(set, expr) && SCIPvarGetType(SCIPgetVarExprVar(expr)) == SCIP_VARTYPE_CONTINUOUS ) 4399 { 4400 *result = TRUE; 4401 break; 4402 } 4403 } 4404 } 4405 4406 SCIPexpriterFree(&it); 4407 4408 return SCIP_OKAY; 4409 } 4410 4411 /** gives dual solution values associated with lower bounds of NLP variables */ 4412 SCIP_Real* SCIPnlpGetVarsLbDualsol( 4413 SCIP_NLP* nlp /**< current NLP data */ 4414 ) 4415 { 4416 assert(nlp != NULL); 4417 4418 return nlp->varlbdualvals; 4419 } 4420 4421 /** gives dual solution values associated with upper bounds of NLP variables */ 4422 SCIP_Real* SCIPnlpGetVarsUbDualsol( 4423 SCIP_NLP* nlp /**< current NLP data */ 4424 ) 4425 { 4426 assert(nlp != NULL); 4427 4428 return nlp->varubdualvals; 4429 } 4430 4431 /** gets array with nonlinear rows of the NLP */ 4432 SCIP_NLROW** SCIPnlpGetNlRows( 4433 SCIP_NLP* nlp /**< current NLP data */ 4434 ) 4435 { 4436 assert(nlp != NULL); 4437 4438 return nlp->nlrows; 4439 } 4440 4441 /** gets current number of nonlinear rows in NLP */ 4442 int SCIPnlpGetNNlRows( 4443 SCIP_NLP* nlp /**< current NLP data */ 4444 ) 4445 { 4446 assert(nlp != NULL); 4447 4448 return nlp->nnlrows; 4449 } 4450 4451 /** gets statistics on convexity of nonlinear rows in NLP */ 4452 void SCIPnlpGetNlRowsStat( 4453 SCIP_NLP* nlp, /**< current NLP data */ 4454 int* nlinear, /**< buffer to store number of linear rows in NLP, or NULL */ 4455 int* nconvexineq, /**< buffer to store number of convex inequalities in NLP, or NULL */ 4456 int* nnonconvexineq, /**< buffer to store number of nonconvex inequalities in NLP, or NULL */ 4457 int* nnonlineareq /**< buffer to store number of nonlinear equalities or ranged rows in NLP, or NULL */ 4458 ) 4459 { 4460 assert(nlp != NULL); 4461 4462 if( nlinear != NULL ) 4463 *nlinear = nlp->nnlrowlinear; 4464 4465 if( nconvexineq != NULL ) 4466 *nconvexineq = nlp->nnlrowconvexineq; 4467 4468 if( nnonconvexineq != NULL ) 4469 *nnonconvexineq = nlp->nnlrownonconvexineq; 4470 4471 if( nnonlineareq ) 4472 *nnonlineareq = nlp->nnlrownonlineareq; 4473 } 4474 4475 /** gets the NLP solver interface */ 4476 SCIP_NLPI* SCIPnlpGetNLPI( 4477 SCIP_NLP* nlp /**< current NLP data */ 4478 ) 4479 { 4480 assert(nlp != NULL); 4481 4482 return nlp->solver; 4483 } 4484 4485 /** gets the NLP problem in the solver interface */ 4486 SCIP_NLPIPROBLEM* SCIPnlpGetNLPIProblem( 4487 SCIP_NLP* nlp /**< current NLP data */ 4488 ) 4489 { 4490 assert(nlp != NULL); 4491 4492 return nlp->problem; 4493 } 4494 4495 /** indicates whether NLP is currently in diving mode */ 4496 SCIP_Bool SCIPnlpIsDiving( 4497 SCIP_NLP* nlp /**< current NLP data */ 4498 ) 4499 { 4500 assert(nlp != NULL); 4501 4502 return nlp->indiving; 4503 } 4504 4505 /** gets solution status of current NLP */ 4506 SCIP_NLPSOLSTAT SCIPnlpGetSolstat( 4507 SCIP_NLP* nlp /**< current NLP data */ 4508 ) 4509 { 4510 assert(nlp != NULL); 4511 4512 return nlp->solstat; 4513 } 4514 4515 /** gets termination status of last NLP solve */ 4516 SCIP_NLPTERMSTAT SCIPnlpGetTermstat( 4517 SCIP_NLP* nlp /**< current NLP data */ 4518 ) 4519 { 4520 assert(nlp != NULL); 4521 4522 return nlp->termstat; 4523 } 4524 4525 /** gives statistics (number of iterations, solving time, ...) of last NLP solve */ 4526 SCIP_RETCODE SCIPnlpGetStatistics( 4527 SCIP_SET* set, /**< global SCIP settings */ 4528 SCIP_NLP* nlp, /**< pointer to NLP datastructure */ 4529 SCIP_NLPSTATISTICS* statistics /**< pointer to store statistics */ 4530 ) 4531 { 4532 assert(nlp != NULL); 4533 assert(nlp->solver != NULL); 4534 assert(nlp->problem != NULL); 4535 assert(statistics != NULL); 4536 4537 SCIP_CALL( SCIPnlpiGetStatistics(set, nlp->solver, nlp->problem, statistics) ); 4538 4539 return SCIP_OKAY; 4540 } 4541 4542 /** indicates whether a solution for the current NLP is available 4543 * 4544 * The solution may be optimal, feasible, or infeasible. 4545 * Thus, returns whether the NLP solution status is at most \ref SCIP_NLPSOLSTAT_LOCINFEASIBLE. 4546 */ 4547 SCIP_Bool SCIPnlpHasSolution( 4548 SCIP_NLP* nlp /**< current NLP data */ 4549 ) 4550 { 4551 assert(nlp != NULL); 4552 4553 return nlp->solstat <= SCIP_NLPSOLSTAT_LOCINFEASIBLE; 4554 } 4555 4556 /* 4557 * NLP diving methods 4558 */ 4559 4560 /** signals start of diving */ 4561 SCIP_RETCODE SCIPnlpStartDive( 4562 SCIP_NLP* nlp, /**< current NLP data */ 4563 BMS_BLKMEM* blkmem, /**< block memory buffers */ 4564 SCIP_SET* set, /**< global SCIP settings */ 4565 SCIP_STAT* stat /**< problem statistics */ 4566 ) 4567 { 4568 assert(nlp != NULL); 4569 4570 if( nlp->indiving ) 4571 { 4572 SCIPerrorMessage("NLP is already in diving mode\n"); 4573 return SCIP_ERROR; 4574 } 4575 4576 if( nlp->solver == NULL ) 4577 { 4578 /* In diving mode we do not cache changes but put them directly in the NLPI problem, which does not exist if there is no solver. 4579 * So we forbid diving of no solver is available. */ 4580 SCIPerrorMessage("Cannot start diving if no NLP solver is available\n"); 4581 return SCIP_ERROR; 4582 } 4583 4584 SCIP_CALL( SCIPnlpFlush(nlp, blkmem, set, stat) ); 4585 4586 nlp->indiving = TRUE; 4587 4588 return SCIP_OKAY; 4589 } 4590 4591 /** resets the bound and objective changes made during diving and disables diving mode */ 4592 SCIP_RETCODE SCIPnlpEndDive( 4593 SCIP_NLP* nlp, /**< current NLP data */ 4594 BMS_BLKMEM* blkmem, /**< block memory */ 4595 SCIP_SET* set, /**< global SCIP settings */ 4596 SCIP_STAT* stat /**< problem statistics data */ 4597 ) 4598 { 4599 int i; 4600 int* varidx; 4601 SCIP_Real* varlb; 4602 SCIP_Real* varub; 4603 4604 assert(nlp != NULL); 4605 assert(set != NULL); 4606 assert(nlp->nvars == nlp->nvars_solver); 4607 4608 if( !nlp->indiving ) 4609 { 4610 SCIPerrorMessage("NLP not in diving mode, cannot end dive\n"); 4611 return SCIP_ERROR; 4612 } 4613 4614 assert(nlp->solver != NULL); 4615 assert(nlp->problem != NULL); 4616 4617 /* reset variable bounds in NLPI problem to their current values */ 4618 SCIP_CALL( SCIPsetAllocBufferArray(set, &varidx, nlp->nvars) ); 4619 SCIP_CALL( SCIPsetAllocBufferArray(set, &varlb, nlp->nvars) ); 4620 SCIP_CALL( SCIPsetAllocBufferArray(set, &varub, nlp->nvars) ); 4621 for( i = 0; i < nlp->nvars; ++i ) 4622 { 4623 varidx[i] = i; 4624 varlb[i] = SCIPvarGetLbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]); 4625 varub[i] = SCIPvarGetUbLocal(nlp->vars[nlp->varmap_nlpi2nlp[i]]); 4626 } 4627 4628 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, nlp->nvars, varidx, varlb, varub) ); 4629 4630 SCIPsetFreeBufferArray(set, &varidx); 4631 SCIPsetFreeBufferArray(set, &varlb); 4632 SCIPsetFreeBufferArray(set, &varub); 4633 4634 /* clear diving objective, if one was used (i.e., if SCIPnlpChgVarObjDive had been called) 4635 * the objective in the NLPI will be reset in the next flush */ 4636 if( nlp->divingobj != NULL ) 4637 { 4638 SCIP_CALL( SCIPnlrowRelease(&nlp->divingobj, blkmem, set, stat) ); 4639 assert(nlp->divingobj == NULL); 4640 assert(nlp->objflushed == FALSE); 4641 } 4642 4643 /* we do not have a valid solution anymore */ 4644 nlp->solstat = SCIP_NLPSOLSTAT_UNKNOWN; 4645 nlp->termstat = SCIP_NLPTERMSTAT_OTHER; 4646 nlp->primalsolobjval = SCIP_INVALID; 4647 4648 nlp->indiving = FALSE; 4649 4650 return SCIP_OKAY; 4651 } 4652 4653 /** changes coefficient of variable in diving NLP */ 4654 SCIP_RETCODE SCIPnlpChgVarObjDive( 4655 SCIP_NLP* nlp, /**< current NLP data */ 4656 BMS_BLKMEM* blkmem, /**< block memory */ 4657 SCIP_SET* set, /**< global SCIP settings */ 4658 SCIP_STAT* stat, /**< problem statistics data */ 4659 SCIP_VAR* var, /**< variable which coefficient to change */ 4660 SCIP_Real coef /**< new linear coefficient of variable in objective */ 4661 ) 4662 { 4663 int pos; 4664 int objidx; 4665 4666 assert(nlp != NULL); 4667 assert(var != NULL); 4668 assert(SCIPhashmapExists(nlp->varhash, var)); 4669 assert(nlp->indiving); 4670 assert(nlp->solver != NULL); 4671 assert(nlp->problem != NULL); 4672 4673 /* get position of variable in NLPI problem */ 4674 pos = SCIPhashmapGetImageInt(nlp->varhash, var); 4675 pos = nlp->varmap_nlp2nlpi[pos]; 4676 assert(pos >= 0); 4677 4678 /* set coefficient in NLPI problem objective */ 4679 objidx = -1; 4680 SCIP_CALL( SCIPnlpiChgLinearCoefs(set, nlp->solver, nlp->problem, objidx, 1, &pos, &coef) ); 4681 4682 /* create an nlrow that holds the diving objective, if not done yet */ 4683 if( nlp->divingobj == NULL ) 4684 { 4685 SCIP_Real* coefs; 4686 int i; 4687 4688 SCIP_CALL( SCIPsetAllocBufferArray(set, &coefs, nlp->nvars) ); 4689 for( i = 0; i < nlp->nvars; ++i ) 4690 coefs[i] = SCIPvarGetObj(nlp->vars[i]); 4691 4692 SCIP_CALL( SCIPnlrowCreate(&nlp->divingobj, blkmem, set, stat, "divingobj", 4693 0.0, nlp->nvars, nlp->vars, coefs, NULL, 4694 -SCIPsetInfinity(set), SCIPsetInfinity(set), 4695 SCIP_EXPRCURV_LINEAR) ); 4696 4697 SCIPsetFreeBufferArray(set, &coefs); 4698 } 4699 assert(nlp->divingobj != NULL); 4700 4701 /* modify coefficient in diving objective */ 4702 SCIP_CALL( SCIPnlrowChgLinearCoef(nlp->divingobj, blkmem, set, stat, nlp, var, coef) ); 4703 4704 /* remember that we have to store objective after diving ended */ 4705 nlp->objflushed = FALSE; 4706 4707 return SCIP_OKAY; 4708 } 4709 4710 /** changes bounds of variable in diving NLP */ 4711 SCIP_RETCODE SCIPnlpChgVarBoundsDive( 4712 SCIP_SET* set, /**< global SCIP settings */ 4713 SCIP_NLP* nlp, /**< current NLP data */ 4714 SCIP_VAR* var, /**< variable which coefficient to change */ 4715 SCIP_Real lb, /**< new lower bound of variable */ 4716 SCIP_Real ub /**< new upper bound of variable */ 4717 ) 4718 { 4719 int pos; 4720 4721 assert(nlp != NULL); 4722 assert(var != NULL); 4723 assert(SCIPhashmapExists(nlp->varhash, var)); 4724 assert(nlp->indiving); 4725 assert(nlp->solver != NULL); 4726 assert(nlp->problem != NULL); 4727 4728 /* get position of variable in NLPI problem */ 4729 pos = SCIPhashmapGetImageInt(nlp->varhash, var); 4730 pos = nlp->varmap_nlp2nlpi[pos]; 4731 assert(pos >= 0); 4732 4733 /* set new bounds in NLPI */ 4734 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, 1, &pos, &lb, &ub) ); 4735 4736 return SCIP_OKAY; 4737 } 4738 4739 /** changes bounds of a set of variables in diving NLP */ 4740 SCIP_RETCODE SCIPnlpChgVarsBoundsDive( 4741 SCIP_NLP* nlp, /**< current NLP data */ 4742 SCIP_SET* set, /**< global SCIP settings */ 4743 int nvars, /**< number of variables which bounds to change */ 4744 SCIP_VAR** vars, /**< variables which bounds to change */ 4745 SCIP_Real* lbs, /**< new lower bounds of variables */ 4746 SCIP_Real* ubs /**< new upper bounds of variables */ 4747 ) 4748 { 4749 int i; 4750 int* poss; 4751 4752 assert(nlp != NULL); 4753 assert(vars != NULL || nvars == 0); 4754 assert(nlp->indiving); 4755 assert(lbs != NULL || nvars == 0); 4756 assert(ubs != NULL || nvars == 0); 4757 assert(nlp->solver != NULL); 4758 assert(nlp->problem != NULL); 4759 4760 if( nvars == 0 ) 4761 return SCIP_OKAY; 4762 4763 SCIP_CALL( SCIPsetAllocBufferArray(set, &poss, nvars) ); 4764 4765 for( i = 0; i < nvars; ++i ) 4766 { 4767 assert(SCIPhashmapExists(nlp->varhash, vars[i])); /*lint !e613*/ 4768 4769 /* get position of variable in NLPI problem */ 4770 poss[i] = SCIPhashmapGetImageInt(nlp->varhash, vars[i]); /*lint !e613*/ 4771 poss[i] = nlp->varmap_nlp2nlpi[poss[i]]; 4772 assert(poss[i] >= 0); 4773 } 4774 4775 /* set new bounds in NLPI */ 4776 SCIP_CALL( SCIPnlpiChgVarBounds(set, nlp->solver, nlp->problem, nvars, poss, lbs, ubs) ); 4777 4778 SCIPsetFreeBufferArray(set, &poss); 4779 4780 return SCIP_OKAY; 4781 } 4782 4783 /** returns whether the objective function has been changed during diving */ 4784 SCIP_Bool SCIPnlpIsDivingObjChanged( 4785 SCIP_NLP* nlp /**< current NLP data */ 4786 ) 4787 { 4788 return nlp->divingobj != NULL; 4789 } 4790