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 scip_nlpi.c 26 * @ingroup OTHER_CFILES 27 * @brief public methods for NLP interfaces 28 * @author Stefan Vigerske 29 * @author Thorsten Gellermann 30 * 31 * @todo check SCIP_STAGE_* switches 32 * @todo allow for optional callbacks 33 */ 34 35 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 36 37 #include "scip/scip_nlp.h" 38 #include "blockmemshell/memory.h" 39 #include "scip/scip_expr.h" 40 #include "scip/scip_lp.h" 41 #include "scip/scip_message.h" 42 #include "scip/scip_mem.h" 43 #include "scip/scip_nlpi.h" 44 #include "scip/scip_numerics.h" 45 #include "scip/scip_param.h" 46 #include "scip/scip_prob.h" 47 #include "scip/pub_expr.h" 48 #include "scip/pub_lp.h" 49 #include "scip/pub_var.h" 50 #include "scip/expr_varidx.h" 51 #include "scip/debug.h" 52 #include "scip/nlpi.h" 53 #include "scip/paramset.h" 54 #include "scip/set.h" 55 #include "scip/struct_scip.h" 56 57 58 /** method to call, when the priority of an NLPI was changed */ 59 static 60 SCIP_DECL_PARAMCHGD(paramChgdNlpiPriority) 61 { /*lint --e{715}*/ 62 SCIP_PARAMDATA* paramdata; 63 64 paramdata = SCIPparamGetData(param); 65 assert(paramdata != NULL); 66 67 /* use SCIPsetSetPriorityNlpi() to mark the nlpis unsorted */ 68 SCIP_CALL( SCIPsetNlpiPriority(scip, (SCIP_NLPI*)paramdata, SCIPparamGetInt(param)) ); 69 70 return SCIP_OKAY; 71 } 72 73 /** create varidx expression for var expression 74 * 75 * called when expr is duplicated for addition to NLPI 76 */ 77 static 78 SCIP_DECL_EXPR_MAPEXPR(mapvar2varidx) 79 { 80 SCIP_HASHMAP* var2idx; 81 int varidx; 82 83 assert(sourcescip != NULL); 84 assert(sourcescip == targetscip); 85 assert(sourceexpr != NULL); 86 assert(targetexpr != NULL); 87 assert(*targetexpr == NULL); 88 assert(mapexprdata != NULL); 89 90 /* do not provide map if not variable */ 91 if( !SCIPisExprVar(sourcescip, sourceexpr) ) 92 return SCIP_OKAY; 93 94 assert(SCIPvarIsActive(SCIPgetVarExprVar(sourceexpr))); 95 96 var2idx = (SCIP_HASHMAP*)mapexprdata; 97 assert(SCIPhashmapExists(var2idx, SCIPgetVarExprVar(sourceexpr))); 98 99 varidx = SCIPhashmapGetImageInt(var2idx, SCIPgetVarExprVar(sourceexpr)); 100 101 SCIP_CALL( SCIPcreateExprVaridx(targetscip, targetexpr, varidx, ownercreate, ownercreatedata) ); 102 103 return SCIP_OKAY; 104 } 105 106 /** creates an NLPI and includes it into SCIP */ 107 SCIP_RETCODE SCIPincludeNlpi( 108 SCIP* scip, /**< SCIP data structure */ 109 const char* name, /**< name of NLP interface */ 110 const char* description, /**< description of NLP interface */ 111 int priority, /**< priority of NLP interface */ 112 SCIP_DECL_NLPICOPY ((*nlpicopy)), /**< copying an NLPI, can be NULL */ 113 SCIP_DECL_NLPIFREE ((*nlpifree)), /**< free NLPI user data */ 114 SCIP_DECL_NLPIGETSOLVERPOINTER ((*nlpigetsolverpointer)), /**< get solver pointer, can be NULL */ 115 SCIP_DECL_NLPICREATEPROBLEM ((*nlpicreateproblem)), /**< create a new problem instance */ 116 SCIP_DECL_NLPIFREEPROBLEM ((*nlpifreeproblem)), /**< free a problem instance */ 117 SCIP_DECL_NLPIGETPROBLEMPOINTER ((*nlpigetproblempointer)), /**< get problem pointer, can be NULL */ 118 SCIP_DECL_NLPIADDVARS ((*nlpiaddvars)), /**< add variables */ 119 SCIP_DECL_NLPIADDCONSTRAINTS ((*nlpiaddconstraints)), /**< add constraints */ 120 SCIP_DECL_NLPISETOBJECTIVE ((*nlpisetobjective)), /**< set objective */ 121 SCIP_DECL_NLPICHGVARBOUNDS ((*nlpichgvarbounds)), /**< change variable bounds */ 122 SCIP_DECL_NLPICHGCONSSIDES ((*nlpichgconssides)), /**< change constraint sides */ 123 SCIP_DECL_NLPIDELVARSET ((*nlpidelvarset)), /**< delete a set of constraints */ 124 SCIP_DECL_NLPIDELCONSSET ((*nlpidelconsset)), /**< delete a set of constraints */ 125 SCIP_DECL_NLPICHGLINEARCOEFS ((*nlpichglinearcoefs)), /**< change coefficients in linear part of a constraint or objective */ 126 SCIP_DECL_NLPICHGEXPR ((*nlpichgexpr)), /**< change nonlinear expression a constraint or objective */ 127 SCIP_DECL_NLPICHGOBJCONSTANT ((*nlpichgobjconstant)), /**< change the constant offset in the objective */ 128 SCIP_DECL_NLPISETINITIALGUESS ((*nlpisetinitialguess)), /**< set initial guess, can be NULL */ 129 SCIP_DECL_NLPISOLVE ((*nlpisolve)), /**< solve NLP */ 130 SCIP_DECL_NLPIGETSOLSTAT ((*nlpigetsolstat)), /**< get solution status */ 131 SCIP_DECL_NLPIGETTERMSTAT ((*nlpigettermstat)), /**< get termination status */ 132 SCIP_DECL_NLPIGETSOLUTION ((*nlpigetsolution)), /**< get solution */ 133 SCIP_DECL_NLPIGETSTATISTICS ((*nlpigetstatistics)), /**< get solve statistics */ 134 SCIP_NLPIDATA* nlpidata /**< NLP interface local data */ 135 ) 136 { 137 SCIP_NLPI* nlpi = NULL; 138 char paramname[SCIP_MAXSTRLEN]; 139 char paramdesc[SCIP_MAXSTRLEN]; 140 141 assert(scip != NULL); 142 143 SCIP_CALL( SCIPcheckStage(scip, "SCIPincludeNlpi", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) ); 144 145 /* check whether NLPI of given name is already present */ 146 if( SCIPfindNlpi(scip, name) != NULL ) 147 { 148 SCIPerrorMessage("NLPI <%s> already included.\n", name); 149 return SCIP_INVALIDDATA; 150 } 151 152 SCIP_CALL( SCIPnlpiCreate(&nlpi, name, description, priority, 153 nlpicopy, nlpifree, nlpigetsolverpointer, 154 nlpicreateproblem, nlpifreeproblem, nlpigetproblempointer, 155 nlpiaddvars, nlpiaddconstraints, nlpisetobjective, nlpichgvarbounds, nlpichgconssides, nlpidelvarset, nlpidelconsset, nlpichglinearcoefs, nlpichgexpr, nlpichgobjconstant, 156 nlpisetinitialguess, nlpisolve, nlpigetsolstat, nlpigettermstat, nlpigetsolution, nlpigetstatistics, 157 nlpidata) ); 158 assert(nlpi != NULL); 159 160 SCIP_CALL( SCIPsetIncludeNlpi(scip->set, nlpi) ); 161 162 /* add parameters */ 163 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "nlpi/%s/priority", name); 164 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "priority of NLPI <%s>", name); 165 SCIP_CALL( SCIPaddIntParam(scip, paramname, paramdesc, 166 NULL, FALSE, SCIPnlpiGetPriority(nlpi), INT_MIN/4, INT_MAX/4, 167 paramChgdNlpiPriority, (SCIP_PARAMDATA*)nlpi) ); /*lint !e740*/ 168 169 return SCIP_OKAY; 170 } 171 172 /** returns the NLPI of the given name, or NULL if not existing */ 173 SCIP_NLPI* SCIPfindNlpi( 174 SCIP* scip, /**< SCIP data structure */ 175 const char* name /**< name of NLPI */ 176 ) 177 { 178 assert(scip != NULL); 179 assert(scip->set != NULL); 180 assert(name != NULL); 181 182 return SCIPsetFindNlpi(scip->set, name); 183 } 184 185 /** returns the array of currently available NLPIs (sorted by priority) */ 186 SCIP_NLPI** SCIPgetNlpis( 187 SCIP* scip /**< SCIP data structure */ 188 ) 189 { 190 assert(scip != NULL); 191 assert(scip->set != NULL); 192 193 SCIPsetSortNlpis(scip->set); 194 195 return scip->set->nlpis; 196 } 197 198 /** returns the number of currently available NLPIs */ 199 int SCIPgetNNlpis( 200 SCIP* scip /**< SCIP data structure */ 201 ) 202 { 203 assert(scip != NULL); 204 assert(scip->set != NULL); 205 206 return scip->set->nnlpis; 207 } 208 209 /** sets the priority of an NLPI */ 210 SCIP_RETCODE SCIPsetNlpiPriority( 211 SCIP* scip, /**< SCIP data structure */ 212 SCIP_NLPI* nlpi, /**< NLPI */ 213 int priority /**< new priority of the NLPI */ 214 ) 215 { 216 assert(scip != NULL); 217 assert(scip->set != NULL); 218 219 SCIPsetSetPriorityNlpi(scip->set, nlpi, priority); 220 221 return SCIP_OKAY; 222 } 223 224 /** gets internal pointer to NLP solver */ 225 SCIP_DECL_NLPIGETSOLVERPOINTER(SCIPgetNlpiSolverPointer) 226 { 227 assert(scip != NULL); 228 229 return SCIPnlpiGetSolverPointer(scip->set, nlpi, problem); 230 } 231 232 /** creates an empty problem instance */ 233 SCIP_DECL_NLPICREATEPROBLEM(SCIPcreateNlpiProblem) 234 { 235 assert(scip != NULL); 236 237 SCIP_CALL( SCIPnlpiCreateProblem(scip->set, nlpi, problem, name) ); 238 239 return SCIP_OKAY; 240 } 241 242 /** frees a problem instance */ 243 SCIP_DECL_NLPIFREEPROBLEM(SCIPfreeNlpiProblem) 244 { 245 assert(scip != NULL); 246 247 SCIP_CALL( SCIPnlpiFreeProblem(scip->set, nlpi, problem) ); 248 249 return SCIP_OKAY; 250 } 251 252 /** gets internal pointer to solver-internal problem instance */ 253 SCIP_DECL_NLPIGETPROBLEMPOINTER(SCIPgetNlpiProblemPointer) 254 { 255 assert(scip != NULL); 256 257 return SCIPnlpiGetProblemPointer(scip->set, nlpi, problem); 258 } 259 260 /** add variables to nlpi */ 261 SCIP_DECL_NLPIADDVARS(SCIPaddNlpiVars) 262 { 263 assert(scip != NULL); 264 265 SCIP_CALL( SCIPnlpiAddVars(scip->set, nlpi, problem, nvars, lbs, ubs, varnames) ); 266 267 return SCIP_OKAY; 268 } 269 270 /** add constraints to nlpi */ 271 SCIP_DECL_NLPIADDCONSTRAINTS(SCIPaddNlpiConstraints) 272 { 273 assert(scip != NULL); 274 275 SCIP_CALL( SCIPnlpiAddConstraints(scip->set, nlpi, problem, nconss, lhss, rhss, nlininds, lininds, linvals, exprs, names) ); 276 277 return SCIP_OKAY; 278 } 279 280 /** sets or overwrites objective, a minimization problem is expected */ 281 SCIP_DECL_NLPISETOBJECTIVE(SCIPsetNlpiObjective) 282 { 283 assert(scip != NULL); 284 285 SCIP_CALL( SCIPnlpiSetObjective(scip->set, nlpi, problem, nlins, lininds, linvals, expr, constant) ); 286 287 return SCIP_OKAY; 288 } 289 290 /** change variable bounds */ 291 SCIP_DECL_NLPICHGVARBOUNDS(SCIPchgNlpiVarBounds) 292 { 293 assert(scip != NULL); 294 295 SCIP_CALL( SCIPnlpiChgVarBounds(scip->set, nlpi, problem, nvars, indices, lbs, ubs) ); 296 297 return SCIP_OKAY; 298 } 299 300 /** change constraint sides */ 301 SCIP_DECL_NLPICHGCONSSIDES(SCIPchgNlpiConsSides) 302 { 303 assert(scip != NULL); 304 305 SCIP_CALL( SCIPnlpiChgConsSides(scip->set, nlpi, problem, nconss, indices, lhss, rhss) ); 306 307 return SCIP_OKAY; 308 } 309 310 /** delete a set of variables */ 311 SCIP_DECL_NLPIDELVARSET(SCIPdelNlpiVarSet) 312 { 313 assert(scip != NULL); 314 315 SCIP_CALL( SCIPnlpiDelVarSet(scip->set, nlpi, problem, dstats, dstatssize) ); 316 317 return SCIP_OKAY; 318 } 319 320 /** delete a set of constraints */ 321 SCIP_DECL_NLPIDELCONSSET(SCIPdelNlpiConsSet) 322 { 323 assert(scip != NULL); 324 325 SCIP_CALL( SCIPnlpiDelConsSet(scip->set, nlpi, problem, dstats, dstatssize) ); 326 327 return SCIP_OKAY; 328 } 329 330 /** changes or adds linear coefficients in a constraint or objective */ 331 SCIP_DECL_NLPICHGLINEARCOEFS(SCIPchgNlpiLinearCoefs) 332 { 333 assert(scip != NULL); 334 335 SCIP_CALL( SCIPnlpiChgLinearCoefs(scip->set, nlpi, problem, idx, nvals, varidxs, vals) ); 336 337 return SCIP_OKAY; 338 } 339 340 /** change the expression in the nonlinear part */ 341 SCIP_DECL_NLPICHGEXPR(SCIPchgNlpiExpr) 342 { 343 assert(scip != NULL); 344 345 SCIP_CALL( SCIPnlpiChgExpr(scip->set, nlpi, problem, idxcons, expr) ); 346 347 return SCIP_OKAY; 348 } 349 350 /** change the constant offset in the objective */ 351 SCIP_DECL_NLPICHGOBJCONSTANT(SCIPchgNlpiObjConstant) 352 { 353 assert(scip != NULL); 354 355 SCIP_CALL( SCIPnlpiChgObjConstant(scip->set, nlpi, problem, objconstant) ); 356 357 return SCIP_OKAY; 358 } 359 360 /** sets initial guess */ 361 SCIP_DECL_NLPISETINITIALGUESS(SCIPsetNlpiInitialGuess) 362 { 363 assert(scip != NULL); 364 365 SCIP_CALL( SCIPnlpiSetInitialGuess(scip->set, nlpi, problem, primalvalues, consdualvalues, varlbdualvalues, varubdualvalues) ); 366 367 return SCIP_OKAY; 368 } 369 370 /** try to solve NLP with all parameters given as SCIP_NLPPARAM struct 371 * 372 * Typical use is 373 * 374 * SCIP_NLPPARAM nlparam = { SCIP_NLPPARAM_DEFAULT(scip); } 375 * nlpparam.iterlim = 42; 376 * SCIP_CALL( SCIPsolveNlpiParam(scip, nlpi, nlpiproblem, nlpparam) ); 377 * 378 * or, in "one" line: 379 * 380 * SCIP_CALL( SCIPsolveNlpiParam(scip, nlpi, nlpiproblem, 381 * (SCIP_NLPPARAM){ SCIP_NLPPARAM_DEFAULT(scip), .iterlimit = 42 }) ); 382 * 383 * To get the latter, also \ref SCIPsolveNlpi can be used. 384 */ 385 SCIP_DECL_NLPISOLVE(SCIPsolveNlpiParam) 386 { 387 assert(scip != NULL); 388 389 SCIP_CALL( SCIPnlpiSolve(scip->set, scip->stat, nlpi, problem, ¶m) ); 390 391 return SCIP_OKAY; 392 } 393 394 #if defined(_MSC_VER) && _MSC_VER < 1800 395 /* warn that SCIPsolveNlpi() macro isn't perfect with ancient MSVC */ 396 #pragma message ( "Warning: designated initializers not supported by this version of MSVC. Parameters given to NLP solves will be ignored." ) 397 #endif 398 399 /** gives solution status */ 400 SCIP_DECL_NLPIGETSOLSTAT(SCIPgetNlpiSolstat) 401 { 402 assert(scip != NULL); 403 404 return SCIPnlpiGetSolstat(scip->set, nlpi, problem); 405 } 406 407 /** gives termination reason */ 408 SCIP_DECL_NLPIGETTERMSTAT(SCIPgetNlpiTermstat) 409 { 410 assert(scip != NULL); 411 412 return SCIPnlpiGetTermstat(scip->set, nlpi, problem); 413 } 414 415 /** gives primal and dual solution 416 * for a ranged constraint, the dual variable is positive if the right hand side is active and negative if the left hand side is active 417 */ 418 SCIP_DECL_NLPIGETSOLUTION(SCIPgetNlpiSolution) 419 { 420 assert(scip != NULL); 421 422 SCIP_CALL( SCIPnlpiGetSolution(scip->set, nlpi, problem, primalvalues, consdualvalues, varlbdualvalues, varubdualvalues, objval) ); 423 424 return SCIP_OKAY; 425 } 426 427 /** gives solve statistics */ 428 SCIP_DECL_NLPIGETSTATISTICS(SCIPgetNlpiStatistics) 429 { 430 assert(scip != NULL); 431 432 SCIP_CALL( SCIPnlpiGetStatistics(scip->set, nlpi, problem, statistics) ); 433 434 return SCIP_OKAY; 435 } 436 437 /** creates a NLPI problem from given nonlinear rows 438 * 439 * The function computes for each variable the number of non-linear occurrences and stores it in the nlscore array. 440 * 441 * @note the first row corresponds always to the cutoff row (even if cutoffbound is SCIPinfinity(scip)) 442 **/ 443 SCIP_RETCODE SCIPcreateNlpiProblemFromNlRows( 444 SCIP* scip, /**< SCIP data structure */ 445 SCIP_NLPI* nlpi, /**< interface to NLP solver */ 446 SCIP_NLPIPROBLEM** nlpiprob, /**< buffer to store pointer to created nlpi problem */ 447 const char* name, /**< name to give to problem */ 448 SCIP_NLROW** nlrows, /**< nonlinear rows */ 449 int nnlrows, /**< number of nonlinear rows */ 450 SCIP_HASHMAP* var2idx, /**< empty hash map to store mapping between variables and indices in nlpiprob */ 451 SCIP_HASHMAP* nlrow2idx, /**< empty hash map to store mapping between variables and indices in nlpiprob, can be NULL */ 452 SCIP_Real* nlscore, /**< array to store the score of each nonlinear variable (NULL if not needed) */ 453 SCIP_Real cutoffbound, /**< cutoff bound */ 454 SCIP_Bool setobj, /**< whether the objective function should be set to one of the SCIP problem */ 455 SCIP_Bool onlyconvex /**< filter only for convex constraints */ 456 ) 457 { 458 SCIP_EXPR** exprs; 459 SCIP_Real** linvals; 460 int** lininds; 461 int* nlininds; 462 SCIP_Real* lhss; 463 SCIP_Real* rhss; 464 const char** names; 465 SCIP_VAR** vars; 466 int nvars; 467 SCIP_Real* lbs; 468 SCIP_Real* ubs; 469 SCIP_Real* objvals = NULL; 470 int* objinds = NULL; 471 const char** varnames; 472 int nobjinds; 473 int nconss; 474 SCIP_EXPRITER* it = NULL; 475 int i; 476 477 assert(nlpiprob != NULL); 478 assert(name != NULL); 479 assert(var2idx != NULL); 480 assert(nlrows != NULL); 481 assert(nnlrows > 0); 482 assert(nlpi != NULL); 483 484 SCIPdebugMsg(scip, "SCIPcreateNlpiProblemFromNlRows() called with cutoffbound %g\n", cutoffbound); 485 486 SCIP_CALL( SCIPnlpiCreateProblem(scip->set, nlpi, nlpiprob, name) ); 487 488 if( nlscore != NULL ) 489 { 490 BMSclearMemoryArray(nlscore, SCIPgetNVars(scip)); 491 } 492 vars = SCIPgetVars(scip); 493 nvars = SCIPgetNVars(scip); 494 nconss = 0; 495 496 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nnlrows + 1) ); 497 SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nnlrows + 1) ); 498 SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nnlrows + 1) ); 499 SCIP_CALL( SCIPallocBufferArray(scip, &nlininds, nnlrows + 1) ); 500 SCIP_CALL( SCIPallocBufferArray(scip, &names, nnlrows + 1) ); 501 SCIP_CALL( SCIPallocBufferArray(scip, &lhss, nnlrows + 1) ); 502 SCIP_CALL( SCIPallocBufferArray(scip, &rhss, nnlrows + 1) ); 503 504 if( setobj ) 505 { 506 SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) ); 507 SCIP_CALL( SCIPallocBufferArray(scip, &objinds, nvars) ); 508 } 509 510 SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) ); 511 SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) ); 512 SCIP_CALL( SCIPallocBufferArray(scip, &varnames, nvars) ); 513 514 /* create a unique mapping between variables and {0,..,nvars-1} */ 515 nobjinds = 0; 516 for( i = 0; i < nvars; ++i ) 517 { 518 assert(vars[i] != NULL); 519 SCIP_CALL( SCIPhashmapInsertInt(var2idx, (void*)vars[i], i) ); 520 521 lbs[i] = SCIPvarGetLbLocal(vars[i]); 522 ubs[i] = SCIPvarGetUbLocal(vars[i]); 523 varnames[i] = SCIPvarGetName(vars[i]); 524 525 /* collect non-zero objective coefficients */ 526 if( setobj && !SCIPisZero(scip, SCIPvarGetObj(vars[i])) ) 527 { 528 assert(objvals != NULL); 529 assert(objinds != NULL); 530 531 objvals[nobjinds] = SCIPvarGetObj(vars[i]); 532 objinds[nobjinds] = i; 533 ++nobjinds; 534 } 535 } 536 537 /* add variables */ 538 SCIP_CALL( SCIPaddNlpiVars(scip, nlpi, *nlpiprob, nvars, lbs, ubs, varnames) ); 539 SCIPfreeBufferArray(scip, &varnames); 540 SCIPfreeBufferArray(scip, &ubs); 541 SCIPfreeBufferArray(scip, &lbs); 542 543 /* set the objective function */ 544 if( setobj ) 545 { 546 if( nobjinds > 0 ) 547 { 548 SCIP_CALL( SCIPsetNlpiObjective(scip, nlpi, *nlpiprob, nobjinds, objinds, objvals, NULL, 0.0) ); 549 } 550 551 SCIPfreeBufferArray(scip, &objinds); 552 SCIPfreeBufferArray(scip, &objvals); 553 } 554 555 /* add row for cutoff bound even if cutoffbound == SCIPinfinity() */ 556 lhss[nconss] = -SCIPinfinity(scip); 557 rhss[nconss] = cutoffbound; 558 names[nconss] = "objcutoff"; 559 lininds[nconss] = NULL; 560 linvals[nconss] = NULL; 561 nlininds[nconss] = 0; 562 exprs[nconss] = NULL; 563 564 SCIP_CALL( SCIPallocBufferArray(scip, &lininds[nconss], nvars) ); /*lint !e866*/ 565 SCIP_CALL( SCIPallocBufferArray(scip, &linvals[nconss], nvars) ); /*lint !e866*/ 566 567 for( i = 0; i < nvars; ++i ) 568 { 569 if( !SCIPisZero(scip, SCIPvarGetObj(vars[i])) ) 570 { 571 linvals[nconss][nlininds[nconss]] = SCIPvarGetObj(vars[i]); 572 lininds[nconss][nlininds[nconss]] = i; 573 ++nlininds[nconss]; 574 } 575 } 576 ++nconss; 577 578 if( nlscore != NULL ) 579 { 580 SCIP_CALL( SCIPcreateExpriter(scip, &it) ); 581 } 582 583 /* add convex nonlinear rows to NLPI problem */ 584 for( i = 0; i < nnlrows; ++i ) 585 { 586 SCIP_Bool userhs; 587 SCIP_Bool uselhs; 588 int k; 589 SCIP_NLROW* nlrow; 590 591 nlrow = nlrows[i]; 592 assert(nlrow != NULL); 593 594 uselhs = FALSE; 595 userhs = FALSE; 596 597 /* check curvature together with constraint sides of a nonlinear row */ 598 if( SCIPnlrowGetExpr(nlrow) == NULL ) 599 { 600 uselhs = TRUE; 601 userhs = TRUE; 602 } 603 else 604 { 605 if( (!onlyconvex || SCIPnlrowGetCurvature(nlrow) == SCIP_EXPRCURV_CONVEX) 606 && !SCIPisInfinity(scip, SCIPnlrowGetRhs(nlrow)) ) 607 userhs = TRUE; 608 if( (!onlyconvex || SCIPnlrowGetCurvature(nlrow) == SCIP_EXPRCURV_CONCAVE) 609 && !SCIPisInfinity(scip, SCIPnlrowGetLhs(nlrow)) ) 610 uselhs = TRUE; 611 } 612 613 if( !uselhs && !userhs ) 614 continue; 615 616 lhss[nconss] = uselhs ? SCIPnlrowGetLhs(nlrow) - SCIPnlrowGetConstant(nlrow) : -SCIPinfinity(scip); 617 rhss[nconss] = userhs ? SCIPnlrowGetRhs(nlrow) - SCIPnlrowGetConstant(nlrow) : SCIPinfinity(scip); 618 names[nconss] = SCIPnlrowGetName(nlrow); 619 nlininds[nconss] = 0; 620 lininds[nconss] = NULL; 621 linvals[nconss] = NULL; 622 623 /* copy linear part */ 624 if( SCIPnlrowGetNLinearVars(nlrow) > 0 ) 625 { 626 SCIP_VAR* var; 627 628 nlininds[nconss] = SCIPnlrowGetNLinearVars(nlrow); 629 630 SCIP_CALL( SCIPallocBufferArray(scip, &lininds[nconss], nlininds[nconss]) ); /*lint !e866*/ 631 SCIP_CALL( SCIPallocBufferArray(scip, &linvals[nconss], nlininds[nconss]) ); /*lint !e866*/ 632 633 for( k = 0; k < nlininds[nconss]; ++k ) 634 { 635 var = SCIPnlrowGetLinearVars(nlrow)[k]; 636 assert(var != NULL); 637 assert(SCIPhashmapExists(var2idx, (void*)var)); 638 639 lininds[nconss][k] = SCIPhashmapGetImageInt(var2idx, (void*)var); 640 assert(var == vars[lininds[nconss][k]]); 641 linvals[nconss][k] = SCIPnlrowGetLinearCoefs(nlrow)[k]; 642 } 643 } 644 645 if( SCIPnlrowGetExpr(nlrow) != NULL ) 646 { 647 /* create copy of expr that uses varidx expressions corresponding to variables indices in NLPI */ 648 SCIP_CALL( SCIPduplicateExpr(scip, SCIPnlrowGetExpr(nlrow), &exprs[nconss], mapvar2varidx, var2idx, NULL, NULL) ); 649 } 650 else 651 { 652 exprs[nconss] = NULL; 653 } 654 655 /* update nlscore */ 656 if( nlscore != NULL && exprs[nconss] != NULL ) 657 { 658 SCIP_EXPR* expr; 659 int varidx; 660 661 SCIP_CALL( SCIPexpriterInit(it, exprs[nconss], SCIP_EXPRITER_DFS, FALSE) ); 662 for( expr = exprs[nconss]; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) ) /*lint !e441*/ /*lint !e440*/ 663 { 664 if( !SCIPisExprVaridx(scip, expr) ) 665 continue; 666 667 varidx = SCIPgetIndexExprVaridx(expr); 668 assert(varidx >= 0); 669 assert(varidx < nvars); 670 671 /* update nlscore */ 672 nlscore[varidx] += 1.0; 673 } 674 } 675 676 /* if the row to index hash map is provided, we need to store the row index */ 677 if( nlrow2idx != NULL ) 678 { 679 SCIP_CALL( SCIPhashmapInsertInt(nlrow2idx, nlrow, nconss) ); 680 } 681 682 ++nconss; 683 } 684 assert(nconss > 0); 685 686 /* pass all constraint information to nlpi */ 687 SCIP_CALL( SCIPaddNlpiConstraints(scip, nlpi, *nlpiprob, nconss, lhss, rhss, nlininds, lininds, linvals, 688 exprs, names) ); 689 690 if( it != NULL ) 691 { 692 SCIPfreeExpriter(&it); 693 } 694 695 /* free memory */ 696 for( i = nconss - 1; i > 0; --i ) 697 { 698 if( nlininds[i] > 0 ) 699 { 700 assert(linvals[i] != NULL); 701 assert(lininds[i] != NULL); 702 SCIPfreeBufferArray(scip, &linvals[i]); 703 SCIPfreeBufferArray(scip, &lininds[i]); 704 } 705 if( exprs[i] != NULL ) 706 { 707 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) ); 708 } 709 } 710 /* free row for cutoff bound even if objective is 0 */ 711 SCIPfreeBufferArray(scip, &linvals[i]); 712 SCIPfreeBufferArray(scip, &lininds[i]); 713 714 SCIPfreeBufferArray(scip, &rhss); 715 SCIPfreeBufferArray(scip, &lhss); 716 SCIPfreeBufferArray(scip, &names); 717 SCIPfreeBufferArray(scip, &nlininds); 718 SCIPfreeBufferArray(scip, &lininds); 719 SCIPfreeBufferArray(scip, &linvals); 720 SCIPfreeBufferArray(scip, &exprs); 721 722 return SCIP_OKAY; 723 } 724 725 /** updates variable bounds and the cutoff row in a NLPI problem 726 * 727 * The NLPI problem must have been setup by SCIPcreateNlpiProblemFromNlRows(). 728 */ 729 SCIP_RETCODE SCIPupdateNlpiProblem( 730 SCIP* scip, /**< SCIP data structure */ 731 SCIP_NLPI* nlpi, /**< interface to NLP solver */ 732 SCIP_NLPIPROBLEM* nlpiprob, /**< nlpi problem representing the convex NLP relaxation */ 733 SCIP_HASHMAP* var2nlpiidx, /**< mapping between variables and nlpi indices */ 734 SCIP_VAR** nlpivars, /**< array containing all variables of the nlpi */ 735 int nlpinvars, /**< total number of nlpi variables */ 736 SCIP_Real cutoffbound /**< new cutoff bound */ 737 ) 738 { 739 SCIP_Real* lbs; 740 SCIP_Real* ubs; 741 SCIP_Real lhs; 742 SCIP_Real rhs; 743 int* inds; 744 int i; 745 746 SCIPdebugMsg(scip, "SCIPupdateNlpiProblem() called\n"); 747 748 /* update variable bounds */ 749 SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nlpinvars) ); 750 SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nlpinvars) ); 751 SCIP_CALL( SCIPallocBufferArray(scip, &inds, nlpinvars) ); 752 753 for( i = 0; i < nlpinvars; ++i ) 754 { 755 assert(nlpivars[i] != NULL); 756 assert(SCIPhashmapExists(var2nlpiidx, (void*)nlpivars[i])); 757 758 lbs[i] = SCIPvarGetLbLocal(nlpivars[i]); 759 ubs[i] = SCIPvarGetUbLocal(nlpivars[i]); 760 inds[i] = SCIPhashmapGetImageInt(var2nlpiidx, (void*)nlpivars[i]); 761 assert(inds[i] >= 0 && inds[i] < nlpinvars); 762 } 763 764 SCIP_CALL( SCIPchgNlpiVarBounds(scip, nlpi, nlpiprob, nlpinvars, inds, lbs, ubs) ); 765 766 SCIPfreeBufferArray(scip, &inds); 767 SCIPfreeBufferArray(scip, &ubs); 768 SCIPfreeBufferArray(scip, &lbs); 769 770 /* update cutoff row */ 771 lhs = -SCIPinfinity(scip); 772 rhs = cutoffbound; 773 i = 0; 774 775 SCIP_CALL( SCIPchgNlpiConsSides(scip, nlpi, nlpiprob, 1, &i, &lhs, &rhs) ); 776 777 return SCIP_OKAY; 778 } 779 780 /** adds SCIP_ROWs to a NLPI problem */ 781 SCIP_RETCODE SCIPaddNlpiProblemRows( 782 SCIP* scip, /**< SCIP data structure */ 783 SCIP_NLPI* nlpi, /**< interface to NLP solver */ 784 SCIP_NLPIPROBLEM* nlpiprob, /**< nlpi problem */ 785 SCIP_HASHMAP* var2idx, /**< empty hash map to store mapping between variables and indices in nlpiprob */ 786 SCIP_ROW** rows, /**< rows to add */ 787 int nrows /**< number of rows to add */ 788 ) 789 { 790 const char** names; 791 SCIP_Real* lhss; 792 SCIP_Real* rhss; 793 SCIP_Real** linvals; 794 int** lininds; 795 int* nlininds; 796 int i; 797 798 assert(nlpi != NULL); 799 assert(nlpiprob != NULL); 800 assert(var2idx != NULL); 801 assert(nrows == 0 || rows != NULL); 802 803 SCIPdebugMsg(scip, "SCIPaddNlpiProblemRows() called with %d rows\n", nrows); 804 805 if( nrows <= 0 ) 806 return SCIP_OKAY; 807 808 SCIP_CALL( SCIPallocBufferArray(scip, &names, nrows) ); 809 SCIP_CALL( SCIPallocBufferArray(scip, &lhss, nrows) ); 810 SCIP_CALL( SCIPallocBufferArray(scip, &rhss, nrows) ); 811 SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nrows) ); 812 SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nrows) ); 813 SCIP_CALL( SCIPallocBufferArray(scip, &nlininds, nrows) ); 814 815 for( i = 0; i < nrows; ++i ) 816 { 817 int k; 818 819 assert(rows[i] != NULL); 820 assert(SCIProwGetNNonz(rows[i]) <= SCIPgetNVars(scip)); 821 822 names[i] = SCIProwGetName(rows[i]); 823 lhss[i] = SCIProwGetLhs(rows[i]) - SCIProwGetConstant(rows[i]); 824 rhss[i] = SCIProwGetRhs(rows[i]) - SCIProwGetConstant(rows[i]); 825 nlininds[i] = SCIProwGetNNonz(rows[i]); 826 linvals[i] = SCIProwGetVals(rows[i]); 827 lininds[i] = NULL; 828 829 SCIP_CALL( SCIPallocBufferArray(scip, &lininds[i], SCIProwGetNNonz(rows[i])) ); /*lint !e866*/ 830 831 for( k = 0; k < SCIProwGetNNonz(rows[i]); ++k ) 832 { 833 SCIP_VAR* var; 834 835 var = SCIPcolGetVar(SCIProwGetCols(rows[i])[k]); 836 assert(var != NULL); 837 assert(SCIPhashmapExists(var2idx, (void*)var)); 838 839 lininds[i][k] = SCIPhashmapGetImageInt(var2idx, (void*)var); 840 assert(lininds[i][k] >= 0 && lininds[i][k] < SCIPgetNVars(scip)); 841 } 842 } 843 844 /* pass all linear rows to the nlpi */ 845 SCIP_CALL( SCIPaddNlpiConstraints(scip, nlpi, nlpiprob, nrows, lhss, rhss, nlininds, lininds, linvals, 846 NULL, names) ); 847 848 /* free memory */ 849 for( i = nrows - 1; i >= 0; --i ) 850 { 851 SCIPfreeBufferArray(scip, &lininds[i]); 852 } 853 SCIPfreeBufferArray(scip, &nlininds); 854 SCIPfreeBufferArray(scip, &lininds); 855 SCIPfreeBufferArray(scip, &linvals); 856 SCIPfreeBufferArray(scip, &rhss); 857 SCIPfreeBufferArray(scip, &lhss); 858 SCIPfreeBufferArray(scip, &names); 859 860 return SCIP_OKAY; 861 } 862 863 /** adds SCIP_NLROWs to a NLPI problem */ 864 SCIP_RETCODE SCIPaddNlpiProblemNlRows( 865 SCIP* scip, /**< SCIP data structure */ 866 SCIP_NLPI* nlpi, /**< interface to NLP solver */ 867 SCIP_NLPIPROBLEM* nlpiprob, /**< nlpi problem */ 868 SCIP_HASHMAP* var2idx, /**< empty hash map to store mapping between variables and indices in nlpiprob */ 869 SCIP_NLROW** nlrows, /**< rows to add */ 870 int nnlrows /**< number of rows to add */ 871 ) 872 { 873 const char** names; 874 SCIP_Real* lhss; 875 SCIP_Real* rhss; 876 SCIP_Real** linvals; 877 int** lininds; 878 int* nlininds; 879 SCIP_EXPR** exprs; 880 int i; 881 882 assert(nlpi != NULL); 883 assert(nlpiprob != NULL); 884 assert(var2idx != NULL); 885 assert(nnlrows == 0 || nlrows != NULL); 886 887 SCIPdebugMsg(scip, "SCIPaddNlpiProblemNlRows() called with %d rows\n", nnlrows); 888 889 if( nnlrows <= 0 ) 890 return SCIP_OKAY; 891 892 SCIP_CALL( SCIPallocBufferArray(scip, &names, nnlrows) ); 893 SCIP_CALL( SCIPallocBufferArray(scip, &lhss, nnlrows) ); 894 SCIP_CALL( SCIPallocBufferArray(scip, &rhss, nnlrows) ); 895 SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nnlrows) ); 896 SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nnlrows) ); 897 SCIP_CALL( SCIPallocBufferArray(scip, &nlininds, nnlrows) ); 898 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nnlrows) ); 899 900 for( i = 0; i < nnlrows; ++i ) 901 { 902 SCIP_NLROW* nlrow; 903 904 nlrow = nlrows[i]; 905 assert(nlrow != NULL); 906 907 lhss[i] = !SCIPisInfinity(scip, -SCIPnlrowGetLhs(nlrow)) ? SCIPnlrowGetLhs(nlrow) - SCIPnlrowGetConstant(nlrow) : -SCIPinfinity(scip); 908 rhss[i] = !SCIPisInfinity(scip, SCIPnlrowGetRhs(nlrow)) ? SCIPnlrowGetRhs(nlrow) - SCIPnlrowGetConstant(nlrow) : SCIPinfinity(scip); 909 names[i] = SCIPnlrowGetName(nlrow); 910 nlininds[i] = 0; 911 lininds[i] = NULL; 912 linvals[i] = NULL; 913 914 /* copy linear part */ 915 if( SCIPnlrowGetNLinearVars(nlrow) > 0 ) 916 { 917 SCIP_VAR* var; 918 int k; 919 920 nlininds[i] = SCIPnlrowGetNLinearVars(nlrow); 921 922 SCIP_CALL( SCIPallocBufferArray(scip, &lininds[i], nlininds[i]) ); /*lint !e866*/ 923 SCIP_CALL( SCIPallocBufferArray(scip, &linvals[i], nlininds[i]) ); /*lint !e866*/ 924 925 for( k = 0; k < nlininds[i]; ++k ) 926 { 927 var = SCIPnlrowGetLinearVars(nlrow)[k]; 928 assert(var != NULL); 929 assert(SCIPhashmapExists(var2idx, (void*)var)); 930 931 lininds[i][k] = SCIPhashmapGetImageInt(var2idx, (void*)var); 932 linvals[i][k] = SCIPnlrowGetLinearCoefs(nlrow)[k]; 933 } 934 } 935 936 if( SCIPnlrowGetExpr(nlrow) != NULL ) 937 { 938 /* create copy of expr that uses varidx expressions corresponding to variables indices in NLPI */ 939 SCIP_CALL( SCIPduplicateExpr(scip, SCIPnlrowGetExpr(nlrow), &exprs[i], mapvar2varidx, var2idx, NULL, NULL) ); 940 } 941 else 942 { 943 exprs[i] = NULL; 944 } 945 } 946 947 /* pass all rows to the nlpi */ 948 SCIP_CALL( SCIPaddNlpiConstraints(scip, nlpi, nlpiprob, nnlrows, lhss, rhss, nlininds, lininds, linvals, exprs, names) ); 949 950 /* free memory */ 951 for( i = nnlrows - 1; i >= 0; --i ) 952 { 953 SCIPfreeBufferArrayNull(scip, &linvals[i]); 954 SCIPfreeBufferArrayNull(scip, &lininds[i]); 955 if( exprs[i] != NULL ) 956 { 957 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) ); 958 } 959 } 960 SCIPfreeBufferArray(scip, &exprs); 961 SCIPfreeBufferArray(scip, &nlininds); 962 SCIPfreeBufferArray(scip, &lininds); 963 SCIPfreeBufferArray(scip, &linvals); 964 SCIPfreeBufferArray(scip, &rhss); 965 SCIPfreeBufferArray(scip, &lhss); 966 SCIPfreeBufferArray(scip, &names); 967 968 return SCIP_OKAY; 969 } 970