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