SCIP Doxygen Documentation
Loading...
Searching...
No Matches
nlhdlr_perspective.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2026 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 nlhdlr_perspective.c
26 * @ingroup DEFPLUGINS_NLHDLR
27 * @brief perspective nonlinear handler
28 * @author Ksenia Bestuzheva
29 */
30
32#include "scip/cons_nonlinear.h"
33#include "scip/scip_sol.h"
35#include "scip/nlhdlr.h"
36
37/* fundamental nonlinear handler properties */
38#define NLHDLR_NAME "perspective"
39#define NLHDLR_DESC "perspective handler for expressions"
40#define NLHDLR_DETECTPRIORITY -20 /**< detect last so that to make use of what other handlers detected */
41#define NLHDLR_ENFOPRIORITY 125 /**< enforce first because perspective cuts are always stronger */
42
43#define DEFAULT_MAXPROPROUNDS 1 /**< maximal number of propagation rounds in probing */
44#define DEFAULT_MINDOMREDUCTION 0.1 /**< minimal relative reduction in a variable's domain for applying probing */
45#define DEFAULT_MINVIOLPROBING 1e-05 /**< minimal violation w.r.t. auxiliary variables for applying probing */
46#define DEFAULT_PROBINGONLYINSEPA TRUE /**< whether to do probing only in separation loop */
47#define DEFAULT_PROBINGFREQ 1 /**< probing frequency (-1 - no probing, 0 - root node only) */
48#define DEFAULT_CONVEXONLY FALSE /**< whether perspective cuts are added only for convex expressions */
49#define DEFAULT_TIGHTENBOUNDS TRUE /**< whether variable semicontinuity is used to tighten variable bounds */
50#define DEFAULT_ADJREFPOINT TRUE /**< whether to adjust the reference point if indicator is not 1 */
51
52/*
53 * Data structures
54 */
55
56/** data structure to store information of a semicontinuous variable
57 *
58 * For a variable x (not stored in the struct), this stores the data of nbnds implications
59 * bvars[i] = 0 -> x = vals[i]
60 * bvars[i] = 1 -> lbs[i] <= x <= ubs[i]
61 * where bvars[i] are binary variables.
62 */
63struct SCVarData
64{
65 SCIP_Real* vals0; /**< values of the variable when the corresponding bvars[i] = 0 */
66 SCIP_Real* lbs1; /**< global lower bounds of the variable when the corresponding bvars[i] = 1 */
67 SCIP_Real* ubs1; /**< global upper bounds of the variable when the corresponding bvars[i] = 1 */
68 SCIP_VAR** bvars; /**< the binary variables on which the variable domain depends */
69 int nbnds; /**< number of suitable on/off bounds the var has */
70 int bndssize; /**< size of the arrays */
71};
72typedef struct SCVarData SCVARDATA;
73
74/** nonlinear handler expression data
75 *
76 * For an expression expr (not stored in the struct), this stores the data of nindicators implications
77 * indicators[i] = 0 -> expr = exprvals[0]
78 * where indicators[i] is an indicator (binary) variable, corresponding to some bvars entry in SCVarData.
79 *
80 * Also stores the variables the expression depends on.
81 */
82struct SCIP_NlhdlrExprData
83{
84 SCIP_Real* exprvals0; /**< 'off' values of the expression for each indicator variable */
85 SCIP_VAR** vars; /**< expression variables (both original and auxiliary) */
86 int nvars; /**< total number of variables in the expression */
87 int varssize; /**< size of the vars array */
88 SCIP_VAR** indicators; /**< all indicator variables for the expression */
89 int nindicators; /**< number of indicator variables */
90};
91
92/** nonlinear handler data */
93struct SCIP_NlhdlrData
94{
95 SCIP_HASHMAP* scvars; /**< maps semicontinuous variables to their on/off bounds (SCVarData) */
96
97 /* parameters */
98 int maxproprounds; /**< maximal number of propagation rounds in probing */
99 SCIP_Real mindomreduction; /**< minimal relative reduction in a variable's domain for applying probing */
100 SCIP_Real minviolprobing; /**< minimal violation w.r.t. auxiliary variables for applying probing */
101 SCIP_Bool probingonlyinsepa; /**< whether to do probing only in separation loop */
102 int probingfreq; /**< if and when to do probing */
103 SCIP_Bool convexonly; /**< whether perspective cuts are added only for convex expressions */
104 SCIP_Bool tightenbounds; /**< whether variable semicontinuity is used to tighten variable bounds */
105 SCIP_Bool adjrefpoint; /**< whether to adjust the reference point if indicator is not 1 */
106};
107
108/*
109 * Local methods
110 */
111
112/*
113 * Helper methods for working with nlhdlrExprData
114 */
115
116/** frees nlhdlrexprdata structure */
117static
119 SCIP* scip, /**< SCIP data structure */
120 SCIP_NLHDLREXPRDATA* nlhdlrexprdata /**< nlhdlr expression data */
121 )
122{
123 int v;
124
125 if( nlhdlrexprdata->nindicators != 0 )
126 {
127 assert(nlhdlrexprdata->indicators != NULL);
128 for( v = nlhdlrexprdata->nindicators - 1; v >= 0; --v )
129 {
130 SCIP_CALL( SCIPreleaseVar(scip, &(nlhdlrexprdata->indicators[v])) );
131 }
132 SCIPfreeBlockMemoryArray(scip, &(nlhdlrexprdata->indicators), nlhdlrexprdata->nindicators);
133 SCIPfreeBlockMemoryArrayNull(scip, &(nlhdlrexprdata->exprvals0), nlhdlrexprdata->nindicators);
134 }
135
136 for( v = nlhdlrexprdata->nvars - 1; v >= 0; --v )
137 {
138 SCIP_CALL( SCIPreleaseVar(scip, &(nlhdlrexprdata->vars[v])) );
139 }
140 SCIPfreeBlockMemoryArrayNull(scip, &nlhdlrexprdata->vars, nlhdlrexprdata->varssize);
141
142 return SCIP_OKAY;
143}
144
145/* remove an indicator from nlhdlr expression data */
146static
148 SCIP* scip, /**< SCIP data structure */
149 SCIP_NLHDLREXPRDATA* nlexprdata, /**< nlhdlr expression data */
150 int pos /**< position of the indicator */
151 )
152{
153 int i;
154
155 assert(pos >= 0 && pos < nlexprdata->nindicators);
156
157 SCIP_CALL( SCIPreleaseVar(scip, &nlexprdata->indicators[pos]) );
158 for( i = pos; i < nlexprdata->nindicators - 1; ++i )
159 {
160 nlexprdata->indicators[i] = nlexprdata->indicators[i+1];
161 }
162
163 --nlexprdata->nindicators;
164
165 return SCIP_OKAY;
166}
167
168/** adds an auxiliary variable to the vars array in nlhdlrexprdata */
169static
171 SCIP* scip, /**< SCIP data structure */
172 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
173 SCIP_HASHMAP* auxvarmap, /**< hashmap linking auxvars to positions in nlhdlrexprdata->vars */
174 SCIP_VAR* auxvar /**< variable to be added */
175 )
176{
177 int pos;
178 int newsize;
179
180 assert(nlhdlrexprdata != NULL);
181 assert(auxvar != NULL);
182
183 pos = SCIPhashmapGetImageInt(auxvarmap, (void*) auxvar);
184
185 if( pos != INT_MAX )
186 return SCIP_OKAY;
187
188 /* ensure size */
189 if( nlhdlrexprdata->nvars + 1 > nlhdlrexprdata->varssize )
190 {
191 newsize = SCIPcalcMemGrowSize(scip, nlhdlrexprdata->nvars + 1);
192 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlhdlrexprdata->vars, nlhdlrexprdata->varssize, newsize) );
193 nlhdlrexprdata->varssize = newsize;
194 }
195 assert(nlhdlrexprdata->nvars + 1 <= nlhdlrexprdata->varssize);
196
197 nlhdlrexprdata->vars[nlhdlrexprdata->nvars] = auxvar;
198 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
199 SCIP_CALL( SCIPhashmapSetImageInt(auxvarmap, (void*) auxvar, nlhdlrexprdata->nvars) );
200 ++(nlhdlrexprdata->nvars);
201
202 return SCIP_OKAY;
203}
204
205/*
206 * Semicontinuous variable methods
207 */
208
209/** adds an indicator to the data of a semicontinuous variable */
210static
212 SCIP* scip, /**< SCIP data structure */
213 SCVARDATA* scvdata, /**< semicontinuous variable data */
214 SCIP_VAR* indicator, /**< indicator to be added */
215 SCIP_Real val0, /**< value of the variable when indicator == 0 */
216 SCIP_Real lb1, /**< lower bound of the variable when indicator == 1 */
217 SCIP_Real ub1 /**< upper bound of the variable when indicator == 1 */
218 )
219{
220 int newsize;
221 int i;
222 SCIP_Bool found;
223 int pos;
224
225 assert(scvdata != NULL);
226 assert(indicator != NULL);
227
228 /* find the position where to insert */
229 if( scvdata->bvars == NULL )
230 {
231 assert(scvdata->nbnds == 0 && scvdata->bndssize == 0);
232 found = FALSE;
233 pos = 0;
234 }
235 else
236 {
237 found = SCIPsortedvecFindPtr((void**)scvdata->bvars, SCIPvarComp, (void*)indicator, scvdata->nbnds, &pos);
238 }
239
240 if( found )
241 return SCIP_OKAY;
242
243 /* ensure sizes */
244 if( scvdata->nbnds + 1 > scvdata->bndssize )
245 {
246 newsize = SCIPcalcMemGrowSize(scip, scvdata->nbnds + 1);
247 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->bvars, scvdata->bndssize, newsize) );
248 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->vals0, scvdata->bndssize, newsize) );
249 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->lbs1, scvdata->bndssize, newsize) );
250 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->ubs1, scvdata->bndssize, newsize) );
251 scvdata->bndssize = newsize;
252 }
253 assert(scvdata->nbnds + 1 <= scvdata->bndssize);
254 assert(scvdata->bvars != NULL);
255
256 /* move entries if needed */
257 for( i = scvdata->nbnds; i > pos; --i )
258 {
259 /* coverity[var_deref_op] */
260 scvdata->bvars[i] = scvdata->bvars[i-1];
261 scvdata->vals0[i] = scvdata->vals0[i-1];
262 scvdata->lbs1[i] = scvdata->lbs1[i-1];
263 scvdata->ubs1[i] = scvdata->ubs1[i-1];
264 }
265
266 scvdata->bvars[pos] = indicator;
267 scvdata->vals0[pos] = val0;
268 scvdata->lbs1[pos] = lb1;
269 scvdata->ubs1[pos] = ub1;
270 ++scvdata->nbnds;
271
272 return SCIP_OKAY;
273}
274
275/** find scvardata of var and position of indicator in it
276 *
277 * If indicator is not there, returns NULL.
278 */
279static
281 SCIP_HASHMAP* scvars, /**< hashmap linking variables to scvardata */
282 SCIP_VAR* var, /**< variable */
283 SCIP_VAR* indicator, /**< indicator variable */
284 int* pos /**< pointer to store the position of indicator */
285 )
286{
287 SCIP_Bool exists;
288 SCVARDATA* scvdata;
289
290 assert(var != NULL);
291 assert(scvars != NULL);
292 assert(indicator != NULL);
293
294 scvdata = (SCVARDATA*) SCIPhashmapGetImage(scvars, (void*)var);
295 if( scvdata != NULL )
296 {
297 /* look for the indicator variable */
298 exists = SCIPsortedvecFindPtr((void**)scvdata->bvars, SCIPvarComp, (void*)indicator, scvdata->nbnds, pos);
299 if( !exists )
300 return NULL;
301
302 return scvdata;
303 }
304
305 return NULL;
306}
307
308/** checks if a variable is semicontinuous and, if needed, updates the scvars hashmap
309 *
310 * A variable \f$x\f$ is semicontinuous if its bounds depend on at least one binary variable called the indicator,
311 * and indicator = 0 &rArr; \f$x = x^0\f$ for some real constant \f$x^0\f$.
312 */
313static
315 SCIP* scip, /**< SCIP data structure */
316 SCIP_VAR* var, /**< the variable to check */
317 SCIP_HASHMAP* scvars, /**< semicontinuous variable information */
318 SCIP_Bool* result /**< buffer to store whether var is semicontinuous */
319 )
320{
321 SCIP_Real lb0;
322 SCIP_Real ub0;
323 SCIP_Real lb1;
324 SCIP_Real ub1;
325 SCIP_Real glb;
326 SCIP_Real gub;
327 SCIP_Bool exists;
328 int c;
329 int pos;
330 SCIP_VAR** vlbvars;
331 SCIP_VAR** vubvars;
332 SCIP_Real* vlbcoefs;
333 SCIP_Real* vubcoefs;
334 SCIP_Real* vlbconstants;
335 SCIP_Real* vubconstants;
336 int nvlbs;
337 int nvubs;
338 SCVARDATA* scvdata;
339 SCIP_VAR* bvar;
340
341 assert(scip != NULL);
342 assert(var != NULL);
343 assert(scvars != NULL);
344 assert(result != NULL);
345
346 scvdata = (SCVARDATA*) SCIPhashmapGetImage(scvars, (void*)var);
347 if( scvdata != NULL )
348 {
349 *result = TRUE;
350 return SCIP_OKAY;
351 }
352
353 vlbvars = SCIPvarGetVlbVars(var);
354 vubvars = SCIPvarGetVubVars(var);
355 vlbcoefs = SCIPvarGetVlbCoefs(var);
356 vubcoefs = SCIPvarGetVubCoefs(var);
357 vlbconstants = SCIPvarGetVlbConstants(var);
358 vubconstants = SCIPvarGetVubConstants(var);
359 nvlbs = SCIPvarGetNVlbs(var);
360 nvubs = SCIPvarGetNVubs(var);
361 glb = SCIPvarGetLbGlobal(var);
362 gub = SCIPvarGetUbGlobal(var);
363
364 *result = FALSE;
365
366 /* Scan through lower bounds; for each binary vlbvar save the corresponding lb0 and lb1.
367 * Then check if there is an upper bound with this vlbvar and save ub0 and ub1.
368 * If the found bounds imply that the var value is fixed to some val0 when vlbvar = 0,
369 * save vlbvar and val0 to scvdata.
370 */
371 for( c = 0; c < nvlbs; ++c )
372 {
373 if( SCIPvarGetType(vlbvars[c]) != SCIP_VARTYPE_BINARY || SCIPvarIsImpliedIntegral(vlbvars[c]) )
374 continue;
375
376 SCIPdebugMsg(scip, "var <%s>[%f, %f] lower bound: %f <%s> %+f", SCIPvarGetName(var), glb, gub, vlbcoefs[c], SCIPvarGetName(vlbvars[c]), vlbconstants[c]);
377
378 bvar = vlbvars[c];
379
380 lb0 = MAX(vlbconstants[c], glb);
381 lb1 = MAX(vlbconstants[c] + vlbcoefs[c], glb);
382
383 /* look for bvar in vubvars */
384 if( vubvars != NULL )
385 exists = SCIPsortedvecFindPtr((void**)vubvars, SCIPvarComp, bvar, nvubs, &pos);
386 else
387 exists = FALSE;
388 if( exists )
389 { /*lint --e{644}*/
390 SCIPdebugMsgPrint(scip, ", upper bound: %f <%s> %+f", vubcoefs[pos], SCIPvarGetName(vubvars[pos]), vubconstants[pos]); /*lint !e613*/
391
392 /* save the upper bounds */
393 ub0 = MIN(vubconstants[pos], gub);
394 ub1 = MIN(vubconstants[pos] + vubcoefs[pos], gub);
395 }
396 else
397 {
398 /* if there is no upper bound with vubvar = bvar, use global var bounds */
399 ub0 = gub;
400 ub1 = gub;
401 }
402
403 /* the 'off' domain of a semicontinuous var should reduce to a single point and be different from the 'on' domain */
404 SCIPdebugMsgPrint(scip, " -> <%s> in [%f, %f] (off), [%f, %f] (on)\n", SCIPvarGetName(var), lb0, ub0, lb1, ub1);
405 if( SCIPisEQ(scip, lb0, ub0) && (!SCIPisEQ(scip, lb0, lb1) || !SCIPisEQ(scip, ub0, ub1)) )
406 {
407 if( scvdata == NULL )
408 {
410 }
411
412 SCIP_CALL( addSCVarIndicator(scip, scvdata, bvar, lb0, lb1, ub1) );
413 }
414 }
415
416 /* look for vubvars that have not been processed yet */
417 assert(vubvars != NULL || nvubs == 0);
418 for( c = 0; c < nvubs; ++c )
419 {
420 /* coverity[var_deref_op] */
421 if( SCIPvarGetType(vubvars[c]) != SCIP_VARTYPE_BINARY || SCIPvarIsImpliedIntegral(vubvars[c]) ) /*lint !e613*/
422 continue;
423
424 bvar = vubvars[c]; /*lint !e613*/
425
426 /* skip vars that are in vlbvars */
427 if( vlbvars != NULL && SCIPsortedvecFindPtr((void**)vlbvars, SCIPvarComp, bvar, nvlbs, &pos) )
428 continue;
429
430 SCIPdebugMsg(scip, "var <%s>[%f, %f] upper bound: %f <%s> %+f",
431 SCIPvarGetName(var), glb, gub, vubcoefs[c], SCIPvarGetName(vubvars[c]), vubconstants[c]); /*lint !e613*/
432
433 lb0 = glb;
434 lb1 = glb;
435 ub0 = MIN(vubconstants[c], gub);
436 ub1 = MIN(vubconstants[c] + vubcoefs[c], gub);
437
438 /* the 'off' domain of a semicontinuous var should reduce to a single point and be different from the 'on' domain */
439 SCIPdebugMsgPrint(scip, " -> <%s> in [%f, %f] (off), [%f, %f] (on)\n", SCIPvarGetName(var), lb0, ub0, lb1, ub1);
440 if( SCIPisEQ(scip, lb0, ub0) && (!SCIPisEQ(scip, lb0, lb1) || !SCIPisEQ(scip, ub0, ub1)) )
441 {
442 if( scvdata == NULL )
443 {
445 }
446
447 SCIP_CALL( addSCVarIndicator(scip, scvdata, bvar, lb0, lb1, ub1) );
448 }
449 }
450
451 if( scvdata != NULL )
452 {
453#ifdef SCIP_DEBUG
454 SCIPdebugMsg(scip, "var <%s> has global bounds [%f, %f] and the following on/off bounds:\n", SCIPvarGetName(var), glb, gub);
455 for( c = 0; c < scvdata->nbnds; ++c )
456 {
457 SCIPdebugMsg(scip, " c = %d, bvar <%s>: val0 = %f\n", c, SCIPvarGetName(scvdata->bvars[c]), scvdata->vals0[c]);
458 }
459#endif
460 SCIP_CALL( SCIPhashmapInsert(scvars, var, scvdata) );
461 *result = TRUE;
462 }
463
464 return SCIP_OKAY;
465}
466
467/*
468 * Semicontinuous expression methods
469 */
470
471/* checks if an expression is semicontinuous
472 *
473 * An expression is semicontinuous if all of its nonlinear variables are semicontinuous
474 * and share at least one common indicator variable
475 */
476static
478 SCIP* scip, /**< SCIP data structure */
479 SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
480 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
481 SCIP_EXPR* expr, /**< expression */
482 SCIP_Bool* res /**< buffer to store whether the expression is semicontinuous */
483 )
484{
485 int v;
486 SCIP_Bool var_is_sc;
487 SCVARDATA* scvdata;
488 SCIP_VAR* var;
489 int nindicators;
490 int nbnds0;
491 int c;
492 SCIP_VAR** indicators;
493 SCIP_Bool* nonlinear;
494
495 *res = FALSE;
496
497 /* constant expression is not semicontinuous; variable expressions are of no interest here */
498 if( nlhdlrexprdata->nvars == 0 )
499 return SCIP_OKAY;
500
501 indicators = NULL;
502 nindicators = 0;
503 nbnds0 = 0;
504
505 if( SCIPisExprSum(scip, expr) )
506 {
507 SCIP_EXPRITER* it;
508 SCIP_EXPR* child;
509 SCIP_EXPR* curexpr;
510 int pos;
511 SCIP_Bool issc;
512
513 /* sums are treated separately because if there are variables that are non-semicontinuous but
514 * appear only linearly, we still want to apply perspective to expr
515 */
516
517 SCIP_CALL( SCIPallocClearBufferArray(scip, &nonlinear, nlhdlrexprdata->nvars) );
519
520 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
521 {
522 child = SCIPexprGetChildren(expr)[c];
523
524 if( SCIPisExprVar(scip, child) )
525 {
526 var = SCIPgetVarExprVar(child);
527
528 /* save information on semicontinuity of child */
529 SCIP_CALL( varIsSemicontinuous(scip, var, nlhdlrdata->scvars, &var_is_sc) );
530
531 /* since child is a variable, go on regardless of the value of var_is_sc */
532 continue;
533 }
534
535 issc = TRUE;
536
538 curexpr = SCIPexpriterGetCurrent(it);
539
540 /* all nonlinear terms of a sum should be semicontinuous in original variables */
541 while( !SCIPexpriterIsEnd(it) )
542 {
543 assert(curexpr != NULL);
544
545 if( SCIPisExprVar(scip, curexpr) )
546 {
547 var = SCIPgetVarExprVar(curexpr);
548
550 {
551 SCIP_CALL( varIsSemicontinuous(scip, var, nlhdlrdata->scvars, &var_is_sc) );
552
553 /* mark the variable as nonlinear */
554 (void) SCIPsortedvecFindPtr((void**) nlhdlrexprdata->vars, SCIPvarComp, (void*) var, nlhdlrexprdata->nvars,
555 &pos);
556 assert(0 <= pos && pos < nlhdlrexprdata->nvars);
557 nonlinear[pos] = TRUE;
558
559 if( !var_is_sc )
560 {
561 /* non-semicontinuous child which is (due to a previous check) not a var ->
562 * expr is non-semicontinuous
563 */
564 issc = FALSE;
565 break;
566 }
567 }
568 }
569 curexpr = SCIPexpriterGetNext(it);
570 }
571
572 if( !issc )
573 {
574 SCIPfreeExpriter(&it);
575 goto TERMINATE;
576 }
577 }
578 SCIPfreeExpriter(&it);
579 }
580 else
581 {
582 /* non-sum expression */
583 nonlinear = NULL;
584
585 /* all variables of a non-sum on/off expression should be semicontinuous */
586 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
587 {
588 SCIP_CALL( varIsSemicontinuous(scip, nlhdlrexprdata->vars[v], nlhdlrdata->scvars, &var_is_sc) );
589 if( !var_is_sc )
590 return SCIP_OKAY;
591 }
592 }
593
594 /* look for common binary variables for all variables of the expression */
595
596 SCIPdebugMsg(scip, "Array intersection for var <%s>\n", SCIPvarGetName(nlhdlrexprdata->vars[0]));
597 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
598 {
599 SCIPdebugMsg(scip, "%s; \n", SCIPvarGetName(nlhdlrexprdata->vars[v]));
600
601 if( nonlinear != NULL && !nonlinear[v] )
602 continue;
603
604 scvdata = (SCVARDATA*)SCIPhashmapGetImage(nlhdlrdata->scvars, (void*) nlhdlrexprdata->vars[v]);
605
606 /* we should have exited earlier if there is a nonlinear non-semicontinuous variable */
607 assert(scvdata != NULL);
608
609 if( indicators == NULL )
610 {
611 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &indicators, scvdata->bvars, scvdata->nbnds) );
612 nbnds0 = scvdata->nbnds;
613 nindicators = nbnds0;
614 }
615 else
616 {
617 SCIPcomputeArraysIntersectionPtr((void**)indicators, nindicators, (void**)scvdata->bvars, scvdata->nbnds,
618 SCIPvarComp, (void**)indicators, &nindicators);
619 }
620
621 /* if we have found out that the intersection is empty, expr is not semicontinuous */
622 if( indicators != NULL && nindicators == 0 )
623 {
624 SCIPfreeBlockMemoryArray(scip, &indicators, nbnds0);
625 goto TERMINATE;
626 }
627 }
628
629 /* this can happen if all children are linear vars and none are semicontinuous */
630 if( indicators == NULL )
631 {
632 goto TERMINATE;
633 }
634 assert(nindicators > 0 && nindicators <= nbnds0);
635
636 if( nindicators < nbnds0 )
637 {
638 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &indicators, nbnds0, nindicators) );
639 }
640
641 for( v = 0; v < nindicators; ++v )
642 {
643 SCIP_CALL( SCIPcaptureVar(scip, indicators[v]) );
644 }
645 nlhdlrexprdata->indicators = indicators;
646 nlhdlrexprdata->nindicators = nindicators;
647 *res = TRUE;
648
649 TERMINATE:
650 SCIPfreeBufferArrayNull(scip, &nonlinear);
651
652 return SCIP_OKAY;
653}
654
655/** computes the 'off' value of the expression and the 'off' values of
656 * semicontinuous auxiliary variables for each indicator variable
657 */
658static
660 SCIP* scip, /**< SCIP data structure */
661 SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
662 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
663 SCIP_EXPR* expr /**< expression */
664 )
665{
666 SCIP_EXPRITER* it;
667 SCIP_SOL* sol;
668 int i;
669 int v;
670 int norigvars;
671 SCIP_Real* origvals0;
672 SCIP_VAR** origvars;
673 SCVARDATA* scvdata;
674 SCIP_VAR* auxvar;
675 SCIP_EXPR* curexpr;
676 SCIP_HASHMAP* auxvarmap;
677 SCIP_Bool hasnonsc;
678 int pos;
679
680 assert(expr != NULL);
681
682 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(nlhdlrexprdata->exprvals0), nlhdlrexprdata->nindicators) );
684 SCIP_CALL( SCIPallocBufferArray(scip, &origvals0, nlhdlrexprdata->nvars) );
685 SCIP_CALL( SCIPhashmapCreate(&auxvarmap, SCIPblkmem(scip), 10) );
687 SCIP_CALL( SCIPduplicateBufferArray(scip, &origvars, nlhdlrexprdata->vars, nlhdlrexprdata->nvars) );
688 norigvars = nlhdlrexprdata->nvars;
689
690 for( i = nlhdlrexprdata->nindicators - 1; i >= 0; --i )
691 {
692 hasnonsc = FALSE;
693
694 /* set sol to the off value of all expr vars for this indicator */
695 for( v = 0; v < norigvars; ++v )
696 {
697 /* set vals0[v] = 0 if var is non-sc with respect to indicators[i] - then it will not
698 * contribute to exprvals0[i] since any non-sc var must be linear
699 */
700 scvdata = getSCVarDataInd(nlhdlrdata->scvars, origvars[v], nlhdlrexprdata->indicators[i], &pos);
701 if( scvdata == NULL )
702 {
703 origvals0[v] = 0.0;
704 hasnonsc = TRUE;
705 }
706 else
707 {
708 origvals0[v] = scvdata->vals0[pos];
709 }
710 }
711 SCIP_CALL( SCIPsetSolVals(scip, sol, norigvars, origvars, origvals0) );
712 SCIP_CALL( SCIPevalExpr(scip, expr, sol, 0L) );
713
714 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID ) /*lint !e777*/
715 {
716 SCIPdebugMsg(scip, "expression evaluation failed for %p, removing indicator %s\n",
717 (void*)expr, SCIPvarGetName(nlhdlrexprdata->indicators[i]));
718 /* TODO should we fix the indicator variable to 1? */
719 /* since the loop is backwards, this only modifies the already processed part of nlhdlrexprdata->indicators */
720 SCIP_CALL( removeIndicator(scip, nlhdlrexprdata, i) );
721 continue;
722 }
723
724 nlhdlrexprdata->exprvals0[i] = SCIPexprGetEvalValue(expr);
725
726 /* iterate through the expression and create scvdata for aux vars */
728 curexpr = SCIPexpriterGetCurrent(it);
729
730 while( !SCIPexpriterIsEnd(it) )
731 {
732 auxvar = SCIPgetExprAuxVarNonlinear(curexpr);
733
734 if( auxvar != NULL )
735 {
736 SCIP_Bool issc = TRUE;
737#ifndef NDEBUG
738 SCIP_EXPR** childvarexprs;
739 int nchildvarexprs;
740 SCIP_VAR* var;
741#endif
742
743 if( hasnonsc )
744 {
745 /* expr is a sum with non-semicontinuous linear terms. Therefore, curexpr might be
746 * non-semicontinuous. In that case the auxvar is also non-semicontinuous, so
747 * we will skip on/off bounds computation.
748 */
749 if( SCIPisExprVar(scip, curexpr) )
750 {
751 /* easy case: curexpr is a variable, can check semicontinuity immediately */
752 scvdata = getSCVarDataInd(nlhdlrdata->scvars, SCIPgetVarExprVar(curexpr),
753 nlhdlrexprdata->indicators[i], &pos);
754 issc = scvdata != NULL;
755 }
756 else if( SCIPisExprSum(scip, curexpr) && curexpr == expr )
757 {
758 /* if expr itself is a sum, this is an exception since a sum with nonlinear terms is
759 * allowed to have both semicontinuous and non-semicontinuous variables; we skip it here
760 * and then analyse it term by term
761 */
762 issc = FALSE;
763 }
764
765#ifndef NDEBUG
766 if( !SCIPisExprVar(scip, curexpr) && (!SCIPisExprSum(scip, curexpr) || curexpr != expr) )
767 {
768 /* curexpr is a non-variable expression and does not fit the sum special case,
769 * so it belongs to the non-linear part of expr.
770 * Since the non-linear part of expr must be semicontinuous with respect to
771 * nlhdlrexprdata->indicators[i], curexpr must be semicontinuous
772 */
773
774 SCIP_CALL( SCIPallocBufferArray(scip, &childvarexprs, norigvars) );
775 SCIP_CALL( SCIPgetExprVarExprs(scip, curexpr, childvarexprs, &nchildvarexprs) );
776
777 /* all nonlinear variables of a sum on/off term should be semicontinuous */
778 for( v = 0; v < nchildvarexprs; ++v )
779 {
780 var = SCIPgetVarExprVar(childvarexprs[v]);
781 scvdata = getSCVarDataInd(nlhdlrdata->scvars, var, nlhdlrexprdata->indicators[i], &pos);
782 assert(scvdata != NULL);
783
784 SCIP_CALL( SCIPreleaseExpr(scip, &childvarexprs[v]) );
785 }
786
787 SCIPfreeBufferArray(scip, &childvarexprs);
788 }
789#endif
790 }
791
792 if( issc )
793 {
794 /* we know that all vars are semicontinuous with respect to exprdata->indicators; it remains to:
795 * - get or create the scvardata structure for auxvar
796 * - if had to create scvardata, add it to scvars hashmap
797 * - add the indicator and the off value (= curexpr's off value) to scvardata
798 */
799 scvdata = (SCVARDATA*) SCIPhashmapGetImage(nlhdlrdata->scvars, (void*)auxvar);
800 if( scvdata == NULL )
801 {
803 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &scvdata->bvars, nlhdlrexprdata->nindicators) );
804 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &scvdata->vals0, nlhdlrexprdata->nindicators) );
805 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &scvdata->lbs1, nlhdlrexprdata->nindicators) );
806 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &scvdata->ubs1, nlhdlrexprdata->nindicators) );
807 scvdata->bndssize = nlhdlrexprdata->nindicators;
808 SCIP_CALL( SCIPhashmapInsert(nlhdlrdata->scvars, auxvar, scvdata) );
809 }
810
811 SCIP_CALL( addSCVarIndicator(scip, scvdata, nlhdlrexprdata->indicators[i],
812 SCIPexprGetEvalValue(curexpr), SCIPvarGetLbGlobal(auxvar), SCIPvarGetUbGlobal(auxvar)) );
813 }
814
815 SCIP_CALL( addAuxVar(scip, nlhdlrexprdata, auxvarmap, auxvar) );
816 }
817
818 curexpr = SCIPexpriterGetNext(it);
819 }
820 }
821
822 SCIPfreeExpriter(&it);
823 SCIPhashmapFree(&auxvarmap);
824 SCIPfreeBufferArray(scip, &origvars);
825 SCIPfreeBufferArray(scip, &origvals0);
827
828 return SCIP_OKAY;
829}
830
831/*
832 * Probing and bound tightening methods
833 */
834
835/** go into probing and set some variable bounds */
836static
838 SCIP* scip, /**< SCIP data structure */
839 SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
840 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
841 SCIP_VAR* indicator, /**< indicator variable */
842 SCIP_VAR** probingvars, /**< array of vars whose bounds we will change in probing */
843 SCIP_INTERVAL* probingdoms, /**< array of intervals to which bounds of probingvars will be changed in probing */
844 int nprobingvars, /**< number of probing vars */
845 SCIP_SOL* sol, /**< solution to be separated */
846 SCIP_SOL** solcopy, /**< buffer for a copy of sol before going into probing; if *solcopy == sol, then copy is created */
847 SCIP_Bool* cutoff_probing /**< pointer to store whether indicator == 1 is infeasible */
848 )
849{
850 int v;
851 SCIP_Real newlb;
852 SCIP_Real newub;
854
856
857 /* if a copy of sol has not been created yet, then create one now and copy the relevant var values from sol,
858 * because sol can change after SCIPstartProbing, e.g., when linked to the LP solution
859 */
860 if( *solcopy == sol )
861 {
862 SCIP_CALL( SCIPcreateSol(scip, solcopy, NULL) );
863 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
864 {
865 SCIP_CALL( SCIPsetSolVal(scip, *solcopy, nlhdlrexprdata->vars[v], SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[v])) );
866 }
867 for( v = 0; v < nlhdlrexprdata->nindicators; ++v )
868 {
869 SCIP_CALL( SCIPsetSolVal(scip, *solcopy, nlhdlrexprdata->indicators[v], SCIPgetSolVal(scip, sol, nlhdlrexprdata->indicators[v])) );
870 }
871 }
872
873 /* go into probing */
875
876 /* create a probing node */
878
879 /* set indicator to 1 */
880 SCIP_CALL( SCIPchgVarLbProbing(scip, indicator, 1.0) );
881
882 /* apply stored bounds */
883 for( v = 0; v < nprobingvars; ++v )
884 {
885 newlb = SCIPintervalGetInf(probingdoms[v]);
886 newub = SCIPintervalGetSup(probingdoms[v]);
887
888 if( SCIPisGT(scip, newlb, SCIPvarGetLbLocal(probingvars[v])) || (newlb >= 0.0 && SCIPvarGetLbLocal(probingvars[v]) < 0.0) )
889 {
890 SCIP_CALL( SCIPchgVarLbProbing(scip, probingvars[v], newlb) );
891 }
892 if( SCIPisLT(scip, newub, SCIPvarGetUbLocal(probingvars[v])) || (newub <= 0.0 && SCIPvarGetUbLocal(probingvars[v]) > 0.0) )
893 {
894 SCIP_CALL( SCIPchgVarUbProbing(scip, probingvars[v], newub) );
895 }
896 }
897
898 if( propagate )
899 {
900 SCIP_Longint ndomreds;
901
902 SCIP_CALL( SCIPpropagateProbing(scip, nlhdlrdata->maxproprounds, cutoff_probing, &ndomreds) );
903 }
904
905 return SCIP_OKAY;
906}
907
908/** analyse on/off bounds on a variable
909 *
910 * analyses for
911 * 1. tightening bounds in probing for indicator = 1,
912 * 2. fixing indicator / detecting cutoff if one or both states are infeasible,
913 * 3. tightening local bounds if indicator is fixed.
914 *
915 * `probinglb` and `probingub` are only set if `doprobing` is TRUE.
916 * They are either set to bounds that should be used in probing or to `SCIP_INVALID` if bounds on
917 * `var` shouldn't be changed in probing.
918 */
919static
921 SCIP* scip, /**< SCIP data structure */
922 SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
923 SCIP_VAR* var, /**< variable */
924 SCIP_VAR* indicator, /**< indicator variable */
925 SCIP_Bool indvalue, /**< indicator value for which the bounds are applied */
926 SCIP_Bool* infeas, /**< pointer to store whether infeasibility has been detected */
927 SCIP_Real* probinglb, /**< pointer to store the lower bound to be applied in probing */
928 SCIP_Real* probingub, /**< pointer to store the upper bound to be applied in probing */
929 SCIP_Bool doprobing, /**< whether we currently consider to go into probing */
930 SCIP_Bool* reduceddom /**< pointer to store whether any variables were fixed */
931 )
932{
933 SCVARDATA* scvdata;
934 int pos;
935 SCIP_Real sclb;
936 SCIP_Real scub;
937 SCIP_Real loclb;
938 SCIP_Real locub;
939 SCIP_Bool bndchgsuccess;
940
941 assert(var != NULL);
942 assert(indicator != NULL);
943 assert(infeas != NULL);
944 assert(reduceddom != NULL);
945
946 /* shouldn't be called if indicator is fixed to !indvalue */
947 assert((indvalue && SCIPvarGetUbLocal(indicator) > 0.5) || (!indvalue && SCIPvarGetLbLocal(indicator) < 0.5));
948
949 *infeas = FALSE;
950 *reduceddom = FALSE;
951 scvdata = getSCVarDataInd(nlhdlrdata->scvars, var, indicator, &pos);
952 if( doprobing )
953 {
954 assert(probinglb != NULL);
955 assert(probingub != NULL);
956
957 *probinglb = SCIP_INVALID;
958 *probingub = SCIP_INVALID;
959 }
960
961 /* nothing to do for non-semicontinuous variables */
962 if( scvdata == NULL )
963 {
964 return SCIP_OKAY;
965 }
966
967 sclb = indvalue ? scvdata->lbs1[pos] : scvdata->vals0[pos];
968 scub = indvalue ? scvdata->ubs1[pos] : scvdata->vals0[pos];
969 loclb = SCIPvarGetLbLocal(var);
970 locub = SCIPvarGetUbLocal(var);
971
972 /* nothing to do for fixed variables */
973 if( SCIPisEQ(scip, loclb, locub) )
974 return SCIP_OKAY;
975
976 /* use a non-redundant lower bound */
977 if( SCIPisGT(scip, sclb, SCIPvarGetLbLocal(var)) || (sclb >= 0.0 && loclb < 0.0) )
978 {
979 /* first check for infeasibility */
981 {
982 SCIP_CALL( SCIPfixVar(scip, indicator, indvalue ? 0.0 : 1.0, infeas, &bndchgsuccess) );
983 *reduceddom += bndchgsuccess;
984 if( *infeas )
985 {
986 return SCIP_OKAY;
987 }
988 }
989 else if( nlhdlrdata->tightenbounds &&
990 (SCIPvarGetUbLocal(indicator) <= 0.5 || SCIPvarGetLbLocal(indicator) >= 0.5) )
991 {
992 /* indicator is fixed; due to a previous check, here it can only be fixed to indvalue;
993 * therefore, sclb is valid for the current node
994 */
995
996 if( indvalue == 0 )
997 {
998 assert(sclb == scub); /*lint !e777*/
999 SCIP_CALL( SCIPfixVar(scip, var, sclb, infeas, &bndchgsuccess) );
1000 }
1001 else
1002 {
1003 SCIP_CALL( SCIPtightenVarLb(scip, var, sclb, FALSE, infeas, &bndchgsuccess) );
1004 }
1005 *reduceddom += bndchgsuccess;
1006 if( *infeas )
1007 {
1008 return SCIP_OKAY;
1009 }
1010 }
1011 }
1012
1013 /* use a non-redundant upper bound */
1014 if( SCIPisLT(scip, scub, SCIPvarGetUbLocal(var)) || (scub <= 0.0 && locub > 0.0) )
1015 {
1016 /* first check for infeasibility */
1017 if( SCIPisFeasLT(scip, scub, SCIPvarGetLbLocal(var)) )
1018 {
1019 SCIP_CALL( SCIPfixVar(scip, indicator, indvalue ? 0.0 : 1.0, infeas, &bndchgsuccess) );
1020 *reduceddom += bndchgsuccess;
1021 if( *infeas )
1022 {
1023 return SCIP_OKAY;
1024 }
1025 }
1026 else if( nlhdlrdata->tightenbounds &&
1027 (SCIPvarGetUbLocal(indicator) <= 0.5 || SCIPvarGetLbLocal(indicator) >= 0.5) )
1028 {
1029 /* indicator is fixed; due to a previous check, here it can only be fixed to indvalue;
1030 * therefore, scub is valid for the current node
1031 */
1032
1033 if( indvalue == 0 )
1034 {
1035 assert(sclb == scub); /*lint !e777*/
1036 SCIP_CALL( SCIPfixVar(scip, var, scub, infeas, &bndchgsuccess) );
1037 }
1038 else
1039 {
1040 SCIP_CALL( SCIPtightenVarUb(scip, var, scub, FALSE, infeas, &bndchgsuccess) );
1041 }
1042 *reduceddom += bndchgsuccess;
1043 if( *infeas )
1044 {
1045 return SCIP_OKAY;
1046 }
1047 }
1048 }
1049
1050 /* If a bound change has been found and indvalue == TRUE, try to use the new bounds.
1051 * This is only done for indvalue == TRUE since this is where enfo asks other nlhdlrs to estimate,
1052 * and at indicator == FALSE we already only have a single point
1053 */
1054 if( doprobing && indvalue && (((scub - sclb) / (locub - loclb)) <= 1.0 - nlhdlrdata->mindomreduction ||
1055 (sclb >= 0.0 && loclb < 0.0) || (scub <= 0.0 && locub > 0.0)) )
1056 {
1057 *probinglb = sclb;
1058 *probingub = scub;
1059 }
1060
1061 SCIPdebugMsg(scip, "%s in [%g, %g] instead of [%g, %g] (vals0 = %g)\n", SCIPvarGetName(var), sclb, scub,
1062 SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), scvdata->vals0[pos]);
1063
1064 return SCIP_OKAY;
1065}
1066
1067/** looks for bound tightenings to be applied either in the current node or in probing
1068 *
1069 * Loops through both possible values of indicator and calls analyseVarOnoffBounds().
1070 * Might update the `*doprobing` flag by setting it to `FALSE` if:
1071 * - indicator is fixed or
1072 * - analyseVarOnoffBounds() hasn't found a sufficient improvement at indicator==1.
1073 *
1074 * If `*doprobing==TRUE`, stores bounds suggested by analyseVarOnoffBounds() in order to apply them in probing together
1075 * with the fixing `indicator=1`.
1076 */
1077static
1079 SCIP* scip, /**< SCIP data structure */
1080 SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
1081 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1082 SCIP_VAR* indicator, /**< indicator variable */
1083 SCIP_VAR*** probingvars, /**< array to store variables whose bounds will be changed in probing */
1084 SCIP_INTERVAL** probingdoms, /**< array to store bounds to be applied in probing */
1085 int* nprobingvars, /**< pointer to store number of vars whose bounds will be changed in probing */
1086 SCIP_Bool* doprobing, /**< pointer to the flag telling whether we want to do probing */
1087 SCIP_RESULT* result /**< pointer to store the result */
1088 )
1089{
1090 int v;
1091 SCIP_VAR* var;
1092 SCIP_Bool infeas;
1093 int b;
1094 SCIP_Real probinglb = SCIP_INVALID;
1095 SCIP_Real probingub = SCIP_INVALID;
1096 SCIP_Bool changed;
1097 SCIP_Bool reduceddom;
1098
1099 assert(indicator != NULL);
1100 assert(nprobingvars != NULL);
1101 assert(doprobing != NULL);
1102 assert(result != NULL);
1103
1104 changed = FALSE;
1105
1106 /* no probing if indicator already fixed */
1107 if( SCIPvarGetUbLocal(indicator) <= 0.5 || SCIPvarGetLbLocal(indicator) >= 0.5 )
1108 {
1109 *doprobing = FALSE;
1110 }
1111
1112 /* consider each possible value of indicator */
1113 for( b = 0; b < 2; ++b )
1114 {
1115 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
1116 {
1117 /* nothing left to do if indicator is already fixed to !indvalue
1118 * (checked in the inner loop since analyseVarOnoff bounds might fix the indicator)
1119 */
1120 if( (b == 1 && SCIPvarGetUbLocal(indicator) <= 0.5) || (b == 0 && SCIPvarGetLbLocal(indicator) >= 0.5) )
1121 {
1122 *doprobing = FALSE;
1123 break;
1124 }
1125
1126 var = nlhdlrexprdata->vars[v];
1127
1128 SCIP_CALL( analyseVarOnoffBounds(scip, nlhdlrdata, var, indicator, b == 1, &infeas, &probinglb,
1129 &probingub, *doprobing, &reduceddom) );
1130
1131 if( infeas )
1132 {
1134 *doprobing = FALSE;
1135 return SCIP_OKAY;
1136 }
1137 else if( reduceddom )
1138 {
1140 }
1141
1142 if( !(*doprobing) )
1143 continue;
1144
1145 /* if bounds to be applied in probing have been found, store them */
1146 if( probinglb != SCIP_INVALID ) /*lint !e777*/
1147 {
1148 assert(probingub != SCIP_INVALID); /*lint !e777*/
1149
1150 SCIP_CALL( SCIPreallocBufferArray(scip, probingvars, *nprobingvars + 1) );
1151 SCIP_CALL( SCIPreallocBufferArray(scip, probingdoms, *nprobingvars + 1) );
1152 (*probingvars)[*nprobingvars] = var;
1153 (*probingdoms)[*nprobingvars].inf = probinglb;
1154 (*probingdoms)[*nprobingvars].sup = probingub;
1155 ++*nprobingvars;
1156
1157 changed = TRUE;
1158 }
1159 }
1160 }
1161
1162 if( !changed )
1163 {
1164 *doprobing = FALSE;
1165 }
1166
1167 return SCIP_OKAY;
1168}
1169
1170/** saves local bounds on all expression variables, including auxiliary variables, obtained from propagating
1171 * indicator == 1 to the corresponding SCVARDATA (should only be used in the root node)
1172 */
1173static
1175 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1176 SCIP_HASHMAP* scvars, /**< hashmap with semicontinuous variables */
1177 SCIP_VAR* indicator /**< indicator variable */
1178 )
1179{
1180 int v;
1181 SCIP_VAR* var;
1182 SCVARDATA* scvdata;
1183 int pos;
1184 SCIP_Real lb;
1185 SCIP_Real ub;
1186
1187 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
1188 {
1189 var = nlhdlrexprdata->vars[v];
1190 lb = SCIPvarGetLbLocal(var);
1191 ub = SCIPvarGetUbLocal(var);
1192 scvdata = getSCVarDataInd(scvars, var, indicator, &pos);
1193
1194 if( scvdata != NULL )
1195 {
1196 scvdata->lbs1[pos] = MAX(scvdata->lbs1[pos], lb);
1197 scvdata->ubs1[pos] = MIN(scvdata->ubs1[pos], ub);
1198 }
1199 }
1200
1201 return SCIP_OKAY;
1202}
1203
1204/*
1205 * Callback methods of nonlinear handler
1206 */
1207
1208/** nonlinear handler copy callback */
1209static
1210SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrPerspective)
1211{ /*lint --e{715}*/
1212 assert(targetscip != NULL);
1213 assert(sourcenlhdlr != NULL);
1214
1216
1218
1219 return SCIP_OKAY;
1220}
1221
1222
1223/** callback to free data of handler */
1224static
1225SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataPerspective)
1226{ /*lint --e{715}*/
1227 SCIPfreeBlockMemory(scip, nlhdlrdata);
1228
1229 return SCIP_OKAY;
1230}
1231
1232
1233/** callback to free expression specific data */
1234static
1235SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataPerspective)
1236{ /*lint --e{715}*/
1237 SCIP_CALL( freeNlhdlrExprData(scip, *nlhdlrexprdata) );
1238 SCIPfreeBlockMemory(scip, nlhdlrexprdata);
1239
1240 return SCIP_OKAY;
1241}
1242
1243/** callback to be called in deinitialization */
1244static
1245SCIP_DECL_NLHDLREXIT(nlhdlrExitPerspective)
1246{ /*lint --e{715}*/
1247 SCIP_HASHMAPENTRY* entry;
1248 SCVARDATA* data;
1249 int c;
1250 SCIP_NLHDLRDATA* nlhdlrdata;
1251
1252 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
1253 assert(nlhdlrdata != NULL);
1254
1255 if( nlhdlrdata->scvars != NULL )
1256 {
1257 for( c = 0; c < SCIPhashmapGetNEntries(nlhdlrdata->scvars); ++c )
1258 {
1259 entry = SCIPhashmapGetEntry(nlhdlrdata->scvars, c);
1260 if( entry != NULL )
1261 {
1262 data = (SCVARDATA*) SCIPhashmapEntryGetImage(entry);
1267 SCIPfreeBlockMemory(scip, &data);
1268 }
1269 }
1270 SCIPhashmapFree(&nlhdlrdata->scvars);
1271 assert(nlhdlrdata->scvars == NULL);
1272 }
1273
1274 return SCIP_OKAY;
1275}
1276
1277/** callback to detect structure in expression tree
1278 *
1279 * We are looking for expressions g(x), where x is a vector of semicontinuous variables that all share at least one
1280 * indicator variable.
1281 */
1282static
1283SCIP_DECL_NLHDLRDETECT(nlhdlrDetectPerspective)
1284{ /*lint --e{715}*/
1285 SCIP_NLHDLRDATA* nlhdlrdata;
1286 SCIP_EXPR** varexprs;
1287 SCIP_Bool success = FALSE;
1288 int i;
1289 SCIP_Bool hassepabelow = FALSE;
1290 SCIP_Bool hassepaabove = FALSE;
1291 SCIP_Bool hasnondefault = FALSE;
1292
1293 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
1294
1295 assert(scip != NULL);
1296 assert(nlhdlr != NULL);
1297 assert(expr != NULL);
1298 assert(participating != NULL);
1299 assert(enforcing != NULL);
1300 assert(nlhdlrexprdata != NULL);
1301 assert(nlhdlrdata != NULL);
1302
1303 /* do not run if we will have no auxvar to add a cut for */
1304 if( SCIPgetExprNAuxvarUsesNonlinear(expr) == 0 )
1305 return SCIP_OKAY;
1306
1307 if( SCIPgetNBinVars(scip) == 0 )
1308 {
1309 SCIPdebugMsg(scip, "problem has no binary variables, not running perspective detection\n");
1310 return SCIP_OKAY;
1311 }
1312
1313 for( i = 0; i < SCIPgetExprNEnfosNonlinear(expr); ++i )
1314 {
1315 SCIP_NLHDLR* nlhdlr2;
1316 SCIP_NLHDLR_METHOD nlhdlr2participates;
1317 SCIP_Bool sepabelowusesactivity;
1318 SCIP_Bool sepaaboveusesactivity;
1319 SCIPgetExprEnfoDataNonlinear(expr, i, &nlhdlr2, NULL, &nlhdlr2participates, &sepabelowusesactivity, &sepaaboveusesactivity, NULL);
1320
1321 if( (nlhdlr2participates & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
1322 continue;
1323
1324 if( !SCIPnlhdlrHasEstimate(nlhdlr2) )
1325 continue;
1326
1327 if( strcmp(SCIPnlhdlrGetName(nlhdlr2), "default") != 0 )
1328 hasnondefault = TRUE;
1329
1330 /* If we are supposed to run only on convex expressions, than check whether there is a nlhdlr
1331 * that participates in separation without using activity for it. Otherwise, check for
1332 * participation regardless of activity usage.
1333 */
1334 if( (nlhdlr2participates & SCIP_NLHDLR_METHOD_SEPABELOW) && (!nlhdlrdata->convexonly || !sepabelowusesactivity) )
1335 hassepabelow = TRUE;
1336
1337 if( (nlhdlr2participates & SCIP_NLHDLR_METHOD_SEPAABOVE) && (!nlhdlrdata->convexonly || !sepaaboveusesactivity) )
1338 hassepaabove = TRUE;
1339 }
1340
1341 /* If a sum expression is handled only by default nlhdlr, then all the children will have auxiliary vars.
1342 * Since the sum will then be linear in auxiliary variables, perspective can't improve anything for it
1343 */
1344 if( SCIPisExprSum(scip, expr) && !hasnondefault )
1345 {
1346 SCIPdebugMsg(scip, "sum expr only has default exprhdlr, not running perspective detection\n");
1347 return SCIP_OKAY;
1348 }
1349
1350 /* If no other nlhdlr separates, neither does perspective (if convexonly, only separation
1351 * without using activity counts)
1352 */
1353 if( !hassepabelow && !hassepaabove )
1354 {
1355 SCIPdebugMsg(scip, "no nlhdlr separates without using activity, not running perspective detection\n");
1356 return SCIP_OKAY;
1357 }
1358
1359#ifdef SCIP_DEBUG
1360 SCIPdebugMsg(scip, "Called perspective detect, expr = %p: ", (void*)expr);
1361 SCIPprintExpr(scip, expr, NULL);
1362 SCIPdebugMsgPrint(scip, "\n");
1363#endif
1364
1365 /* allocate memory */
1366 SCIP_CALL( SCIPallocClearBlockMemory(scip, nlhdlrexprdata) );
1367 if( nlhdlrdata->scvars == NULL )
1368 {
1369 SCIP_CALL( SCIPhashmapCreate(&(nlhdlrdata->scvars), SCIPblkmem(scip), SCIPgetNVars(scip)) );
1370 }
1371
1372 /* save varexprs to nlhdlrexprdata */
1373 SCIP_CALL( SCIPgetExprNVars(scip, expr, &(*nlhdlrexprdata)->nvars) );
1374 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlhdlrexprdata)->vars, (*nlhdlrexprdata)->nvars) );
1375 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, (*nlhdlrexprdata)->nvars) );
1376 (*nlhdlrexprdata)->varssize = (*nlhdlrexprdata)->nvars;
1377 SCIP_CALL( SCIPgetExprVarExprs(scip, expr, varexprs, &(*nlhdlrexprdata)->nvars) );
1378 for( i = 0; i < (*nlhdlrexprdata)->nvars; ++i )
1379 {
1380 (*nlhdlrexprdata)->vars[i] = SCIPgetVarExprVar(varexprs[i]);
1381 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[i]) );
1382 SCIP_CALL( SCIPcaptureVar(scip, (*nlhdlrexprdata)->vars[i]) );
1383 }
1384 SCIPsortPtr((void**) (*nlhdlrexprdata)->vars, SCIPvarComp, (*nlhdlrexprdata)->nvars);
1385 SCIPfreeBufferArray(scip, &varexprs);
1386
1387 /* check if expr is semicontinuous and save indicator variables */
1388 SCIP_CALL( exprIsSemicontinuous(scip, nlhdlrdata, *nlhdlrexprdata, expr, &success) );
1389
1390 if( success )
1391 {
1392 assert(*nlhdlrexprdata != NULL);
1393 assert((*nlhdlrexprdata)->nindicators > 0);
1394
1395 if( hassepaabove )
1396 *participating |= SCIP_NLHDLR_METHOD_SEPAABOVE;
1397 if( hassepabelow )
1398 *participating |= SCIP_NLHDLR_METHOD_SEPABELOW;
1399
1400#ifdef SCIP_DEBUG
1401 SCIPinfoMessage(scip, NULL, "detected an on/off expr: ");
1402 SCIPprintExpr(scip, expr, NULL);
1403 SCIPinfoMessage(scip, NULL, "\n");
1404#endif
1405 }
1406 else
1407 {
1408 assert(*nlhdlrexprdata != NULL);
1409 SCIP_CALL( nlhdlrFreeExprDataPerspective(scip, nlhdlr, expr, nlhdlrexprdata) );
1410 }
1411
1412 return SCIP_OKAY;
1413}
1414
1415
1416/** auxiliary evaluation callback of nonlinear handler */
1417static
1418SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxPerspective)
1419{ /*lint --e{715}*/
1420 int e;
1421 SCIP_Real maxdiff;
1422 SCIP_Real auxvarvalue;
1423 SCIP_Real enfoauxval;
1424
1425 assert(scip != NULL);
1426 assert(expr != NULL);
1427 assert(auxvalue != NULL);
1428
1429 auxvarvalue = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr));
1430 maxdiff = 0.0;
1431 *auxvalue = auxvarvalue;
1432
1433 /* use the auxvalue from one of the other nlhdlrs that estimates for this expr: take the one that is farthest
1434 * from the current value of auxvar
1435 */
1436 for( e = 0; e < SCIPgetExprNEnfosNonlinear(expr); ++e )
1437 {
1438 SCIP_NLHDLR* nlhdlr2;
1439 SCIP_NLHDLREXPRDATA* nlhdlr2exprdata;
1440 SCIP_NLHDLR_METHOD nlhdlr2participation;
1441
1442 SCIPgetExprEnfoDataNonlinear(expr, e, &nlhdlr2, &nlhdlr2exprdata, &nlhdlr2participation, NULL, NULL, NULL);
1443
1444 /* skip nlhdlr that do not participate or do not provide estimate */
1445 if( (nlhdlr2participation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 || !SCIPnlhdlrHasEstimate(nlhdlr2) )
1446 continue;
1447
1448 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr2, expr, nlhdlr2exprdata, &enfoauxval, sol) );
1449
1450 SCIPsetExprEnfoAuxValueNonlinear(expr, e, enfoauxval);
1451
1452 if( REALABS(enfoauxval - auxvarvalue) > maxdiff && enfoauxval != SCIP_INVALID ) /*lint !e777*/
1453 {
1454 maxdiff = REALABS(enfoauxval - auxvarvalue);
1455 *auxvalue = enfoauxval;
1456 }
1457 }
1458
1459 return SCIP_OKAY;
1460}
1461
1462/** separation initialization method of a nonlinear handler */
1463static
1464SCIP_DECL_NLHDLRINITSEPA(nlhdlrInitSepaPerspective)
1465{ /*lint --e{715}*/
1466 int sindicators;
1467
1468 sindicators = nlhdlrexprdata->nindicators;
1469
1470 /* compute 'off' values of expr and subexprs (and thus auxvars too) */
1471 SCIP_CALL( computeOffValues(scip, SCIPnlhdlrGetData(nlhdlr), nlhdlrexprdata, expr) );
1472
1473 /* some indicator variables might have been removed if evaluation failed, check how many remain */
1474 if( nlhdlrexprdata->nindicators == 0 )
1475 {
1476 SCIPfreeBlockMemoryArray(scip, &nlhdlrexprdata->indicators, sindicators);
1477 SCIPfreeBlockMemoryArray(scip, &nlhdlrexprdata->exprvals0, sindicators);
1478 }
1479 else if( nlhdlrexprdata->nindicators < sindicators )
1480 {
1481 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlhdlrexprdata->indicators, sindicators, nlhdlrexprdata->nindicators) );
1482 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlhdlrexprdata->exprvals0, sindicators, nlhdlrexprdata->nindicators) );
1483 }
1484
1485 return SCIP_OKAY;
1486}
1487
1488/** nonlinear handler enforcement callback
1489 *
1490 * "Perspectivies" cuts produced by other nonlinear handlers.
1491 *
1492 * Suppose that we want to separate \f$x\f$ from the set \f$\{ x : g(x) \leq 0\}\f$.
1493 * If \f$g(x) = g^0\f$ if indicator \f$z = 0\f$, and a cut is given by \f$\sum_i a_ix_i + c \leq \text{aux}\f$, where \f$x_i = x_i^0\f$ if \f$z = 0\f$ for all \f$i\f$,
1494 * then the "perspectivied" cut is \f[\sum_i a_ix_i + c + (1 - z)\,(g^0 - c - \sum_i a_ix_i^0) \leq \text{aux}.\f]
1495 * This ensures that at \f$z = 1\f$, the new cut is equivalent to the given cut, and at \f$z = 0\f$ it reduces to \f$g^0 \leq \text{aux}\f$.
1496 */
1497static
1498SCIP_DECL_NLHDLRENFO(nlhdlrEnfoPerspective)
1499{ /*lint --e{715}*/
1500 SCIP_ROWPREP* rowprep;
1501 SCIP_VAR* auxvar;
1502 int i;
1503 int j;
1504 SCIP_NLHDLRDATA* nlhdlrdata;
1505 SCIP_Real cst0;
1506 SCIP_VAR* indicator;
1507 SCIP_PTRARRAY* rowpreps2;
1508 SCIP_PTRARRAY* rowpreps;
1509 int nrowpreps;
1510 SCIP_SOL* solcopy;
1511 SCIP_Bool doprobing;
1512 SCIP_BOOLARRAY* addedbranchscores2;
1513 SCIP_Bool stop;
1514 int nenfos;
1515 int* enfoposs;
1516 SCIP_SOL* soladj;
1517 int pos;
1518 SCVARDATA* scvdata;
1519
1520 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
1521
1522#ifdef SCIP_DEBUG
1523 SCIPinfoMessage(scip, NULL, "enforcement method of perspective nonlinear handler called for expr %p: ", (void*)expr);
1524 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
1525 SCIPinfoMessage(scip, NULL, " at\n");
1526 for( i = 0; i < nlhdlrexprdata->nvars; ++i )
1527 {
1528 SCIPinfoMessage(scip, NULL, "%s = %g\n", SCIPvarGetName(nlhdlrexprdata->vars[i]),
1529 SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[i]));
1530 }
1533#endif
1534
1535 assert(scip != NULL);
1536 assert(expr != NULL);
1537 assert(conshdlr != NULL);
1538 assert(nlhdlrexprdata != NULL);
1539 assert(nlhdlrdata != NULL);
1540
1541 if( nlhdlrexprdata->nindicators == 0 )
1542 {
1543 /* we might have removed all indicators in initsepa */
1545 return SCIP_OKAY;
1546 }
1547
1548 if( branchcandonly )
1549 {
1550 /* let the regular calls to the nlhdlrs after perspective register branching candidates */
1552 return SCIP_OKAY;
1553 }
1554
1555 auxvar = SCIPgetExprAuxVarNonlinear(expr);
1556 assert(auxvar != NULL);
1557
1558 /* detect should have picked only those expressions for which at least one other nlhdlr can enforce */
1560
1562
1563 doprobing = FALSE;
1564 nenfos = 0;
1565 soladj = NULL;
1566
1567 /* find suitable nlhdlrs and check if there is enough violation to do probing */
1568 for( j = 0; j < SCIPgetExprNEnfosNonlinear(expr); ++j )
1569 {
1570 SCIP_NLHDLR* nlhdlr2;
1571 SCIP_NLHDLREXPRDATA* nlhdlr2exprdata;
1572 SCIP_NLHDLR_METHOD nlhdlr2participate;
1573 SCIP_Real nlhdlr2auxvalue;
1574 SCIP_Real violation;
1575 SCIP_Bool violbelow;
1576 SCIP_Bool violabove;
1577 SCIP_Bool sepausesactivity = FALSE;
1578
1579 SCIPgetExprEnfoDataNonlinear(expr, j, &nlhdlr2, &nlhdlr2exprdata, &nlhdlr2participate, !overestimate ? &sepausesactivity : NULL, overestimate ? &sepausesactivity: NULL, &nlhdlr2auxvalue); /*lint !e826*/
1580
1581 if( nlhdlr2 == nlhdlr )
1582 continue;
1583
1584 /* if nlhdlr2 cannot estimate, then cannot use it */
1585 if( !SCIPnlhdlrHasEstimate(nlhdlr2) )
1586 continue;
1587
1588 /* if nlhdlr2 does not participate in the separation on the desired side (overestimate), then skip it */
1589 if( (nlhdlr2participate & (overestimate ? SCIP_NLHDLR_METHOD_SEPAABOVE : SCIP_NLHDLR_METHOD_SEPABELOW)) == 0 )
1590 continue;
1591
1592 /* if only working on convex-looking expressions, then skip nlhdlr if it uses activity for estimates */
1593 if( nlhdlrdata->convexonly && sepausesactivity )
1594 continue;
1595
1596 /* evalaux should have called evalaux of nlhdlr2 by now
1597 * check whether handling the violation for nlhdlr2 requires under- or overestimation and this fits to
1598 * overestimate flag
1599 */
1600 SCIP_CALL( SCIPgetExprAbsAuxViolationNonlinear(scip, expr, nlhdlr2auxvalue, sol, &violation, &violbelow,
1601 &violabove) );
1602 assert(violation >= 0.0);
1603
1604 if( (overestimate && !violabove) || (!overestimate && !violbelow) )
1605 continue;
1606
1607 /* if violation is small, cuts would likely be weak - skip perspectification */
1608 if( !allowweakcuts && violation < SCIPfeastol(scip) )
1609 continue;
1610
1611 enfoposs[nenfos] = j;
1612 ++nenfos;
1613
1614 /* enable probing if tightening the domain could be useful for nlhdlr and violation is above threshold */
1615 if( sepausesactivity && violation >= nlhdlrdata->minviolprobing )
1616 doprobing = TRUE;
1617 }
1618
1619 if( nenfos == 0 )
1620 {
1622 SCIPfreeBufferArray(scip, &enfoposs);
1623 return SCIP_OKAY;
1624 }
1625
1626 /* check probing frequency against depth in b&b tree */
1627 if( nlhdlrdata->probingfreq == -1 || (nlhdlrdata->probingfreq == 0 && SCIPgetDepth(scip) != 0) ||
1628 (nlhdlrdata->probingfreq > 0 && SCIPgetDepth(scip) % nlhdlrdata->probingfreq != 0) )
1629 doprobing = FALSE;
1630
1631 /* if addbranchscores is TRUE, then we can assume to be in enforcement and not in separation */
1632 if( nlhdlrdata->probingonlyinsepa && addbranchscores )
1633 doprobing = FALSE;
1634
1635 /* disable probing if already being in probing or if in a subscip */
1637 doprobing = FALSE;
1638
1639 nrowpreps = 0;
1641 solcopy = sol;
1642 stop = FALSE;
1643
1644 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps2) );
1645 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
1646 SCIP_CALL( SCIPcreateBoolarray(scip, &addedbranchscores2) );
1647
1648 /* build cuts for every indicator variable */
1649 for( i = 0; i < nlhdlrexprdata->nindicators && !stop; ++i )
1650 {
1651 int v;
1652 int minidx;
1653 int maxidx;
1654 int r;
1655 SCIP_VAR** probingvars;
1656 SCIP_INTERVAL* probingdoms;
1657 int nprobingvars;
1658 SCIP_Bool doprobingind;
1659 SCIP_Real indval;
1660 SCIP_Real solval;
1661 SCIP_Bool adjrefpoint;
1662
1663 indicator = nlhdlrexprdata->indicators[i];
1664 probingvars = NULL;
1665 probingdoms = NULL;
1666 nprobingvars = 0;
1667 doprobingind = doprobing;
1668 solval = SCIPgetSolVal(scip, solcopy, indicator);
1669 adjrefpoint = nlhdlrdata->adjrefpoint && !SCIPisFeasEQ(scip, solval, 1.0);
1670
1671 SCIP_CALL( analyseOnoffBounds(scip, nlhdlrdata, nlhdlrexprdata, indicator, &probingvars, &probingdoms,
1672 &nprobingvars, &doprobingind, result) );
1673
1674 /* don't add perspective cuts for fixed indicators since there is no use for perspectivy */
1675 if( SCIPvarGetLbLocal(indicator) >= 0.5 )
1676 {
1677 assert(!doprobingind);
1678 continue;
1679 }
1680
1681 if( SCIPvarGetUbLocal(indicator) <= 0.5 )
1682 { /* this case is stronger as it implies that everything is fixed; therefore we are now happy */
1683 assert(!doprobingind);
1684 SCIPfreeBufferArrayNull(scip, &probingvars);
1685 SCIPfreeBufferArrayNull(scip, &probingdoms);
1686 goto TERMINATE;
1687 }
1688
1689 if( doprobingind )
1690 {
1692 SCIP_Bool cutoff_probing = FALSE;
1694 SCIP_Bool fixed;
1695
1696#ifndef NDEBUG
1697 SCIP_Real* solvals;
1698 SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nlhdlrexprdata->nvars) );
1699 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
1700 {
1701 solvals[v] = SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[v]);
1702 }
1703#endif
1704
1705 propagate = SCIPgetDepth(scip) == 0;
1706
1707 SCIP_CALL( startProbing(scip, nlhdlrdata, nlhdlrexprdata, indicator, probingvars, probingdoms, nprobingvars,
1708 sol, &solcopy, &cutoff_probing) );
1709
1710#ifndef NDEBUG
1711 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
1712 {
1713 assert(solvals[v] == SCIPgetSolVal(scip, solcopy, nlhdlrexprdata->vars[v])); /*lint !e777*/
1714 }
1715 SCIPfreeBufferArray(scip, &solvals);
1716#endif
1717
1718 SCIPfreeBufferArrayNull(scip, &probingvars);
1719 SCIPfreeBufferArrayNull(scip, &probingdoms);
1720
1721 if( propagate )
1722 { /* we are in the root node and startProbing did propagation */
1723 /* probing propagation might have detected infeasibility */
1724 if( cutoff_probing )
1725 {
1726 /* indicator == 1 is infeasible -> set indicator to 0 */
1727
1729
1730 SCIP_CALL( SCIPfixVar(scip, indicator, 0.0, &cutoff, &fixed) );
1731
1732 if( cutoff )
1733 {
1735 goto TERMINATE;
1736 }
1737
1738 continue;
1739 }
1740
1741 /* probing propagation in the root node can provide better on/off bounds */
1742 SCIP_CALL( tightenOnBounds(nlhdlrexprdata, nlhdlrdata->scvars, indicator) );
1743 }
1744 }
1745
1746 if( adjrefpoint )
1747 {
1748 /* make sure that when we adjust the point, we don't divide by something too close to 0.0 */
1749 indval = MAX(solval, 0.1);
1750
1751 /* create an adjusted point x^adj = (x* - x0) / z* + x0 */
1752 SCIP_CALL( SCIPcreateSol(scip, &soladj, NULL) );
1753 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
1754 {
1755 if( SCIPvarGetStatus(nlhdlrexprdata->vars[v]) == SCIP_VARSTATUS_FIXED )
1756 continue;
1757
1758 scvdata = getSCVarDataInd(nlhdlrdata->scvars, nlhdlrexprdata->vars[v], indicator, &pos);
1759
1760 /* a non-semicontinuous variable must be linear in expr; skip it */
1761 if( scvdata == NULL )
1762 continue;
1763
1764 SCIP_CALL( SCIPsetSolVal(scip, soladj, nlhdlrexprdata->vars[v],
1765 (SCIPgetSolVal(scip, solcopy, nlhdlrexprdata->vars[v]) - scvdata->vals0[pos]) / indval
1766 + scvdata->vals0[pos]) );
1767 }
1768 for( v = 0; v < nlhdlrexprdata->nindicators; ++v )
1769 {
1770 if( SCIPvarGetStatus(nlhdlrexprdata->indicators[v]) == SCIP_VARSTATUS_FIXED )
1771 continue;
1772
1773 SCIP_CALL( SCIPsetSolVal(scip, soladj, nlhdlrexprdata->indicators[v],
1774 SCIPgetSolVal(scip, solcopy, nlhdlrexprdata->indicators[v])) );
1775 }
1776 if( SCIPvarGetStatus(auxvar) != SCIP_VARSTATUS_FIXED )
1777 {
1778 SCIP_CALL( SCIPsetSolVal(scip, soladj, auxvar, SCIPgetSolVal(scip, solcopy, auxvar)) );
1779 }
1780 }
1781
1782 /* use cuts from every suitable nlhdlr */
1783 for( j = 0; j < nenfos; ++j )
1784 {
1785 SCIP_Bool addedbranchscores2j;
1786 SCIP_NLHDLR* nlhdlr2;
1787 SCIP_NLHDLREXPRDATA* nlhdlr2exprdata;
1788 SCIP_Real nlhdlr2auxvalue;
1789 SCIP_Bool success2;
1790
1791 SCIPgetExprEnfoDataNonlinear(expr, enfoposs[j], &nlhdlr2, &nlhdlr2exprdata, NULL, NULL, NULL, &nlhdlr2auxvalue);
1792 assert(SCIPnlhdlrHasEstimate(nlhdlr2) && nlhdlr2 != nlhdlr);
1793
1794 SCIPdebugMsg(scip, "asking nonlinear handler %s to %sestimate\n", SCIPnlhdlrGetName(nlhdlr2), overestimate ? "over" : "under");
1795
1796 /* ask the nonlinear handler for an estimator */
1797 if( adjrefpoint )
1798 {
1799 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr2, expr, nlhdlr2exprdata, &nlhdlr2auxvalue, soladj) );
1800
1801 /* coverity[copy_paste_error] */
1802 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr2, expr,
1803 nlhdlr2exprdata, soladj,
1804 nlhdlr2auxvalue, overestimate, SCIPgetSolVal(scip, solcopy, auxvar),
1805 FALSE, rowpreps2, &success2, &addedbranchscores2j) );
1806 }
1807 else
1808 {
1809 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr2, expr,
1810 nlhdlr2exprdata, solcopy,
1811 nlhdlr2auxvalue, overestimate, SCIPgetSolVal(scip, solcopy, auxvar),
1812 FALSE, rowpreps2, &success2, &addedbranchscores2j) );
1813 }
1814
1815 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps2);
1816 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps2);
1817
1818 assert((success2 && minidx <= maxidx) || (!success2 && minidx > maxidx));
1819
1820 /* perspectivy all cuts from nlhdlr2 and add them to rowpreps */
1821 for( r = minidx; r <= maxidx; ++r )
1822 {
1823 SCIP_Real maxcoef;
1824 SCIP_Real* rowprepcoefs;
1825 SCIP_VAR** rowprepvars;
1826
1827 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps2, r);
1828 assert(rowprep != NULL);
1829
1830#ifdef SCIP_DEBUG
1831 SCIPinfoMessage(scip, NULL, "rowprep for expr ");
1832 SCIPprintExpr(scip, expr, NULL);
1833 SCIPinfoMessage(scip, NULL, "rowprep before perspectivy is: \n");
1834 SCIPprintRowprep(scip, rowprep, NULL);
1835#endif
1836
1837 /* given a rowprep: sum aixi + sum biyi + c, where xi are semicontinuous variables and yi are
1838 * non-semicontinuous variables (which appear in expr linearly, which detect must have ensured),
1839 * perspectivy the semicontinuous part by adding (1-z)(g0 - c - sum aix0i) (the constant is
1840 * treated as belonging to the semicontinuous part)
1841 */
1842
1843 /* we want cst0 = g0 - c - sum aix0i; first add g0 - c */
1844 cst0 = nlhdlrexprdata->exprvals0[i] + SCIProwprepGetSide(rowprep);
1845
1846 maxcoef = 0.0;
1847 rowprepcoefs = SCIProwprepGetCoefs(rowprep);
1848 rowprepvars = SCIProwprepGetVars(rowprep);
1849
1850 for( v = 0; v < SCIProwprepGetNVars(rowprep); ++v )
1851 {
1852 if( REALABS( rowprepcoefs[v]) > maxcoef )
1853 {
1854 maxcoef = REALABS(rowprepcoefs[v]);
1855 }
1856
1857 scvdata = getSCVarDataInd(nlhdlrdata->scvars, rowprepvars[v], indicator, &pos);
1858
1859 /* a non-semicontinuous variable must be linear in expr; skip it */
1860 if( scvdata == NULL )
1861 continue;
1862
1863 cst0 -= rowprepcoefs[v] * scvdata->vals0[pos];
1864 }
1865
1866 /* only perspectivy when the absolute value of cst0 is not too small
1867 * TODO on ex1252a there was cst0=0 - ok to still use the cut?
1868 */
1869 if( cst0 == 0.0 || maxcoef / REALABS(cst0) <= 10.0 / SCIPfeastol(scip) )
1870 {
1871 /* update the rowprep by adding cst0 - cst0*z */
1872 SCIProwprepAddConstant(rowprep, cst0);
1873 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, indicator, -cst0) );
1874 }
1875 else
1876 {
1877 SCIPfreeRowprep(scip, &rowprep);
1878 continue;
1879 }
1880
1881 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
1882
1883 SCIPdebugMsg(scip, "rowprep after perspectivy is: \n");
1884#ifdef SCIP_DEBUG
1885 SCIPprintRowprep(scip, rowprep, NULL);
1886#endif
1887
1888 SCIP_CALL( SCIPsetPtrarrayVal(scip, rowpreps, nrowpreps, rowprep) );
1889 SCIP_CALL( SCIPsetBoolarrayVal(scip, addedbranchscores2, nrowpreps, addedbranchscores2j) );
1890 ++nrowpreps;
1891 }
1892
1893 SCIP_CALL( SCIPclearPtrarray(scip, rowpreps2) );
1894 }
1895
1896 if( adjrefpoint )
1897 {
1898 SCIP_CALL( SCIPfreeSol(scip, &soladj) );
1899 }
1900
1901 if( doprobingind )
1902 {
1904 }
1905
1906 /* add all cuts found for indicator i */
1907 for( r = SCIPgetPtrarrayMinIdx(scip, rowpreps); r <= SCIPgetPtrarrayMaxIdx(scip, rowpreps) && !stop; ++r )
1908 {
1909 SCIP_RESULT resultr;
1910
1911#ifdef SCIP_DEBUG
1912 SCIPprintRowprep(scip, rowprep, NULL);
1913#endif
1914 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
1915 resultr = SCIP_DIDNOTFIND;
1916
1917 (void) strcat(SCIProwprepGetName(rowprep), "_persp_indicator_");
1918 (void) strcat(SCIProwprepGetName(rowprep), SCIPvarGetName(indicator));
1919
1920 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar, auxvalue,
1921 allowweakcuts, SCIPgetBoolarrayVal(scip, addedbranchscores2, r), FALSE, solcopy, &resultr) );
1922
1923 if( resultr == SCIP_SEPARATED )
1925 else if( resultr == SCIP_CUTOFF )
1926 {
1928 stop = TRUE;
1929 }
1930 else if( resultr == SCIP_BRANCHED )
1931 {
1934 }
1935 else if( resultr != SCIP_DIDNOTFIND )
1936 {
1937 SCIPerrorMessage("estimate called by perspective nonlinear handler returned invalid result <%d>\n", resultr);
1938 return SCIP_INVALIDRESULT;
1939 }
1940 }
1941
1942 /* free all rowpreps for indicator i */
1943 for( r = SCIPgetPtrarrayMinIdx(scip, rowpreps); r <= SCIPgetPtrarrayMaxIdx(scip, rowpreps); ++r )
1944 {
1945 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
1946 SCIPfreeRowprep(scip, &rowprep);
1947 }
1948
1949 SCIP_CALL( SCIPclearPtrarray(scip, rowpreps) );
1950 }
1951
1952TERMINATE:
1953 SCIP_CALL( SCIPfreeBoolarray(scip, &addedbranchscores2) );
1954 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
1955 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps2) );
1956 if( solcopy != sol )
1957 {
1958 SCIP_CALL( SCIPfreeSol(scip, &solcopy) );
1959 }
1960 SCIPfreeBufferArray(scip, &enfoposs);
1961
1962 return SCIP_OKAY;
1963}
1964
1965
1966/*
1967 * nonlinear handler specific interface methods
1968 */
1969
1970/** includes perspective nonlinear handler in nonlinear constraint handler */
1972 SCIP* scip /**< SCIP data structure */
1973 )
1974{
1975 SCIP_NLHDLRDATA* nlhdlrdata;
1976 SCIP_NLHDLR* nlhdlr;
1977
1978 assert(scip != NULL);
1979
1980 /* create nonlinear handler data */
1981 SCIP_CALL( SCIPallocBlockMemory(scip, &nlhdlrdata) );
1982 BMSclearMemory(nlhdlrdata);
1983
1985 NLHDLR_ENFOPRIORITY, nlhdlrDetectPerspective, nlhdlrEvalauxPerspective, nlhdlrdata) );
1986 assert(nlhdlr != NULL);
1987
1988 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/maxproprounds",
1989 "maximal number of propagation rounds in probing",
1990 &nlhdlrdata->maxproprounds, FALSE, DEFAULT_MAXPROPROUNDS, -1, INT_MAX, NULL, NULL) );
1991
1992 SCIP_CALL( SCIPaddRealParam(scip, "nlhdlr/" NLHDLR_NAME "/mindomreduction",
1993 "minimal relative reduction in a variable's domain for applying probing",
1994 &nlhdlrdata->mindomreduction, FALSE, DEFAULT_MINDOMREDUCTION, 0.0, 1.0, NULL, NULL) );
1995
1996 SCIP_CALL( SCIPaddRealParam(scip, "nlhdlr/" NLHDLR_NAME "/minviolprobing",
1997 "minimal violation w.r.t. auxiliary variables for applying probing",
1998 &nlhdlrdata->minviolprobing, FALSE, DEFAULT_MINVIOLPROBING, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1999
2000 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/probingonlyinsepa",
2001 "whether to do probing only in separation",
2002 &nlhdlrdata->probingonlyinsepa, FALSE, DEFAULT_PROBINGONLYINSEPA, NULL, NULL) );
2003
2004 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/probingfreq",
2005 "probing frequency (-1 - no probing, 0 - root node only)",
2006 &nlhdlrdata->probingfreq, FALSE, DEFAULT_PROBINGFREQ, -1, INT_MAX, NULL, NULL) );
2007
2008 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/convexonly",
2009 "whether perspective cuts are added only for convex expressions",
2010 &nlhdlrdata->convexonly, FALSE, DEFAULT_CONVEXONLY, NULL, NULL) );
2011
2012 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/tightenbounds",
2013 "whether variable semicontinuity is used to tighten variable bounds",
2014 &nlhdlrdata->tightenbounds, FALSE, DEFAULT_TIGHTENBOUNDS, NULL, NULL) );
2015
2016 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/adjrefpoint",
2017 "whether to adjust the reference point",
2018 &nlhdlrdata->adjrefpoint, FALSE, DEFAULT_ADJREFPOINT, NULL, NULL) );
2019
2020 SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrPerspective);
2021 SCIPnlhdlrSetFreeHdlrData(nlhdlr, nlhdlrFreehdlrdataPerspective);
2022 SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrFreeExprDataPerspective);
2023 SCIPnlhdlrSetInitExit(nlhdlr, NULL, nlhdlrExitPerspective);
2024 SCIPnlhdlrSetSepa(nlhdlr, nlhdlrInitSepaPerspective, nlhdlrEnfoPerspective, NULL, NULL);
2025
2026 return SCIP_OKAY;
2027}
#define DEFAULT_MAXPROPROUNDS
SCIP_VAR ** b
constraint handler for nonlinear constraints specified by algebraic expressions
#define NULL
Definition def.h:257
#define SCIP_Longint
Definition def.h:150
#define SCIP_REAL_MAX
Definition def.h:167
#define SCIP_INVALID
Definition def.h:187
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define REALABS(x)
Definition def.h:191
#define SCIP_CALL(x)
Definition def.h:364
void SCIPcomputeArraysIntersectionPtr(void **array1, int narray1, void **array2, int narray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void **intersectarray, int *nintersectarray)
Definition misc.c:10583
unsigned int SCIPgetExprNAuxvarUsesNonlinear(SCIP_EXPR *expr)
void SCIPgetExprEnfoDataNonlinear(SCIP_EXPR *expr, int idx, SCIP_NLHDLR **nlhdlr, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_NLHDLR_METHOD *nlhdlrparticipation, SCIP_Bool *sepabelowusesactivity, SCIP_Bool *sepaaboveusesactivity, SCIP_Real *auxvalue)
void SCIPsetExprEnfoAuxValueNonlinear(SCIP_EXPR *expr, int idx, SCIP_Real auxvalue)
SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPprocessRowprepNonlinear(SCIP *scip, SCIP_NLHDLR *nlhdlr, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_ROWPREP *rowprep, SCIP_Bool overestimate, SCIP_VAR *auxvar, SCIP_Real auxvalue, SCIP_Bool allowweakcuts, SCIP_Bool branchscoresuccess, SCIP_Bool inenforcement, SCIP_SOL *sol, SCIP_RESULT *result)
int SCIPgetExprNEnfosNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPgetExprAbsAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
int SCIPgetSubscipDepth(SCIP *scip)
Definition scip_copy.c:2589
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
int SCIPgetNBinVars(SCIP *scip)
Definition scip_prob.c:2293
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
Definition misc.c:3613
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3304
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3284
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition misc.c:3143
int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
Definition misc.c:3584
SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
Definition misc.c:3592
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3400
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
#define SCIPdebugMsgPrint
#define SCIPdebugMsg
SCIP_RETCODE SCIPincludeNlhdlrPerspective(SCIP *scip)
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
int SCIPgetPtrarrayMinIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
SCIP_Bool SCIPgetBoolarrayVal(SCIP *scip, SCIP_BOOLARRAY *boolarray, int idx)
SCIP_RETCODE SCIPclearPtrarray(SCIP *scip, SCIP_PTRARRAY *ptrarray)
void * SCIPgetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx)
SCIP_RETCODE SCIPfreePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
SCIP_RETCODE SCIPfreeBoolarray(SCIP *scip, SCIP_BOOLARRAY **boolarray)
int SCIPgetPtrarrayMaxIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
SCIP_RETCODE SCIPsetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx, void *val)
SCIP_RETCODE SCIPcreateBoolarray(SCIP *scip, SCIP_BOOLARRAY **boolarray)
SCIP_RETCODE SCIPsetBoolarrayVal(SCIP *scip, SCIP_BOOLARRAY *boolarray, int idx, SCIP_Bool val)
SCIP_RETCODE SCIPcreatePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition scip_expr.c:1661
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition expr.c:3872
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition expriter.c:969
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1479
SCIP_RETCODE SCIPgetExprNVars(SCIP *scip, SCIP_EXPR *expr, int *nvars)
Definition scip_expr.c:2083
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition scip_expr.c:1443
SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
Definition expriter.c:683
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1457
SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
Definition scip_expr.c:2362
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition scip_expr.c:1512
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition expr.c:3946
SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
Definition expriter.c:858
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition expr.c:3882
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition expr_var.c:423
void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
Definition scip_expr.c:2376
SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
Definition expriter.c:501
SCIP_RETCODE SCIPgetExprVarExprs(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **varexprs, int *nvarexprs)
Definition scip_expr.c:2121
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
struct SCIP_Interval SCIP_INTERVAL
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
#define SCIPallocClearBlockMemory(scip, ptr)
Definition scip_mem.h:91
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition scip_mem.h:126
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:93
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition scip_mem.h:111
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
void SCIPnlhdlrSetInitExit(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINIT((*init)),)
Definition nlhdlr.c:111
SCIP_NLHDLRDATA * SCIPnlhdlrGetData(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:217
void SCIPnlhdlrSetFreeExprData(SCIP_NLHDLR *nlhdlr,)
Definition nlhdlr.c:99
const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:167
SCIP_Bool SCIPnlhdlrHasEstimate(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:277
void SCIPnlhdlrSetSepa(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINITSEPA((*initsepa)), SCIP_DECL_NLHDLRENFO((*enfo)), SCIP_DECL_NLHDLRESTIMATE((*estimate)),)
Definition nlhdlr.c:137
void SCIPnlhdlrSetFreeHdlrData(SCIP_NLHDLR *nlhdlr,)
Definition nlhdlr.c:88
void SCIPnlhdlrSetCopyHdlr(SCIP_NLHDLR *nlhdlr,)
Definition nlhdlr.c:77
SCIP_RETCODE SCIPincludeNlhdlrNonlinear(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
SCIP_RETCODE SCIPsetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition scip_sol.c:1660
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition scip_sol.c:1569
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6401
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition var.c:24514
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition var.c:24536
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23418
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition var.c:23530
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6651
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23485
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition var.c:24546
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition var.c:24556
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_Bool SCIPvarIsRelaxationOnly(SCIP_VAR *var)
Definition var.c:23632
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition var.c:24526
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:10318
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition var.c:24588
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition var.c:24568
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition var.c:24578
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1853
SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
SCIP_Real SCIProwprepGetSide(SCIP_ROWPREP *rowprep)
SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
void SCIProwprepAddConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
return SCIP_OKAY
SCIPfreeSol(scip, &heurdata->sol))
SCIPcreateSol(scip, &heurdata->sol, heur))
struct SCVarData SCVARDATA
int c
SCIPendProbing(scip))
SCIP_Bool cutoff
static SCIP_SOL * sol
int r
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
#define BMSclearMemory(ptr)
Definition memory.h:129
private functions of nonlinear handlers of nonlinear constraints
#define NLHDLR_DETECTPRIORITY
#define NLHDLR_ENFOPRIORITY
#define NLHDLR_DESC
#define NLHDLR_NAME
static SCIP_RETCODE varIsSemicontinuous(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *scvars, SCIP_Bool *result)
static SCIP_RETCODE tightenOnBounds(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_HASHMAP *scvars, SCIP_VAR *indicator)
#define DEFAULT_MINVIOLPROBING
static SCIP_RETCODE freeNlhdlrExprData(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata)
static SCIP_RETCODE startProbing(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *indicator, SCIP_VAR **probingvars, SCIP_INTERVAL *probingdoms, int nprobingvars, SCIP_SOL *sol, SCIP_SOL **solcopy, SCIP_Bool *cutoff_probing)
static SCIP_RETCODE removeIndicator(SCIP *scip, SCIP_NLHDLREXPRDATA *nlexprdata, int pos)
static SCIP_RETCODE exprIsSemicontinuous(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_EXPR *expr, SCIP_Bool *res)
#define DEFAULT_TIGHTENBOUNDS
#define DEFAULT_ADJREFPOINT
static SCIP_RETCODE analyseVarOnoffBounds(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_VAR *var, SCIP_VAR *indicator, SCIP_Bool indvalue, SCIP_Bool *infeas, SCIP_Real *probinglb, SCIP_Real *probingub, SCIP_Bool doprobing, SCIP_Bool *reduceddom)
#define DEFAULT_MINDOMREDUCTION
#define DEFAULT_PROBINGFREQ
static SCIP_RETCODE addAuxVar(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_HASHMAP *auxvarmap, SCIP_VAR *auxvar)
#define DEFAULT_PROBINGONLYINSEPA
#define DEFAULT_CONVEXONLY
static SCIP_RETCODE analyseOnoffBounds(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *indicator, SCIP_VAR ***probingvars, SCIP_INTERVAL **probingdoms, int *nprobingvars, SCIP_Bool *doprobing, SCIP_RESULT *result)
static SCIP_RETCODE addSCVarIndicator(SCIP *scip, SCVARDATA *scvdata, SCIP_VAR *indicator, SCIP_Real val0, SCIP_Real lb1, SCIP_Real ub1)
static SCIP_RETCODE computeOffValues(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_EXPR *expr)
static SCVARDATA * getSCVarDataInd(SCIP_HASHMAP *scvars, SCIP_VAR *var, SCIP_VAR *indicator, int *pos)
perspective nonlinear handler
#define SCIPerrorMessage
Definition pub_message.h:64
preparation of a linear inequality to become a SCIP_ROW
public methods for solutions
SCIP_Real * vals0
SCIP_VAR ** bvars
struct SCIP_Expr SCIP_EXPR
Definition type_expr.h:55
struct SCIP_ExprIter SCIP_EXPRITER
Definition type_expr.h:722
@ SCIP_EXPRITER_DFS
Definition type_expr.h:718
struct SCIP_RowPrep SCIP_ROWPREP
Definition type_misc.h:173
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
struct SCIP_HashMapEntry SCIP_HASHMAPENTRY
Definition type_misc.h:100
struct SCIP_PtrArray SCIP_PTRARRAY
Definition type_misc.h:124
struct SCIP_BoolArray SCIP_BOOLARRAY
Definition type_misc.h:121
#define SCIP_NLHDLR_METHOD_SEPAABOVE
Definition type_nlhdlr.h:52
#define SCIP_DECL_NLHDLREVALAUX(x)
struct SCIP_NlhdlrData SCIP_NLHDLRDATA
#define SCIP_NLHDLR_METHOD_SEPABOTH
Definition type_nlhdlr.h:53
#define SCIP_DECL_NLHDLRCOPYHDLR(x)
Definition type_nlhdlr.h:70
unsigned int SCIP_NLHDLR_METHOD
Definition type_nlhdlr.h:57
#define SCIP_DECL_NLHDLREXIT(x)
#define SCIP_DECL_NLHDLRFREEEXPRDATA(x)
Definition type_nlhdlr.h:94
#define SCIP_DECL_NLHDLRDETECT(x)
struct SCIP_Nlhdlr SCIP_NLHDLR
#define SCIP_DECL_NLHDLRINITSEPA(x)
#define SCIP_DECL_NLHDLRFREEHDLRDATA(x)
Definition type_nlhdlr.h:82
struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
#define SCIP_DECL_NLHDLRENFO(x)
#define SCIP_NLHDLR_METHOD_SEPABELOW
Definition type_nlhdlr.h:51
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_BRANCHED
Definition type_result.h:54
@ SCIP_SEPARATED
Definition type_result.h:49
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_INVALIDRESULT
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64
@ SCIP_VARSTATUS_FIXED
Definition type_var.h:54