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 scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file nlhdlr_default.c
17 * @ingroup DEFPLUGINS_NLHDLR
18 * @brief default nonlinear handler that calls expression handler methods
19 * @author Stefan Vigerske
20 */
21
22 #include <string.h>
23
24 #include "scip/nlhdlr_default.h"
25 #include "scip/pub_nlhdlr.h"
26 #include "scip/cons_nonlinear.h"
27
28 /* fundamental nonlinear handler properties */
29 #define NLHDLR_NAME "default"
30 #define NLHDLR_DESC "default handler for expressions"
31 #define NLHDLR_DETECTPRIORITY 0
32 #define NLHDLR_ENFOPRIORITY 0
33
34 /** translate from one value of infinity to another
35 *
36 * if val is ≥ infty1, then give infty2, else give val
37 */
38 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
39
40 #define UNDERESTIMATEUSESACTIVITY 0x1u /**< whether underestimation uses activity */
41 #define OVERESTIMATEUSESACTIVITY 0x2u /**< whether overestimation uses activity */
42
43 /*lint -e666*/
44 /*lint -e850*/
45
46 /** evaluates an expression w.r.t. the values in the auxiliary variables */
47 static
48 SCIP_RETCODE evalExprInAux(
49 SCIP* scip, /**< SCIP data structure */
50 SCIP_EXPR* expr, /**< expression to be evaluated */
51 SCIP_Real* val, /**< buffer to store value of expression */
52 SCIP_SOL* sol /**< solution to be evaluated */
53 )
54 {
55 SCIP_Real* childvals;
56 SCIP_VAR* childvar;
57 int c;
58
59 assert(scip != NULL);
60 assert(expr != NULL);
61 assert(val != NULL);
62 assert(SCIPexprGetNChildren(expr) > 0);
63
64 SCIP_CALL( SCIPallocBufferArray(scip, &childvals, SCIPexprGetNChildren(expr)) );
65
66 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
67 {
68 childvar = SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(expr)[c]);
69 /* there should be an auxiliary variable, because we created them in detect for every child if we said that we will separate;
70 * at the moment, EVALAUX should only be called for nlhdlrs that said they will separate
71 * if that changes, then we should handle this here, e.g., via *val = SCIPexprGetEvalValue(expr); break;
72 */
73 assert(childvar != NULL);
74
75 childvals[c] = SCIPgetSolVal(scip, sol, childvar);
76 }
77
78 SCIP_CALL( SCIPcallExprEval(scip, expr, childvals, val) );
79
80 SCIPfreeBufferArray(scip, &childvals);
81
82 return SCIP_OKAY;
83 }
84
85 /** check whether expression should be handled by the default nlhdlr
86 *
87 * if no nlhdlr so far provides enforcement or boundtightening for expr, then the default nlhdlr takes over
88 */
89 static
90 SCIP_DECL_NLHDLRDETECT(nlhdlrDetectDefault)
91 { /*lint --e{715}*/
92 SCIP_EXPRHDLR* exprhdlr;
93 SCIP_Bool estimatebelowusesactivity = FALSE;
94 SCIP_Bool estimateaboveusesactivity = FALSE;
95 int c;
96
97 assert(scip != NULL);
98 assert(nlhdlr != NULL);
99 assert(expr != NULL);
100 assert(enforcing != NULL);
101 assert(participating != NULL);
102 assert(nlhdlrexprdata != NULL);
103
104 exprhdlr = SCIPexprGetHdlr(expr);
105 assert(exprhdlr != NULL);
106
107 if( (*enforcing & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
108 {
109 /* expr handlers having reverseprop but no inteval is something that we don't support at the moment for simplicity */
110 assert(!SCIPexprhdlrHasReverseProp(exprhdlr) || SCIPexprhdlrHasIntEval(exprhdlr));
111
112 /* participate in inteval and/or reverseprop if that is not yet provided in enforcing and we have inteval */
113 if( SCIPexprhdlrHasIntEval(exprhdlr) )
114 *participating = SCIP_NLHDLR_METHOD_ACTIVITY;
115 }
116
117 /* participate in sepa if exprhdlr for expr has an estimate callback and sepa below or above is still missing */
118 if( ((*enforcing & SCIP_NLHDLR_METHOD_SEPABOTH) != SCIP_NLHDLR_METHOD_SEPABOTH) && SCIPexprhdlrHasEstimate(exprhdlr) )
119 {
120 /* communicate back that the nlhdlr will provide the separation on the currently missing sides */
121 if( (*enforcing & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 )
122 *participating |= SCIP_NLHDLR_METHOD_SEPABELOW;
123
124 if( (*enforcing & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 )
125 *participating |= SCIP_NLHDLR_METHOD_SEPAABOVE;
126 }
127
128 if( !*participating )
129 return SCIP_OKAY;
130
131 /* since this is the default handler, we enforce where we participate */
132 *enforcing |= *participating;
133
134 /* increment activity usage counter and create auxiliary variables if necessary
135 * if separating, first guess whether we will use activities in estimate (distinguish under- and overestimation)
136 * we assume that the exprhdlr will use activity on all children iff we are estimating on a nonconvex side
137 * TODO it would be better to request this information directly from the exprhdlr than inferring it from curvature,
138 * but with the currently available exprhdlr that wouldn't make a difference
139 */
140 if( *participating & SCIP_NLHDLR_METHOD_SEPABOTH )
141 {
142 SCIP_EXPRCURV* childcurv;
143
144 /* allocate memory to store the required curvature of the children (though we don't use it) */
145 SCIP_CALL( SCIPallocBufferArray(scip, &childcurv, SCIPexprGetNChildren(expr)) );
146
147 if( *participating & SCIP_NLHDLR_METHOD_SEPABELOW )
148 {
149 /* check whether the expression is convex */
150 SCIP_Bool isconvex;
151 SCIP_CALL( SCIPcallExprCurvature(scip, expr, SCIP_EXPRCURV_CONVEX, &isconvex, childcurv) );
152 estimatebelowusesactivity = !isconvex;
153 }
154
155 if( *participating & SCIP_NLHDLR_METHOD_SEPAABOVE )
156 {
157 /* check whether the expression is concave */
158 SCIP_Bool isconcave;
159 SCIP_CALL( SCIPcallExprCurvature(scip, expr, SCIP_EXPRCURV_CONCAVE, &isconcave, childcurv) );
160 estimateaboveusesactivity = !isconcave;
161 }
162
163 /* free memory */
164 SCIPfreeBufferArray(scip, &childcurv);
165 }
166
167 /* indicate enforcement methods required in children:
168 * - if separating, make sure that (auxiliary) variable will exist
169 * - if activity computation, then register activity usage
170 * - if estimating on a non-convex side, then indicate activity usage for separation for that side
171 */
172 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
173 {
174 /* todo skip auxvarusage for value-expressions? would then need update in evalExprInAux, too */
175 SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, SCIPexprGetChildren(expr)[c],
176 *participating & SCIP_NLHDLR_METHOD_SEPABOTH,
177 *participating & SCIP_NLHDLR_METHOD_ACTIVITY, estimatebelowusesactivity, estimateaboveusesactivity) );
178 }
179
180 /* remember estimatebelowusesactivity and estimateaboveusesactivity in nlhdlrexprdata */
181 *nlhdlrexprdata = (SCIP_NLHDLREXPRDATA*)(size_t)((estimatebelowusesactivity ? UNDERESTIMATEUSESACTIVITY : 0x0u)
182 | (estimateaboveusesactivity ? OVERESTIMATEUSESACTIVITY : 0x0u));
183
184 return SCIP_OKAY;
185 }
186
187 /** evaluate expression w.r.t. values of auxiliary variables in children */
188 static
189 SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalAuxDefault)
190 { /*lint --e{715}*/
191 assert(expr != NULL);
192 assert(auxvalue != NULL);
193
194 SCIP_CALL( evalExprInAux(scip, expr, auxvalue, sol) );
195
196 return SCIP_OKAY;
197 }
198
199 /** initialize LP relaxation by initial estimators */
200 static
201 SCIP_DECL_NLHDLRINITSEPA(nlhdlrInitSepaDefault)
202 { /*lint --e{715}*/
203 SCIP_INTERVAL* childrenbounds;
204 SCIP_Real* coefs[SCIP_EXPR_MAXINITESTIMATES];
205 SCIP_Real constant[SCIP_EXPR_MAXINITESTIMATES];
206 SCIP_VAR* auxvar;
207 SCIP_ROWPREP* rowprep;
208 int nreturned;
209 int i, j;
210
211 assert(scip != NULL);
212 assert(expr != NULL);
213 assert(infeasible != NULL);
214
215 *infeasible = FALSE;
216
217 if( !SCIPexprhdlrHasInitEstimates(SCIPexprGetHdlr(expr)) )
218 return SCIP_OKAY;
219
220 SCIPdebug( SCIPinfoMessage(scip, NULL, "initsepa exprhdlr %s for expr ", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))) );
221 SCIPdebug( SCIPprintExpr(scip, expr, NULL) );
222 SCIPdebug( SCIPinfoMessage(scip, NULL, "\n") );
223
224 /* use global bounds of auxvar as global valid bounds for children
225 * if at root node (thus local=global) and estimate actually uses bounds, then intersect with (local) activity of expression
226 */
227 SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
228 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
229 {
230 auxvar = SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(expr)[i]);
231 assert(auxvar != NULL);
232
233 SCIPintervalSetBounds(&childrenbounds[i],
234 -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -SCIPvarGetLbGlobal(auxvar)),
235 infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, SCIPvarGetUbGlobal(auxvar)));
236
237 if( SCIPgetDepth(scip) == 0 &&
238 ((underestimate && ((size_t)nlhdlrexprdata & UNDERESTIMATEUSESACTIVITY)) ||
239 (overestimate && ((size_t)nlhdlrexprdata & OVERESTIMATEUSESACTIVITY ))) )
240 {
241 SCIP_CALL( SCIPevalExprActivity(scip, SCIPexprGetChildren(expr)[i]) );
242 SCIPintervalIntersect(&childrenbounds[i], childrenbounds[i], SCIPexprGetActivity(SCIPexprGetChildren(expr)[i]));
243 }
244
245 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, childrenbounds[i]) )
246 {
247 SCIPdebugMsg(scip, "activity for expression %d (unexpectedly) empty in initsepa\n", i);
248 *infeasible = TRUE;
249 SCIPfreeBufferArray(scip, &childrenbounds);
250 return SCIP_OKAY;
251 }
252 }
253
254 /* allocate each coefficients array */
255 for( i = 0; i < SCIP_EXPR_MAXINITESTIMATES; ++i )
256 {
257 SCIP_CALL( SCIPallocBufferArray(scip, &coefs[i], SCIPexprGetNChildren(expr)) );
258 }
259
260 /* create rowprep */
261 SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, SCIP_SIDETYPE_RIGHT, FALSE) );
262 SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, SCIPexprGetNChildren(expr)+1) );
263
264 /* call the separation initialization callback of the expression handler and turn estimates into SCIP rows */
265 for( i = 0; i < 2 && !*infeasible; ++i )
266 {
267 nreturned = 0;
268 if( i == 0 && underestimate )
269 {
270 SCIP_CALL( SCIPcallExprInitestimates(scip, expr, childrenbounds, FALSE, coefs, constant, &nreturned) );
271 assert(SCIProwprepGetSidetype(rowprep) == SCIP_SIDETYPE_RIGHT);
272 }
273 if( i == 1 && overestimate )
274 {
275 SCIP_CALL( SCIPcallExprInitestimates(scip, expr, childrenbounds, TRUE, coefs, constant, &nreturned) );
276 SCIProwprepSetSidetype(rowprep, SCIP_SIDETYPE_LEFT);
277 }
278
279 for( j = 0; j < nreturned && !*infeasible; ++j )
280 {
281 SCIP_Bool success;
282 int v;
283
284 SCIProwprepReset(rowprep);
285
286 for( v = 0; v < SCIPexprGetNChildren(expr); ++v )
287 {
288 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(expr)[v]), coefs[j][v]) );
289 }
290 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
291 SCIProwprepAddConstant(rowprep, constant[j]); /*lint !e644*/
292
293 /* special treatment for sums to get equality rows */
294 if( j == 0 && SCIPisExprSum(scip, expr) )
295 {
296 SCIP_Real scalefactor;
297 SCIP_ROW* row;
298
299 /* improve numerics by scaling only (does not relax inequality) */
300 scalefactor = SCIPscaleupRowprep(scip, rowprep, 1.0, &success);
301 if( success && scalefactor == 1.0 && underestimate && overestimate )
302 {
303 /* if the rowprep didn't have to be changed, then turn it into a row, change this to an equality, and add it to the LP */
304 /* TODO do this also if not actually needing both under- and overestimator (should still be valid, but also stronger?) */
(1) Event extra_argument: |
This argument was not used by the format string: "j". [details] |
305 (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "initestimate_sum", j);
306
307 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
308
309 /* since we did not relax the estimator, we can turn the row into an equality */
310 if( SCIPisInfinity(scip, SCIProwGetRhs(row)) )
311 {
312 SCIP_CALL( SCIPchgRowRhs(scip, row, SCIProwGetLhs(row)) );
313 }
314 else
315 {
316 SCIP_CALL( SCIPchgRowLhs(scip, row, SCIProwGetRhs(row)) );
317 }
318 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
319
320 SCIPdebug( SCIPinfoMessage(scip, NULL, " added %scut ", *infeasible ? "infeasible " : "") );
321 SCIPdebug( SCIPprintRow(scip, row, NULL) );
322
323 SCIP_CALL( SCIPreleaseRow(scip, &row) );
324
325 i = 2; /* to break outside loop on i, too */
326 break;
327 }
328 }
329
330 /* straighten out numerics */
331 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, NULL, SCIPgetHugeValue(scip), &success) );
332
333 /* if cleanup removed all but one variable, then the cut is essentially a bound; we can skip this and rely on boundtightening */
334 if( success && SCIProwprepGetNVars(rowprep) > 1 )
335 {
336 /* add the cut */
337 SCIP_ROW* row;
338
339 (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "init%sestimate%d_%s",
340 i == 0 ? "under" : "over", j, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
341
342 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
343 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
344
345 SCIPdebug( SCIPinfoMessage(scip, NULL, " added %scut ", *infeasible ? "infeasible " : "") );
346 SCIPdebug( SCIPprintRow(scip, row, NULL) );
347
348 SCIP_CALL( SCIPreleaseRow(scip, &row) );
349 }
350 }
351 }
352
353 SCIPfreeRowprep(scip, &rowprep);
354
355 for( i = SCIP_EXPR_MAXINITESTIMATES-1; i >= 0; --i )
356 {
357 SCIPfreeBufferArray(scip, &coefs[i]);
358 }
359
360 SCIPfreeBufferArray(scip, &childrenbounds);
361
362 return SCIP_OKAY;
363 }
364
365 /** compute linear estimator */
366 static
367 SCIP_DECL_NLHDLRESTIMATE(nlhdlrEstimateDefault)
368 { /*lint --e{715}*/
369 SCIP_Real constant;
370 SCIP_Bool local;
371 SCIP_Bool* branchcand = NULL;
372 int nchildren;
373 int c;
374 SCIP_INTERVAL* localbounds;
375 SCIP_INTERVAL* globalbounds;
376 SCIP_Real* refpoint;
377 SCIP_ROWPREP* rowprep;
378 SCIP_VAR* auxvar;
379
380 assert(scip != NULL);
381 assert(expr != NULL);
382 assert(rowpreps != NULL);
383 assert(success != NULL);
384
385 *addedbranchscores = FALSE;
386
387 nchildren = SCIPexprGetNChildren(expr);
388
389 SCIP_CALL( SCIPallocBufferArray(scip, &localbounds, nchildren) );
390 SCIP_CALL( SCIPallocBufferArray(scip, &globalbounds, nchildren) );
391 SCIP_CALL( SCIPallocBufferArray(scip, &refpoint, nchildren) );
392 /* we need to pass a branchcand array to exprhdlr's estimate also if not asked to add branching scores */
393 SCIP_CALL( SCIPallocBufferArray(scip, &branchcand, nchildren) );
394
395 SCIPdebug( SCIPinfoMessage(scip, NULL, "estimate exprhdlr %s for expr ", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))) );
396 SCIPdebug( SCIPprintExpr(scip, expr, NULL) );
397 SCIPdebug( SCIPinfoMessage(scip, NULL, "\n") );
398
399 for( c = 0; c < nchildren; ++c )
400 {
401 auxvar = SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(expr)[c]);
402 assert(auxvar != NULL);
403
404 SCIPintervalSetBounds(&localbounds[c],
405 -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -SCIPvarGetLbLocal(auxvar)),
406 infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, SCIPvarGetUbLocal(auxvar)));
407
408 if( ((size_t)nlhdlrexprdata & (overestimate ? OVERESTIMATEUSESACTIVITY : UNDERESTIMATEUSESACTIVITY)) )
409 {
410 /* if expr estimate uses bounds, then intersect the auxvar bounds with the current activity, in case the latter is a bit tighter */
411 SCIP_CALL( SCIPevalExprActivity(scip, SCIPexprGetChildren(expr)[c]) );
412 SCIPintervalIntersectEps(&localbounds[c], SCIPepsilon(scip), localbounds[c], SCIPexprGetActivity(SCIPexprGetChildren(expr)[c]));
413
414 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, localbounds[c]) )
415 {
416 *success = FALSE;
417 goto TERMINATE;
418 }
419 }
420 else
421 {
422 /* if we think that expr estimate wouldn't use bounds, then just set something valid */
423 }
424
425 SCIPintervalSetBounds(&globalbounds[c],
426 -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -SCIPvarGetLbGlobal(auxvar)),
427 infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, SCIPvarGetUbGlobal(auxvar)));
428
429 refpoint[c] = SCIPgetSolVal(scip, sol, auxvar);
430
431 branchcand[c] = TRUE;
432 }
433
434 SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT, TRUE) );
435
436 /* make sure enough space is available in rowprep arrays */
437 SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nchildren) );
438
439 /* call the estimation callback of the expression handler */
440 SCIP_CALL( SCIPcallExprEstimate(scip, expr, localbounds, globalbounds, refpoint, overestimate, targetvalue,
441 SCIProwprepGetCoefs(rowprep), &constant, &local, success, branchcand) );
442
443 if( *success )
444 {
445 int i;
446
447 SCIProwprepSetLocal(rowprep, local);
448
449 /* add variables to rowprep (coefs were already added by SCIPexprhdlrEstimateExpr) */
450 for( i = 0; i < nchildren; ++i )
451 {
452 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(expr)[i]),
453 SCIProwprepGetCoefs(rowprep)[i]) );
454 }
455
456 SCIProwprepAddConstant(rowprep, constant);
457
458 SCIPdebug( SCIPinfoMessage(scip, NULL, " found rowprep ") );
459 SCIPdebug( SCIPprintRowprepSol(scip, rowprep, sol, NULL) );
460
461 SCIP_CALL( SCIPsetPtrarrayVal(scip, rowpreps, 0, rowprep) );
462
463 (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "%sestimate_%s%p_%s%d",
464 overestimate ? "over" : "under",
465 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
466 (void*)expr,
467 sol != NULL ? "sol" : "lp",
468 sol != NULL ? SCIPsolGetIndex(sol) : SCIPgetNLPs(scip));
469 }
470 else
471 {
472 SCIPfreeRowprep(scip, &rowprep);
473 }
474
475 if( addbranchscores )
476 {
477 SCIP_Real violation;
478
479 #ifndef BRSCORE_ABSVIOL
480 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violation, NULL, NULL) );
481 #else
482 SCIP_CALL( SCIPgetExprAbsAuxViolationNonlinear(scip, expr, auxvalue, sol, &violation, NULL, NULL) );
483 #endif
484 assert(violation > 0.0); /* there should be a violation if we were called to enforce */
485
486 if( nchildren == 1 )
487 {
488 if( branchcand[0] )
489 {
490 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, SCIPexprGetChildren(expr), 1, violation, sol, addedbranchscores) );
491 }
492 }
493 else
494 {
495 SCIP_EXPR** exprs;
496 int nexprs = 0;
497
498 /* get list of those children that have the branchcand-flag set */
499 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
500
501 for( c = 0; c < nchildren; ++c )
502 if( branchcand[c] )
503 exprs[nexprs++] = SCIPexprGetChildren(expr)[c];
504
505 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violation, sol, addedbranchscores) );
506
507 SCIPfreeBufferArray(scip, &exprs);
508 }
509
510 if( *addedbranchscores )
511 {
512 /* count this branchscore as belonging to the exprhdlr, too
513 * thus, it will be counted for the default nlhdlr, but also for this exprhdlr
514 */
515 SCIPexprhdlrIncrementNBranchings(SCIPexprGetHdlr(expr));
516 }
517 }
518
519 TERMINATE:
520 SCIPfreeBufferArray(scip, &branchcand);
521 SCIPfreeBufferArray(scip, &refpoint);
522 SCIPfreeBufferArray(scip, &globalbounds);
523 SCIPfreeBufferArray(scip, &localbounds);
524
525 return SCIP_OKAY;
526 }
527
528 /** interval-evaluate expression w.r.t. activity of children */
529 static
530 SCIP_DECL_NLHDLRINTEVAL(nlhdlrIntevalDefault)
531 { /*lint --e{715}*/
532 assert(scip != NULL);
533 assert(expr != NULL);
534
535 /* call the interval evaluation callback of the expression handler */
536 SCIP_CALL( SCIPcallExprInteval(scip, expr, interval, intevalvar, intevalvardata) );
537
538 return SCIP_OKAY;
539 }
540
541 /** tighten bounds on children from bounds on expression and bounds on children */
542 static
543 SCIP_DECL_NLHDLRREVERSEPROP(nlhdlrReversepropDefault)
544 { /*lint --e{715}*/
545 SCIP_INTERVAL* childrenbounds;
546 int c;
547
548 assert(scip != NULL);
549 assert(expr != NULL);
550 assert(infeasible != NULL);
551 assert(nreductions != NULL);
552
553 *nreductions = 0;
554
555 SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
556 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
557 childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
558
559 /* call the reverse propagation callback of the expression handler */
560 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, bounds, childrenbounds, infeasible) );
561
562 if( !*infeasible )
563 {
564 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
565 {
566 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c],
567 infeasible, nreductions) );
568 }
569 SCIPexprhdlrIncrementNDomainReductions(SCIPexprGetHdlr(expr), *nreductions);
570 }
571
572 SCIPfreeBufferArray(scip, &childrenbounds);
573
574 return SCIP_OKAY;
575 }
576
577 /** nonlinear handler copy callback */
578 static
579 SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrDefault)
580 { /*lint --e{715}*/
581 assert(targetscip != NULL);
582 assert(sourcenlhdlr != NULL);
583 assert(strcmp(SCIPnlhdlrGetName(sourcenlhdlr), NLHDLR_NAME) == 0);
584
585 SCIP_CALL( SCIPincludeNlhdlrDefault(targetscip) );
586
587 return SCIP_OKAY;
588 }
589
590 /** callback to free expression specific data */
591 static
592 SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataDefault)
593 { /*lint --e{715}*/
594 assert(nlhdlrexprdata != NULL);
595
596 *nlhdlrexprdata = NULL;
597
598 return SCIP_OKAY;
599 }
600
601 /** includes default nonlinear handler in nonlinear constraint handler */
602 SCIP_RETCODE SCIPincludeNlhdlrDefault(
603 SCIP* scip /**< SCIP data structure */
604 )
605 {
606 SCIP_NLHDLR* nlhdlr;
607
608 assert(scip != NULL);
609
610 SCIP_CALL( SCIPincludeNlhdlrNonlinear(scip, &nlhdlr, NLHDLR_NAME, NLHDLR_DESC, NLHDLR_DETECTPRIORITY,
611 NLHDLR_ENFOPRIORITY, nlhdlrDetectDefault, nlhdlrEvalAuxDefault, NULL) );
612 assert(nlhdlr != NULL);
613
614 SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrDefault);
615 SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrFreeExprDataDefault);
616 SCIPnlhdlrSetSepa(nlhdlr, nlhdlrInitSepaDefault, NULL, nlhdlrEstimateDefault, NULL);
617 SCIPnlhdlrSetProp(nlhdlr, nlhdlrIntevalDefault, nlhdlrReversepropDefault);
618
619 return SCIP_OKAY;
620 }
621